| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- # coding=utf-8
- from __future__ import print_function, absolute_import
- from gm.api import *
- from MyTT import *
- """
- 示例策略仅供参考,不建议直接实盘使用。
- 本策略采用布林线进行均值回归交易。当价格触及布林线上轨的时候进行卖出,当触及下轨的时候,进行买入。
- """
- # 策略中必须有init方法
- def init(context):
- # 设置布林线的三个参数
- context.maPeriod = 26 # 计算BOLL布林线中轨的参数
- context.stdPeriod = 150 # 计算BOLL 标准差的参数
- context.stdRange = 1 # 计算BOLL 上下轨和中轨距离的参数
- # 设置要进行回测的合约
- context.symbol2 = 'SZSE.399673' # 订阅&交易标的, 此处订阅的是600004 ['SHSE.600519', 'SHSE.600419'],
- context.symbol = 'SZSE.159949'
- context.symbolTwo = ['SZSE.399673','SZSE.159949']
- context.period = max(context.maPeriod, context.stdPeriod, context.stdRange) + 1 # 订阅数据滑窗长度
- # 订阅行情
- subscribe(symbols= context.symbolTwo, frequency='1d', count=context.period)
- def on_bar(context, bars):
- # 获取数据滑窗,只要在init里面有订阅,在这里就可以取的到,返回值是pandas.DataFrame
- data2 = context.data(symbol=context.symbol, frequency='1d', count=context.period, fields='close,open,high,low,bob,eob')
- data = context.data(symbol=context.symbol2, frequency='1d', count=context.period, fields='close,open,high,low,bob,eob')
- # print(data2)
- #print(data.bob.values[-1])
- close = data.close.values
- low = data.low.values
- high = data.high.values
- dopen = data.open.values
- H1_5 = EMA(close, 8)
- H2_5 = EMA(H1_5, 20)
- # print('h1-5:', H1_5[-4:])
- # print('h2-5:', H2_5[-4:])
- H1H2_CROSS = CROSS(H1_5, H2_5)
- H2H1_CROSS = CROSS(H2_5, H1_5)
- # print('cross H1 H2:', H1H2_CROSS)
- # print('cross H2 H1', H2H1_CROSS)
- # qrld
- rsv = (close - LLV(low, 7)) / (HHV(high, 7) - LLV(low, 7)) * 100
- rsv = np.nan_to_num(rsv)
- # print('rsv :', rsv)
- Y0 = SMA(rsv, 3, 1)
- Y0 = np.nan_to_num(Y0)
- # print('Y0 :', Y0)
- Y1 = SMA(Y0, 3, 1)
- Y1 = np.nan_to_num(Y1)
- # print('Y1 :', Y1)
- CROSS_Y0_Y1 = CROSS(Y0, Y1)
- CROSS_Y1_Y0 = CROSS(Y1, Y0)
- RSV1 = (close - LLV(low, 38)) / (HHV(high, 38) - LLV(low, 38)) * 100
- RSV1 = np.nan_to_num(RSV1)
- # print('RSV1 :', RSV1)
- Y2 = SMA(RSV1, 5, 1)
- Y2 = np.nan_to_num(Y2)
- # print('Y2 :', Y2)
- Y3 = SMA(Y2, 10, 1)
- Y3 = np.nan_to_num(Y3)
- # print('Y3 :', Y3)
- # lq
- N = 1
- xopen = (REF(dopen, N) + REF(close, N)) / 2
- xclose = close
- xhigh = MAX(high, xopen)
- xlow = MIN(low, xopen)
- volality = MA(xhigh - xlow, 8)
- h_line = MA(xclose, 5) + volality / 2
- f_line = MA(xclose, 5) - volality / 2
- bu = CROSS(xclose, h_line)
- sel = CROSS(f_line, xclose)
- var1 = BARSLAST(bu)
- var2 = BARSLAST(sel)
- # 布林带上轨
- bollUpper = H1H2_CROSS
- # 布林带下轨
- bollBottom = H2H1_CROSS
- # cross_kdj_up = cross_y0_y1[-1] and (Y0[-1] > Y1[-1]);
- a1 = (H1_5[-1]-H2_5[-1])/((H1_5[-1]+H2_5[-1])/2)
- b1 = (Y2[-1] - Y3[-1]) / 100
- c1 = (Y2[-1] + Y3[-1]) / 2
- if(CROSS_Y0_Y1[-1] == 0 or CROSS_Y1_Y0[-1] == 0):
- return
- else:
- #print('有信号:CROSS_Y0_Y1[-1]:'+str(CROSS_Y0_Y1[-1]))
- #print('有信号:CROSS_Y1_Y0[-1]:'+str(CROSS_Y1_Y0[-1]))
- pos = list(filter(lambda x:x['symbol']==context.symbol,get_position()))
- if(Y0[-1]>Y1[-1] and (b1>0) and ( a1>-0.02 or a1<0.02)):
- #BUY
- if( (a1<-0.04 or b1<-0.17)):
- # print('a#1<-0.04 or b1<-0.17 cant buy')
- return
- # 交易逻辑与下单
- # 当有持仓,且股价穿过BOLL上界的时候卖出股票。
- # # 当没有持仓,且股价穿过BOLL下界的时候买入股票。
- if not pos:
- cash_info = get_cash() # 返回 DictLikeObject
- balance = cash_info['balance'] # 仍然可以通过键访问
- # print("balance b:"+str(balance))
- volumeTmp = int(balance/data2.close.values[-1])
- volumeTmp = (volumeTmp // 100) * 100 - 500
- order_volume(symbol=context.symbol, volume=volumeTmp, side=OrderSide_Buy,
- order_type=OrderType_Limit, position_effect=PositionEffect_Open, price=data2.close.values[-1])
- elif(Y0[-1]<=Y1[-1] and ( a1>-0.02 or a1<0.02)):
- #sell
- # print("a1:"+str(a1))
- if(a1>0.05):
- print("a1>0.05")
- return
- if pos :
- cash_info = get_cash() # 返回 DictLikeObject
- balance = cash_info['balance'] # 仍然可以通过键访问
- #print("balance s:"+str(balance))
- #print("pos:"+str(pos))
- volume_value = next((p['volume'] for p in pos if p['symbol'] == 'SZSE.159949'), None)
- volumeTmp = int(volume_value)
- order_volume(symbol=context.symbol, volume=volumeTmp, side=OrderSide_Sell,
- order_type=OrderType_Limit, position_effect=PositionEffect_Close, price=data2.close.values[-1])
- # 交易逻辑与下单
- # 当有持仓,且股价穿过BOLL上界的时候卖出股票。
- # if pos and (bollBottom[-1] or bollUpper[-1]) and (H1_5[-1]<H2_5[-1]) :
- # cash_info = get_cash() # 返回 DictLikeObject
- # balance = cash_info['balance'] # 仍然可以通过键访问
- # print("balance s:"+str(balance))
- # print("pos:"+str(pos))
- # volume_value = next((p['volume'] for p in pos if p['symbol'] == 'SZSE.159949'), None)
- # volumeTmp = int(volume_value)
- # order_volume(symbol=context.symbol, volume=volumeTmp, side=OrderSide_Sell,
- # order_type=OrderType_Limit, position_effect=PositionEffect_Close, price=data2.close.values[-1])
- # # 当没有持仓,且股价穿过BOLL下界的时候买入股票。
- # elif not pos and (bollBottom[-1] or bollUpper[-1]) and ((H1_5[-1]>=H2_5[-1])):
- # cash_info = get_cash() # 返回 DictLikeObject
- # balance = cash_info['balance'] # 仍然可以通过键访问
- # print("balance b:"+str(balance))
- # volumeTmp = int(balance/data2.close.values[-1])
- # volumeTmp = (volumeTmp // 100) * 100 - 500
- # order_volume(symbol=context.symbol, volume=volumeTmp, side=OrderSide_Buy,
- # order_type=OrderType_Limit, position_effect=PositionEffect_Open, price=data2.close.values[-1])
- def on_order_status(context, order):
- # 标的代码
- symbol = order['symbol']
- # 委托价格
- price = order['price']
- # 委托数量
- volume = order['volume']
- # 目标仓位
- target_percent = order['target_percent']
- # 查看下单后的委托状态,等于3代表委托全部成交
- status = order['status']
- # 买卖方向,1为买入,2为卖出
- side = order['side']
- # 开平仓类型,1为开仓,2为平仓
- effect = order['position_effect']
- # 委托类型,1为限价委托,2为市价委托
- order_type = order['order_type']
- if status == 3:
- if effect == 1:
- if side == 1:
- side_effect = '开多仓'
- else:
- side_effect = '开空仓'
- else:
- if side == 1:
- side_effect = '平空仓'
- else:
- side_effect = '平多仓'
- order_type_word = '限价' if order_type==1 else '市价'
- print('{}:标的:{},操作:以{}{},委托价格:{},委托数量:{}'.format(context.now,symbol,order_type_word,side_effect,price,volume))
- def on_backtest_finished(context, indicator):
- print('*'*50)
- print('回测已完成,请通过右上角“回测历史”功能查询详情。')
- if __name__ == '__main__':
- '''
- strategy_id策略ID,由系统生成
- filename文件名,请与本文件名保持一致
- mode实时模式:MODE_LIVE回测模式:MODE_BACKTEST
- token绑定计算机的ID,可在系统设置-密钥管理中生成
- backtest_start_time回测开始时间
- backtest_end_time回测结束时间
- backtest_adjust股票复权方式不复权:ADJUST_NONE前复权:ADJUST_PREV后复权:ADJUST_POST
- backtest_initial_cash回测初始资金
- backtest_commission_ratio回测佣金比例
- backtest_slippage_ratio回测滑点比例
- backtest_match_mode市价撮合模式,以下一tick/bar开盘价撮合:0,以当前tick/bar收盘价撮合:1
- '''
- run(strategy_id='3b7f1e3f-8e41-11f0-aae9-00155d8e2a12',
- filename='main.py',
- mode=MODE_BACKTEST,
- token='a130ee5e899369902d1e95d0a116b297ad1edbfb',
- backtest_start_time='2016-08-01 08:00:00',
- backtest_end_time='2025-09-19 15:30:00',
- backtest_adjust=ADJUST_PREV,
- backtest_initial_cash=10000,
- backtest_commission_ratio=0.0001,
- backtest_slippage_ratio=0.0001,
- backtest_match_mode=1)
|