该策略是一个结合了指数移动平均线(EMA)和时间间隔的双向交易系统。系统在用户定义的固定时间间隔内,根据不同周期EMA的位置关系确定主要交易方向,同时通过监控另一组EMA指标的交叉信号或时间临近下一个交易周期时,选择合适时机进行反向对冲交易,从而实现双向交易机会的把握。
策略运作基于两个核心机制:固定时间间隔的主要交易和灵活的反向交易。主要交易依据5/40分钟EMA的相对位置判断趋势方向,在每个交易间隔(默认30分钟)执行交易。反向交易则通过监控5/10分钟EMA的交叉信号,或在距离下一次主要交易前1分钟时进行,以较早发生的条件为准。整个交易在用户自定义的时间窗口内进行,确保交易的时效性。
这是一个融合了趋势跟踪和反向交易的综合策略,通过时间间隔和EMA指标的配合,实现了交易机会的双向把握。策略的可定制性强,具有良好的风险控制潜力,但需要根据实际市场情况进行参数优化和风险管理的完善。在实盘应用时,建议进行充分的回测和参数优化,并结合市场特征进行针对性的调整。
/*backtest
start: 2025-01-02 00:00:00
end: 2025-01-09 00:00:00
period: 3m
basePeriod: 3m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/
//@version=5
strategy("SPX EMA Strategy with Opposite Trades", overlay=true)
// User-defined inputs
tradeIntervalMinutes = input.int(30, title="Main Trade Interval (in minutes)", minval=1)
oppositeTradeDelayMinutes = input.int(1, title="Opposite Trade time from next trade (in minutes)", minval=1) // Delay of opposite trade (1 min before the next trade)
startHour = input.int(10, title="Start Hour", minval=0, maxval=23)
startMinute = input.int(30, title="Start Minute", minval=0, maxval=59)
stopHour = input.int(15, title="Stop Hour", minval=0, maxval=23)
stopMinute = input.int(0, title="Stop Minute", minval=0, maxval=59)
// User-defined EMA periods for main trade and opposite trade
mainEmaShortPeriod = input.int(5, title="Main Trade EMA Short Period", minval=1)
mainEmaLongPeriod = input.int(40, title="Main Trade EMA Long Period", minval=1)
oppositeEmaShortPeriod = input.int(5, title="Opposite Trade EMA Short Period", minval=1)
oppositeEmaLongPeriod = input.int(10, title="Opposite Trade EMA Long Period", minval=1)
// Calculate the EMAs for main trade
emaMainShort = ta.ema(close, mainEmaShortPeriod)
emaMainLong = ta.ema(close, mainEmaLongPeriod)
// Calculate the EMAs for opposite trade (using different periods)
emaOppositeShort = ta.ema(close, oppositeEmaShortPeriod)
emaOppositeLong = ta.ema(close, oppositeEmaLongPeriod)
// Condition to check if it is during the user-defined time window
startTime = timestamp(year, month, dayofmonth, startHour, startMinute)
stopTime = timestamp(year, month, dayofmonth, stopHour, stopMinute)
currentTime = timestamp(year, month, dayofmonth, hour, minute)
// Ensure the script only trades within the user-defined time window
isTradingTime = currentTime >= startTime and currentTime <= stopTime
// Time condition: Execute the trade every tradeIntervalMinutes
var float lastTradeTime = na
timePassed = na(lastTradeTime) or (currentTime - lastTradeTime) >= tradeIntervalMinutes * 60 * 1000
// Entry Conditions for Main Trade
longCondition = emaMainShort > emaMainLong // Enter long if short EMA is greater than long EMA
shortCondition = emaMainShort < emaMainLong // Enter short if short EMA is less than long EMA
// Detect EMA crossovers for opposite trade (bullish or bearish)
bullishCrossoverOpposite = ta.crossover(emaOppositeShort, emaOppositeLong) // Opposite EMA short crosses above long
bearishCrossoverOpposite = ta.crossunder(emaOppositeShort, emaOppositeLong) // Opposite EMA short crosses below long
// Track the direction of the last main trade (true for long, false for short)
var bool isLastTradeLong = na
// Track whether an opposite trade has already been executed after the last main trade
var bool oppositeTradeExecuted = false
// Execute the main trades if within the time window and at the user-defined interval
if isTradingTime and timePassed
if longCondition
strategy.entry("Main Long", strategy.long)
isLastTradeLong := true // Mark the last trade as long
oppositeTradeExecuted := false // Reset opposite trade status
lastTradeTime := currentTime
// label.new(bar_index, low, "Main Long", color=color.green, textcolor=color.white, size=size.small)
else if shortCondition
strategy.entry("Main Short", strategy.short)
isLastTradeLong := false // Mark the last trade as short
oppositeTradeExecuted := false // Reset opposite trade status
lastTradeTime := currentTime
// label.new(bar_index, high, "Main Short", color=color.red, textcolor=color.white, size=size.small)
// Execute the opposite trade only once after the main trade
if isTradingTime and not oppositeTradeExecuted
// 1 minute before the next main trade or EMA crossover
if (currentTime - lastTradeTime) >= (tradeIntervalMinutes - oppositeTradeDelayMinutes) * 60 * 1000 or bullishCrossoverOpposite or bearishCrossoverOpposite
if isLastTradeLong
// If the last main trade was long, enter opposite short trade
strategy.entry("Opposite Short", strategy.short)
//label.new(bar_index, high, "Opposite Short", color=color.red, textcolor=color.white, size=size.small)
else
// If the last main trade was short, enter opposite long trade
strategy.entry("Opposite Long", strategy.long)
//label.new(bar_index, low, "Opposite Long", color=color.green, textcolor=color.white, size=size.small)
// After entering the opposite trade, set the flag to true so no further opposite trades are placed
oppositeTradeExecuted := true
// Plot the EMAs for visual reference
plot(emaMainShort, title="Main Trade Short EMA", color=color.blue)
plot(emaMainLong, title="Main Trade Long EMA", color=color.red)
plot(emaOppositeShort, title="Opposite Trade Short EMA", color=color.purple)
plot(emaOppositeLong, title="Opposite Trade Long EMA", color=color.orange)