spring.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. # coding=utf-8
  2. from __future__ import print_function, absolute_import
  3. from gm.api import *
  4. from MyTT import *
  5. """
  6. 示例策略仅供参考,不建议直接实盘使用。
  7. 本策略采用布林线进行均值回归交易。当价格触及布林线上轨的时候进行卖出,当触及下轨的时候,进行买入。
  8. """
  9. # 策略中必须有init方法
  10. def init(context):
  11. # 设置布林线的三个参数
  12. context.maPeriod = 26 # 计算BOLL布林线中轨的参数
  13. context.stdPeriod = 150 # 计算BOLL 标准差的参数
  14. context.stdRange = 1 # 计算BOLL 上下轨和中轨距离的参数
  15. # 设置要进行回测的合约
  16. context.symbol2 = 'SZSE.399673' # 订阅&交易标的, 此处订阅的是600004 ['SHSE.600519', 'SHSE.600419'],
  17. context.symbol = 'SZSE.159949'
  18. context.symbolTwo = ['SZSE.399673','SZSE.159949']
  19. context.period = max(context.maPeriod, context.stdPeriod, context.stdRange) + 1 # 订阅数据滑窗长度
  20. # 订阅行情
  21. subscribe(symbols= context.symbolTwo, frequency='1d', count=context.period)
  22. def on_bar(context, bars):
  23. # 获取数据滑窗,只要在init里面有订阅,在这里就可以取的到,返回值是pandas.DataFrame
  24. data2 = context.data(symbol=context.symbol, frequency='1d', count=context.period, fields='close,open,high,low,bob,eob')
  25. data = context.data(symbol=context.symbol2, frequency='1d', count=context.period, fields='close,open,high,low,bob,eob')
  26. # print(data2)
  27. #print(data.bob.values[-1])
  28. close = data.close.values
  29. low = data.low.values
  30. high = data.high.values
  31. dopen = data.open.values
  32. H1_5 = EMA(close, 8)
  33. H2_5 = EMA(H1_5, 20)
  34. # print('h1-5:', H1_5[-4:])
  35. # print('h2-5:', H2_5[-4:])
  36. H1H2_CROSS = CROSS(H1_5, H2_5)
  37. H2H1_CROSS = CROSS(H2_5, H1_5)
  38. # print('cross H1 H2:', H1H2_CROSS)
  39. # print('cross H2 H1', H2H1_CROSS)
  40. # qrld
  41. rsv = (close - LLV(low, 7)) / (HHV(high, 7) - LLV(low, 7)) * 100
  42. rsv = np.nan_to_num(rsv)
  43. # print('rsv :', rsv)
  44. Y0 = SMA(rsv, 3, 1)
  45. Y0 = np.nan_to_num(Y0)
  46. # print('Y0 :', Y0)
  47. Y1 = SMA(Y0, 3, 1)
  48. Y1 = np.nan_to_num(Y1)
  49. # print('Y1 :', Y1)
  50. CROSS_Y0_Y1 = CROSS(Y0, Y1)
  51. CROSS_Y1_Y0 = CROSS(Y1, Y0)
  52. RSV1 = (close - LLV(low, 38)) / (HHV(high, 38) - LLV(low, 38)) * 100
  53. RSV1 = np.nan_to_num(RSV1)
  54. # print('RSV1 :', RSV1)
  55. Y2 = SMA(RSV1, 5, 1)
  56. Y2 = np.nan_to_num(Y2)
  57. # print('Y2 :', Y2)
  58. Y3 = SMA(Y2, 10, 1)
  59. Y3 = np.nan_to_num(Y3)
  60. # print('Y3 :', Y3)
  61. # lq
  62. N = 1
  63. xopen = (REF(dopen, N) + REF(close, N)) / 2
  64. xclose = close
  65. xhigh = MAX(high, xopen)
  66. xlow = MIN(low, xopen)
  67. volality = MA(xhigh - xlow, 8)
  68. h_line = MA(xclose, 5) + volality / 2
  69. f_line = MA(xclose, 5) - volality / 2
  70. bu = CROSS(xclose, h_line)
  71. sel = CROSS(f_line, xclose)
  72. var1 = BARSLAST(bu)
  73. var2 = BARSLAST(sel)
  74. # 布林带上轨
  75. bollUpper = H1H2_CROSS
  76. # 布林带下轨
  77. bollBottom = H2H1_CROSS
  78. # cross_kdj_up = cross_y0_y1[-1] and (Y0[-1] > Y1[-1]);
  79. a1 = (H1_5[-1]-H2_5[-1])/((H1_5[-1]+H2_5[-1])/2)
  80. b1 = (Y2[-1] - Y3[-1]) / 100
  81. c1 = (Y2[-1] + Y3[-1]) / 2
  82. if(CROSS_Y0_Y1[-1] == 0 or CROSS_Y1_Y0[-1] == 0):
  83. return
  84. else:
  85. #print('有信号:CROSS_Y0_Y1[-1]:'+str(CROSS_Y0_Y1[-1]))
  86. #print('有信号:CROSS_Y1_Y0[-1]:'+str(CROSS_Y1_Y0[-1]))
  87. pos = list(filter(lambda x:x['symbol']==context.symbol,get_position()))
  88. if(Y0[-1]>Y1[-1] and (b1>0) and ( a1>-0.02 or a1<0.02)):
  89. #BUY
  90. if( (a1<-0.04 or b1<-0.17)):
  91. # print('a#1<-0.04 or b1<-0.17 cant buy')
  92. return
  93. # 交易逻辑与下单
  94. # 当有持仓,且股价穿过BOLL上界的时候卖出股票。
  95. # # 当没有持仓,且股价穿过BOLL下界的时候买入股票。
  96. if not pos:
  97. cash_info = get_cash() # 返回 DictLikeObject
  98. balance = cash_info['balance'] # 仍然可以通过键访问
  99. # print("balance b:"+str(balance))
  100. volumeTmp = int(balance/data2.close.values[-1])
  101. volumeTmp = (volumeTmp // 100) * 100 - 500
  102. order_volume(symbol=context.symbol, volume=volumeTmp, side=OrderSide_Buy,
  103. order_type=OrderType_Limit, position_effect=PositionEffect_Open, price=data2.close.values[-1])
  104. elif(Y0[-1]<=Y1[-1] and ( a1>-0.02 or a1<0.02)):
  105. #sell
  106. # print("a1:"+str(a1))
  107. if(a1>0.05):
  108. print("a1>0.05")
  109. return
  110. if pos :
  111. cash_info = get_cash() # 返回 DictLikeObject
  112. balance = cash_info['balance'] # 仍然可以通过键访问
  113. #print("balance s:"+str(balance))
  114. #print("pos:"+str(pos))
  115. volume_value = next((p['volume'] for p in pos if p['symbol'] == 'SZSE.159949'), None)
  116. volumeTmp = int(volume_value)
  117. order_volume(symbol=context.symbol, volume=volumeTmp, side=OrderSide_Sell,
  118. order_type=OrderType_Limit, position_effect=PositionEffect_Close, price=data2.close.values[-1])
  119. # 交易逻辑与下单
  120. # 当有持仓,且股价穿过BOLL上界的时候卖出股票。
  121. # if pos and (bollBottom[-1] or bollUpper[-1]) and (H1_5[-1]<H2_5[-1]) :
  122. # cash_info = get_cash() # 返回 DictLikeObject
  123. # balance = cash_info['balance'] # 仍然可以通过键访问
  124. # print("balance s:"+str(balance))
  125. # print("pos:"+str(pos))
  126. # volume_value = next((p['volume'] for p in pos if p['symbol'] == 'SZSE.159949'), None)
  127. # volumeTmp = int(volume_value)
  128. # order_volume(symbol=context.symbol, volume=volumeTmp, side=OrderSide_Sell,
  129. # order_type=OrderType_Limit, position_effect=PositionEffect_Close, price=data2.close.values[-1])
  130. # # 当没有持仓,且股价穿过BOLL下界的时候买入股票。
  131. # elif not pos and (bollBottom[-1] or bollUpper[-1]) and ((H1_5[-1]>=H2_5[-1])):
  132. # cash_info = get_cash() # 返回 DictLikeObject
  133. # balance = cash_info['balance'] # 仍然可以通过键访问
  134. # print("balance b:"+str(balance))
  135. # volumeTmp = int(balance/data2.close.values[-1])
  136. # volumeTmp = (volumeTmp // 100) * 100 - 500
  137. # order_volume(symbol=context.symbol, volume=volumeTmp, side=OrderSide_Buy,
  138. # order_type=OrderType_Limit, position_effect=PositionEffect_Open, price=data2.close.values[-1])
  139. def on_order_status(context, order):
  140. # 标的代码
  141. symbol = order['symbol']
  142. # 委托价格
  143. price = order['price']
  144. # 委托数量
  145. volume = order['volume']
  146. # 目标仓位
  147. target_percent = order['target_percent']
  148. # 查看下单后的委托状态,等于3代表委托全部成交
  149. status = order['status']
  150. # 买卖方向,1为买入,2为卖出
  151. side = order['side']
  152. # 开平仓类型,1为开仓,2为平仓
  153. effect = order['position_effect']
  154. # 委托类型,1为限价委托,2为市价委托
  155. order_type = order['order_type']
  156. if status == 3:
  157. if effect == 1:
  158. if side == 1:
  159. side_effect = '开多仓'
  160. else:
  161. side_effect = '开空仓'
  162. else:
  163. if side == 1:
  164. side_effect = '平空仓'
  165. else:
  166. side_effect = '平多仓'
  167. order_type_word = '限价' if order_type==1 else '市价'
  168. print('{}:标的:{},操作:以{}{},委托价格:{},委托数量:{}'.format(context.now,symbol,order_type_word,side_effect,price,volume))
  169. def on_backtest_finished(context, indicator):
  170. print('*'*50)
  171. print('回测已完成,请通过右上角“回测历史”功能查询详情。')
  172. if __name__ == '__main__':
  173. '''
  174. strategy_id策略ID,由系统生成
  175. filename文件名,请与本文件名保持一致
  176. mode实时模式:MODE_LIVE回测模式:MODE_BACKTEST
  177. token绑定计算机的ID,可在系统设置-密钥管理中生成
  178. backtest_start_time回测开始时间
  179. backtest_end_time回测结束时间
  180. backtest_adjust股票复权方式不复权:ADJUST_NONE前复权:ADJUST_PREV后复权:ADJUST_POST
  181. backtest_initial_cash回测初始资金
  182. backtest_commission_ratio回测佣金比例
  183. backtest_slippage_ratio回测滑点比例
  184. backtest_match_mode市价撮合模式,以下一tick/bar开盘价撮合:0,以当前tick/bar收盘价撮合:1
  185. '''
  186. run(strategy_id='3b7f1e3f-8e41-11f0-aae9-00155d8e2a12',
  187. filename='main.py',
  188. mode=MODE_BACKTEST,
  189. token='a130ee5e899369902d1e95d0a116b297ad1edbfb',
  190. backtest_start_time='2016-08-01 08:00:00',
  191. backtest_end_time='2025-09-19 15:30:00',
  192. backtest_adjust=ADJUST_PREV,
  193. backtest_initial_cash=10000,
  194. backtest_commission_ratio=0.0001,
  195. backtest_slippage_ratio=0.0001,
  196. backtest_match_mode=1)