而传统的python对C 库调用方法,需要自己编写很多封装函数,且聚宽的策略回测平台本身也不支持调用本地的C 库。
这时可以借助一个开源的第三方平台hikyuu来方便地完成该需求。将jqdata与hikyuu整合起来实现C /python混合编程。
首先我们需要在hikyuu的C 工程文件中添加自己的策略代码,自己的策略代码可以作为自定义指标的一部分。
在hikyuu_msvc10工程下增加一个指标,首先在indicator/crt目录下增加一个策略的包装头文件,例如一个移动平均线的策略:
#ifndef EMA_H_
#define EMA_H_
#include "../Indicator.h"
namespace hku {
/**
* 指数移动平均线(Exponential Moving Average)
* @param n 计算均值的周期窗口,必须为大于0的整数
* @ingroup Indicator
*/
Indicator HKU_API EMA(int n = 22);
/**
* 指数移动平均线(Exponential Moving Average)
* @param data 待计算的源数据
* @param n 计算均值的周期窗口,必须为大于0的整数
* @ingroup Indicator
*/
Indicator HKU_API EMA(const Indicator& data, int n = 22);
} /* namespace */
#endif /* EMA_H_ */
然后在indicator/imp目录中增加这个策略的实现类,包含头文件和实现文件:
#ifndef EMA_H_
#define EMA_H_
#include "../Indicator.h"
namespace hku {
/*
* 指数移动平均线(Exponential Moving Average)
* 参数: n: 计算均值的周期窗口,必须为大于0的整数
* 抛弃数 = 0
*/
class Ema: public IndicatorImp {
INDICATOR_IMP(Ema)
INDICATOR_IMP_NO_PRIVATE_MEMBER_SERIALIZATION
public:
Ema();
virtual ~Ema();
};
} /* namespace hku */
#endif /* EMA_H_ */
#include "Ema.h"
namespace hku {
Ema::Ema(): IndicatorImp("EMA", 1) {
setParam("n", 22);
}
Ema::~Ema() {
}
bool Ema::check() {
int n = getParam("n");
if (n <= 0) {
HKU_ERROR("Invalid param[n] must > 0 ! [Ema::check]");
return false;
}
return true;
}
void Ema::_calculate(const Indicator& indicator) {
size_t total = indicator.size();
int n = getParam("n");
m_discard = indicator.discard();
if (total <= m_discard) {
return;
}
size_t startPos = discard();
price_t ema = indicator[startPos];
_set(ema, startPos);
price_t multiplier = 2.0 / (n 1);
for (size_t i = startPos 1; i < total; i) {
ema = (indicator[i] - ema) * multiplier ema;
_set(ema, i);
}
}
Indicator HKU_API EMA(int n) {
IndicatorImpPtr p = make_shared();
p->setParam("n", n);
return Indicator(p);
}
Indicator HKU_API EMA(const Indicator& data, int n) {
IndicatorImpPtr p = make_shared();
p->setParam("n", n);
p->calculate(data);
return Indicator(p);
}
} /* namespace hku */
最后在indicator目录下的build_in.h文件中增加包含关系:
#include "crt/EMA.h"
在indicator目录下的export.cpp文件中导出策略类:
#include "imp/Ema.h"
BOOST_CLASS_EXPORT(hku::Ema)
最后编译整个hikyuu_msvc10工程得到一个新的dll库,直接代替原hikyuu相应的dll库就实现了C 策略类的导出。
第二步就是在python中直接使用这个新的移动平均线策略指标。
首先导入jqdata和hikyuu
from jqdatasdk import *
from hikyuu.interactive.interactive import *
然后封装一个由jqdata作为数据源的自定义数据源类,具体的要实现的接口可以参考hikyuu平台的文档。这个封装只需要编写一次即可,不需要每个策略都编写。
封装类如下:
from .._hikyuu import KDataDriver, DataDriverFactory
from hikyuu import KRecord, Query, Datetime, Parameter
from jqdatasdk import *
from datetime import *
class jqdataKDataDriver(KDataDriver):
def __init__(self):
super(jqdataKDataDriver, self).__init__('jqdata')
def _init(self):
"""【重载接口】(可选)初始化子类私有变量"""
self._max = {Query.DAY:10,
Query.WEEK:2,
Query.MONTH:1,
Query.QUARTER:1,
#Query.HALFYEAR:1,
Query.YEAR:1,
Query.MIN:25,
Query.MIN5:25,
Query.MIN15:25,
Query.MIN30:25,
Query.MIN60:25}
return
def loadKData(self, market, code, ktype, start_ix, end_ix, out_buffer):
"""
【重载接口】(必须)按指定的位置[start_ix, end_ix)读取K线数据至out_buffer
:param str market: 市场标识
:param str code: 证券代码
:param KQuery.KType ktype: K线类型
:param int start_ix: 起始位置
:param int end_ix: 结束位置
:param KRecordListPtr out_buffer: 传入的数据缓存,读取数据后使用
out_buffer.append(krecord) 加入数据
"""
if start_ix >= end_ix or start_ix <0 or end_ix <0:
return
data = self._get_bars(market, code, ktype)
if len(data) < start_ix:
return
total = end_ix if end_ix < len(data) else len(data)
for i in range(start_ix, total):
record = KRecord()
record.datetime = Datetime(data.index[i])
record.openPrice = data['open'][i]
record.highPrice = data['high'][i]
record.lowPrice = data['low'][i]
record.closePrice = data['close'][i]
record.transAmount = data['money'][i]
record.transCount = data['volume'][i]
out_buffer.append(record)
def getCount(self, market, code, ktype):
"""
【重载接口】(必须)获取K线数量
:param str market: 市场标识
:param str code: 证券代码
:param KQuery.KType ktype: K线类型
"""
data = self._get_bars(market, code, ktype)
return len(data)
def _getIndexRangeByDate(self, market, code, query):
"""
【重载接口】(必须)按日期获取指定的K线数据
:param str market: 市场标识
:param str code: 证券代码
:param KQuery query: 日期查询条件(QueryByDate)
"""
print("getIndexRangeByDate")
if query.queryType != Query.DATE:
return (0, 0)
start_datetime = query.startDatetime
end_datetime = query.endDatetime
if start_datetime >= end_datetime or start_datetime > Datetime.max():
return (0, 0)
data = self._get_bars(market, code, query.kType)
total = len(data)
if total == 0:
return (0, 0)
mid, low = 0, 0
high = total-1
while low <= high:
tmp_datetime = Datetime(data.index[high])
if start_datetime > tmp_datetime:
mid = high 1
break
tmp_datetime = Datetime(data.index[low])
if tmp_datetime >= start_datetime:
mid = low
break
mid = (low high) // 2
tmp_datetime = Datetime(data.index[mid])
if start_datetime > tmp_datetime:
low = mid 1
else:
high = mid - 1
if mid >= total:
return (0, 0)
start_pos = mid
low = mid
high = total - 1
while low <= high:
tmp_datetime = Datetime(data.index[high])
if end_datetime > tmp_datetime:
mid = high 1
break
tmp_datetime = Datetime(data.index[low])
if tmp_datetime >= end_datetime:
mid = low
break
mid = (low high) // 2
tmp_datetime = Datetime(data.index[mid])
if end_datetime > tmp_datetime:
low = mid 1
else:
high = mid - 1
end_pos = total if mid >= total else mid
if start_pos >= end_pos:
return (0,0)
return (start_pos, end_pos)
def getKRecord(self, market, code, pos, ktype):
"""
【重载接口】(必须)获取指定位置的K线记录
:param str market: 市场标识
:param str code: 证券代码
:param int pos: 指定位置(大于等于0)
:param KQuery.KType ktype: K线类型
"""
record = KRecord()
if pos < 0:
return record
data = self._get_bars(market, code, ktype)
if data is None:
return record
if pos < len(data):
record.datetime = Datetime(data.index[pos])
record.openPrice = data['open'][pos]
record.highPrice = data['high'][pos]
record.lowPrice = data['low'][pos]
record.closePrice = data['close'][pos]
record.transAmount = data['money'][pos]
record.transCount = data['volume'][pos]
return record
def _trans_ktype(self, ktype): #此处的周月季年数据只是近似的,目前jqdata未提供聚宽网络平台上的get_bar函数,不能直接取,需要自行用日线数据拼装
ktype_map = {Query.MIN: '1m',
Query.MIN5: '5m',
Query.MIN15: '15m',
Query.MIN30: '30m',
Query.MIN60: '60m',
Query.DAY: '1d',
Query.WEEK: '7d',
Query.MONTH: '30d',
Query.QUARTER: '90d',
Query.YEAR: '365d'}
return ktype_map.get(ktype)
def _get_bars(self, market, code, ktype):
data = []
username = self.getParam('username')
password = self.getParam('password')
auth(username, password)
jqdataCode = normalize_code(code)
jqdata_ktype = self._trans_ktype(ktype)
if jqdata_ktype is None:
print("jqdata_ktype == None")
return data
print(jqdataCode)
security_info = get_security_info(jqdataCode)
if security_info is None: #有可能取不到任何信息
return data
#print(security_info)
data = get_price(jqdataCode, security_info.start_date, datetime.now(), jqdata_ktype)
return data
在interactive.py文件中替换原来的数据源即可
DataDriverFactory.regKDataDriver(jqdataKDataDriver())
jqdata_param = Parameter()
jqdata_param.set('type', 'jqdata')
jqdata_param.set('username', '用户名')
jqdata_param.set('password', '密码')
base_param = sm.getBaseInfoDriverParameter()
block_param = sm.getBlockDriverParameter()
kdata_param = sm.getKDataDriverParameter()
preload_param = sm.getPreloadParameter()
hku_param = sm.getHikyuuParameter()
#切换K线数据驱动,重新初始化
sm.init(base_param, block_param, jqdata_param, preload_param, hku_param)
最后一步就是在python中直接使用jqdata数据源调用C 编写的指标了
s = sm['sz000001']
k = s.getKData(Query(-200))
#抽取K线收盘价指标,一般指标计算参数只能是指标类型,所以必须先将K线数据生成指标类型
c = CLOSE(k)
#调用自定义的C 均线策略计算收盘价的EMA指标
a = EMA(c)
#绘制指标
c.plot(legend_on=True)
a.plot(new=False, legend_on=True)
#绘制柱状图
a.bar()
以上三步,中最复杂的第二步,写一次后就可以通用,这样可以大大简化,python中,调用C 策略库的难度。
很多时候为了运行复杂的策略用python速度会很慢,而核心部分用C 编写可以大幅提升策略的运行速度。另外通达信、金字塔等主流证券软件都支持C 的dll库,而且可以很方便地图形化展示策略结果,那么策略核心部分用C 编写成dll库也是一种通用的跨平台方案。
而传统的python对C 库调用方法,需要自己编写很多封装函数,且聚宽的策略回测平台本身也不支持调用本地的C 库。
这时可以借助一个开源的第三方平台hikyuu来方便地完成该需求。将jqdata与hikyuu整合起来实现C /python混合编程。
首先我们需要在hikyuu的C 工程文件中添加自己的策略代码,自己的策略代码可以作为自定义指标的一部分。
在hikyuu_msvc10工程下增加一个指标,首先在indicator/crt目录下增加一个策略的包装头文件,例如一个移动平均线的策略:
#ifndef EMA_H_
#define EMA_H_
namespace hku {
/**
* 指数移动平均线(Exponential Moving Average)
Indicator HKU_API EMA(int n = 22);
/**
* 指数移动平均线(Exponential Moving Average)
* @param data 待计算的源数据
* @param n 计算均值的周期窗口,必须为大于0的整数
* @ingroup Indicator
*/
Indicator HKU_API EMA(const Indicator& data, int n = 22);
} /* namespace */
然后在indicator/imp目录中增加这个策略的实现类,包含头文件和实现文件:
namespace hku {
/*
* 指数移动平均线(Exponential Moving Average)
* 参数: n: 计算均值的周期窗口,必须为大于0的整数
* 抛弃数 = 0
*/
class Ema: public IndicatorImp {
INDICATOR_IMP(Ema)
INDICATOR_IMP_NO_PRIVATE_MEMBER_SERIALIZATION
public:
Ema();
virtual ~Ema();
};
} /* namespace hku */
namespace hku {
Ema::Ema(): IndicatorImp(“EMA”, 1) {
setParam(“n”, 22);
}
Ema::~Ema() {
}
bool Ema::check() {
int n = getParam(“n”);
if (n <= 0) {
HKU_ERROR(“Invalid param[n] must > 0 ! [Ema::check]”);
return false;
}
return true;
}
void Ema::_calculate(const Indicator& indicator) {
size_t total = indicator.size();
int n = getParam(“n”);
m_discard = indicator.discard();
if (total <= m_discard) {
return;
}
size_t startPos = discard();
price_t ema = indicator[startPos];
_set(ema, startPos);
price_t multiplier = 2.0 / (n 1);
for (size_t i = startPos 1; i < total; i) {
ema = (indicator[i] - ema) * multiplier ema;
_set(ema, i);
}
}
Indicator HKU_API EMA(int n) {
IndicatorImpPtr p = make_shared();
p->setParam(“n”, n);
return Indicator§;
}
Indicator HKU_API EMA(const Indicator& data, int n) {
IndicatorImpPtr p = make_shared();
p->setParam(“n”, n);
p->calculate(data);
return Indicator§;
}
} /* namespace hku */
最后在indicator目录下的build_in.h文件中增加包含关系:
#include "crt/EMA.h"
在indicator目录下的export.cpp文件中导出策略类:
#include "imp/Ema.h"
BOOST_CLASS_EXPORT(hku::Ema)
最后编译整个hikyuu_msvc10工程得到一个新的dll库,直接代替原hikyuu相应的dll库就实现了C 策略类的导出。
第二步就是在python中直接使用这个新的移动平均线策略指标。
首先导入jqdata和hikyuu
from jqdatasdk import *
from hikyuu.interactive.interactive import *
然后封装一个由jqdata作为数据源的自定义数据源类,具体的要实现的接口可以参考hikyuu平台的文档。这个封装只需要编写一次即可,不需要每个策略都编写。
封装类如下:
from .._hikyuu import KDataDriver, DataDriverFactory
from hikyuu import KRecord, Query, Datetime, Parameter
from jqdatasdk import *
from datetime import *
class jqdataKDataDriver(KDataDriver):
def init(self):
super(jqdataKDataDriver, self).init(‘jqdata’)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_init</span><span class="hljs-params">(self)</span>:</span>
<span class="hljs-string">"""【重载接口】(可选)初始化子类私有变量"""</span>
self._max = {Query.DAY:<span class="hljs-number">10</span>,
Query.WEEK:<span class="hljs-number">2</span>,
Query.MONTH:<span class="hljs-number">1</span>,
Query.QUARTER:<span class="hljs-number">1</span>,
<span class="hljs-comment">#Query.HALFYEAR:1,</span>
Query.YEAR:<span class="hljs-number">1</span>,
Query.MIN:<span class="hljs-number">25</span>,
Query.MIN5:<span class="hljs-number">25</span>,
Query.MIN15:<span class="hljs-number">25</span>,
Query.MIN30:<span class="hljs-number">25</span>,
Query.MIN60:<span class="hljs-number">25</span>}
<span class="hljs-keyword">return</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">loadKData</span><span class="hljs-params">(self, market, code, ktype, start_ix, end_ix, out_buffer)</span>:</span>
<span class="hljs-string">"""
【重载接口】(必须)按指定的位置[start_ix, end_ix)读取K线数据至out_buffer
:param str market: 市场标识
:param str code: 证券代码
:param KQuery.KType ktype: K线类型
:param int start_ix: 起始位置
:param int end_ix: 结束位置
:param KRecordListPtr out_buffer: 传入的数据缓存,读取数据后使用
out_buffer.append(krecord) 加入数据
"""</span>
<span class="hljs-keyword">if</span> start_ix >= end_ix <span class="hljs-keyword">or</span> start_ix <<span class="hljs-number">0</span> <span class="hljs-keyword">or</span> end_ix <<span class="hljs-number">0</span>:
<span class="hljs-keyword">return</span>
data = self._get_bars(market, code, ktype)
<span class="hljs-keyword">if</span> len(data) < start_ix:
<span class="hljs-keyword">return</span>
total = end_ix <span class="hljs-keyword">if</span> end_ix < len(data) <span class="hljs-keyword">else</span> len(data)
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(start_ix, total):
record = KRecord()
record.datetime = Datetime(data.index[i])
record.openPrice = data[<span class="hljs-string">'open'</span>][i]
record.highPrice = data[<span class="hljs-string">'high'</span>][i]
record.lowPrice = data[<span class="hljs-string">'low'</span>][i]
record.closePrice = data[<span class="hljs-string">'close'</span>][i]
record.transAmount = data[<span class="hljs-string">'money'</span>][i]
record.transCount = data[<span class="hljs-string">'volume'</span>][i]
out_buffer.append(record)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">getCount</span><span class="hljs-params">(self, market, code, ktype)</span>:</span>
<span class="hljs-string">"""
【重载接口】(必须)获取K线数量
:param str market: 市场标识
:param str code: 证券代码
:param KQuery.KType ktype: K线类型
"""</span>
data = self._get_bars(market, code, ktype)
<span class="hljs-keyword">return</span> len(data)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_getIndexRangeByDate</span><span class="hljs-params">(self, market, code, query)</span>:</span>
<span class="hljs-string">"""
【重载接口】(必须)按日期获取指定的K线数据
:param str market: 市场标识
:param str code: 证券代码
:param KQuery query: 日期查询条件(QueryByDate)
"""</span>
print(<span class="hljs-string">"getIndexRangeByDate"</span>)
<span class="hljs-keyword">if</span> query.queryType != Query.DATE:
<span class="hljs-keyword">return</span> (<span class="hljs-number">0</span>, <span class="hljs-number">0</span>)
start_datetime = query.startDatetime
end_datetime = query.endDatetime
<span class="hljs-keyword">if</span> start_datetime >= end_datetime <span class="hljs-keyword">or</span> start_datetime > Datetime.max():
<span class="hljs-keyword">return</span> (<span class="hljs-number">0</span>, <span class="hljs-number">0</span>)
data = self._get_bars(market, code, query.kType)
total = len(data)
<span class="hljs-keyword">if</span> total == <span class="hljs-number">0</span>:
<span class="hljs-keyword">return</span> (<span class="hljs-number">0</span>, <span class="hljs-number">0</span>)
mid, low = <span class="hljs-number">0</span>, <span class="hljs-number">0</span>
high = total<span class="hljs-number">-1</span>
<span class="hljs-keyword">while</span> low <= high:
tmp_datetime = Datetime(data.index[high])
<span class="hljs-keyword">if</span> start_datetime > tmp_datetime:
mid = high <span class="hljs-number">1</span>
<span class="hljs-keyword">break</span>
tmp_datetime = Datetime(data.index[low])
<span class="hljs-keyword">if</span> tmp_datetime >= start_datetime:
mid = low
<span class="hljs-keyword">break</span>
mid = (low high) // <span class="hljs-number">2</span>
tmp_datetime = Datetime(data.index[mid])
<span class="hljs-keyword">if</span> start_datetime > tmp_datetime:
low = mid <span class="hljs-number">1</span>
<span class="hljs-keyword">else</span>:
high = mid - <span class="hljs-number">1</span>
<span class="hljs-keyword">if</span> mid >= total:
<span class="hljs-keyword">return</span> (<span class="hljs-number">0</span>, <span class="hljs-number">0</span>)
start_pos = mid
low = mid
high = total - <span class="hljs-number">1</span>
<span class="hljs-keyword">while</span> low <= high:
tmp_datetime = Datetime(data.index[high])
<span class="hljs-keyword">if</span> end_datetime > tmp_datetime:
mid = high <span class="hljs-number">1</span>
<span class="hljs-keyword">break</span>
tmp_datetime = Datetime(data.index[low])
<span class="hljs-keyword">if</span> tmp_datetime >= end_datetime:
mid = low
<span class="hljs-keyword">break</span>
mid = (low high) // <span class="hljs-number">2</span>
tmp_datetime = Datetime(data.index[mid])
<span class="hljs-keyword">if</span> end_datetime > tmp_datetime:
low = mid <span class="hljs-number">1</span>
<span class="hljs-keyword">else</span>:
high = mid - <span class="hljs-number">1</span>
end_pos = total <span class="hljs-keyword">if</span> mid >= total <span class="hljs-keyword">else</span> mid
<span class="hljs-keyword">if</span> start_pos >= end_pos:
<span class="hljs-keyword">return</span> (<span class="hljs-number">0</span>,<span class="hljs-number">0</span>)
<span class="hljs-keyword">return</span> (start_pos, end_pos)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">getKRecord</span><span class="hljs-params">(self, market, code, pos, ktype)</span>:</span>
<span class="hljs-string">"""
【重载接口】(必须)获取指定位置的K线记录
:param str market: 市场标识
:param str code: 证券代码
:param int pos: 指定位置(大于等于0)
:param KQuery.KType ktype: K线类型
"""</span>
record = KRecord()
<span class="hljs-keyword">if</span> pos < <span class="hljs-number">0</span>:
<span class="hljs-keyword">return</span> record
data = self._get_bars(market, code, ktype)
<span class="hljs-keyword">if</span> data <span class="hljs-keyword">is</span> <span class="hljs-keyword">None</span>:
<span class="hljs-keyword">return</span> record
<span class="hljs-keyword">if</span> pos < len(data):
record.datetime = Datetime(data.index[pos])
record.openPrice = data[<span class="hljs-string">'open'</span>][pos]
record.highPrice = data[<span class="hljs-string">'high'</span>][pos]
record.lowPrice = data[<span class="hljs-string">'low'</span>][pos]
record.closePrice = data[<span class="hljs-string">'close'</span>][pos]
record.transAmount = data[<span class="hljs-string">'money'</span>][pos]
record.transCount = data[<span class="hljs-string">'volume'</span>][pos]
<span class="hljs-keyword">return</span> record
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_trans_ktype</span><span class="hljs-params">(self, ktype)</span>:</span> <span class="hljs-comment">#此处的周月季年数据只是近似的,目前jqdata未提供聚宽网络平台上的get_bar函数,不能直接取,需要自行用日线数据拼装</span>
ktype_map = {Query.MIN: <span class="hljs-string">'1m'</span>,
Query.MIN5: <span class="hljs-string">'5m'</span>,
Query.MIN15: <span class="hljs-string">'15m'</span>,
Query.MIN30: <span class="hljs-string">'30m'</span>,
Query.MIN60: <span class="hljs-string">'60m'</span>,
Query.DAY: <span class="hljs-string">'1d'</span>,
Query.WEEK: <span class="hljs-string">'7d'</span>,
Query.MONTH: <span class="hljs-string">'30d'</span>,
Query.QUARTER: <span class="hljs-string">'90d'</span>,
Query.YEAR: <span class="hljs-string">'365d'</span>}
<span class="hljs-keyword">return</span> ktype_map.get(ktype)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_get_bars</span><span class="hljs-params">(self, market, code, ktype)</span>:</span>
data = []
username = self.getParam(<span class="hljs-string">'username'</span>)
password = self.getParam(<span class="hljs-string">'password'</span>)
auth(username, password)
jqdataCode = normalize_code(code)
jqdata_ktype = self._trans_ktype(ktype)
<span class="hljs-keyword">if</span> jqdata_ktype <span class="hljs-keyword">is</span> <span class="hljs-keyword">None</span>:
print(<span class="hljs-string">"jqdata_ktype == None"</span>)
<span class="hljs-keyword">return</span> data
print(jqdataCode)
security_info = get_security_info(jqdataCode)
<span class="hljs-keyword">if</span> security_info <span class="hljs-keyword">is</span> <span class="hljs-keyword">None</span>: <span class="hljs-comment">#有可能取不到任何信息</span>
<span class="hljs-keyword">return</span> data
<span class="hljs-comment">#print(security_info)</span>
data = get_price(jqdataCode, security_info.start_date, datetime.now(), jqdata_ktype)
<span class="hljs-keyword">return</span> data
在interactive.py文件中替换原来的数据源即可
DataDriverFactory.regKDataDriver(jqdataKDataDriver())
jqdata_param = Parameter()
jqdata_param.set('type', 'jqdata')
jqdata_param.set('username', '用户名')
jqdata_param.set('password', '密码')
base_param = sm.getBaseInfoDriverParameter()
block_param = sm.getBlockDriverParameter()
kdata_param = sm.getKDataDriverParameter()
preload_param = sm.getPreloadParameter()
hku_param = sm.getHikyuuParameter()
#切换K线数据驱动,重新初始化
sm.init(base_param, block_param, jqdata_param, preload_param, hku_param)
最后一步就是在python中直接使用jqdata数据源调用C 编写的指标了
s = sm['sz000001']
k = s.getKData(Query(-200))
#抽取K线收盘价指标,一般指标计算参数只能是指标类型,所以必须先将K线数据生成指标类型
c = CLOSE(k)
#调用自定义的C 均线策略计算收盘价的EMA指标
a = EMA(c)
#绘制指标
c.plot(legend_on=True)
a.plot(new=False, legend_on=True)
#绘制柱状图
a.bar()
以上三步,中最复杂的第二步,写一次后就可以通用,这样可以大大简化,python中,调用C 策略库的难度。