在商品期货交易中,趋势跟踪、日内短线、手工炒单、套利、高频是大家比较常见的几种交易方法,但是除了这些方法之外,网格交易也是一种不错的选择,商品期货量化交易也是可以使用网格策略的,那具体怎么操作呢?本篇我们就用优宽量化(youquant.com)交易平台来实现一个简单的商品期货网格策略,希望大家阅读完这篇文章后可以有所收获,话不多说,一起来看看吧。
网格交易又称渔网交易,它也是量化交易的一种策略,简单的说,网格交易是利用行情震荡波动来赚钱的交易方法,在价格不断上下波动中,通过价格波动的上下区间布置网格低吸高抛获取利润。网格交易不依赖人的主观思考,完全是一种机械行为,比较适合用量化的方式进行交易,利用价格波动在网格区间内低买高卖,通过反复循环差价赚取利润,这种赚取差价的获利方式,可以参照下面这个图片:
网格交易本质上是一种空间变时间的玩法,其秉持的原则是“仓位策略比择时策略更重要”。简单的网格是以某个价位为基准点,当价格上涨戓下跌一定的点数或者一定的比例,挂N手数量空单戓多单,每一个格子即是盈利点位,但通常并不设置止损,当价格朝向与持仓有利的方向运动并达到网格点位时获利平仓,并且在该点位挂同样的买单戓卖单。这样这些交易订单就像渔网一样阵列,在行情的波动中来回盈利。
网格编号 | 网格价格 | 多头持仓 | 空头持仓 |
---|---|---|---|
0 | 5000 | 1 | |
1 | 4950 | 1 | 2 |
2 | 4900 | 2 | 3 |
3 | 4850 | 3 | 4 |
4 | 4800 | 4 | 5 |
5 | 4750 | 5 | 6 |
6 | 4700 | 6 | 7 |
7 | 4650 | 7 | 8 |
8 | 4600 | 8 | 9 |
9 | 4550 | 9 | 10 |
10 | 4500 | 10 |
如上面的表格所示:网格的上限为5000元,下限为4500元,起始价格为5000元,网格的间距是50元,一共有10个网格,多头和空头最大的持仓量为10手。
在设计网格之前,首先需要根据历史数据确定网格的上限和下限,然后根据品种的波动率情况设置网格的宽度,还要根据自己的资金实力设计网格的数量,网格数量越多,则需要加仓的点位就越多,以及计算好补仓资金份额,防止潜在的风险导致破网。
由于网格策略比较适合震荡较多的行情,所以这里选择相对合适的农副产品鸡蛋为标的。从上图中可以发现,鸡蛋品种的期货价格整体呈现出震荡行情,历史的最高价大约在4800附近,历史的最低价大约在3100附近。
回测配置 - 初始资金:100万 - 回测日期:2016-01-01至2021-11-28 - 回测周期:1小时 - 回测品种:鸡蛋指数 - 网格上限:5000 - 网格下限:3000 - 网格间距:50 - 交易数量:1手
从上面的回测报告上来看,该网格策略整体盈利,其中累计收益率为41%,最大回撤率为20%,收益回撤比为2,最大回撤日期是2020年2月4号,从K线图上看鸡蛋指数在这里天价格低于历史最低价,差点破网。但在随后的价格上升中资金曲线又稳步上升。
任何策略是有适用范围的,网格策略也不例外,商品期货属于杠杆交易,尤其是网格交易有逆势加仓的特点,风险巨大!因此在使用网格策略交易商品期货时有两个建议: 1、只做多不做空,这样在买入时确定最大成本。因为商品本身自有价值属性,其归零的可能性几乎没有,所以导致商品易涨难跌,长期来看价格上涨空间大,下跌空间小。 2、在期货期权上买入一定张数的虚沽期权进行保护。因为买入虚沽期权是时间价值,同时卖出平值认沽进行时间价值的对冲。那么如果期货价格上涨,期权因为是时间价值对冲,所以不会亏钱,而期货的多单是能赚钱的;如果期货价格下跌,因为有期权虚沽,所以还能赚钱。 3、使用跨期或跨品种价差进行网格交易。假如单个品种的历史走势有很强的规律性,如鸡蛋品种常年在3500~4500之间震荡,但是这仅仅是历史数据,以历史回测的最大单边幅度去设计网格的承受极限都是不可靠的,历史总是会被打破,谁也不能保证其价格会不会走出长期趋势行情。那么安全期间,我们可以利用主力合约与次主力合约的价差或者有相关性的跨品种价差做网格策略,相比于单品种价差的波动是相对稳定的。
本策略只用于学习、交流、演示,不构成任何投资建议。
'''backtest start: 2016-01-01 00:00:00 end: 2021-11-28 00:00:00 period: 1h basePeriod: 1h exchanges: [{"eid":"Futures_CTP","currency":"FUTURES"}] args: [["space",50],["init_amount",1]] ''' def cancel_order(): orders = exchange.GetOrders() if orders and len(orders) > 0: for i in orders: exchange.CancelOrder(i.Id) def trade(type, price, unit): exchange.SetDirection(type) if type == 'buy' or type == 'closesell': exchange.Buy(price, unit) elif type == 'sell' or type == 'closebuy': exchange.Sell(price, unit) def on_bar(): global buy_line, sell_line position = exchange.GetPosition() depth = exchange.GetDepth() if not depth: return ask = depth['Asks'][0].Price bid = depth['Bids'][0].Price if len(position) == 0: if bid > top: trade('sell', bid, unit * init_amount) # Log(contract_code, '到达开空区域, 买入空头底仓') else: trade('buy', ask, unit * init_amount) # Log(contract_code, '到达开多区域, 买入多头底仓') if len(position) != 1: return if position[0]["Type"] == 1: if ask < bottom: # Log(contract_code, '空单全部止盈反手') trade('closesell', ask, position[0].Amount) else: orders = exchange.GetOrders() if len(orders) == 0: trade('sell', sell_line, unit) trade('closesell', buy_line, unit) if len(orders) == 1: if orders[0]["Type"] == 1: #止盈成交 # Log(contract_code, '网格减仓, 当前份数:', position[0].Amount) cancel_order() buy_line = buy_line - space sell_line = sell_line - space if orders[0]["Type"] == 0: # Log(contract_code, '网格加仓, 当前份数:', position[0].Amount) cancel_order() buy_line = buy_line + space sell_line = sell_line + space if position[0]["Type"] == 0: if bid > top: # Log(contract_code, '多单全部止盈反手') trade('closebuy', bid, position[0].Amount) else: orders = exchange.GetOrders() if len(orders) == 0: trade('buy', buy_line, unit) trade('closebuy', sell_line, unit) if len(orders) == 1: if orders[0]["Type"] == 0: # Log(contract_code, '网格减仓, 当前份数:', position[0].Amount) cancel_order() buy_line = buy_line + space sell_line = sell_line + space if orders[0]["Type"] == 1: # Log(contract_code, '网格加仓, 当前份数:', position[0].Amount) cancel_order() buy_line = buy_line - space sell_line = sell_line - space def initialize(): global buy_line, sell_line while not exchange.IO("status"): Sleep(1000) while not exchange.SetContractType(contract_code): Sleep(1000) if _G('buy_line') and _G('sell_line'): buy_line = _G('buy_line') sell_line = _G('sell_line') # Log('恢复网格') else: while True: ticker = exchange.GetTicker() if ticker: break Sleep(1000) buy_line = ticker["Last"] - space sell_line = ticker["Last"] + space _G('buy_line', buy_line) _G('sell_line', sell_line) # Log('重置网格') def main(): initialize() while True: on_bar() Sleep(1000)