def init(context):
context.s1 = "000001.XSHE"
update_universe([context.s1])
def handle_bar(context, bar_dict):
MA_short= bar_dict[context.s1].mavg(20,frequency='day')
MA_long = bar_dict[context.s1].mavg(50,frequency ='day')
curPosition =context.portfolio.positions[context.s1].quantity
shares = context.portfolio.cash/bar_dict[context.s1].close
如上是上一篇教程写的简单的一个交易策略,接下来我们的目标是建立起交易落单的逻辑,以便于我们使用历史数据进行回测。金叉的交易思路我们在上一篇教程中已经分析,如果短期均线从底部突破长期均线,是买入信号,我们把思路转化为python
代码。
if MA_short > MA_long and curPosition == 0:
order_shares(context.s1,shares)
在这里我们接触到了新的api,就是落单功能order_shares
,这里有两个参数,第一个是股票代码,第二个代表买多少share,如果数值为负数就代表卖出。在这个例子里,我们满仓买入。
Ricequant提供了强大而灵活的各种order的方法,除了最基本的order_shares
之外,还可以使用order_target_value
,order_lot
,order_percent
等等。在上面这个例子中,满仓买入我们使用order_target_percent
会更加方便,在这里传入的第二个参数不再是购买(卖出)的数量,而是购买(卖出)后该股票占到投资组合的百分比,0代表0%,1代表100%。
if MA_short > MA_long and curPosition == 0:
order_target_percent(context.s1,1)
如果短期均线从顶部跌破,那么出现一个清仓的信号。
if MA_short < MA_long and curPosition != 0:
order_target_percent(context.s1,0)
在进行回测前,我们还有最后一个步骤要完成,只要是交易策略不免会涉及到手续费,印花税和滑点费用。目前ricequant的默认设置如下
固定印花税: 0.1%,
手续费: 0.08% - 可以用context.commission
手动修改(废弃)
滑点: 0.246% - 可以用context.slippage
手动修改(废弃)
第一个完整回测策略:
def init(context):
context.s1 = "000001.XSHE"
context.slippage = 0.05
update_universe([context.s1])
def handle_bar(context, bar_dict):
MA_short= bar_dict[context.s1].mavg(20,frequency ='day')
MA_long = bar_dict[context.s1].mavg(50,frequency ='day')
curPosition =context.portfolio.positions[context.s1].quantity
shares = context.portfolio.cash/bar_dict[context.s1].close
if MA_short > MA_long and curPosition == 0:
order_target_percent(context.s1,1)
if MA_short < MA_long and curPosition != 0:
order_target_percent(context.s1,0)
除了策略表现以外,我们经常希望直观的看到一些历史数据以图表的方式展现出来,以上面金叉策略为例,我们想画出短均线,长均线和股票价格,可是直观地看出产生金叉的时候是不是一个交易的好的信号。
这时候就可以使用Ricequant的plot 功能来实现,在上述策略中的handle_bar function下面加入这几行代码
plot('close', bar_dict[context.s1].close)
plot('short_avg',MA_short)
plot('long_avg',MA_long)
这段code的意义是在每个handle_bar的时间切片上绘制下该时间的数值,这个数值可以是bar_dict当中存储的股票价格,也可以是任意我们赋值的参数,比如当前的N日均价,或者当天的某个技术指标(之后的教程中会降到),等等。
Ricequant的回测结果中,我们比较关心的回测数据主要是
1.回测收益 & 基准收益
这是最直观的收益对比。其他风险数据相似的情况下,回测收益相对基准收益越高,策略表现越好。
2.Beta
Beta 主要是衡量策略相对于大盘的系统风险性。比较优秀稳健的量化策略通常追求较低的beta值,降低策略的系统风险。也就是说无论大盘是熊是牛都能保证稳定的收益。
降低策略的beta值有几种方法,1)在策略中加入对冲部分 2)在只能做单边的情况下,增加股票数量,选择相关性较低的一篮子股票。
3.最大回撤和波动率
这两个数据主要是体现策略的风险性。波动率越高,最大回撤越高,策略的风险性就越大。最大回撤的数值尤为重要,如果看到过大的最大回撤,通常要考虑策略的可行性,增加止损或者其他有效的仓位控制方式。
4.夏普比率
Sharpe Ratio,和Sortino Ratio一样,是把风险和收益综合起来的数据,可以看成是一种考虑风险因素之后的调整收益率 。夏普指数越高,相当于每多承担一份风险,获得的额外收益越高。这是我们在策略调试中,综合衡量评定一个策略价值的重要标准。
为何需要查看回测历史?
为了让大家更方便的看到同一策略使用不同参数和不同时间段的回测表现,我们开发了查看回测历史的功能,在每一个策略下面,都能看到所有的历史回测表现。
比如我们可以选择在14-15年的牛市段和13-14年的熊市段分别运行金叉这样的动量策略
当然值得注意的是,不管是参数优化还是市场行情相关,我们在优化策略的时候仍然需要以理论框架为出发点,不然单纯追求回报率,很容易造成历史数据过度拟合的情况。
order_lots(id_or_ins, amount, style=OrderType)
指定手数发送买/卖单。如有需要落单类型当做一个参量传入,如果忽略掉落单类型,那么默认是市价单(market order)。
参数
参数 类型 注释 id_or_ins str或instrument对象 order_book_id或symbol或instrument对象,用户必须指定 amount float 多少手的数目。正数表示买入,负数表示卖出,用户必须指定 style OrderType 订单类型,默认是市价单。目前支持的订单类型有:
- style=MarketOrder
- style=LimitOrder(limit_price)
范例
order_lots('000001.XSHE', 20)
order_lots('000001.XSHE', 10, style=LimitOrder(10))
plot(series_name, value)
plot
函数可以将时间序列的数据传给页面进行绘图,结果是以时间为横轴,value为纵轴的曲线。
参数
参数 类型 注释 series_name str 绘制曲线的名称,用户必须填写 value float 当前日期的曲线的点的值,用户必须填写
范例
# 你选择的证券的数据更新将会触发此段逻辑,例如日或分钟历史数据切片或者是实时数据切片更新
def handle_bar(context, bar_dict):
# TODO: 开始编写你的算法吧!
plot('close', bar_dict['000001.XSHE'].close)
plot('high', bar_dict['000001.XSHE'].high)
plot('low', bar_dict['000001.XSHE'].low)
plot('open', bar_dict['000001.XSHE'].open)
以上代码画图的结果截图:
order_percent(id_or_ins, percent, style=OrderType)
发送一个等于目前投资组合价值(市场价值和目前现金的总和)一定百分比的买/卖单,正数代表买,负数代表卖(暂不支持卖空)。股票的股数总是会被调整成对应的一手的股票数的倍数(1手是100股)。百分比是一个小数,并且小于1(<100%),0.5表示的是50%.需要注意,百分比不能为1,因为下单时手续费将会计入下单金额中。当买入股票所需金额加上手续费大于资金时,该API将不会创建发送订单。
参数
参数 类型 注释 id_or_ins str或instrument对象 order_book_id或symbol或instrument object,用户必须指定 percent float 占有现有的投资组合价值的百分比。正数表示买入,负数表示卖出。用户必须指定 style OrderType 订单类型,默认是市价单。目前支持的订单类型有:
- style=MarketOrder()
- style=LimitOrder(limit_price)
范例
order_percent('000001.XSHE', 0.5)
order_target_value(id_or_ins, cash_amount, style=OrderType)
买入/卖出并且自动调整该证券的仓位到一个目标价值(暂不支持卖空)。如果还没有任何该证券的仓位,那么会买入全部目标价值的证券。如果已经有了该证券的仓位,则会买入/卖出调整该证券的现在仓位和目标仓位的价值差值的数目的证券。需要注意,如果资金不足,该API将不会创建发送订单。
参数
参数 类型 注释 id_or_ins str或instrument对象 order_book_id或symbol或instrument object,用户必须指定 cash_amount float-required 最终的该证券的仓位目标价值 style OrderType 订单类型,默认是市价单。目前支持的订单类型有:
- style=MarketOrder()
- style=LimitOrder(limit_price)
范例
order_target_value('000001.XSHE', 10000)
为了更好模拟实际交易中订单对市场的冲击,我们引入滑点的设置。您可以在策略编辑页面"更多"选项下进行滑点设置,允许设置的范围是[0, 1)。该设置将在一定程度上使最后的成交价"恶化",也就是买得更贵,卖得更便宜。我们的滑点方式是按照最后成交价的一定比例进行恶化。例如,设置滑点为0.1,那么如果原本买入交易的成交价为10元,则设置之后成交价将变成11元,即买得更贵。
注意,滑点默认为0,原有的默认0.246%的滑点值以及通过context.slippage设置的方式被废弃。