策略名称:**迪马克TD趋势反转策略**
策略说明:
本策略基于迪马克(Tom DeMark)的TD序列理论,通过识别市场的趋势反转信号进行交易决策。策略的核心思想是通过计算价格的高低点和趋势的延续性,捕捉市场的反转机会,并结合止损和止盈机制控制风险。
策略核心逻辑:
1. **TD序列计算**:
- **Setup阶段**:识别连续4天的价格变化方向(上升或下降),并确定趋势的起始点。
- **Count阶段**:在Setup阶段完成后,继续计算价格的高低点,直到达到设定的计数条件(如13天)。
2. **趋势反转信号**:
- **做空信号**:在下降Setup完成后,价格跌破前3天的收盘价时,触发做空信号。
- **做多信号**:在上升Setup完成后,价格突破前3天的收盘价时,触发做多信号。
3. **止损与止盈**:
- **顺势交易**:当价格达到设定的止损或止盈条件时,平仓并反手开仓。
- **反转交易**:当价格达到设定的止损或止盈条件时,平仓并结束交易。
4. **移仓机制**:
- 当合约临近到期时,自动移仓至下一个主力合约。
策略特点:
- **趋势反转捕捉**:通过TD序列理论捕捉市场的趋势反转信号,适合震荡市和趋势反转行情。
- **动态止损止盈**:根据价格变化动态调整止损和止盈条件,控制风险。
- **自动移仓**:在合约到期前自动移仓,避免交割风险。
适用场景:
- 适用于股指期货市场,能够有效捕捉市场的趋势反转机会。
- 适合中短线交易者,通过趋势反转信号进行快速交易。
风险提示:
- 在趋势延续性较强的市场中,TD序列可能产生较多的错误信号,导致频繁交易。
- 策略依赖于历史数据的有效性,需定期优化参数以适应市场变化。
策略代码结构:
1. **初始化函数(`initialize`)**:
- 设定基准指数(沪深300)。
- 配置交易手续费和滑点。
- 定义每日运行的函数(开盘前、开盘时、收盘后)。
2. **开盘前运行函数(`before_market_open`)**:
- 获取当前交易日的主力合约和次主力合约。
- 计算当前合约的持仓手数。
3. **开盘时运行函数(`market_open`)**:
- 根据TD序列信号进行交易决策。
- 触发做多或做空信号时,开仓并设置止损止盈条件。
- 当价格达到止损或止盈条件时,平仓并反手开仓。
4. **收盘后运行函数(`after_market_close`)**:
- 计算当日的TD序列信号,更新Setup和Count阶段的状态。
5. **辅助函数**:
- **`calc_setup`**:计算TD序列的Setup和Count阶段。
- **`reverse_posi`**:在达到止损或止盈条件时,反手开仓。
- **`calc_hands`**:根据账户资金计算开仓手数。
策略优化建议:
1. **参数优化**:
- 可对TD序列的Setup和Count参数(如4天、13天)进行优化,以适应不同的市场周期。
- 调整止损和止盈条件(如5%、10%),以更好地控制风险。
2. **风险控制**:
- 增加最大回撤限制,当回撤超过一定比例时暂停交易。
- 设置单笔交易的最大亏损比例,避免单笔交易亏损过大。
3. **多品种扩展**:
- 可将策略应用于其他期货品种(如商品期货),测试其普适性。
- 通过多品种分散风险,提高策略的稳定性。
总结:
本策略通过迪马克TD序列理论捕捉市场的趋势反转信号,结合止损和止盈机制控制风险,适合中短线交易者在股指期货市场中获取收益。策略逻辑清晰,适合有一定编程基础的投资者进行进一步优化和实盘测试。
策略代码
# 标题:迪马克TD趋势反转指标
# 作者:魔术先生
# 回测资金选择 100万
# 导入函数库
from jqdata import *
## 初始化函数,设定基准等等
def initialize(context):
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
set_option("avoid_future_data", True)
# 过滤掉order系列API产生的比error级别低的log
# log.set_level('order', 'error')
# 输出内容到日志 log.info()
log.info('初始函数开始运行且全局只运行一次')
g.code = '000300.XSHG'
g.n1 = 8
g.n2 = 13
g.count = 0 # setup完成后开始count
g.stop = 0
g.setup_high = 0 #下跌setup中的最高价
g.setup_low = 0 #上升setup中的最低价
g.setup = 0 #1:上升;-1:下降;0:无
g.flag = 0
g.price = 0
g.p = 0
g.hold = ''
g.lc = False
g.trend = 0 # -1:反转 0:空仓 1:顺势
### 期货相关设定 ###
# 设定账户为金融账户
set_subportfolios([SubPortfolioConfig(cash=context.portfolio.starting_cash, type='index_futures')])
# 期货类每笔交易时的手续费是:买入时万分之0.23,卖出时万分之0.23,平今仓为万分之23
set_order_cost(OrderCost(open_commission=0.000023, close_commission=0.000023,close_today_commission=0.0023), type='index_futures')
# 设定保证金比例
set_option('futures_margin_rate', 0.15)
# 设置期货交易的滑点
set_slippage(StepRelatedSlippage(2))
# 运行函数(reference_security为运行时间的参考标的;传入的标的只做种类区分,因此传入'IF8888.CCFX'或'IH1602.CCFX'是一样的)
# 注意:before_open/open/close/after_close等相对时间不可用于有夜盘的交易品种,有夜盘的交易品种请指定绝对时间(如9:30)
# 开盘前运行
run_daily( before_market_open, time='09:00', reference_security='IF8888.CCFX')
# 开盘时运行
run_daily( market_open, time='09:30', reference_security='IF8888.CCFX')
# 收盘后运行
run_daily( after_market_close, time='15:30', reference_security='IF8888.CCFX')
## 开盘前运行函数
def before_market_open(context):
# 输出运行时间
# log.info('函数运行时间(before_market_open):'+str(context.current_dt.time()))
g.today = context.current_dt.date()
g.hands = calc_hands(context)
g.c = get_future_contracts('IF')
g.sub = g.c[1]
g.main = g.c[0]
if (get_security_info(g.main).end_date - context.current_dt.date()).days < 10:
g.main = g.sub
## 开盘时运行函数
def market_open(context):
# if g.lc and g.stop!=0:
# g.stop += 1
# return
# elif g.lc and g.stop==0:
# g.stop = 0
# g.lc = False
current_data = get_current_data()
last = current_data[g.code].last_price
if g.hold:
end = get_security_info(g.hold).end_date
if (end - context.current_dt.date()).days < 5: gap = current_data[g.sub].last_price - last g.price += gap g.p += gap if g.trend == 1: if g.setup==-1: print('顺势移仓空头') order_target(g.hold,0,None,'short') order(g.sub,g.hands,None,'short') g.hold = g.sub elif g.setup==1: print('顺势移仓多头') order_target(g.hold,0,None,'long') order(g.sub,g.hands,None,'long') g.hold = g.sub elif g.trend == -1: if g.setup==1: print('反转移仓空头') order_target(g.hold,0,None,'short') order(g.sub,g.hands,None,'short') g.hold = g.sub elif g.setup==-1: print('反转移仓多头') order_target(g.hold,0,None,'long') order(g.sub,g.hands,None,'long') g.hold = g.sub if g.setup==-1 and g.count==g.n2 and not g.flag: pre3close = attribute_history(g.code,3,'1d','close').close.values[0] pre1low = attribute_history(g.code,1,'1d','low').low.values[0] if pre1low > pre3close:
print('做空信号----------------')
g.price = last
g.p = last
g.hold = g.main
g.flag = 1
g.trend = 1
order(g.main,g.hands,None,'short')
elif g.setup==1 and g.count==g.n2 and not g.flag:
pre3close = attribute_history(g.code,3,'1d','close').close.values[0]
pre1high = attribute_history(g.code,1,'1d','high').high.values[0]
if pre1high < pre3close: print('做多信号----------------') g.flag = 1 g.price = last g.p = last g.hold = g.main g.trend = 1 order(g.main,g.hands,None,'long') if g.setup==-1 and g.flag==1 and g.trend == 1: if g.price/last >1.05 or g.price/last <0.95: if g.price/last >1.05:
print('顺势空头止盈')
else:
print('顺势空头止损')
g.price = last
g.p = last
reverse_posi()
elif g.setup==1 and g.flag==1 and g.trend == 1:
if last/g.price >1.05 or last/g.price <0.95: order_target(g.hold,0,None,'long') if last/g.price >1.05:
print('顺势多头止盈')
else:
print('顺势多头止损')
g.price = last
g.p = last
reverse_posi()
if g.setup==1 and g.flag==1 and g.trend == -1:
if g.price>last:
g.price = last
elif g.price < 0.9*last or g.p > 1.2*last:
# if g.price/last >1.15 or g.price/last <0.85: order_target(g.hold,0,None,'long') if g.p > 1.2*last:
print('反转空头止盈')
else:
print('反转空头止损')
g.lc = True
g.trend = 0
g.price = 0
g.p = 0
g.setup = 0
g.setup_high = 0
g.hold = ''
g.count = 0
g.flag = 0
elif g.setup==-1 and g.flag==1 and g.trend == -1:
if g.price < last: g.price = last elif g.price > 1.2*last or g.p < 0.8*last: # if last/g.price >1.15 or last/g.price <0.85:
order_target(g.hold,0,None,'short')
if g.p < 0.9*last:
print('反转多头止盈')
else:
print('反转多头止损')
g.lc = True
g.trend = 0
g.price = 0
g.p = 0
g.setup = 0
g.setup_low = 0
g.hold = ''
g.count = 0
g.flag = 0
## 收盘后运行函数
def after_market_close(context):
calc_setup()
# print(g.count)
def reverse_posi():
if g.setup==-1:
print('空头反手')
order_target(g.hold,0,None,'short')
order(g.hold,g.hands,None,'long')
g.trend = -1
elif g.setup==1:
print('多头反手')
order_target(g.hold,0,None,'long')
order(g.hold,g.hands,None,'short')
g.trend = -1
def calc_setup():
close = get_price(g.code,end_date=g.today,count=g.n1+5,fields='close')
diff4 = close.diff(4).dropna().values
first = g.setup
#setup
if (diff4[:-1]<0).all() and diff4[-1]>0 and not g.setup: #下降setup
g.setup = -1
high = get_price(g.code,end_date=g.today,count=g.n1,fields='high').values.max()
g.setup_high = high
elif (diff4[:-1]>0).all() and diff4[-1]<0 and not g.setup: #上升setup
g.setup = 1
low = get_price(g.code,end_date=g.today,count=g.n1,fields='low').values.min()
g.setup_low = low
#count
if g.setup == -1 and g.count!=g.n2:
pre2low = get_price(g.code,end_date=g.today,count=3,fields='low').values[0]
if close.values[-1]pre2high:
g.count+=1
print('上升setup完成,count加1,当前数量:【{}】'.format(g.count))
#cancel
if g.setup==-1 and g.count!=g.n2:
info = '下跌setup完成,'
if close.values[-1] > g.setup_high:
info += '当日收盘价大于setup中的最高价,停止'
g.setup = 0
g.setup_high = 0
g.count = 0
print(info)
elif (diff4>0).all():
info += '出现反向setup,优先新setup'
g.setup = 1
g.count = 0
g.setup_high = 0
low = get_price(g.code,end_date=g.today,count=g.n1,fields='low').values.min()
g.setup_low = low
print(info)
elif not first and (diff4<0).all():
info += '出现同向setup,重新计数'
g.count = 0
print(info)
elif g.setup==1 and g.count!=g.n2:
info = '上升setup完成,'
if close.values[-1] < g.setup_low:
info += '当日收盘价小于setup中最低价,停止'
g.setup = 0
g.setup_low = 0
g.count = 0
print(info)
elif (diff4<0).all(): info += '出现反向setup,优先新setup' g.setup = -1 g.count = 0 g.setup_low = 0 high = get_price(g.code,end_date=g.today,count=g.n1,fields='high').values.max() g.setup_high = high print(info) elif not first and (diff4>0).all():
info += '出现同向setup,重新计数'
g.count = 0
print(info)
