![]() |
气势凌人的莴苣 · Ora-01426: Numeric ...· 4 月前 · |
![]() |
侠义非凡的课本 · 陈丹青《局部》 - 播单 - 优酷视频· 7 月前 · |
![]() |
焦虑的铁板烧 · 百亿资产转移英国 重病缠身“跑路”加拿大 ...· 7 月前 · |
![]() |
成熟的沙滩裤 · 如何在XPath中找到第一级别的嵌套元素?· 11 月前 · |
![]() |
小胡子的大葱 · 成都实时技术股份有限公司· 1 年前 · |
感谢您使用一创一创聚宽量化交易云平台量化交易云平台量化交易平台,以下内容主要介绍一创聚宽量化交易云平台量化交易平台的API使用方法,目录中带有”♠” 标识的API是
"回测环境/模拟"
的专用API,
不能在研究模块中调用
。
内容较多,可使用
Ctrl+F
进行搜索。
如果以下内容仍没有解决您的问题,请您通过 社区提问 的方式告诉我们,谢谢。
先来看一个简单但是完整的策略:
def initialize(context):
# 定义一个全局变量, 保存要操作的股票
g.security = '000001.XSHE'
# 运行函数
run_daily(market_open, time='every_bar')
def market_open(context):
if g.security not in context.portfolio.positions:
order(g.security, 1000)
else:
order(g.security, -800)
一个完整策略只需要两步:
这个策略里, 每当我们没有股票时就买入1000股, 每当我们有股票时又卖出800股, 具体的下单API请看 order 函数.
这个策略里, 我们有了交易, 但是只是无意义的交易, 没有依据当前的数据做出合理的分析
下面我们来看一个真正实用的策略
在这个策略里, 我们会根据历史价格做出判断:
def initialize(context):
# 按月运行
run_monthly(func, monthday, time='open', reference_security)
# 按周运行
run_weekly(func, weekday, time='open', reference_security)
# 每天内何时运行
run_daily(func, time='open', reference_security)
具体参见 定时运行
一个字符串,可以是具体执行时间,支持 time 表达式。比如 “10:00”, “01:00”, 或者 “every_bar”, “open”, “before_open”, “after_close”, “morning” 和 “night”。(具体执行时间如见下方)def weekly(context):
print 'weekly %s %s' % (context.current_dt, context.current_dt.isoweekday())
def monthly(context):
print 'monthly %s %s' % (context.current_dt, context.current_dt.month)
def daily(context):
print 'daily %s' % context.current_dt
def initialize(context):
# 指定每月第一个交易日, 在开盘后一小时10分钟执行
run_monthly(monthly, 1, 'open + 1h10m')
# 指定每天收盘前10分钟运行
run_daily(daily, 'close - 10m')
# 指定每天收盘后执行
run_daily(daily, 'after_close')
# 指定在每天的10:00运行
run_daily(daily, '10:00')
# 参照股指期货的时间每分钟运行一次, 必须选择分钟回测, 否则每天执行
run_daily(daily, 'every_bar', reference_security='IF1512.CCFX')
handle_data(context, data)
该函数每个单位时间会调用一次, 如果按天回测,则每天调用一次,如果按分钟,则每分钟调用一次。
该函数依据的时间是股票的交易时间,即 9:30 - 15:00. 期货请使用 定时运行 函数。
该函数在回测中的非交易日是不会触发的(如回测结束日期为2016年1月5日,则程序在2016年1月1日-3日时,handle_data不会运行,4日继续运行)。
对于使用当日开盘价撮合的日级模拟盘,在9:25集合竞价完成时就可以获取到开盘价,出于减少并发运行模拟盘数量的目的,我们会提前到9:27~9:30之间运行, 策略类获取到逻辑时间(context.current_dt)仍然是 9:30。
context: Context 对象, 存放有当前的账户/标的持仓信息
data[security]
时该 security 的数据才会被获取.
def handle_data(context, data):
order("000001.XSHE",100)
before_trading_start(context)
该函数会在每天开始交易前被调用一次, 您可以在这里添加一些每天都要初始化的东西.
该函数依据的时间是股票的交易时间,即该函数启动时间为 9:00. 期货请使用 定时运行 函数,time 参数设定为’before_open’ 。
context: Context 对象, 存放有当前的账户/股票持仓信息
def before_trading_start(context):
log.info(str(context.current_dt))
after_trading_end(context)
该函数会在每天结束交易后被调用一次, 您可以在这里添加一些每天收盘后要执行的内容. 这个时候所有未完成的订单已经取消.
该函数依据的时间是股票的交易时间,即该函数启动时间为 15:30. 期货请使用 定时运行 函数,time 参数设定为’after_close’ 。
context: Context 对象, 存放有当前的账户/股票持仓信息
def after_trading_end(context):
log.info(str(context.current_dt))
process_initialize(context)
该函数会在每次模拟盘/回测进程重启时执行, 一般用来初始化一些 不能持久化保存 的内容. 在 initialize 后执行.
因为模拟盘会每天重启, 所以这个函数会每天都执行.
context: Context 对象, 存放有当前的账户/股票持仓信息
def process_initialize(context):
# query 对象不能被 pickle 序列化, 所以不能持久保存, 所以每次进程重启时都给它初始化
# 以两个下划线开始, 系统序列化 [g] 时就会自动忽略这个变量, 更多信息, 请看 [g] 和 [模拟盘注意事项]
g.__q = query(valuation)
def handle_data(context, data):
get_fundamentals(g.__q)
def on_strategy_end(context)
在回测、模拟交易正常结束时被调用, 失败时不会被调用。
在模拟交易到期结束时也会被调用, 手动在到期前关闭不会被调用。
context: Context 对象, 存放有当前的账户/股票持仓信息
def on_strategy_end(context):
print '回测结束'
after_code_changed(context)
模拟盘在每天的交易时间结束后会休眠,第二天开盘时会恢复,如果在恢复时发现代码已经发生了修改,则会在恢复时执行这个函数。
具体的使用场景:可以利用这个函数修改一些模拟盘的数据。
注意: 因为一些原因, 执行回测时这个函数也会被执行一次, 在 process_initialize 执行完之后执行.
context: Context 对象, 存放有当前的账户/股票持仓信息
def after_code_changed(context):
g.stock = '000001.XSHE'
回测时您的策略会在一个安全的进程中执行, 我们使用了进程隔离的方案来确保系统不会被任何用户的代码攻击, 每个用户的代码都运行在一个有很强限制的进程中:
我们使用了linux内核级别的apparmer技术来实现这一点.
有了这些限制我们确保了任何用户不能侵入我们的系统, 更别提盗取他人的策略了.
2. 频率详解
下列图片中齿轮为 handle_data(context, data) 的运行时间,before_trading_start(context) 等其他函数运行时间详见 相关API 。
当选择天频率时, 算法在每根日线 Bar 都会运行一次,即每天运行一次。
在算法中,可以获取任何粒度的数据。
频率:分钟
当选择分钟频率时, 算法在每根分钟 Bar 都会运行一次,即每分钟运行一次。
在算法中,可以获取任何粒度的数据。
频率:Tick
当选择 Tick 频率时,每当新来一个 Tick,算法都会被执行一次。
执行示意图如下图所示:
所有市价单下单之后同步完成(也即 order_XXX 系列函数返回时完成), context.portfolio 会同步变化
上述过程中, 如果实际价格已经涨停或者跌停, 则相对应的买单或卖单不成交, 市价单直接取消(log中有警告信息), 限价单会挂单直到可以成交.
所有市价单下单之后同步完成(也即 order_XXX 系列函数返回时完成), context.portfolio 会同步变化
模拟交易(天、分钟、Tick):
不是立即完成, 下单之后 context.portfolio.cash 和 context.portfolio.positions 不会同步变化.
按天模拟交易暂时不支持限价单
上述过程中, 如果实际价格已经涨停或者跌停, 则相对应的买单或卖单不成交, 市价单直接取消(log中有警告信息), 限价单会挂单直到可以成交.
真实价格(动态复权)回测模式: 当股票发生拆分,合并或者分红时,会按照历史情况,对账户进行处理,会在账户账户中增加现金或持股数量发生变化,并会有日志提示。
注: 传统前复权回测模式 与 真实价格(动态复权)回测模式 区别 见这里
在回测及模拟交易中,由于需要在分红当天将扣税后的分红现金发放到账户,因此无法准确计算用户的持仓时间(不知道股票卖出时间),我们的计算方式是,统一按照 20% 的税率计算的。
在实战交易中,往往最终成交价和预期价格有一定偏差,因此我们加入了滑点模式来帮助您更好地模拟真实市场的表现。
您可以通过 set_slippage 来设置回测具体的滑点参数。
交易税费包含券商手续费和印花税。您可以通过 set_order_cost 来设置具体的交易税费的参数。
中国A股市场目前为双边收费,券商手续费系默认值为万分之三,即0.03%,最少5元。
印花税对卖方单边征收,对买方不再征收,系统默认为千分之一,即0.1%。
风险指标数据有利于您对策略进行一个客观的评价。
注意 : 无论是回测还是模拟, 所有风险指标(年化收益/alpha/beta/sharpe/max_drawdown等指标)都只会 每天更新一次, 也只根据每天收盘后的收益计算, 并不考虑每天盘中的收益情况 . 例外:
那么可能会造成这种现象: 模拟时收益曲线中有回撤, 但是 max_drawdown 可能为0.
盘中运行:
run_daily(func, '14:50')
会在每天的14:50:00(精确到秒)执行
收盘后(15:00后半小时内)运行:
同一个时间点, 总是先运行 run_XXX 指定的函数, 然后是 before_trading_start , handle_data 和 after_trading_end
g
将不能被保存, 因为 query() 返回的对象并不能被持久化. 重启后也不会再执行
initialize
, 使用 g.query 将会抛出 AttributeError 异常
正确的做法是, 在
process_initialize
中初始化它, 并且名字以 ‘__’ 开头.
def process_initialize(context):
g.__query = query(valuation)
注意: 涉及到IO(打开的文件, 网络连接, 数据库连接)的对象是不能被序列化的:
query(valuation)
: 数据库连接
open("some/path")
: 打开的文件
requests.get('')
: 网络连接
恢复过程是这样的:
重启后不再执行 initialize 函数, initialize 函数在整个模拟盘的生命周期中只执行一次. 即使是更改回测后, initialize 也不会执行.
模拟盘更改回测之后上述的全局变量(包括 g 和 context 中保存的)不会丢失. 新代码中
initialize
不会执行.
如果需要修改原来的值, 可以在
after_code_changed
函数里面修改, 比如, 原来代码是:
a = 1
def initialize(context):
g.stock = '000001.XSHE'
代码改成:
a = 2
def initialize(context):
g.stock = '000002.XSHE'
执行时, a 仍然是 1, g.stock 仍然是 ‘000001.XSHE’, 要修改他们的值, 必须定义 after_code_changed :
def after_code_changed(context):
global a
a = 2
g.stock = '000002.XSHE'
创建模拟交易时, 如果选择的日期是今天, 则从今天当前时间点开始运行, 应该在当前时间点之前运行的函数不再运行. 比如: 今天10:00创建了 按天 的模拟交易, 选择日期是今天, 代码中实现了 handle_data 和 after_trading_end, 则 handle_data 今天不运行, 而 after_trading_end 会在 15:10 运行
当模拟交易在A时间点失败后, 然后在B时间点”重跑”, 那么 A-B 之间的时间点应该运行的函数不再运行
因为模拟盘资源有限, 为了防止用户创建之后长期搁置浪费资源, 我们做出如下限制: 如果一个模拟盘同时满足下面条件, 则暂缓运行:
当用户重新使用网站后, 第二天会继续运行(会把之前的交易日执行一遍, 并不会跳过日期)
强烈建议模拟盘使用真实价格成交, 即调用
set_option('use_real_price', True)
. 更多细节请看
set_option
这会导致同样的日期同样的程序回测结果可能会和模拟交易结果不一样, 请注意
按天模拟交易暂时不支持限价单, 所有限价单会自动转成市价单
理论上对运行结果不会有影响: 模拟交易进程每天会重启(请看[模拟交易注意事项]). 回测进程一般不会重启, 如果需要重启(比如机器宕机了) 也会做和模拟交易同样的处理.
"回测环境/模拟"
专用的API,
不能在研究模块中调用
。整个 【jqdata 模块】在研究环境与回测环境下都可以使用.
如需使用 分仓操作 ,请看 账户分仓操作 .
set_benchmark(security)
默认我们选定了沪深300指数的每日价格作为判断您策略好坏和一系列风险值计算的基准. 您也可以使用 set_benchmark 指定其他股票/指数/ETF的价格作为基准。注意:这个函数只能在initialize中调用。
set_benchmark('600000.XSHG')
set_order_cost(cost, type, ref=None)
指定每笔交易要收取的手续费, 系统会根据用户指定的费率计算每笔交易的手续费
cost: OrderCost 对象
type: 股票、基金、金融期货、期货、债券基金、股票基金、QDII 基金、货币基金、混合基金,’stock’/ ‘fund’ / ‘index_futures’ / ‘futures’ / ‘bond_fund’ / ‘stock_fund’ / ‘QDII_fund’ / ‘money_market_fund’ / ‘mixture_fund’
默认与示例
# 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5), type='stock')
# 期货类每笔交易时的手续费是:买入时万分之0.23,卖出时万分之0.23,平今仓为万分之23
set_order_cost(OrderCost(open_tax=0, close_tax=0, open_commission=0.000023, close_commission=0.000023, close_today_commission=0.0023, min_commission=0), type='index_futures')
# 单独设置 000300.XSHG 的费用
set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5), type='stock', ref='000300.XSHG')
# 设置所有期货(包括金融指数期货)的费用
set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5), type='futures')
# 对 IF/IH/IC 三个品种有效
set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5), type='index_futures')
# 单独设置AU期货品种的费用
set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5), type='futures', ref='AU')
# 单独设置AU1709合约的费用
set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5), type='futures', ref='AU1709')
注:期货持仓到交割日会以当天结算价平仓, 没有手续费, 不会有交易记录.
set_slippage(object)
设定滑点,回测/模拟时有效.
当您下单后, 真实的成交价格与下单时预期的价格总会有一定偏差, 因此我们加入了滑点模式来帮您更好的模拟真实市场的表现. 我们暂时只支持固定滑点
当您使用固定滑点的时候, 我们认为您的落单的多少并不会影响您最后的成交价格. 您只需要指定一个价差,这个价差可以是一个固定的值(比如0.02元, 交易时加减0.01元), 设定方式为:FixedSlippage(0.02) 这个价差可以是是当时价格的一个百分比(比如0.2%, 交易时加减当时价格的0.1%), 设定方式为:PriceRelatedSlippage(0.002)
该设定必须在
initialize
中调用
设置是否开启动态复权(真实价格)模式,
原理讲解图示见帖子
。默认是False(主要是为了让旧的策略不会出错).
是否开启动态复权模式对模拟交易是有影响的,
详情参见这里
。
# 开启动态复权模式
set_option('use_real_price', True)
是否开启动态复权对于回测及模拟交易的影响:
1.
动态复权原理
2.
是否开启动态复权模式对模拟交易的影响
开启 ,value 值为 True: 回测过程中:
history(3, '1d', 'close')
取得的就是你穿越到2015-01-01这一天所看到的前复权价格. 另一方面, 你在不同日期调用
history
/
attribute_history
/
get_price
/
SecurityUnitData
.mavg/vwap 返回的价格可能是不一样的, 因为我们在不同日期看到的前复权价格是不一样的. 所以
不要跨日期缓存这些API返回的结果.
注意事项:
如果想通过 history 拿到昨天的真实价格, 还是需要用取得价格除以factor, 因为可能今天发生了拆合分红, 导致拿到的昨天的价格是相对于今天的前复权价格.
s = '000001.XSHE'
df = attribute_history(s, 1, '1d', fields=['close', 'factor'])
real_close = df['close'][-1] / df['factor'][-1]
关闭 ,value 值为 False: 此选项的核心是选定一个日期作为基准, 保证这个日期的价格是真实价格, 然后调整其他日期的价格. 最终保证所有价格是连续的, 在回测或者模拟交易过程中不同日期看到的价格是一致的. 下面分回测和模拟交易单独做介绍:
模拟交易: 基准日期是建立模拟交易的日期, 模拟交易过程所看到的所有价格都是基于此日期调整过的. 为了方便计算, 我举一个虚拟的例子: 某只股票在如下三个日期的实际价格和后复权因子分别是:
为了更好的模拟, 建议大家都设成 True. 将来对接实盘交易时, 此选项会强制设成 True
注意: 设置 use_real_price 为 True之后, 如下的按天回测的代码是不对的:
def initialize(context):
g.cached_data = []
g.s = '000001.XSHE'
def handle_data(content, data):
g.cached_data.append(data)
if len(g.cached_data) > 1:
# 如果昨天收盘价比前天涨了5%, 则买入. 这是不对的, 如果昨天早上发生了拆合, 则昨天和前天的股价不具可比性.
if g.cached_data[-1][g.s].close > g.cached_data[-2][g.s].close * 1.05:
order(g.s, 1000)
set_option('order_volume_ratio', value)
设定成交量比例,根据实际行情限制每个订单的成交量.
value: value 是一个 float 值, 根据实际行情限制每个订单的成交量.
对于每一笔订单:
如果是限价单, 限价单撮合 时设定分价表中每一个价格的成交量的比率, 假设某一分钟分价表如下:
get_price(security, start_date=None, end_date=None, frequency='daily', fields=None, skip_paused=False, fq='pre', count=None)
获取一支或者多只股票的行情数据, 按天或者按分钟,这里在使用时注意 end_date 的设置, 不要引入未来的数据。
关于停牌 : 因为此API可以获取多只股票的数据, 可能有的股票停牌有的没有, 为了保持时间轴的一致,
我们默认没有跳过停牌的日期, 停牌时使用停牌前的数据填充(请看 SecurityUnitData 的 paused 属性). 如想跳过, 请使用 skip_paused=True 参数, 同时只取一只股票的信息
datetime.datetime(2015, 1, 1, 10, 0, 0)
或者
'2015-01-01 10:00:00'
.
frequency: 单位时间长度, 几天或者几分钟, 现在支持’Xd’,’Xm’, ‘daily’(等同于’1d’), ‘minute’(等同于’1m’), X是一个正整数, 分别表示X天和X分钟(不论是按天还是按分钟回测都能拿到这两种单位的数据), 注意, 当X > 1时, fields只支持[‘open’, ‘close’, ‘high’, ‘low’, ‘volume’, ‘money’]这几个标准字段. 默认值是daily
fields: 字符串list, 选择要获取的行情数据字段, 默认是None(表示[‘open’, ‘close’, ‘high’, ‘low’, ‘volume’, ‘money’]这几个标准字段), 支持 SecurityUnitData 里面的所有基本属性,,包含:[‘open’, ’ close’, ‘low’, ‘high’, ‘volume’, ‘money’, ‘factor’, ‘high_limit’,’ low_limit’, ‘avg’, ’ pre_close’, ‘paused’]
skip_paused: 是否跳过不交易日期(包括停牌, 未上市或者退市后的日期). 如果不跳过, 停牌时会使用停牌前的数据填充(具体请看SecurityUnitData的paused属性), 上市前或者退市后数据都为 nan, 但要注意:
fq: 复权选项:
'pre'
: 前复权(根据’use_real_price’选项不同含义会有所不同, 参见
set_option
), 默认是前复权
None
: 不复权, 返回实际价格
'post'
: 后复权
请注意, 为了方便比较一只股票的多个属性, 同时也满足对比多只股票的一个属性的需求, 我们在security参数是一只股票和多只股票时返回的结构完全不一样
如果是一支股票, 则返回
pandas.DataFrame
对象, 行索引是
datetime.datetime
对象, 列索引是行情字段名字, 比如’open’/’close’. 比如:
get_price('000300.XSHG')[:2]
返回:
# 获取一支股票
df = get_price('000001.XSHE') # 获取000001.XSHE的2015年的按天数据
df = get_price('000001.XSHE', start_date='2015-01-01', end_date='2015-01-31 23:00:00', frequency='minute', fields=['open', 'close']) # 获得000001.XSHG的2015年01月的分钟数据, 只获取open+close字段
df = get_price('000001.XSHE', count = 2, end_date='2015-01-31', frequency='daily', fields=['open', 'close']) # 获取获得000001.XSHG在2015年01月31日前2个交易日的数据
df = get_price('000001.XSHE', start_date='2015-12-01 14:00:00', end_date='2015-12-02 12:00:00', frequency='1m') # 获得000001.XSHG的2015年12月1号14:00-2015年12月2日12:00的分钟数据
# 获取多只股票
panel = get_price(get_index_stocks('000903.XSHG')) # 获取中证100的所有成分股的2015年的天数据, 返回一个[pandas.Panel]
df_open = panel['open'] # 获取开盘价的[pandas.DataFrame], 行索引是[datetime.datetime]对象, 列索引是股票代号
df_volume = panel['volume'] # 获取交易量的[pandas.DataFrame]
df_open['000001.XSHE'] # 获取平安银行的2015年每天的开盘价数据
history(count, unit='1d', field='avg', security_list=None, df=True, skip_paused=False, fq='pre')
回测环境/模拟专用API
查看历史的行情数据。
关于停牌 : 因为获取了多只股票的数据, 可能有的股票停牌有的没有, 为了保持时间轴的一致, 我们默认没有跳过停牌的日期, 停牌时使用停牌前的数据填充(请看 SecurityUnitData 的paused属性). 如想跳过, 请使用 skip_paused=True 参数
当取天数据时, 不包括当天的, 即使是在收盘后
skip_paused: 是否跳过不交易日期(包括停牌, 未上市或者退市后的日期). 如果不跳过, 停牌时会使用停牌前的数据填充(具体请看SecurityUnitData的paused属性), 上市前或者退市后数据都为 nan, 但要注意:
fq: 复权选项:
'pre'
: 前复权(根据’use_real_price’选项不同含义会有所不同, 参见
set_option
), 默认是前复权
None
: 不复权, 返回实际价格
'post'
: 后复权
df=True:
pandas.DataFrame
对象, 行索引是
datetime.datetime
对象, 列索引是股票代号. 比如: 如果当前时间是2015-01-07, universe是[‘000300.XSHG’, ‘000001.XSHE’],
history(2, '1d', 'open')
将返回:
关于numpy和pandas, 请看下面的第三方库介绍
df=False:
dict, key是股票代码, 值是一个numpy数组
numpy.ndarray
, 对应上面的DataFrame的每一列, 例如
history(2, '1d', 'open', df=False)
将返回:
h = history(5, security_list=['000001.XSHE', '000002.XSHE'])
h['000001.XSHE'] #000001(平安银行)过去5天的每天的平均价, 一个pd.Series对象, index是datatime
h['000001.XSHE'][-1] #000001(平安银行)昨天(数组最后一项)的平均价
h.iloc[-1] #所有股票在昨天的平均价, 一个pd.Series对象, index是股票代号
h.iloc[-1]['000001.XSHE'] #000001(平安银行)昨天(数组最后一项)的平均价
h.mean() # 取得每一列的平均值
## set_universe 之后可以,调用 history 可以不用指定 security_list
set_universe(['000001.XSHE']) # 设定universe
history(5) # 获取universe中股票的过去5天(不包含今天)的每天的平均价
history(5, '1m') # 获取universe中股票的过去5分钟(不包含当前分钟)的每分钟的平均价
history(5, '1m', 'price') # 获取universe中股票的过去5分钟(不包含当前分钟)的每分钟的平均价
history(5, '1m', 'volume') # 获取universe中股票的过去5分钟(不包含当前分钟)的每分钟的交易额
history(5, '1m', 'price', ['000001.XSHE']) # 获取平安银行的过去5分钟(不包含当前分钟)的每分钟的平均价
h = history(5, security_list=['000001.XSHE', '000002.XSHE'], df=False)
h['000001.XSHE'] #h 是一个 dict,获取 h 中 000001.XSHE 对应的值。
h['000001.XSHE'][0] #返回000001.XSHE最新一日的数据
h['000001.XSHE'][-1] #返回000001.XSHE第五天的数据
h['000001.XSHE'].sum() #对返回的五日数据求和
h['000001.XSHE'].mean() # 对返回的五日数据求平均
# 因为h本身是一个dict, 下列panda.DataFrame的特性将不可用:
# h.illoc[-1]
# h.sum()
attribute_history(security, count, unit='1d',
fields=['open', 'close', 'high', 'low', 'volume', 'money'],
skip_paused=True, df=True, fq='pre')
回测环境/模拟专用API
查看某一支股票的历史数据, 可以选这只股票的多个属性, 默认跳过停牌日期 .
当取天数据时, 不包括当天的, 即使是在收盘后
df: 若是True, 返回 pandas.DataFrame , 否则返回一个dict, 具体请看下面的返回值介绍. 默认是True.我们之所以增加df参数, 是因为 pandas.DataFrame 创建和操作速度太慢, 很多情况并不需要使用它. 为了保持向上兼容, df默认是True, 但是如果你的回测速度很慢, 请考虑把df设成False.
fq: 复权选项:
'pre'
: 前复权(根据’use_real_price’选项不同含义会有所不同, 参见
set_option
), 默认是前复权
None
: 不复权, 返回实际价格
'post'
: 后复权
df=True
pandas.DataFrame
对象, 行索引是
datetime.datetime
对象, 列索引是属性名字. 比如: 如果当前时间是2015-01-07,
attribute_history('000300.XSHG', 2)
将返回:
df=False:
dict, key是股票代码, 值是一个numpy数组
numpy.ndarray
, 对应上面的DataFrame的每一列, 例如
attribute_history('000300.XSHG', 2, df=False)
将返回:
stock = '000001.XSHE'
h = attribute_history(stock, 5, '1d', ('open','close', 'volume', 'factor')) # 取得000001(平安银行)过去5天的每天的开盘价, 收盘价, 交易量, 复权因子
# 不管df等于True还是False, 下列用法都是可以的
h['open'] #过去5天的每天的开盘价, 一个pd.Series对象, index是datatime
h['close'][-1] #昨天的收盘价
h['open'].mean()
# 下面的pandas.DataFrame的特性, df=False时将不可用
# 行的索引可以是整数, 也可以是日期的各种形式:
h['open']['2015-01-05']
h['open'][datetime.date(2015, 1, 5)]
h['open'][datetime.datetime(2015, 1, 5)]
# 按行取数据
h.iloc[-1] #昨天的开盘价和收盘价, 一个pd.Series对象, index是字符串:'open'/'close'
h.iloc[-1]['open'] #昨天的开盘价
h.loc['2015-01-05']['open']
# 高级运算
h = h[h['volume'] > 1000000] # 只保留交易量>1000000股的行
h['open'] = h['open']/h['factor'] #让open列都跟factor列相除, 把价格都转化成原始价格
h['close'] = h['close']/h['factor']
get_current_data()
回测环境/模拟专用API
获取当前单位时间(当天/当前分钟)的涨跌停价, 是否停牌,当天的开盘价等。
回测时, 通过 API 获取到的是前一个单位时间(天/分钟)的数据, 而有些数据, 我们在这个单位时间是知道的, 比如涨跌停价, 是否停牌, 当天的开盘价. 我们添加了这个API用来获取这些数据.
current_data[security]
时(假设 current_data 是返回的 dict), 该 security 的数据才会被获取.
def handle_data(context, data):
current_data = get_current_data()
print current_data
print current_data['000001.XSHE']
print current_data['000001.XSHE'].paused
print current_data['000001.XSHE'].day_open
get_bars(security, count, unit='1d',
fields=['date', 'open','high','low','close'],
include_now=False)
回测环境/模拟专用API
获取各种时间周期的 bar 数据, bar 的分割方式与主流股票软件相同, 而且支持返回当前时刻所在 bar 的数据。
一个 numpy.ndarry 对象。可以通过 array[‘close’] 的方式直接访问列数据。
array = get_bars('000001.XSHG', 5, unit='1d',fields=['open','close'],include_now=False)
array['close']
get_extras(info, security_list, start_date='2015-01-01', end_date='2015-12-31', df=True, count=None)
得到多只标的在一段时间的如下额外的数据:
df=True:
pandas.DataFrame
对象, 列索引是股票代号, 行索引是
datetime.datetime
, 比如
get_extras('acc_net_value', ['510300.XSHG', '510050.XSHG'], start_date='2015-12-01', end_date='2015-12-03')
返回:
df=False
一个dict, key是基金代号, value是
numpy.ndarray
, 比如
get_extras('acc_net_value', ['510300.XSHG', '510050.XSHG'], start_date='2015-12-01', end_date='2015-12-03', df=False)
返回:
get_fundamentals(query_object, date=None, statDate=None)
查询财务数据,详细的数据字段描述请点击 财务数据文档 查看
date和statDate参数只能传入一个:
当 date 和 statDate 都不传入时, 相当于使用 date 参数, date 的默认值下面会描述.
date: 查询日期, 一个字符串(格式类似’2015-10-15’)或者 datetime.date / datetime.datetime 对象, 可以是None, 使用默认日期. 这个默认日期在回测和研究模块上有点差别:
statDate: 财报统计的季度或者年份, 一个字符串, 有两种格式:
# 查询'000001.XSHE'的所有市值数据, 时间是2015-10-15
q = query(
valuation
).filter(
valuation.code == '000001.XSHE'
df = get_fundamentals(q, '2015-10-15')
# 打印出总市值
log.info(df['market_cap'][0])
# 获取多只股票在某一日期的市值, 利润
df = get_fundamentals(query(
valuation, income
).filter(
# 这里不能使用 in 操作, 要使用in_()函数
valuation.code.in_(['000001.XSHE', '600000.XSHG'])
), date='2015-10-15')
# 选出所有的总市值大于1000亿元, 市盈率小于10, 营业总收入大于200亿元的股票
df = get_fundamentals(query(
valuation.code, valuation.market_cap, valuation.pe_ratio, income.total_operating_revenue
).filter(
valuation.market_cap > 1000,
valuation.pe_ratio < 10,
income.total_operating_revenue > 2e10
).order_by(
# 按市值降序排列
valuation.market_cap.desc()
).limit(
# 最多返回100个
), date='2015-10-15')
# 使用 or_ 函数: 查询总市值大于1000亿元 **或者** 市盈率小于10的股票
from sqlalchemy.sql.expression import or_
get_fundamentals(query(
valuation.code
).filter(
valuation.market_cap > 1000,
valuation.pe_ratio < 10
# 查询平安银行2014年四个季度的季报, 放到数组中
q = query(
income.statDate,
income.code,
income.basic_eps,
balance.cash_equivalents,
cash_flow.goods_sale_and_service_render_cash
).filter(
income.code == '000001.XSHE',
rets = [get_fundamentals(q, statDate='2014q'+str(i)) for i in range(1, 5)]
# 查询平安银行2014年的年报
q = query(
income.statDate,
income.code,
income.basic_eps,
cash_flow.goods_sale_and_service_render_cash
).filter(
income.code == '000001.XSHE',
ret = get_fundamentals(q, statDate='2014')
get_fundamentals_continuously - 查询多日的财务数据
get_fundamentals_continuously(query_object, end_date=None,count=None)
查询财务数据,详细的数据字段描述请点击财务数据文档查看
query_object: 一个sqlalchemy.orm.query.Query对象, 可以通过全局的 query 函数获取 Query 对象
end_date: 查询日期, 一个字符串(格式类似’2015-10-15’)或者datetime.date/datetime.datetime对象, 可以是None, 使用默认日期. 这个默认日期在回测和研究模块上有点差别:
- 回测模块: 默认值会随着回测日期变化而变化, 等于 context.current_dt 的前一天(实际生活中我们只能看到前一天的财报和市值数据, 所以要用前一天)
- 研究模块: 使用平台财务数据的最新日期, 一般是昨天.
如果传入的 date 不是交易日, 则使用这个日期之前的最近的一个交易日
count: 获取 end_date 前 count 个日期的数据
返回一个 pandas.Panel
出于性能方面考虑,我们做出了返回总条数不超过10000条的限制。 也就是说:查询的股票数量*count 要小于10000。 否则,返回的数据会不完整。
>>> q = query(valuation.turnover_ratio,
valuation.market_cap,
indicator.eps
).filter(valuation.code.in_(['000001.XSHE', '600000.XSHG']))
>>> panel = get_fundamentals_continuously(q, end_date='2018-01-01', count=5)
>>> panel
<class 'pandas.core.panel.Panel'>
Dimensions: 3 (items) x 5 (major_axis) x 2 (minor_axis)
Items axis: turnover_ratio to eps
Major_axis axis: 2017-12-25 to 2017-12-29
Minor_axis axis: 000001.XSHE to 600000.XSHG
>>> panel.minor_xs('600000.XSHG')
turnover_ratio market_cap eps
2017-12-25 0.0687 3695.4270 0.48
2017-12-26 0.0542 3710.1030 0.48
2017-12-27 0.1165 3704.2324 0.48
2017-12-28 0.0849 3680.7510 0.48
2017-12-29 0.0582 3695.4270 0.48
>>> panel.major_xs('2017-12-25')
turnover_ratio market_cap eps
000001.XSHE 0.9372 2275.0796 0.38
600000.XSHG 0.0687 3695.4270 0.48
>>> panel.xs('turnover_ratio',axis=0)
# axis=0 表示 items axis; axis=1 表示 major axis; axis=2 表示 minor axis
code 000001.XSHE 600000.XSHG
2017-12-25 0.9372 0.0687
2017-12-26 0.6642 0.0542
2017-12-27 0.8078 0.1165
2017-12-28 0.9180 0.0849
2017-12-29 0.5810 0.0582
# 查询'股票基本信息表 - STK_STOCKINFO'的数据, 并返回前10条数据
from jqdata import jy
df = jy.run_query(query(jy.LC_StockArchives).limit(10))
# 打印出公司名称
log.info(df['ChiName'])
gta.run_query - 更多财务及宏观数据
from jqdata import gta
gta.run_query(query_object)
查询国泰安数据,详细的数据字段描述请点击国泰安数据查看,数据库包括股票的深度数据、银行财务、宏观数据等。
注意未来函数,建议使用filter进行过滤; 需导入 jqdata 模块,即在策略或研究起始位置加入from jqdata import gta
query_object: 一个sqlalchemy.orm.query.Query对象(http://docs.sqlalchemy.org/en/rel_1_0/orm/query.html), 可以通过全局的query函数获取Query对象
返回一个pandas.DataFrame, 每一行对应数据库返回的每一行, 列索引是你查询的所有字段
1. 为了防止返回数据量过大, 我们每次最多返回3000行
2. 不能进行连表查询,即同时查询多张表内数据
# 查询'股票基本信息表 - STK_STOCKINFO'的数据, 并返回前10条数据
from jqdata import gta
df = gta.run_query(query(gta.STK_STOCKINFO).limit(10))
# 打印出股票简称
log.info(df['SHORTNAME'])
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
# 选出所有的发行价格大于10元, 股票类别为A类的的股票,并返回前20条记录
from jqdata import gta
df = gta.run_query(query(
gta.STK_STOCKINFO
).filter(
gta.STK_STOCKINFO.ISSUEPRICE > 10,
gta.STK_STOCKINFO.SHARETYPE == 'A'
).limit(20))
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
# 将国泰安数据取到的股票代码转化为一创聚宽量化交易云平台所使用的代码形式
from jqdata import gta
df = gta.run_query(query(gta.STK_STOCKINFO))
# 获取国泰安提供的6为股票代码
symbol = df['SYMBOL'][0]
# 转化为带后缀的股票代码
stock_code = normalize_code(symbol)
# symbol输出为'000971'
# stock_code输出为'000971.XSHE'
get_index_stocks - 获取指数成份股
get_index_stocks(index_symbol, date=None)
获取一个指数给定日期在平台可交易的成分股列表,请点击指数列表查看指数信息
index_symbol: 指数代码
date: 查询日期, 一个字符串(格式类似’2015-10-15’)或者datetime.date/datetime.datetime对象, 可以是None, 使用默认日期. 这个默认日期在回测和研究模块上有点差别:
- 回测模块: 默认值会随着回测日期变化而变化, 等于context.current_dt
- 研究模块: 默认是今天
返回股票代码的list
# 获取所有沪深300的股票
stocks = get_index_stocks('000300.XSHG')
log.info(stocks)
get_industry_stocks - 获取行业成份股
get_industry_stocks(industry_code, date=None)
获取在给定日期一个行业的所有股票,行业分类列表见数据页面-行业概念数据。
industry_code: 行业编码
date: 查询日期, 一个字符串(格式类似’2015-10-15’)或者datetime.date/datetime.datetime对象, 可以是None, 使用默认日期. 这个默认日期在回测和研究模块上有点差别:
- 回测模块: 默认值会随着回测日期变化而变化, 等于context.current_dt
- 研究模块: 默认是今天
返回股票代码的list
# 获取计算机/互联网行业的成分股
stocks = get_industry_stocks('I64')
get_concept_stocks - 获取概念成份股
get_concept_stocks(concept_code, date=None)
获取在给定日期一个概念板块的所有股票,概念板块分类列表见数据页面-行业概念数据。
concept_code: 概念板块编码
date: 查询日期, 一个字符串(格式类似’2015-10-15’)或者datetime.date/datetime.datetime对象, 可以是None, 使用默认日期. 这个默认日期在回测和研究模块上有点差别:
- 回测模块: 默认值会随着回测日期变化而变化, 等于context.current_dt
- 研究模块: 默认是今天
返回股票代码的list
# 获取风力发电概念板块的成分股
stocks = get_concept_stocks('GN036')
get_all_securities - 获取所有标的信息
get_all_securities(types=[], date=None)
获取平台支持的所有股票、基金、指数、期货信息
types: list: 用来过滤securities的类型, list元素可选: ‘stock’, ‘fund’, ‘index’, ‘futures’, ‘etf’, ‘lof’, ‘fja’, ‘fjb’, ‘open_fund’, ‘bond_fund’, ‘stock_fund’, ‘QDII_fund’, ‘money_market_fund’, ‘mixture_fund’。 types为空时返回所有股票, 不包括基金,指数和期货
date: 日期, 一个字符串或者 datetime.datetime/datetime.date 对象, 用于获取某日期还在上市的股票信息. 默认值为 None, 表示获取所有日期的股票信息
pandas.DataFrame, 比如:get_all_securities()[:2]
返回:
start_date: 上市日期
end_date: 退市日期,如果没有退市则为2200-01-01
type: 类型,stock(股票),index(指数),etf(ETF基金),fja(分级A),fjb(分级B),open_fund(开放式基金), bond_fund(债券基金), stock_fund(股票型基金), QDII_fund(QDII 基金), money_market_fund(货币基金), mixture_fund(混合型基金)
def initialize(context):
#获得所有股票列表
log.info(get_all_securities())
log.info(get_all_securities(['stock']))
#将所有股票列表转换成数组
stocks = list(get_all_securities(['stock']).index)
#获得所有指数列表
get_all_securities(['index'])
#获得所有基金列表
df = get_all_securities(['fund'])
#获取所有期货列表
get_all_securities(['futures'])
#获得etf基金列表
df = get_all_securities(['etf'])
#获得lof基金列表
df = get_all_securities(['lof'])
#获得分级A基金列表
df = get_all_securities(['fja'])
#获得分级B基金列表
df = get_all_securities(['fjb'])
#获得2015年10月10日还在上市的所有股票列表
get_all_securities(date='2015-10-10')
#获得2015年10月10日还在上市的 etf 和 lof 基金列表
get_all_securities(['etf', 'lof'], '2015-10-10')
get_security_info - 获取单个标的信息
get_security_info(code)
获取股票/基金/指数的信息.
code: 证券代码
一个对象, 有如下属性:
- display_name: 中文名称
- name: 缩写简称
- start_date: 上市日期, datetime.date 类型
- end_date: 退市日期, datetime.date 类型, 如果没有退市则为2200-01-01
- type: 类型,stock(股票),index(指数),etf(ETF基金),fja(分级A),fjb(分级B)
- parent: 分级基金的母基金代码
# 获取基金的母基金, 下面的判断为真.
assert get_security_info('502050.XSHG').parent == '502048.XSHG'
get_billboard_list - 获取龙虎榜数据
get_billboard_list(stock_list, start_date, end_date, count)
获取指定日期区间内的龙虎榜数据
stock_list: 一个股票代码的 list。 当值为 None 时, 返回指定日期的所有股票。
start_date:开始日期
end_date: 结束日期
count: 交易日数量, 可以与 end_date 同时使用, 表示获取 end_date 前 count 个交易日的数据(含 end_date 当日)
pandas.DataFrame, 各 column 的含义如下:
- code: 股票代码
- day: 日期
- direction: ALL 表示『汇总』,SELL 表示『卖』,BUY 表示『买』
- abnormal_code: 异常波动类型
- abnormal_name: 异常波动名称
- sales_depart_name: 营业部名称
- rank: 0 表示汇总, 1~5 表示买一到买5, 6~10 表示卖一到卖五
- buy_value:买入金额
- buy_rate:买入金额占比(买入金额/市场总成交额)
- sell_value:卖出金额
- sell_rate:卖出金额占比(卖出金额/市场总成交额)
- net_value:净额(买入金额 - 卖出金额)
- amount:市场总成交额
# 在策略中获取前一日的龙虎榜数据
get_billboard_list(stock_list=None, end_date = context.previous_date, count =1)
get_locked_shares - 获取限售解禁数据
get_locked_shares(stock_list, start_date, end_date, forward_count)
获取指定日期区间内的限售解禁数据
stock_list: 一个股票代码的 list
start_date: 开始日期
end_date: 结束日期
forward_count: 交易日数量, 可以与 start_date 同时使用, 表示获取 start_date 到 forward_count 个交易日区间的数据
pandas.DataFrame, 各 column 的含义如下:
- day: 解禁日期
- code: 股票代码
- num: 解禁股数
- rate1: 解禁股数/总股本
- rate2: 解禁股数/总流通股本
# 在策略中获取个股未来500天的解禁情况
get_locked_shares(stock_list=['000001.XSHE', '000002.XSHE'], start_date=context.current_dt, forward_count=500)
jqdata.get_all_trade_days - 获取所有交易日
jqdata.get_all_trade_days()
获取所有交易日, 不需要传入参数, 返回一个包含所有交易日的 numpy.ndarray, 每个元素为一个 datetime.date 类型.
注: 需导入 jqdata 模块,即在策略或研究起始位置加入import jqdata
jqdata.get_trade_days - 获取指定范围交易日
jqdata.get_trade_days(start_date=None, end_date=None, count=None)
获取指定日期范围内的所有交易日, 返回 numpy.ndarray, 包含指定的 start_date 和 end_date, 默认返回至 datatime.date.today() 的所有交易日
注: 需导入 jqdata 模块,即在策略或研究起始位置加入import jqdata
start_date: 开始日期, 与 count 二选一, 不可同时使用. str/datetime.date/datetime.datetime 对象
end_date: 结束日期, str/datetime.date/datetime.datetime 对象, 默认为 datetime.date.today()
count: 数量, 与 start_date 二选一, 不可同时使用, 必须大于 0. 表示取 end_date 往前的 count 个交易日,包含 end_date 当天。
jqdata.get_money_flow(security_list, start_date=None, end_date=None, fields=None, count=None)
获取一只或者多只股票在一个时间段内的资金流向数据,仅包含股票数据,不可用于获取期货数据。
注: 需导入 jqdata 模块,即在策略或研究起始位置加入import jqdata
security_list: 一只股票代码或者一个股票代码的 list
start_date: 开始日期, 与 count 二选一, 不可同时使用, 一个字符串或者 datetime.datetime/datetime.date 对象, 默认为平台提供的数据的最早日期
end_date: 结束日期, 一个字符串或者 datetime.date/datetime.datetime 对象, 默认为 datetime.date.today()
count: 数量, 与 start_date 二选一,不可同时使用, 必须大于 0. 表示返回 end_date 之前 count 个交易日的数据, 包含 end_date
fields: 字段名或者 list, 可选. 默认为 None, 表示取全部字段, 各字段含义如下:
# 获取一只股票在一个时间段内的资金流量数据
jqdata.get_money_flow('000001.XSHE', '2016-02-01', '2016-02-04')
jqdata.get_money_flow('000001.XSHE', '2015-10-01', '2015-12-30', fields="change_pct")
jqdata.get_money_flow(['000001.XSHE'], '2010-01-01', '2010-01-30', ["date", "sec_code", "change_pct", "net_amount_main", "net_pct_l", "net_amount_m"])
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
# 获取多只股票在一个时间段内的资金流向数据
jqdata.get_money_flow(['000001.XSHE', '000040.XSHE', '000099.XSHE'], '2010-01-01', '2010-01-30')
# 获取多只股票在某一天的资金流向数据
jqdata.get_money_flow(['000001.XSHE', '000040.XSHE', '000099.XSHE'], '2016-04-01', '2016-04-01')
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
# 获取股票 000001.XSHE 在日期 2016-06-30 往前 20 个交易日的资金流量数据
jqdata.get_money_flow('000001.XSHE', end_date="2016-06-30", count=20)
# 获取股票 000001.XSHE 往前 20 个交易日的资金流量数据
jqdata.get_money_flow('000001.XSHE', count=20)
jqdata.get_concepts - 获取概念列表
jqdata.get_concepts()
获取概念板块列表
pandas.DataFrame, 各 column 的含义如下:
- index: 概念代码
- name: 概念名称
- start_date: 开始日期
# 查询分地区农林牧渔业总产值表(季度累计) 的前10条数据
q = query(macro.MAC_INDUSTRY_AREA_AGR_OUTPUT_VALUE_QUARTER
).limit(10)
df = macro.run_query(q)
# 查询2014年的分地区农林牧渔业总产值表(年度)
q = query(macro.MAC_INDUSTRY_AREA_AGR_OUTPUT_VALUE_YEAR
).filter(macro.MAC_INDUSTRY_AREA_AGR_OUTPUT_VALUE_YEAR.stat_year=='2014')
df = macro.run_query(q)
jqlib
Alpha 101 因子
因子来源:
根据 WorldQuant LLC 发表的论文 101 Formulaic Alphas 中给出的 101 个 Alphas 因子公式,我们将公式编写成了函数,方便大家使用。
详细介绍:
函数计算公式、API 调用方法,输入输出值详情请见:数据 - Alpha 101.
使用方法:
# 导入 Alpha101 库
>>> from jqlib.alpha101 import *
# 获取沪深300成分股的 alpha_001 因子值
>>> a = alpha_001('2017-03-10','000300.XSHG')
# 查看前5行的因子值
>>> a.head()
000001.XSHE -0.496667
000002.XSHE 0.226667
000008.XSHE -0.043333
000009.XSHE -0.093333
000027.XSHE -0.030000
Name: rank_value_boolean, dtype: float64
# 查看平安银行的因子值
>>> a['000001.XSHE']
-0.49666666666666665
# 获取所有股票 alpha_007 的因子值
>>> a = alpha_007('2014-10-22')
# 查看欣旺达(300207)的因子值
>>> a['300207.XSHE']
# 查询函数说明
>>> alpha_101?
Type: cython_function_or_method
String form: <cyfunction alpha_101 at 0x7f037a0167d0>
Docstring:
((close - open) / ((high - low) + .001))
Inputs:
enddate: 查询日期
index: 股票池
Outputs:
Alpha 191 因子
因子来源:
根据国泰君安数量化专题研究报告 - 基于短周期价量特征的多因子选股体系给出了 191 个短周期交易型阿尔法因子,方便大家使用。
详细介绍:
函数计算公式、API 调用方法,输入输出值详情请见:数据 - Alpha 191.
使用方法:
# 导入 Alpha191 库
>>> from jqlib.alpha191 import *
# 获取沪深300成分股的 alpha_001 因子值
>>> a = alpha_001('2017-03-10','000300.XSHG')
# 查看前5行的因子值
>>> a.head()
000001.XSHE -0.496667
000002.XSHE 0.226667
000008.XSHE -0.043333
000009.XSHE -0.093333
000027.XSHE -0.030000
Name: rank_value_boolean, dtype: float64
# 查看平安银行的因子值
>>> a['000001.XSHE']
-0.49666666666666665
# 获取所有股票 alpha_007 的因子值
>>>end_date = '2017-04-04'
>>>code = list(get_all_securities(['stock'],date=end_date).index)
>>> a = alpha_007(code,end_date)
# 查看欣旺达(300207)的因子值
>>> a['300207.XSHE']
1.2494895018526142
# 查询函数说明
>>> alpha_001?
Signature: alpha_001(code, end_date=None)
Docstring:
(-1 * CORR(RANK(DELTA(LOG(VOLUME),1)),RANK(((CLOSE-OPEN)/OPEN)),6)
Inputs:
code: 股票池
end_date: 查询日期
Outputs:
File: ~/alpha191.py
Type: function
技术分析指标
因子说明:
为了让用户有更多可直接调用的技术分析指标因子,我们计划基于通达信、东方财富、同花顺等的公式,来完善我们的技术分析指标因子库。
我们给出了公式的API、参数说明、返回值的结果及类型说明、备注(相较于上述三家结果及算法的比对)、用法注释及示例,旨在帮助您更方便、更快速的在策略研究中使用这些因子函数。
详细介绍:
函数计算公式、API 调用方法,用法注释, 输入输出值详情请见:数据 - 技术分析指标.
使用方法:
# 导入 Alpha101 库
>>> from jqlib.technical_analysis import *
# 定义股票池列表
security_list1 = '000001.XSHE'
security_list2 = ['000001.XSHE','000002.XSHE','601211.XSHG','603177.XSHG']
# 计算并输出 security_list1 的 GDX 值,分别返回:济安线、压力线和支撑线的值。
gdx_jax, gdx_ylx, gdx_zcx = GDX(security_list1,check_date='2017-01-04', N = 30, M = 9)
print gdx_jax[security_list1]
print gdx_ylx[security_list1]
print gdx_zcx[security_list1]
# 输出 security_list2 的 GDX 值
gdx_jax, gdx_ylx, gdx_zcx = GDX(security_list2,check_date='2017-01-04', N = 30, M = 9)
for stock in security_list2:
print gdx_jax[stock]
print gdx_ylx[stock]
print gdx_zcx[stock]
# 查询函数说明
Signature: GDX(security_list, check_date, N=30, M=9)
Docstring:
计算公式:
AA:=ABS((2*CLOSE+HIGH+LOW)/4-MA(CLOSE,N))/MA(CLOSE,N);
JAX:DMA(CLOSE,AA);
压力线:(1+M/100)*JAX;
支撑线:(1-M/100)*JAX;
AA赋值:(2*收盘价+最高价+最低价)/4-收盘价的N日简单移动平均的绝对值/收盘价的N日简单移动平均
输出济安线 = 以AA为权重收盘价的动态移动平均
输出压力线 = (1+M/100)*JAX
输出支撑线 = (1-M/100)*JAX
security_list:股票列表
check_date:要查询数据的日期
N:统计的天数 N
M:统计的天数 M
济安线、压力线和支撑线的值。
输出结果类型:
字典(dict):键(key)为股票代码,值(value)为数据。
提示:所有下单函数可以在 handle_data中 与 定时运行函数 的 time 参数为 “every_bar”, “open”, “morning”, “night” 时使用。
order - 按股数下单
order(security, amount, style=None, side='long', pindex=0)
买卖标的。调用成功后, 您将可以调用get_open_orders取得所有未完成的交易, 也可以调用cancel_order取消交易
security: 标的代码
amount: 交易数量, 正数表示买入, 负数表示卖出
style: 参见order styles, None代表MarketOrder
side: ‘long’/’short’,开空单还是多单。默认为多单,股票、基金暂不支持开空单。
pindex: 在使用set_subportfolios创建了多个仓位时,指定subportfolio 的序号, 从 0 开始, 比如 0 指定第一个 subportfolio, 1 指定第二个 subportfolio,默认为0。
Order对象或者None, 如果创建订单成功, 则返回Order对象, 失败则返回None
#买入平安银行股票100股
order('000001.XSHE', 100) # 下一个市价单
order('000001.XSHE', 100, MarketOrderStyle()) # 下一个市价单, 功能同上
order('000001.XSHE', 100, LimitOrderStyle(10.0)) # 以10块价格下一个限价单
可能的失败原因:
股票数量经调整后变成0 (请看下面的说明)
股票未上市或者退市
股票不存在
为股票、基金开了空单
选择了不存在的仓位号,如没有建立多个仓位,而设定pindex的数大于0
对于原因4, 我们会抛出异常停止运行, 因为我们认为这是您代码的bug.
因为下列原因, 有时候实际买入或者卖出的股票数量跟您设置的不一样,这个时候我们会在您的log中添加警告信息。
- 买入时会根据您当前的现金来限制您买入的数量
- 卖出时会根据您持有股票的数量来限制您卖出的数量
- 我们会遵守A股交易规则: 每次交易数量只能是100的整数倍, 但是卖光所有股票时不受这个限制
根据交易所规则, 每天结束时会取消所有未完成交易
order_target(security, amount, style=None, side='long', pindex=0)
买卖标的, 使最终标的的数量达到指定的amount
security: 标的代码
amount: 期望的最终数量
style: 参见order styles, None代表MarketOrder
side: ‘long’/’short’,平空单还是多单。默认为多单,股票、基金暂不支持开空单。
pindex: 在使用set_subportfolios创建了多个仓位时,指定subportfolio 的序号, 从 0 开始, 比如 0为 指定第一个 subportfolio, 1 为指定第二个 subportfolio,默认为0。
Order对象或者None, 如果创建委托成功, 则返回Order对象, 失败则返回None
# 卖出平安银行所有股票
order_target('000001.XSHE', 0)
# 买入平安银行所有股票到100股
order_target('000001.XSHE', 100)
order_value - 按价值下单
order_value(security, value, style=None, side='long', pindex=0)
买卖价值为value的股票,金融期货暂不支持该API
security: 股票名字
value: 股票价值
style: 参见order styles, None代表MarketOrder
side: ‘long’/’short’,平空单还是多单。默认为多单,股票、基金暂不支持开空单。
pindex: 在使用set_subportfolios创建了多个仓位时,指定subportfolio 的序号, 从 0 开始, 比如 0为 指定第一个 subportfolio, 1 为指定第二个 subportfolio,默认为0。
Order对象或者None, 如果创建委托成功, 则返回Order对象, 失败则返回None
#卖出价值为10000元的平安银行股票
order_value('000001.XSHE', -10000)
#买入价值为10000元的平安银行股票
order_value('000001.XSHE', 10000)
order_target_value - 目标价值下单
order_target_value(security, value, style=None, side='long', pindex=0)
调整股票仓位到value价值,金融期货暂不支持该API
security: 股票名字
value: 期望的股票最终价值
style: 参见order styles, None代表MarketOrder
side: ‘long’/’short’,平空单还是多单。默认为多单,股票、基金暂不支持开空单。
pindex: 在使用set_subportfolios创建了多个仓位时,指定subportfolio 的序号, 从 0 开始, 比如 0为 指定第一个 subportfolio, 1 为指定第二个 subportfolio,默认为0。
Order对象或者None, 如果创建委托成功, 则返回Order对象, 失败则返回None
#卖出平安银行所有股票
order_target_value('000001.XSHE', 0)
#调整平安银行股票仓位到10000元价值
order_target_value('000001.XSHE', 10000)
cancel_order - 撤单
cancel_order(order)
order: Order对象或者order_id
Order对象或者None, 如果取消委托成功, 则返回Order对象, 委托不存在返回None
#每个交易日结束运行
def after_trading_end(context):
# 得到当前未完成订单
orders = get_open_orders()
# 循环,撤销订单
for _order in orders.values():
cancel_order(_order)
get_open_orders - 获取未完成订单
get_open_orders()
获得当天的所有未完成的订单
返回一个dict, key是order_id, value是Order对象
#每个交易日结束运行
def after_trading_end(context):
#得到当前未完成订单
orders = get_open_orders()
for _order in orders.values():
log.info(_order.order_id)
get_orders - 获取订单信息
get_orders(order_id=None, security=None, status=None)
获取当天的所有订单
order_id: 订单 id
security: 标的代码,可以用来查询指定标的的所有订单
status: OrderStatus, 查询特定订单状态的所有订单
返回一个dict, key是order_id, value是Order对象
#每个交易日结束运行
def after_trading_end(context):
#得到当天所有订单
orders = get_orders()
for _order in orders.values():
log.info(_order.order_id)
# 根据订单id查询订单
get_orders(order_id='1517627499')
# 查询所有标的为 000002.XSHE 的订单
get_orders(security='000002.XSHE')
# 查询订单状态为 OrderStatus.held 的所有订单
get_orders(status=OrderStatus.held)
# 查询标的为 000002.XSHE 且状态为 OrderStatus.held 的所有订单
get_orders(security='000002.XSHE', status=OrderStatus.held)
def initialize(context):
# 按月运行
run_monthly(func, monthday, time='open', reference_security)
# 按周运行
run_weekly(func, weekday, time='open', reference_security)
# 每天内何时运行
run_daily(func, time='open', reference_security)
回测环境/模拟专用API
指定每月, 每周或者每天要运行的函数, 可以在具体每月/周的第几个交易日(或者倒数第几天)的某一分钟执行。
在日级模拟中使用时,如果设置 time=’open’ 或 time=’9:30’,策略的实际运行时间是9:27~9:30之间。策略类获取到逻辑时间(context.current_dt)仍然是 9:30。
调用这些函数后, handle_data可以不实现
一个字符串,可以是具体执行时间,支持 time 表达式。比如 “10:00”, “01:00”, 或者 “every_bar”, “open”, “before_open”, “after_close”, “morning” 和 “night”。(具体执行时间如见下方)
time 表达式具有 ‘base +/-offset’ 的形式,如:’open-30m’表示开盘前30分钟,’close+1h30m’表示收盘后一小时三十分钟。
reference_security
时间的参照标的。
如参照 ‘000001.XSHG’,交易时间为 9:30-15:00。
如参照’IF1512.CCFX’,2016-01-01之后的交易时间为 9:30-15:00,在此之前为 9:15-15:15。
如参照’A9999.XDCE’,因为有夜盘,因此开始时间为21:00,结束时间为15:00。
# 错误, 下面的语句会报错
run_weekly(MyObject().on_week_start2, 1)
通过history/attribute_history取天数据时, 是不包括当天的数据的(即使在15:00和after_close里面也是如此), 要取得当天数据, 只能取分钟的
这些函数可以重复调用, 比如下面的代码可以在每周的第一个交易日和最后一个交易日分别调用两个函数:
def on_week_start(context):
def on_week_end(context):
def initialize(context):
run_weekly(on_week_start, 1)
run_weekly(on_week_end, -1)
每次调用这些函数都会产生一个新的定时任务, 如果想修改或者删除旧的定时任务, 请先调用 unschedule_all 来删除所有定时任务, 然后再添加新的.
在一月/一周交易日数不够以致于monthday/weekday无法满足时, 我们会找这周内最近的一个日期来执行, 比如, 如果某一周只有4个交易日:
- 若 weekday == 5, 我们会在第4个交易日执行
- 若 weekday == -5, 我们会在第1个交易日执行
如果要避免这样的行为, 您可以这样做:
def initialize(context):
run_weekly(weekly, 1)
def weekly(context):
if context.current_dt.isoweekday() != 1:
# 不在周一, 跳过执行
return
def weekly(context):
print 'weekly %s %s' % (context.current_dt, context.current_dt.isoweekday())
def monthly(context):
print 'monthly %s %s' % (context.current_dt, context.current_dt.month)
def daily(context):
print 'daily %s' % context.current_dt
def initialize(context):
# 指定每月第一个交易日, 在开盘后十分钟执行
run_monthly(monthly, 1, 'open+10m')
# 指定每周倒数第一个交易日, 在开盘前执行
run_weekly(weekly, -1, 'before_open')
# 指定每天收盘前10分钟运行
run_weekly(daily, 'close - 10m')
# 指定每天收盘后执行
run_daily(daily, 'after_close')
# 指定在每天的10:00运行
run_daily(daily, '10:00')
# 指定在每天的01:00运行
run_daily(daily, '01:00')
# 参照股指期货的时间每分钟运行一次, 必须选择分钟回测, 否则每天执行
run_daily(daily, 'every_bar', reference_security='IF1512.CCFX')
取消所有定时运行 ♠
# 取消所有定时运行
unschedule_all()
画图函数record ♠
record(**kwargs)
回测环境/模拟专用API
我们会帮您在图表上画出收益曲线和基准的收益曲线,您也可以调用record函数来描画额外的曲线。
因为我们是按天展现的,如果您使用按分钟回测,我们画出的点是您最后一次调用record的值。
很多key=>value形式的参数,key曲线名称,value为值
# d是一个SecurityUnitData结构体,会画出每个单元时间(天或分钟)的平均价,开始价,结束价
record(price=d.price, open=d.open, close=d.close)
# 也可以画一条100的直线
record(price=100)
发送自定义消息 ♠
send_message(message, channel='weixin')
回测环境/模拟专用API
给用户自己发送消息, 暂时只支持微信消息.
message: 消息内容. 字符串.
channel: 消息渠道, 暂时只支持微信: weixin. 默认值是 weixin
True/False, 表示是否发送成功. 当发送失败时, 会在日志中显示错误信息.
要使用功能, 必须开启模拟交易的 微信通知.
此功能只能在 模拟交易 中使用, 回测中使用会直接忽略, 无任何提示.
微信消息每人每天不超过 5 条, 超出会失败.
微信消息主页只显示前 200 个字符, 点击详情可查看全部消息, 全部消息不得超过 10000 个字符.
send_message("测试消息")
日志log
log.error(content)
log.warn(content)
log.info(content)
log.debug(content)
print content1, content2, ...
分级别打log,跟python的logging模块一致
print输出的结果等同于log.info, 但是print后面的每一个元素会占用一行
参数可以是字符串、对象等
log.info(history(10)) # 打印出 history(10)返回的结果
log.info("Selling %s, amount=%s", security, amount) # 打印出一个格式化后的字符串
print history(10), data, context.portfolio
设定log级别:log.set_level
log.set_level(name, level)
设置不同种类的log的级别, 低于这个级别的log不会输出. 所有log的默认级别是debug
name: 字符串, log种类, 必须是’order’, ‘history’, ‘strategy’中的一个, 含义分别是:
order: 调用order系列API产生的log
history: 调用history系列API(history/attribute_history/get_price)产生的log
strategy: 您自己在策略代码中打的log
level: 字符串, 必须是’debug’, ‘info’, ‘warning’, ‘error’中的一个, 级别: debug < info < warning < error
# 过滤掉order系列API产生的比error级别低的log
log.set_level('order', 'error')
write_file - 写文件
write_file(path, content, append=False)
写入内容到研究模块path文件, 写入后, 您可以立即在研究模块中看到这个文件
path: 相对路径, 相对于您的私有空间的根目录的路径
content: 文件内容, str或者unicode, 如果是unicode, 则会使用UTF-8编码再存储.可以是二进制内容.
append: 是否是追加模式, 当为False会清除原有文件内容,默认为False.
如果写入失败(一般是因为路径不合法), 会抛出异常
write_file("test.txt", "hello world")
# 写入沪深300的股票到HS300.stocks.json文件中
import json
write_file('HS300.stocks.json', json.dumps(get_index_stocks('000300.XSHG')))
# 把 DataFrame 表保存到文件
df = attribute_history('000001.XSHE', 5, '1d') #获取DataFrame表
write_file('df.csv', df.to_csv(), append=False) #写到文件中
## 详细用法可以参考文档:/post/580
content = read_file('HS300.stocks.json')
securities = json.loads(content)
log.info(securities)
#解析csv文件
import pandas as pd
from six import StringIO
body=read_file("open.csv")
data=pd.read_csv(StringIO(body))
## 详细用法可以参考文档:/post/580
自定义python库
您可以在把.py文件放在’研究’的根目录, 然后在回测中就可以通过import的方式来引用此文件. 比如
研究根目录/mylib.py:
#-*- coding: utf-8 -*-
# 如果你的文件包含中文, 请在文件的第一行使用上面的语句指定你的文件编码
# 用到回测API请加入下面的语句
from kuanke.user_space_api import *
my_stocks = get_index_stocks('000300.XSHG')
在策略代码中:
# 导入自己创建的库
from mylib import *
def initialize(context):
log.info(my_stocks)
注意: 暂时只能import研究根目录下的.py文件, 还不能import子目录下的文件(比如通过 import a.b.c 来引用a/b/c.py)
研究中创建回测函数
create_backtest(algorithm_id, start_date, end_date, frequency="day", initial_cash=10000, initial_positions=None, extras=None, name=None)
通过一个策略ID从研究中创建回测,暂不支持期货回测
algorithm_id: 策略ID,从策略编辑页的 url 中获取, 比如 ‘/algorithm/index/edit?algorithmId=xxxx’,则策略ID为 xxxx
start_date: 回测开始日期
end_date: 回测结束日期
frequency: 数据频率,支持 day,minute
initial_cash: 初始资金
extras: 额外参数,一个 dict, 用于设置全局的 g 变量,如 extras={‘x’:1, ‘y’:2},则回测中 g.x = 1, g.y = 2,需要注意的是,该参数的值是在 initialize 函数执行之后
才设置给 g 变量的,所以这会覆盖掉 initialize 函数中 g 变量同名属性的值
name: 回测名, 用于指定回测名称, 如果没有指定则默认采用策略名作为回测名
initial_positions: 初始持仓。持仓会根据价格换成现金加到初始资金中,如果没有给定价格则默认获取股票最近的价格。格式如下:
algorithm_id = "xxxx"
extra_vars = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
initial_positions = [
'security':'000001.XSHE',
'amount':'100',
'security':'000063.XSHE',
'amount':'100',
'avg_cost': '1.0'
params = {
"algorithm_id": algorithm_id,
"start_date": "2015-10-01"
,
"end_date": "2016-07-31",
"frequency": "day",
"initial_cash": "1000000",
"initial_positions": initial_positions,
"extras": extra_vars,
created_bt_id = create_backtest(**params)
print(created_bt_id)
研究中获取回测信息
gt = get_backtest(backtest_id)
backtest_id: 回测ID,从回测详情页的 url 中获取, 比如 ‘/algorithm/backtest/detail?backtestId=’,则回测ID为 xxxx
。如下图所示:
paused: 暂停
deleted: 已删除
gt.get_params():
获得回测参数
. 返回一个 dict, 包含调用 create_backtest 时传入的所有信息. (注: algorithm_id,initial_positions,extras 只有在研究中创建的回测才能取到)
gt.get_results():
获得收益曲线
. 返回一个 list,每个交易日是一个 dict,键的含义如下:
-
time: 时间
-
returns: 收益
-
benchmark_returns: 基准收益
-
如果没有收益则返回一个空的 list
gt.get_positions():
获得持仓详情
. 返回一个 list,每个交易日为一个 dict,键的含义为:
-
time: 时间
-
security: 证券代码
-
security_name: 证券名称
-
amount: 持仓数量
-
price: 股票价格
-
avg_cost: 买入股票平均每股所花的钱
-
closeable_amount: 可平仓数量
-
如果没有持仓则返回一个空的 list
gt.get_orders():
获得交易详情
. 返回一个 list,每个交易日为一个 dict,键的含义为:
-
time: 时间
-
security: 证券代码
-
security_name: 证券名称
-
action: 交易类型, 开仓(‘open’)/平仓(‘close’)
-
amount: 下单数量
-
filled: 成交数量
-
price: 平均成交价格
-
commission: 交易佣金
-
如果没有持仓则返回一个空的 list
gt.get_records():
获得所有 record 记录
. 返回一个 list,每个交易日为一个 dict,键是 time 以及调用 record() 函数时设置的值.
gt.get_risk():
获得总的风险指标
. 返回一个 dict,键是各类收益指标数据,如果没有风险指标则返回一个空的 dict.
gt.get_period_risks():
获得分月计算的风险指标
. 返回一个 dict,键是各类指标, 值为一个 pandas.DataFrame. 如果没有风险指标则返回一个空的 dict.
gt = get_backtest("xxxx")
gt.get_status() # 获取回测状态
gt.get_params() # 获取回测参数
gt.get_results() # 获取收益曲线
gt.get_positions() # 获取所有持仓列表
gt.get_orders() # 获取交易列表
gt.get_records() # 获取所有record()记录
gt.get_risk() # 获取总的风险指标
gt.get_period_risks() # 获取分月计算的风险指标
股票代码格式转换
normalize_code()
将其他形式的股票代码转换为一创聚宽量化交易云平台可用的股票代码形式。
仅适用于A股市场股票代码以及基金代码
for
code
in
(
'000001'
,
'SZ000001'
,
'000001SZ'
,
'000001.sz'
,
'000001.XSHE'
):
print
normalize_code(code)
000001.
XSHE
000001.
XSHE
000001.
XSHE
000001.
XSHE
000001.
XSHE
性能分析 ♠
enable_profile()
回测环境/模拟专用API
开启性能分析功能,
请在所有代码之前调用这句话(即在策略编译页面的代码编辑框最上方放置该代码)
, 只在点击 ‘运行回测’ 运行的时候才能看到性能分析结果.
开启性能分析之后, 你会在回测结果页面看到性能分析结果.
请注意, 不需要时, 请不要调用此函数, 因为它本身会影响程序性能.
结果示例(真实输出中没有中文说明):
// 时间单位: 微秒
Timer unit: 1e-06 s
// 函数执行总时间
Total time: 0.00277 s
// 文件名
File: user_code.py
// 函数名
Function: initialize at line 3
// 行号, 这一行执行次数,总执行时间,每次执行时间, 这一行执行时间在整个函数的比例
Line # Hits Time Per Hit % Time Line Contents
==============================================================
3 def initialize(context):
4 # 定义一个全局变量, 保存要操作的股票
5 # 000001(股票:平安银行)
6 1 31 31.0 1.1 g.security = '000001.XSHE'
7 # 初始化此策略
8 # 设置我们要操作的股票池, 这里我们只操作一支股票
9 1 2739 2739.0 98.9 set_universe([g.security])
Total time: 0.426325 s
File: user_code.py
Function: handle_data at line 12
Line # Hits Time Per Hit % Time Line Contents
==============================================================
12 def handle_data(context, data):
13 122 398 3.3 0.1 security = g.security
14 # 取得过去五天的平均价格
15 122 168565 1381.7 39.5 average_price = data[security].mavg(5)
16 # 取得上一时间点价格
17 122 493 4.0 0.1 current_price = data[security].price
18 # 取得当前的现金
19 122 240 2.0 0.1 cash = context.portfolio.cash
21 # 如果上一时间点价格高出五天平均价1%, 则全仓买入
22 122 396 3.2 0.1 if current_price > 1.01*average_price:
23 # 计算可以买多少只股票
24 30 124 4.1 0.0 number_of_shares = int(cash/current_price)
25 # 购买量大于0时,下单
26 30 56 1.9 0.0 if number_of_shares > 0:
27 # 买入股票
28 30 83190 2773.0 19.5 order(security, +number_of_shares)
29 # 记录这次买入
30 30 16202 540.1 3.8 log.info("Buying %s" % (security))
31 # 如果上一时间点价格低于五天平均价, 则空仓卖出
32 92 1119 12.2 0.3 elif current_price < average_price and context.portfolio.positions[security].amount > 0:
33 # 卖出所有股票,使这只股票的最终持有量为0
34 13 86702 6669.4 20.3 order_target(security, 0)
35 # 记录这次卖出
36 13 8210 631.5 1.9 log.info("Selling %s" % (security))
37 # 画出上一时间点价格
38 122 60630 497.0 14.2 record(stock_price=data[security].price)
全局对象 g
全局对象 g,用来存储用户的各类可被
pickle.dumps
函数序列化的全局数据
在模拟盘中,如果中途进程中断,我们会使用
pickle.dumps
序列化所有的g下面的变量内容, 保存到磁盘中,再启动的时候模拟盘就不会有任何数据影响。如果没有用g声明,会出现模拟盘重启后,变量数据丢失的问题。
如果不想 g 中的某个变量被序列化, 可以让变量以 ‘__’ 开头, 这样, 这个变量在序列化时就会被忽略
更多模拟盘细节, 请看
模拟盘注意事项
.
def initialize(context):
g.security = "000001.XSHE"
g.count = 1
g.flag = 0
def process_initialize(context):
# 保存不能被序列化的对象, 进程每次重启都初始化, 更多信息, 请看 [process_initialize]
g.__q = query(valuation)
def handle_data(context, data):
log.info(g.security)
log.info(g.count)
log.info(g.flag)
Context
subportfolios: 当前单个操作仓位的资金、标的信息,是一个
SubPortfolio
的数组
portfolio: 账户信息,即subportfolios 的汇总信息,
Portfolio
对象,单个操作仓位时,portfolio 指向 subportfolios[0]
current_dt: 当前单位时间的开始时间,
datetime.datetime
对象,
-
按天回测时, hour = 9, minute = 30, second = microsecond = 0,
-
按分钟回测时, second = microsecond = 0
previous_date: 前一个交易日,
datetime.date
对象, 注意, 这是一个日期, 是 date, 而不是 datetime
universe: 查询set_universe()设定的股票池, 比如: [‘000001.XSHE’, ‘600000.XSHG’]
run_params: 表示此次运行的参数, 有如下属性
-
start_date: 回测/模拟开始日期,
datetime.date
对象
-
end_date: 回测/模拟结束日期,
datetime.date
对象
-
type: 运行方式, 如下三个字符串之一
-
’simple_backtest’: 回测, 通过点击’编译运行’运行
-
‘full_backtest’: 回测, 通过点击’运行回测’运行
-
‘sim_trade’: 模拟交易
-
frequency: 运行频率, 如下三个字符串之一
-
’day’
-
‘minute’
-
‘tick’
为了让从其他平台迁移过来的同学更顺手的使用系统, 我们对此对象也做了和
g
一样的处理:
-
可以添加自己的变量, 每次进程关闭时持久保存, 进程重启时恢复.
-
以 ‘__’ 开头的变量不会被持久保存
-
如果添加的变量与系统的冲突, 将覆盖掉系统变量, 如果想恢复系统变量, 请删除自己的变量. 示例:
def handle_data(context, data):
# 执行下面的语句之后, context.portfolio 的整数 1
context.portfolio = 1
log.info(context.portfolio)
# 要恢复系统的变量, 只需要使用下面的语句即可
del context.portfolio
# 此时, context.portfolio 将变成账户信息.
log.info(context.portfolio.portfolio_value)
-
我们以后可能会往 context 添加新的变量来支持更多功能, 为了减少不必要的迷惑, 还是建议大家使用
g
def handle_data(context, data):
#获得当前回测相关时间
year = context.current_dt.year
month = context.current_dt.month
day = context.current_dt.day
hour = context.current_dt.hour
minute = context.current_dt.minute
second = context.current_dt.second
#得到"年-月-日"格式
date = context.current_dt.strftime("%Y-%m-%d")
#得到周几
weekday = context.current_dt.isoweekday()
# 获取账户的持仓价值
positions_value = context.portfolio.positions_value
# 获取仓位subportfolios[0]的可用资金
available_cash = context.subportfolios[0].available_cash
# 获取subportfolios[0]中多头仓位的security的持仓成本
hold_cost = context.subportfolios[0].long_positions[security].hold_cost
SubPortfolio
某个仓位的资金,标的信息,如未使用 SubPortfolioConfig 设置多仓位,默认只有subportfolios[0]一个仓位,Portfolio 指向该仓位。
inout_cash: 累计出入金, 比如初始资金 1000, 后来转移出去 100, 则这个值是 1000 - 100
available_cash: 可用资金, 可用来购买证券的资金
transferable_cash: 可取资金, 即可以提现的资金, 不包括今日卖出证券所得资金
locked_cash: 挂单锁住资金
type: 账户所属类型
long_positions: 多单的仓位, 一个 dict, key 是证券代码, value 是
Position
对象
short_positions: 空单的仓位, 一个 dict, key 是证券代码, value 是
Position
对象
positions_value: 持仓价值, 股票基金才有持仓价值, 期货为0
total_value: 总资产, 包括现金, 保证金, 仓位的总价值, 可用来计算收益
total_liability: 总负债, 等于融资负债、融券负债、利息总负债的总和
net_value: 净资产, 等于总资产减去总负债
cash_liability: 融资负债
sec_liability: 融券负债
interest: 利息总负债
maintenance_margin_rate: 维持担保比例
available_margin: 融资融券可用保证金
margin: 保证金,股票、基金保证金都为100%;融资融券保证金为0;期货保证金会实时更新, 总是等于当前期货价值 乘以 保证金比率, 当保证金不足时, 强制平仓. 平仓顺序是: 亏损多的(相对于开仓均价)先平仓
Portfolio
账户当前的资金,标的信息,即所有标的操作仓位的信息汇总。如未使用 SubPortfolioConfig 设置多仓位,默认只有subportfolios[0]一个仓位,Portfolio 指向该仓位。
inout_cash: 累计出入金, 比如初始资金 1000, 后来转移出去 100, 则这个值是 1000 - 100
available_cash: 可用资金, 可用来购买证券的资金
transferable_cash: 可取资金, 即可以提现的资金, 不包括今日卖出证券所得资金
locked_cash: 挂单锁住资金
margin: 保证金,股票、基金保证金都为100%
positions: 等同于 long_positions
long_positions: 多单的仓位, 一个 dict, key 是证券代码, value 是
Position
对象
short_positions: 空单的仓位, 一个 dict, key 是证券代码, value 是
Position
对象
total_value: 总的权益, 包括现金, 保证金, 仓位的总价值, 可用来计算收益
returns: 总权益的累计收益
starting_cash: 初始资金, 现在等于 inout_cash
positions_value: 持仓价值, 股票基金才有持仓价值, 期货为0
locked_cash_by_purchase: 基金申购未完成所冻结的金额
locked_cash_by_redeem: 基金赎回未到账的金额
locked_amount_by_redeem: 基金赎回时,冻结的份额
cash:
已过时
,等价于 available_cash
portfolio_value:
已过时
,等价于 total_value
unsell_positions:
已过时, 请使用 positions 代替
, 当前持有的不可以卖出的持仓(比如在A股T+1市场, 今天购票的股票), 并没有考虑股票今天是否停牌, 一个dict, key是股票代码, value是
Position
对象.
price: 最新行情价格
avg_cost: 开仓均价,买入标的的加权平均价, 计算方法是:
(buy_volume1 * buy_price1 + buy_volume2 * buy_price2 + …) / (buy_volume1 + buy_volume2 + …)
每次买入后会调整avg_cost, 卖出时avg_cost不变. 这个值也会被用来计算浮动盈亏.
hold_cost: 持仓成本,
针对期货有效
。
init_time: 建仓时间,格式为 datetime.datetime
transact_time: 最后交易时间,格式为 datetime.datetime
total_amount: 总仓位, 但不包括挂单冻结仓位
closeable_amount: 可卖出的仓位
today_amount: 今天开的仓位
locked_amount: 挂单冻结仓位
value: 标的价值,计算方法是: price * total_amount * multiplier, 其中股票、基金的multiplier为1,期货为相应的合约乘数
side: 多/空,’long’ or ‘short’
pindex: 仓位索引,subportfolio index
sellable_amount:
已过时
, 为了向前兼容, 等同于 closeable_amount
amount:
已过时
, 为了向前兼容, 等同于 closeable_amount
volume: 成交的股票数量
money: 成交的金额
factor: 前复权因子, 我们提供的价格都是前复权后的, 但是利用这个值可以算出原始价格, 方法是价格除以factor, 比如:
close/factor
high_limit: 涨停价
low_limit: 跌停价
avg: 这段时间的平均价, 等于
money/volume
price:
已经过时
, 为了向前兼容, 等同于 avg
pre_close: 前一个单位时间结束时的价格, 按天则是前一天的收盘价, 按分钟则是前一分钟的结束价格
paused: bool值, 这只股票是否停牌, 停牌时open/close/low/high/pre_close依然有值,都等于停牌前的收盘价, volume=money=0
security: 股票代码, 比如’000001.XSHE’
returns: 股票在这个单位时间的相对收益比例, 等于
(close-pre_close)/pre_close
isnan(): 数据是否有效, 当股票未上市或者退市时, 无数据, isnan()返回True
mavg(days, field='close')
: 过去days天的每天收盘价的平均值, 把field设成’avg’(等同于已过时的’price’)则为每天均价的平均价, 下同
vwap(days)
: 过去days天的每天均价的加权平均值, 以days=2为例子, 算法是:
position: 截至到当前时刻的持仓量,只适用于期货 tick 对象
a1_v ~ a5_v: 卖一量到卖五量,对于期货,只有卖一量
a1_p ~ a5_p: 卖一价到卖五价,对于期货,只有卖一量
b1_v ~ b5_v: 买一量到买五量,对于期货,只有买一量
b1_p ~ b5_p: 买一价到买五价,对于期货,只有买一价
status: 状态, 一个
OrderStatus
值
add_time: 订单添加时间,
datetime.datetime
对象
is_buy: bool值, 买还是卖,对于期货:
-
开多/平空 -> 买
-
开空/平多 -> 卖
amount: 下单数量, 不管是买还是卖, 都是正数
filled: 已经成交的股票数量, 正数
security: 股票代码
order_id: 订单ID
price: 平均成交价格, 已经成交的股票的平均成交价格(一个订单可能分多次成交)
avg_cost: 卖出时表示下卖单前的此股票的持仓成本, 用来计算此次卖出的收益. 买入时表示此次买入的均价(等同于price).
side: 多/空,’long’/’short’
action: 开/平, ‘open’/’close’
set_subportfolios([SubPortfolioConfig(cash,type), ... ])
初始化或者修改 subportfolios 的配置,只能在 initialize 中调用, 每个 SubPortfolioConfig 中 cash 的和应该等于总的初始资金
SubPortfolioConfig 参数
SubPortfolioConfig(cash,type)
cash: 仓位初始资金
type: 可操作标的的类型,’stock’ / ‘index_futures’ / ‘futures’ / ‘stock_margin’, 其中 stock 包括股票和基金,index_futures 指金融期货,futures 包含股指期货和商品期货,stock_margin 为融资融券账户。
init_cash = 500000 # 定义一个变量
# 设定subportfolios[0]为 股票和基金仓位,初始资金为 init_cash 变量代表的数值
# 设定subportfolios[1]为 金融期货仓位,初始资金为 init_cash 变量代表的数值
# 设定subportfolios[2]为 融资融券账户,初始资金为 init_cash 变量代表的数值
set_subportfolios([SubPortfolioConfig(cash=init_cash, type='stock'),\
SubPortfolioConfig(cash=init_cash, type='futures'),\
SubPortfolioConfig(cash=init_cash, type='stock_margin')])
SubPortfolio
某个仓位的资金,标的信息,如不使用 SubPortfolioConfig 设置多仓位,默认只有subportfolios[0]一个仓位,Portfolio 指向该仓位。每个策略最多可以创建100个 subportfolio。
有关 SubPortfolio 详情见
对象 - SubPortfolio
仓位间转移资金
transfer_cash(from_pindex, to_pindex, cash)
从序号为 from_pindex 的 subportfolio 转移 cash 到序号为 to_pindex 的 subportfolio
资金转移及时到账
从subportfolio[0] 向 subportfolio[1] 转移 500000
transfer_cash(from_pindex=0, to_pindex=1, cash=500000)
融资融券专用API
初始化融资融券账户
初始化的仓位是
不允许
直接进行融资融券操作的,因为初始默认 subportfolios[0] 中 SubPortfolioConfig 的 type = ‘stock’,只允许买卖股票与基金等。
因此要买卖金融期货,您需要设定 SubPortfolioConfig 的 type = ‘stock_margin’,具体方法如下:
def initialize(context):
## 设置单个账户
# 获取初始资金
init_cash = context.portfolio.starting_cash
# 设定账户为融资融券账户,初始资金为 init_cash 变量代表的数值(如不使用设置多账户,默认只有subportfolios[0]一个账户,Portfolio 指向该账户。)
set_subportfolios([SubPortfolioConfig(cash=init_cash, type='stock_margin')])
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
## 设置多个账户
# 获取初始资金,并等分为三份
init_cash = context.portfolio.starting_cash/3
# 设定subportfolios[0]为 股票和基金仓位,初始资金为 init_cash 变量代表的数值
# 设定subportfolios[1]为 金融期货仓位,初始资金为 init_cash 变量代表的数值
# 设定subportfolios[2]为 融资融券账户,初始资金为 init_cash 变量代表的数值
set_subportfolios([SubPortfolioConfig(cash=init_cash, type='stock'),\
SubPortfolioConfig(cash=init_cash, type='index_futures'),\
SubPortfolioConfig(cash=init_cash, type='stock_margin')])
设置融资利率
set_option('margincash_interest_rate', value)
设定融资利率, 默认 8%
value: 融资利率的值, 默认 8%
# 设定融资利率: 年化8%
set_option('margincash_interest_rate', 0.08)
设置融资保证金比率
set_option('margincash_margin_rate', value)
设置融资保证金比率, 默认 100%
value: 融资保证金比率的值, 默认 100%
# 设置融资保证金比率: 150%
set_option('margincash_margin_rate', 1.5)
设置融券利率
set_option('marginsec_interest_rate', value)
设定融券利率: 年化 10%, 默认 10%
value: 融券利率的值, 默认 10%
# 设定融券利率: 年化10%
set_option('marginsec_interest_rate', 0.10)
设置融券保证金比率
set_option('marginsec_margin_rate', value)
设定融券保证金比率: 150%, 默认 100%
value: 融券保证金比率的值, 默认 100%
# 设定融券保证金比率: 150%
set_option('marginsec_margin_rate', 1.5)
margincash_open - 融资买入
margincash_open(security, amount, style=None, pindex=0)
security: 标的代码
amount: 数量
style: 参见
order styles
, None代表MarketOrder
pindex: 在使用set_subportfolios创建了多个仓位时,指定subportfolio 的序号, 从 0 开始, 比如 0为 指定第一个 subportfolio, 1 为指定第二个 subportfolio,
默认为0
。
Order对象或者None, 如果创建委托成功, 则返回Order对象, 失败则返回None
# 融资买入平安银行 1000 股
margincash_open('000001.XSHE', 1000)
margincash_close - 卖券还款
margincash_close(security, amount, style=None, pindex=0)
security: 标的代码
amount: 数量
style: 参见
order styles
, None代表MarketOrder
pindex: 在使用set_subportfolios创建了多个仓位时,指定subportfolio 的序号, 从 0 开始, 比如 0为 指定第一个 subportfolio, 1 为指定第二个 subportfolio,
默认为0
。
# 卖出 1000 股平安银行用以还款
margincash_close('000001.XSHE', 1000)
margincash_direct_refund - 直接还款
margincash_direct_refund(value, pindex=0)
value: 还款金额
# 还款 100000 元
margincash_direct_refund(100000)
marginsec_open - 融券卖出
marginsec_open(security, amount, style=None, pindex=0)
security: 标的代码
amount: 数量
style: 参见
order styles
, None代表MarketOrder
pindex: 在使用set_subportfolios创建了多个仓位时,指定subportfolio 的序号, 从 0 开始, 比如 0为 指定第一个 subportfolio, 1 为指定第二个 subportfolio,
默认为0
。
Order对象或者None, 如果创建委托成功, 则返回Order对象, 失败则返回None
# 融券卖出 1000 股 平安银行
marginsec_open('000001.XSHE', 1000)
marginsec_close - 买券还券
marginsec_close(security, amount, style=None, pindex=0)
security: 标的代码
amount: 数量
style: 参见
order styles
, None代表MarketOrder
pindex: 在使用set_subportfolios创建了多个仓位时,指定subportfolio 的序号, 从 0 开始, 比如 0为 指定第一个 subportfolio, 1 为指定第二个 subportfolio,
默认为0
。
# 买入 1000 股平安银行用以还券
marginsec_close('000001.XSHE', 1000)
marginsec_direct_refund - 直接还券
marginsec_direct_refund(security, amount, pindex=0)
security: 标的代码
amount: 数量
pindex: 在使用set_subportfolios创建了多个仓位时,指定subportfolio 的序号, 从 0 开始, 比如 0为 指定第一个 subportfolio, 1 为指定第二个 subportfolio,
默认为0
。
## 如果账户持仓中"有" 1000股 平安银行
# 直接还 1000 股平安银行
marginsec_direct_refund('000001.XSHE', 1000)
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
## 如果账户持仓中"没有" 1000股 平安银行
# 需先买入 1000 股平安银行
order('000001.XSHE', 1000)
# 再直接还 1000 股平安银行
marginsec_direct_refund('000001.XSHE', 1000)
get_margincash_stocks - 获取融资标的列表
get_margincash_stocks()
返回上交所、深交所最近一次披露的的可融资标的列表的list。
# 获取融资标的列表,并赋值给 margincash_stocks
margincash_stocks = get_margincash_stocks()
# 判断平安银行是否在可融资列表
>>> '000001.XSHE' in get_margincash_stocks()
get_marginsec_stocks - 获取融券标的列表
get_marginsec_stocks()
返回上交所、深交所最近一次披露的的可融券标的列表的list。
# 获取融券标的列表,并赋值给 marginsec_stocks
marginsec_stocks= get_marginsec_stocks()
# 判断平安银行是否在可融券列表
>>> '000001.XSHE' in get_marginsec_stocks()
jqdata.get_mtss - 获取融资融券信息
jqdata.get_mtss(security_list, start_date=None, end_date=None, fields=None, count=None)
获取一只或者多只股票在一个时间段内的融资融券信息
注: 需导入 jqdata 模块,即在策略或研究起始位置加入import jqdata
security_list: 一只股票代码或者一个股票代码的 list
start_date: 开始日期, 与 count 二选一, 不可同时使用. 一个字符串或者 datetime.datetime/datetime.date 对象, 默认为平台提供的数据的最早日期
end_date: 结束日期, 一个字符串或者 datetime.date/datetime.datetime 对象, 默认为 datetime.date.today()
count: 数量, 与 start_date 二选一,不可同时使用, 必须大于 0. 表示返回 end_date 之前 count 个交易日的数据, 包含 end_date
fields: 字段名或者 list, 可选. 默认为 None, 表示取全部字段, 各字段含义如下:
# 获取一只股票的融资融券信息
jqdata.get_mtss('000001.XSHE', '2016-01-01', '2016-04-01')
jqdata.get_mtss('000001.XSHE', '2016-01-01', '2016-04-01', fields=["date", "sec_code", "fin_value", "fin_buy_value"])
jqdata.get_mtss('000001.XSHE', '2016-01-01', '2016-04-01', fields="sec_sell_value")
# 获取多只股票的融资融券信息
jqdata.get_mtss(['000001.XSHE', '000002.XSHE', '000099.XSHE'], '2015-03-25', '2016-01-25')
jqdata.get_mtss(['000001.XSHE', '000002.XSHE', '000099.XSHE'], '2015-03-25', '2016-01-25', fields=["date", "sec_code", "sec_value", "fin_buy_value", "sec_sell_value"])
# 获取股票 000001.XSHE 在日期 2016-06-30 往前 20 个交易日的融资融券信息
jqdata.get_mtss('000001.XSHE', end_date="2016-06-30", count=20)
# 获取股票 000001.XSHE 往前 20 个交易日的融资融券信息
jqdata.get_mtss('000001.XSHE', count=20)
期货专用API
初始化期货账户
初始化的仓位是不允许直接买卖期货的,因为初始默认 subportfolios[0] 中 SubPortfolioConfig 的 type = ‘stock’,只允许买卖股票与基金等。
因此要买卖期货,您需要设定 SubPortfolioConfig 的 type = ‘futures’,具体方法如下:
def initialize(context):
## 设置单个账户
# 获取初始资金
init_cash = context.portfolio.starting_cash
# 设定账户为金融账户,初始资金为 init_cash 变量代表的数值(如不使用设置多账户,默认只有subportfolios[0]一个账户,Portfolio 指向该账户。)
set_subportfolios([SubPortfolioConfig(cash=init_cash, type='futures')])
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
## 设置多个账户
# 获取初始资金,并等分为三份
init_cash = context.portfolio.starting_cash/3
# 设定subportfolios[0]为 股票和基金仓位,初始资金为 init_cash 变量代表的数值
# 设定subportfolios[1]为 金融期货仓位,初始资金为 init_cash 变量代表的数值
# 设定subportfolios[2]为 融资融券账户,初始资金为 init_cash 变量代表的数值
set_subportfolios([SubPortfolioConfig(cash=init_cash, type='stock'),\
SubPortfolioConfig(cash=init_cash, type='futures'),\
SubPortfolioConfig(cash=init_cash, type='stock_margin')])
主力连续合约
期货合约的生存周期是有限的,到合约最后交易日后就要交割。因此我们根据持仓量对期货合约进行拼接,形成主力连续合约。
合约代码:品种代号+9999,例如AG9999(白银主力合约)、Y9999(豆油主力合约)。
主力合约定义:如果某合约持仓量连续2天为同一个品种中最大的,且该合约相对于当前主力合约为远期合约,则自动变成主力合约。不会在日内进行主力合约切换。
下面是主要期货交易所的主力合约列表:
order(security, amount, style=None, side='long', pindex=0)
买卖标的。调用成功后, 您将可以调用get_open_orders取得所有未完成的交易, 也可以调用cancel_order取消交易
security: 标的代码
amount: 交易数量, 正数表示买入, 负数表示卖出
style: 参见order styles, None代表MarketOrder
side: ‘long’/’short’,开空单还是多单,默认为多单。
pindex: 在使用set_subportfolios创建了多个仓位时,指定subportfolio 的序号, 从 0 开始, 比如 0 指定第一个 subportfolio, 1 指定第二个 subportfolio,默认为0。
Order对象或者None, 如果创建订单成功, 则返回Order对象, 失败则返回None
## 如果期货账户是默认账户
# 在仓位0中开一手沪深300指数期货的空单
order('IF1412.CCFX', 1 , side='short', pindex=0)
# 在仓位0中开一手沪深300指数期货的多单
order('IF1412.CCFX', 1 , side='long', pindex=0)
## 如果期货账户是仓位1
# 在仓位1中以3600的限价单,平一手沪深300指数期货的空单
order('IF1412.CCFX', -1 , LimitOrderStyle(3600.0), side='short', pindex=1)
# 在仓位1中平一手沪深300指数期货的多单
order('IF1412.CCFX', -1 , side='long', pindex=1)
可能的失败原因:
标的不存在,对于该原因, 我们会抛出异常停止运行, 因为我们认为这是您代码的bug.
选择了不存在的仓位号,如没有建立多个仓位,而设定pindex的数大于0
因为下列原因, 有时候实际买入或者卖出的股票数量跟您设置的不一样,这个时候我们会在您的log中添加警告信息。
- 买入时会根据您当前的现金来限制您买入的数量
- 卖出时会根据您持有股票的数量来限制您卖出的数量
- 我们会遵守A股交易规则: 每次交易数量只能是100的整数倍, 但是卖光所有股票时不受这个限制
根据交易所规则, 每天结束时会取消所有未完成交易
order_target(security, amount, style=None, side='long', pindex=0)
买卖标的, 使最终标的的数量达到指定的amount
security: 标的代码
amount: 期望的最终数量
style: 参见order styles, None代表MarketOrder
side: ‘long’/’short’,平空单还是多单,默认为多单。
pindex: 在使用set_subportfolios创建了多个仓位时,指定subportfolio 的序号, 从 0 开始, 比如 0为 指定第一个 subportfolio, 1 为指定第二个 subportfolio,默认为0。
Order对象或者None, 如果创建委托成功, 则返回Order对象, 失败则返回None
# 如果期货账户是仓位1
# 平掉空单标的
order_target('IF1412.CCFX', 0 , side='short', pindex=1)
tick 级模拟回测
目前支持股票和期货的 tick 级回测。
期货部分, 支持 2010-01-01 至今的回测。
股票部分, 支持 2017-01-01 至今的回测。
tick 回测在申请开通后才可使用, 申请链接
首先, 需要使用 subscribe 订阅所需标的的行情数据。 其次, 需要实现 handle_tick 函数。 每当订阅的标的有新的 tick 事件产生时, 都会执行一次 handle_tick 函数, 并将新的 tick 对象通过 handle_tick 的 tick 参数提供。
handle_tick
handle_tick(context, tick)
该函数在策略订阅的标的产生 tick 事件时被调用一次。如果没有 tick 事件, 则不会被调用。
context: context 对象, 存放有当前的账户/标的持仓信息
tick: tick 对象, 存放了触发 handle_tick 事件的 tick 数据。
def handle_tick(context, tick):
log.info(tick)
subscribe - 订阅标的的 tick 事件
subscribe(security, frequency)
订阅标的的 tick 事件, 必须在频率为 tick 的回测、模拟中使用。
security:要订阅的标的代码或代码列表。 不能直接订阅主力合约、指数合约代码, 每个策略中最多可同时订阅10个标的。目前支持订阅股票、商品期货和股指期货。
frequency:目前必须使用’tick’
def initialize(context):
init_cash = context.portfolio.starting_cash
set_subportfolios([SubPortfolioConfig(cash=init_cash, type='futures')])
g.code1 = 'RB1802.XSGE'
g.code2 = 'I1710.XDCE'
subscribe(g.code1, 'tick')
#subscribe(g.code2, 'tick')
unsubscribe(g.code2, 'tick')
unsubscribe_all()
subscribe(g.code1, 'tick')
def handle_tick(context, tick):
#pass
log.info(tick)
get_current_tick(g.code1)
#order(g.code1, 1 , side='short', pindex=0)
def initialize(context):
set_benchmark('000300.XSHG')
set_option('use_real_price', True)
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
def before_trading_start(context):
subscribe('000001.XSHE','tick')
def handle_tick(context, tick):
log.info(tick)
def after_trading_end(context):
unsubscribe_all()
场外基金模拟回测
请使用 get_extras 获取场外基金的净值信息。
在进行申购与赎回操作前, 需要先使用 set_subportfolios 设置独立的场外基金仓位。
在申购与赎回份额时, 使用 purchase 和 redeem 两个 API 实现。
purchase - 申购基金
purchase(security, cash, pindex=0)
security: 基金代码编号,OF作为尾缀的字符串,例如招商中证白酒指数分级基金为“161725.OF”
cash: 申购的金额
pindex: 在使用set_subportfolios创建了多个仓位时,指定subportfolio 的序号, 从 0 开始, 比如 0 指定第一个 subportfolio, 1 指定第二个 subportfolio,默认为0
Order对象或者None, 如果创建订单成功, 则返回Order对象, 失败则返回None
security: 基金代码编号,OF作为尾缀的字符串,例如招商中证白酒指数分级基金为“161725.OF”
amount: 赎回的份额
pindex: 在使用set_subportfolios创建了多个仓位时,指定subportfolio 的序号, 从 0 开始, 比如 0 指定第一个 subportfolio, 1 指定第二个 subportfolio,默认为0
Order对象或者None, 如果创建订单成功, 则返回Order对象, 失败则返回None
set_redeem_latency(day,type, ref=None)
设置指定类型基金的赎回到帐日, 默认的赎回到帐日: 非货币基金:T+4, QDII:T+7,货币型基金:T+2
day: int 型,day=4 表示 T+4 日到账。
type: 场外基金类型:’bond_fund’/’stock_fund’/’QDII_fund’/’money_market_fund’/’mixture_fund’
ref: 参考代码,仅支持场外基金代码,如 ‘000300.OF’。 取值可以为空, 当 ref 为空时, 表示设置的到账时间对 type 下的所有基金生效。
- None
# 设置股票型基金的到帐日为 T+7
set_redeem_latency(day=7, type='stock_fund')
# 设置 000697.OF 的到帐日为 T+7
set_redeem_latency(day=7, type='stock_fund',ref='000697.OF')
get_fund_info - 基金基础信息数据接口
get_fund_info(security, date=None)
获取单个基金的基本信息
security: 基金代码
date: 查询日期, 一个字符串(格式类似’2015-10-15’)或者datetime.date/datetime.datetime对象, 可以是None, 使用默认日期。回测模块中, 默认日期等于 context.current_dt。 研究模块中, 默认日期是今天。
dict, 各 key 的含义如下:
- fund_name: 基金全称
- fund_type: 基金类型
- fund_establishment_day: 基金成立日
- fund_manager: 基金管理人及基本信息
- fund_management_fee: 基金管理费
- fund_custodian_fee: 基金托管费
- fund_status: 基金申购赎回状态
- fund_size: 基金规模(季度)
- fund_share: 基金份额(季度)
- fund_asset_allocation_proportion: 基金资产配置比例(季度)
- heavy_hold_stocks: 基金重仓股(季度)
- heavy_hold_stocks_proportion: 基金重仓股占基金资产净值比例(季度)
- heavy_hold_bond: 基金重仓债券(季度)
- heavy_hold_bond_proportion: 基金重仓债券占基金资产净值比例(季度)
g.day = 0
# 初始化场外基金仓位
set_subportfolios([SubPortfolioConfig(context.portfolio.cash, 'open_fund')])
# 设置 QDII 的赎回到账日为 T+3
set_redeem_latency(3, 'QDII_fund')
def handle_data(context, data):
s = '000311.OF'
if g.day == 1:
o = purchase(s, 100000)
print o
if g.day == 10:
o2 = redeem(s, 500)
print o2
print context.current_dt
print context.portfolio.cash
print context.portfolio.total_value
g.day += 1
anyjson, arch, graphviz, Lasagne, numpy, pandas, pybrain, scipy, seaborn, sklearn, statsmodels, talib, tushare, Theanom, requests, hmm, hmmlearn, pywt, pycrypto, beautifulsoup4, prettytable, PyBrain, xlrd
研究模块:
anyjson, arch, beautifulsoup4, cvxopt, graphviz, gensim, jieba, matplotlib, mpl_toolkits, numpy, pandas, pybrain, pymc, pillow, scipy, seaborn, sklearn, statsmodels, tables, talib, hmm, hmmlearn, tushare, theano, Lasagne, requests, pywt, zipline, xlrd, xlwt, openpyxl, snownlp, pycrypto, prettytable, PyBrain, seaborn
主要模块介绍:
0.12.2
gensim用于计算文本相似度,依赖NumPy和SciPy这两大Python科学计算工具包
http://radimrehurek.com/gensim/tutorial.html
jieba
jieba是一个中文分词组件
https://pypi.python.org/pypi/jieba
matplotlib
1.4.3
matplotlib可能是Python 2D绘图领域使用最广泛的库。它能让使用者很轻松地将数据图形化,并且提供多样化的输出格式
http://matplotlib.org/contents.html
mpl_toolkits
1.4.3
mpl_toolkits是一个Python 3D绘图领域函数库
http://matplotlib.org/mpl_toolkits/index.html
NumPy
1.9.3
NumPy系统是Python的一种开源的数值计算扩展。NumPy(Numeric Python)提供了许多高级的数值编程工具,如:矩阵数据类型、矢量处理,以及精密的运算库。专为进行严格的数字处理而产生
http://www.numpy.org/
pandas
0.16.2
Python Data Analysis Library 或 pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。Pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具。pandas提供了大量能使我们快速便捷地处理数据的函数和方法
http://pandas.pydata.org/pandas-docs/version/0.16.2/
pybrain
pybrain一个开源的Python神经网络库
http://pybrain.org/docs/
2.3.6
pymc是机器学习中一个图模型的Python库
https://pypi.python.org/pypi/pymc/
SciPy
0.15.1
SciPy是一款方便、易于使用、专为科学和工程设计的Python工具包。它包括统计,优化,整合,线性代数模块,傅里叶变换,信号和图像处理,常微分方程求解器等等
http://www.scipy.org/
seaborn
0.6.0
该模块是一个统计数据可视化库
http://web.stanford.edu/~mwaskom/software/seaborn/
sklearn
Scikit-Learn是基于python的机器学习模块,基于BSD开源许可证。scikit-learn的基本功能主要被分为六个部分,分类,回归,聚类,数据降维,模型选择,数据预处理。Scikit-Learn中的机器学习模型非常丰富,包括SVM,决策树,GBDT,KNN等等,可以根据问题的类型选择合适的模型
http://scikit-learn.org/stable/
Statsmodels
0.6.1
Statismodels是一个Python包,提供一些互补scipy统计计算的功能,包括描述性统计和统计模型估计和推断
http://statsmodels.sourceforge.net/
PyTables
3.2.2
PyTables提供了一些用于结构化数组的高级查询功能,而且还能添加列索引以提升查询速度,这跟关系型数据库所提供的表索引功能非常类似
http://www.pytables.org/usersguide/tutorials.html
TALib
0.4.9
TALib是一个处理金融数据和技术分析的开放代码库
http://mrjbq7.github.io/ta-lib/funcs.html
hmmlearn
0.2.0
是在python上实现隐马可夫模型的一个组件包
https://github.com/hmmlearn/hmmlearn
Theano
0.8.1
Pyhton深度学习库
http://deeplearning.net/software/theano/
Lasagne
Pyhton深度学习库
http://lasagne.readthedocs.org/en/latest/
requests
2.7.0
网络访问模块
http://docs.python-requests.org/en/v2.7.0/
0.4.0
小波工具箱
http://pywavelets.readthedocs.io/en/v0.4.0/
Zipline
0.9.0
开源的交易算法库,目前作为Quantopian的回溯检验引擎
https://github.com/quantopian/zipline
1.0.0
Python语言中,读取Excel的扩展工具
https://pypi.python.org/pypi/xlrd/
1.1.2
Python语言中,写入Excel文件的扩展工具
https://pypi.python.org/pypi/xlwt/
openpyxl
2.4.0
Openpyxl是一个python读写Excel 2010文件的库
http://openpyxl.readthedocs.io/en/default/
snownlp
0.12.3
处理中文文本的Python库
https://pypi.python.org/pypi/snownlp/
pycrypto
2.6.2
Python加密工具包
https://pypi.python.org/pypi/pycrypto
beautifulsoup4
4.5.1
python下很帅气的爬虫包
https://www.crummy.com/software/BeautifulSoup/
prettytable
0.7.2
Python通过prettytable模块可以将输出内容如表格方式整齐的输出。
https://pypi.python.org/pypi/PrettyTable
PyBrain
Python的一个机器学习模块,它的目标是为机器学习任务提供灵活、易应、强大的机器学习算法。
http://www.pybrain.org/
seaborn
0.6.0
基于matplotlib的Python可视化库
http://seaborn.pydata.org/
# 每个单位时间(如果按天回测,则每天调用一次,如果按分钟,则每分钟调用一次)调用一次
def handle_data(context, data):
security = g.security
# 获取股票的收盘价
close_data = attribute_history(security, 10, '1d', ['close'],df=False)
# 取得过去五天的平均价格
ma5 = close_data['close'][-5:].mean()
# 取得过去10天的平均价格
ma10 = close_data['close'].mean()
# 取得当前的现金
cash = context.portfolio.cash
# 如果当前有余额,并且五日均线大于十日均线
if ma5 > ma10:
# 用所有 cash 买入股票
order_value(security, cash)
# 记录这次买入
log.info("Buying %s" % (security))
# 如果五日均线小于十日均线,并且目前有头寸
elif ma5 < ma10 and context.portfolio.positions[security].closeable_amount> 0:
# 全部卖出
order_target(security, 0)
# 记录这次卖出
log.info("Selling %s" % (security))
# 绘制五日均线价格
record(ma5=ma5)
# 绘制十日均线价格
record(ma10=ma10)
双均线策略均线回归策略
当价格低于5日均线平均价格*0.95时买入,当价格高于5日平均价格*1.05时卖出。
# 导入一创聚宽量化交易云平台函数库
import jqdata
# 初始化函数,设定要操作的股票、基准等等
def initialize(context):
# 定义一个全局变量, 保存要操作的股票
# 000001(股票:平安银行)
g.security = '000001.XSHE'
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 每个单位时间(如果按天回测,则每天调用一次,如果按分钟,则每分钟调用一次)调用一次
def handle_data(context, data):
security = g.security
# 获取股票的收盘价
close_data = attribute_history(security, 5, '1d', ['close'])
# 取得过去五天的平均价格
MA5 = close_data['close'].mean()
# 取得上一时间点价格
current_price = close_data['close'][-1]
# 取得当前的现金
cash = context.portfolio.cash
# 如果上一时间点价格高出五天平均价1%, 则全仓买入
if current_price > 1.05*MA5:
# 用所有 cash 买入股票
order_value(security, cash)
# 记录这次买入
log.info("Buying %s" % (security))
# 如果上一时间点价格低于五天平均价, 则空仓卖出
elif current_price < 0.95*MA5 and context.portfolio.positions[security].closeable_amount > 0:
# 卖出所有股票,使这只股票的最终持有量为0
order_target(security, 0)
# 记录这次卖出
log.info("Selling %s" % (security))
# 画出上一时间点价格
record(stock_price=current_price)
# 初始化此策略
# 设置我们要操作的股票池
g.stocks = ['000001.XSHE','000002.XSHE','000004.XSHE','000005.XSHE']
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 每个单位时间(如果按天回测,则每天调用一次,如果按分钟,则每分钟调用一次)调用一次
def handle_data(context, data):
# 循环每只股票
for security in g.stocks:
# 得到股票之前3天的平均价
vwap = data[security].vwap(3)
# 得到上一时间点股票平均价
price = data[security].close
# 得到当前资金余额
cash = context.portfolio.cash
# 如果上一时间点价格小于三天平均价*0.995,并且持有该股票,卖出
if price < vwap * 0.995 and context.portfolio.positions[security].closeable_amount > 0:
# 下入卖出单
order(security,-100)
# 记录这次卖出
log.info("Selling %s" % (security))
# 如果上一时间点价格大于三天平均价*1.005,并且有现金余额,买入
elif price > vwap * 1.005 and cash > 0:
# 下入买入单
order(security,100)
# 记录这次买入
log.info("Buying %s" % (security))
多股票追涨策略
当股票在当日收盘30分钟内涨幅到达9.5%~9.9%时间段的时候,我们进行买入,在第二天开盘卖出。注意:
请按照分钟进行回测该策略
。
# 导入一创聚宽量化交易云平台函数库
import jqdata
# 初始化程序, 整个回测只运行一次
def initialize(context):
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 每天买入股票数量
g.daily_buy_count = 5
# 设置我们要操作的股票池, 这里我们操作多只股票,下列股票选自计算机信息技术相关板块
g.stocks = get_industry_stocks('I64') + get_industry_stocks('I65')
# 防止板块之间重复包含某只股票, 排除掉重复的, g.stocks 现在是一个集合(set)
g.stocks = set(g.stocks)
# 让每天早上开盘时执行 morning_sell_all
run_daily(morning_sell_all, 'open')
def morning_sell_all(context):
# 将目前所有的股票卖出
for security in context.portfolio.positions:
# 全部卖出
order_target(security, 0)
# 记录这次卖出
log.info("Selling %s" % (security))
def before_trading_start(context):
# 今天已经买入的股票
g.today_bought_stocks = set()
# 得到所有股票昨日收盘价, 每天只需要取一次, 所以放在 before_trading_start 中
g.last_df = history(1,'1d','close',g.stocks)
# 在每分钟的第一秒运行, data 是上一分钟的切片数据
def handle_data(context, data):
# 判断是否在当日最后的2小时,我们只追涨最后2小时满足追涨条件的股票
if context.current_dt.hour < 13:
return
# 每天只买这么多个
if len(g.today_bought_stocks) >= g.daily_buy_count:
return
# 只遍历今天还没有买入的股票
for security in (g.stocks - g.today_bought_stocks):
# 得到当前价格
price = data[security].close
# 获取这只股票昨天收盘价
last_close = g.last_df[security][0]
# 如果上一时间点价格已经涨了9.5%~9.9%
# 今天的涨停价格区间大于1元,今天没有买入该支股票
if price/last_close > 1.095 \
and price/last_close < 1.099 \
and data[security].high_limit - last_close >= 1.0:
# 得到当前资金余额
cash = context.portfolio.cash
# 计算今天还需要买入的股票数量
need_count = g.daily_buy_count - len(g.today_bought_stocks)
# 把现金分成几份,
buy_cash = context.portfolio.cash / need_count
# 买入这么多现金的股票
order_value(security, buy_cash)
# 放入今日已买股票的集合
g.today_bought_stocks.add(security)
# 记录这次买入
log.info("Buying %s" % (security))
# 买够5个之后就不买了
if len(g.today_bought_stocks) >= g.daily_buy_count:
break
万圣节效应策略
股市投资中的“万圣节效应”是指在北半球的冬季(11月至4月份),股市回报通常明显高於夏季(5月至10月份)。这里我们选取了中国蓝筹股,采用10月15日后买入,5月15日后卖出的简单策略进行示例。
# 导入一创聚宽量化交易云平台函数库
import jqdata
# 初始化此策略
def initialize(context):
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 设置我们要操作的股票池,这里我们选择蓝筹股
g.stocks = ['000001.XSHE','600000.XSHG','600019.XSHG','600028.XSHG','600030.XSHG','600036.XSHG','600519.XSHG','601398.XSHG','601857.XSHG','601988.XSHG']
# 每个单位时间(如果按天回测,则每天调用一次,如果按分钟,则每分钟调用一次)调用一次
def handle_data(context, data):
# 得到每只股票可以花费的现金,这里我们使用总现金股票数数量
cash = context.portfolio.cash / len(g.stocks)
# 获取数据
hist = history(1,'1d','close',g.stocks)
# 循环股票池
for security in g.stocks:
# 得到当前时间
today = context.current_dt
# 得到该股票上一时间点价格
current_price = hist[security][0]
# 如果当前为10月且日期大于15号,并且现金大于上一时间点价格,并且当前该股票空仓
if today.month == 10 and today.day > 15 and cash > current_price and context.portfolio.positions[security].closeable_amount == 0:
order_value(security, cash)
# 记录这次买入
log.info("Buying %s" % (security))
# 如果当前为5月且日期大于15号,并且当前有该股票持仓,则卖出
elif today.month == 5 and today.day > 15 and context.portfolio.positions[security].closeable_amount > 0:
# 全部卖出
order_target(security, 0)
# 记录这次卖出
log.info("Selling %s" % (security))
如果以上内容仍没有解决您的问题,请您通过
社区提问
的方式告诉我们,谢谢
![]() |
气势凌人的莴苣 · Ora-01426: Numeric Overflow in Package Qp_list_headers_pvt Procedure Process_price_list When Attempt 4 月前 |
![]() |
侠义非凡的课本 · 陈丹青《局部》 - 播单 - 优酷视频 7 月前 |
![]() |
成熟的沙滩裤 · 如何在XPath中找到第一级别的嵌套元素? 11 月前 |
![]() |
小胡子的大葱 · 成都实时技术股份有限公司 1 年前 |