├── README.md ├── attach.png └── example.py /README.md: -------------------------------------------------------------------------------- 1 | # 海龟交易法(期货) 2 | 基于海龟交易法则的交易策略 3 | 4 | ## 源码 5 | ```python 6 | # coding=utf-8 7 | from __future__ import print_function, absolute_import, unicode_literals 8 | 9 | import sys 10 | 11 | import numpy as np 12 | import pandas as pd 13 | 14 | try: 15 | import talib 16 | except: 17 | print('请安装TA-Lib库') 18 | sys.exit(-1) 19 | from gm.api import * 20 | 21 | ''' 22 | 本策略通过计算CZCE.FG801和SHFE.rb1801的ATR.唐奇安通道和MA线, 23 | 当价格上穿唐奇安通道且短MA在长MA上方时开多仓;当价格下穿唐奇安通道且短MA在长MA下方时开空仓(8手) 24 | 若有多仓则在价格跌破唐奇安平仓通道下轨的时候全平仓位,否则根据跌破 25 | 持仓均价 - x(x=0.5,1,1.5,2)倍ATR把仓位平至6/4/2/0手 26 | 若有空仓则在价格涨破唐奇安平仓通道上轨的时候全平仓位,否则根据涨破 27 | 持仓均价 + x(x=0.5,1,1.5,2)倍ATR把仓位平至6/4/2/0手 28 | 回测数据为:CZCE.FG801和SHFE.rb1801的1min数据 29 | 回测时间为:2017-09-15 09:15:00到2017-10-01 15:00:00 30 | ''' 31 | 32 | 33 | def init(context): 34 | # context.parameter分别为唐奇安开仓通道.唐奇安平仓通道.短ma.长ma.ATR的参数 35 | context.parameter = [55, 20, 10, 60, 20] 36 | context.tar = context.parameter[4] 37 | # context.goods交易的品种 38 | context.goods = ['CZCE.FG801', 'SHFE.rb1801'] 39 | # 订阅context.goods里面的品种, bar频率为1min 40 | subscribe(symbols=context.goods, frequency='60s', count=101) 41 | # 止损的比例区间 42 | 43 | 44 | def on_bar(context, bars): 45 | bar = bars[0] 46 | symbol = bar['symbol'] 47 | recent_data = context.data(symbol=symbol, frequency='60s', count=101, fields='close,high,low') 48 | close = recent_data['close'].values[-1] 49 | # 计算ATR 50 | atr = talib.ATR(recent_data['high'].values, recent_data['low'].values, recent_data['close'].values, 51 | timeperiod=context.tar)[-1] 52 | # 计算唐奇安开仓和平仓通道 53 | context.don_open = context.parameter[0] + 1 54 | upper_band = talib.MAX(recent_data['close'].values[:-1], timeperiod=context.don_open)[-1] 55 | context.don_close = context.parameter[1] + 1 56 | lower_band = talib.MIN(recent_data['close'].values[:-1], timeperiod=context.don_close)[-1] 57 | # 若没有仓位则开仓 58 | position_long = context.account().position(symbol=symbol, side=PositionSide_Long) 59 | 60 | position_short = context.account().position(symbol=symbol, side=PositionSide_Short) 61 | if not position_long and not position_short: 62 | # 计算长短ma线.DIF 63 | ma_short = talib.MA(recent_data['close'].values, timeperiod=(context.parameter[2] + 1))[-1] 64 | ma_long = talib.MA(recent_data['close'].values, timeperiod=(context.parameter[3] + 1))[-1] 65 | dif = ma_short - ma_long 66 | # 获取当前价格 67 | # 上穿唐奇安通道且短ma在长ma上方则开多仓 68 | if close > upper_band and (dif > 0): 69 | order_target_volume(symbol=symbol, volume=8, position_side=PositionSide_Long, order_type=OrderType_Market) 70 | print(symbol, '市价单开多仓8手') 71 | # 下穿唐奇安通道且短ma在长ma下方则开空仓 72 | if close < lower_band and (dif < 0): 73 | order_target_volume(symbol=symbol, volume=8, position_side=PositionSide_Short, order_type=OrderType_Market) 74 | print(symbol, '市价单开空仓8手') 75 | elif position_long: 76 | # 价格跌破唐奇安平仓通道全平仓位止损 77 | if close < lower_band: 78 | order_close_all() 79 | print(symbol, '市价单全平仓位') 80 | else: 81 | # 获取持仓均价 82 | vwap = position_long['vwap'] 83 | # 获取持仓的资金 84 | band = vwap - np.array([200, 2, 1.5, 1, 0.5, -100]) * atr 85 | # 计算最新应持仓位 86 | grid_volume = int(pd.cut([close], band, labels=[0, 1, 2, 3, 4])[0]) * 2 87 | order_target_volume(symbol=symbol, volume=grid_volume, position_side=PositionSide_Long, 88 | order_type=OrderType_Market) 89 | print(symbol, '市价单平多仓到', grid_volume, '手') 90 | elif position_short: 91 | # 价格涨破唐奇安平仓通道或价格涨破持仓均价加两倍ATR平空仓 92 | if close > upper_band: 93 | order_close_all() 94 | print(symbol, '市价单全平仓位') 95 | else: 96 | # 获取持仓均价 97 | vwap = position_short['vwap'] 98 | # 获取平仓的区间 99 | band = vwap + np.array([-100, 0.5, 1, 1.5, 2, 200]) * atr 100 | # 计算最新应持仓位 101 | grid_volume = int(pd.cut([close], band, labels=[0, 1, 2, 3, 4])[0]) * 2 102 | order_target_volume(symbol=symbol, volume=grid_volume, position_side=PositionSide_Short, 103 | order_type=OrderType_Market) 104 | print(symbol, '市价单平空仓到', grid_volume, '手') 105 | 106 | 107 | if __name__ == '__main__': 108 | ''' 109 | strategy_id策略ID,由系统生成 110 | filename文件名,请与本文件名保持一致 111 | mode实时模式:MODE_LIVE回测模式:MODE_BACKTEST 112 | token绑定计算机的ID,可在系统设置-密钥管理中生成 113 | backtest_start_time回测开始时间 114 | backtest_end_time回测结束时间 115 | backtest_adjust股票复权方式不复权:ADJUST_NONE前复权:ADJUST_PREV后复权:ADJUST_POST 116 | backtest_initial_cash回测初始资金 117 | backtest_commission_ratio回测佣金比例 118 | backtest_slippage_ratio回测滑点比例 119 | ''' 120 | run(strategy_id='strategy_id', 121 | filename='main.py', 122 | mode=MODE_BACKTEST, 123 | token='token_id', 124 | backtest_start_time='2017-09-15 09:15:00', 125 | backtest_end_time='2017-10-01 15:00:00', 126 | backtest_adjust=ADJUST_PREV, 127 | backtest_initial_cash=10000000, 128 | backtest_commission_ratio=0.0001, 129 | backtest_slippage_ratio=0.0001) 130 | ``` 131 | 132 | ## 绩效 133 | ![绩效](attach.png) 134 | -------------------------------------------------------------------------------- /attach.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TruthHun/Turtle-Trading/4975386d21f10426c0aece5b1821ba9370e644fa/attach.png -------------------------------------------------------------------------------- /example.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | from __future__ import print_function, absolute_import, unicode_literals 3 | 4 | import sys 5 | 6 | import numpy as np 7 | import pandas as pd 8 | 9 | try: 10 | import talib 11 | except: 12 | print('请安装TA-Lib库') 13 | sys.exit(-1) 14 | from gm.api import * 15 | 16 | ''' 17 | 本策略通过计算CZCE.FG801和SHFE.rb1801的ATR.唐奇安通道和MA线, 18 | 当价格上穿唐奇安通道且短MA在长MA上方时开多仓;当价格下穿唐奇安通道且短MA在长MA下方时开空仓(8手) 19 | 若有多仓则在价格跌破唐奇安平仓通道下轨的时候全平仓位,否则根据跌破 20 | 持仓均价 - x(x=0.5,1,1.5,2)倍ATR把仓位平至6/4/2/0手 21 | 若有空仓则在价格涨破唐奇安平仓通道上轨的时候全平仓位,否则根据涨破 22 | 持仓均价 + x(x=0.5,1,1.5,2)倍ATR把仓位平至6/4/2/0手 23 | 回测数据为:CZCE.FG801和SHFE.rb1801的1min数据 24 | 回测时间为:2017-09-15 09:15:00到2017-10-01 15:00:00 25 | ''' 26 | 27 | 28 | def init(context): 29 | # context.parameter分别为唐奇安开仓通道.唐奇安平仓通道.短ma.长ma.ATR的参数 30 | context.parameter = [55, 20, 10, 60, 20] 31 | context.tar = context.parameter[4] 32 | # context.goods交易的品种 33 | context.goods = ['CZCE.FG801', 'SHFE.rb1801'] 34 | # 订阅context.goods里面的品种, bar频率为1min 35 | subscribe(symbols=context.goods, frequency='60s', count=101) 36 | # 止损的比例区间 37 | 38 | 39 | def on_bar(context, bars): 40 | bar = bars[0] 41 | symbol = bar['symbol'] 42 | recent_data = context.data(symbol=symbol, frequency='60s', count=101, fields='close,high,low') 43 | close = recent_data['close'].values[-1] 44 | # 计算ATR 45 | atr = talib.ATR(recent_data['high'].values, recent_data['low'].values, recent_data['close'].values, 46 | timeperiod=context.tar)[-1] 47 | # 计算唐奇安开仓和平仓通道 48 | context.don_open = context.parameter[0] + 1 49 | upper_band = talib.MAX(recent_data['close'].values[:-1], timeperiod=context.don_open)[-1] 50 | context.don_close = context.parameter[1] + 1 51 | lower_band = talib.MIN(recent_data['close'].values[:-1], timeperiod=context.don_close)[-1] 52 | # 若没有仓位则开仓 53 | position_long = context.account().position(symbol=symbol, side=PositionSide_Long) 54 | 55 | position_short = context.account().position(symbol=symbol, side=PositionSide_Short) 56 | if not position_long and not position_short: 57 | # 计算长短ma线.DIF 58 | ma_short = talib.MA(recent_data['close'].values, timeperiod=(context.parameter[2] + 1))[-1] 59 | ma_long = talib.MA(recent_data['close'].values, timeperiod=(context.parameter[3] + 1))[-1] 60 | dif = ma_short - ma_long 61 | # 获取当前价格 62 | # 上穿唐奇安通道且短ma在长ma上方则开多仓 63 | if close > upper_band and (dif > 0): 64 | order_target_volume(symbol=symbol, volume=8, position_side=PositionSide_Long, order_type=OrderType_Market) 65 | print(symbol, '市价单开多仓8手') 66 | # 下穿唐奇安通道且短ma在长ma下方则开空仓 67 | if close < lower_band and (dif < 0): 68 | order_target_volume(symbol=symbol, volume=8, position_side=PositionSide_Short, order_type=OrderType_Market) 69 | print(symbol, '市价单开空仓8手') 70 | elif position_long: 71 | # 价格跌破唐奇安平仓通道全平仓位止损 72 | if close < lower_band: 73 | order_close_all() 74 | print(symbol, '市价单全平仓位') 75 | else: 76 | # 获取持仓均价 77 | vwap = position_long['vwap'] 78 | # 获取持仓的资金 79 | band = vwap - np.array([200, 2, 1.5, 1, 0.5, -100]) * atr 80 | # 计算最新应持仓位 81 | grid_volume = int(pd.cut([close], band, labels=[0, 1, 2, 3, 4])[0]) * 2 82 | order_target_volume(symbol=symbol, volume=grid_volume, position_side=PositionSide_Long, 83 | order_type=OrderType_Market) 84 | print(symbol, '市价单平多仓到', grid_volume, '手') 85 | elif position_short: 86 | # 价格涨破唐奇安平仓通道或价格涨破持仓均价加两倍ATR平空仓 87 | if close > upper_band: 88 | order_close_all() 89 | print(symbol, '市价单全平仓位') 90 | else: 91 | # 获取持仓均价 92 | vwap = position_short['vwap'] 93 | # 获取平仓的区间 94 | band = vwap + np.array([-100, 0.5, 1, 1.5, 2, 200]) * atr 95 | # 计算最新应持仓位 96 | grid_volume = int(pd.cut([close], band, labels=[0, 1, 2, 3, 4])[0]) * 2 97 | order_target_volume(symbol=symbol, volume=grid_volume, position_side=PositionSide_Short, 98 | order_type=OrderType_Market) 99 | print(symbol, '市价单平空仓到', grid_volume, '手') 100 | 101 | 102 | if __name__ == '__main__': 103 | ''' 104 | strategy_id策略ID,由系统生成 105 | filename文件名,请与本文件名保持一致 106 | mode实时模式:MODE_LIVE回测模式:MODE_BACKTEST 107 | token绑定计算机的ID,可在系统设置-密钥管理中生成 108 | backtest_start_time回测开始时间 109 | backtest_end_time回测结束时间 110 | backtest_adjust股票复权方式不复权:ADJUST_NONE前复权:ADJUST_PREV后复权:ADJUST_POST 111 | backtest_initial_cash回测初始资金 112 | backtest_commission_ratio回测佣金比例 113 | backtest_slippage_ratio回测滑点比例 114 | ''' 115 | run(strategy_id='strategy_id', 116 | filename='main.py', 117 | mode=MODE_BACKTEST, 118 | token='token_id', 119 | backtest_start_time='2017-09-15 09:15:00', 120 | backtest_end_time='2017-10-01 15:00:00', 121 | backtest_adjust=ADJUST_PREV, 122 | backtest_initial_cash=10000000, 123 | backtest_commission_ratio=0.0001, 124 | backtest_slippage_ratio=0.0001) --------------------------------------------------------------------------------