开盘收盘均线交叉结合ADX动态指标的量化交易策略

MA ADX SMMA EMA DEMA TEMA WMA VWMA HullMA LSMA ALMA SSMA TMA ATR
创建日期: 2025-02-18 13:35:54 最后修改: 2025-02-18 13:35:54
复制: 0 点击次数: 74
1
关注
1196
关注者

开盘收盘均线交叉结合ADX动态指标的量化交易策略

概述

这是一个基于开盘价和收盘价移动均线交叉,并结合平均趋向指标(ADX)作为过滤器的量化交易策略。该策略采用多种移动均线类型,包括SMMA、EMA、DEMA等,通过识别均线交叉点来捕捉市场趋势变化,同时使用ADX指标来确认趋势强度,提高交易的可靠性。

策略原理

策略的核心逻辑是通过计算开盘价和收盘价的移动均线,当收盘价均线向上穿越开盘价均线且ADX值大于设定阈值时,产生做多信号;当收盘价均线向下穿越开盘价均线且ADX值大于设定阈值时,产生做空信号。策略支持多种移动均线计算方法,包括简单移动均线(SMA)、指数移动均线(EMA)、双重指数移动均线(DEMA)等,可根据不同市场特征选择最适合的均线类型。

策略优势

  1. 灵活性强:支持多种移动均线类型,可以根据不同市场环境选择最优的均线计算方法
  2. 趋势确认:通过ADX指标过滤,能有效降低震荡市场下的虚假信号
  3. 风险控制完善:包含止损和止盈功能,可以有效控制每笔交易的风险
  4. 可定制性高:提供多个参数接口,包括均线周期、ADX阈值、交易方向等,便于策略优化
  5. 支持多时间周期:可以在不同的时间周期上运行,适应不同的交易风格

策略风险

  1. 均线滞后性:移动均线本质上是滞后指标,在快速波动的市场中可能产生滞后信号
  2. 假突破风险:市场震荡时可能出现均线假突破,虽然有ADX过滤但仍需注意
  3. 参数敏感性:策略效果对参数设置较为敏感,不同市场环境下需要适当调整
  4. 市场适应性:在趋势明显的市场表现较好,但在震荡市场中可能频繁交易
  5. 计算复杂性:多种均线类型的计算可能增加系统负担,需要注意运行效率

策略优化方向

  1. 引入成交量指标:可以结合成交量变化来确认趋势的有效性
  2. 优化ADX参数:根据不同市场周期动态调整ADX阈值
  3. 增加趋势确认指标:可以考虑添加其他趋势指标来提高信号可靠性
  4. 完善止损机制:引入追踪止损或波动率自适应止损
  5. 优化交易时机:考虑市场波动率和流动性因素,选择最佳交易时间

总结

这是一个将经典的均线交叉策略与ADX指标相结合的量化交易系统。通过多种均线类型的支持和ADX趋势确认,能够较好地把握市场趋势,同时具备完善的风险控制机制。策略的可定制性强,可以根据不同市场环境进行优化调整。虽然存在一些固有的风险,但通过合理的参数设置和持续优化,该策略具有良好的实用价值。

策略源码
/*backtest
start: 2024-02-18 00:00:00
end: 2025-02-16 08:00:00
period: 3d
basePeriod: 3d
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © algostudio

//@version=6
strategy("Open Close Cross Strategy R5.1", shorttitle="OCC Strategy R5.1", overlay=true,
     pyramiding=0, default_qty_type=strategy.percent_of_equity, default_qty_value=10, calc_on_every_tick=false)

// === INPUTS ===
useRes      = input.bool(true, title="Use Alternate Resolution?")
intRes      = input.int(3, title="Multiplier for Alternate Resolution", minval=1)
stratRes    = timeframe.ismonthly ? str.tostring(timeframe.multiplier * intRes) + "M" :
              timeframe.isweekly ? str.tostring(timeframe.multiplier * intRes) + "W" :
              timeframe.isdaily ? str.tostring(timeframe.multiplier * intRes) + "D" :
              timeframe.isintraday ? str.tostring(timeframe.multiplier * intRes) : "60"

basisType   = input.string("SMMA", title="MA Type:", options=["SMA", "EMA", "DEMA", "TEMA", "WMA", "VWMA", "SMMA", "HullMA", "LSMA", "ALMA", "SSMA", "TMA"])
basisLen    = input.int(8, title="MA Period", minval=1)
offsetSigma = input.int(6, title="Offset for LSMA / Sigma for ALMA", minval=0)
offsetALMA  = input.float(0.85, title="Offset for ALMA", minval=0, step=0.01)
scolor      = input.bool(false, title="Show Colored Bars to Indicate Trend?")
delayOffset = input.int(0, title="Delay Open/Close MA (Forces Non-Repainting)", minval=0, step=1)
tradeType   = input.string("BOTH", title="What trades should be taken:", options=["LONG", "SHORT", "BOTH", "NONE"])

// === BASE FUNCTIONS ===
variant(type, src, len, offSig, offALMA) =>
    if type == "EMA"
        ta.ema(src, len)
    else if type == "DEMA"
        ta.ema(ta.ema(src, len), len) * 2 - ta.ema(ta.ema(ta.ema(src, len), len), len)
    else if type == "TEMA"
        3 * (ta.ema(src, len) - ta.ema(ta.ema(src, len), len)) + ta.ema(ta.ema(ta.ema(src, len), len), len)
    else if type == "WMA"
        ta.wma(src, len)
    else if type == "VWMA"
        ta.vwma(src, len)
    else if type == "SMMA"
        ta.sma(src, len)
    else if type == "HullMA"
        ta.wma(2 * ta.wma(src, len / 2) - ta.wma(src, len), math.round(math.sqrt(len)))
    else if type == "LSMA"
        ta.linreg(src, len, offSig)
    else if type == "ALMA"
        ta.alma(src, len, offALMA, offSig)
    else if type == "TMA"
        ta.sma(ta.sma(src, len), len)
    else
        ta.sma(src, len)

// Security wrapper
reso(exp, use, res) => use ? request.security(syminfo.tickerid, res, exp, lookahead=barmerge.lookahead_on) : exp

// === SERIES SETUP ===
closeSeries = variant(basisType, close[delayOffset], basisLen, offsetSigma, offsetALMA)
openSeries  = variant(basisType, open[delayOffset], basisLen, offsetSigma, offsetALMA)

// Alternate resolution series
closeSeriesAlt = reso(closeSeries, useRes, stratRes)
openSeriesAlt  = reso(openSeries, useRes, stratRes)

// Trend Colors
trendColour = closeSeriesAlt > openSeriesAlt ? color.green : color.red
bcolour     = closeSeries > openSeriesAlt ? color.lime : color.red
barcolor(scolor ? bcolour : na, title="Bar Colours")

closeP = plot(closeSeriesAlt, title="Close Series", color=trendColour, linewidth=2, style=plot.style_line)
openP  = plot(openSeriesAlt, title="Open Series", color=trendColour, linewidth=2, style=plot.style_line)
fill(closeP, openP, color=trendColour)
// === ADX FILTER ===
// ADX Calculation
// Input parameters
adxLength = input.int(14, title="ADX Length", minval=1)
adxfilter = input.int(13, title="ADX filter", minval=1)
// Calculate +DM and -DM (Directional Movement)
plusDM = math.max(high - high[1], 0)
minusDM = math.max(low[1] - low, 0)

// Remove cases where both are positive
plusDM := plusDM > minusDM ? plusDM : 0
minusDM := minusDM > plusDM ? minusDM : 0

// Smooth the directional movement using RMA
smoothedPlusDM = ta.rma(plusDM, adxLength)
smoothedMinusDM = ta.rma(minusDM, adxLength)

// Calculate True Range and smooth it
tr = ta.atr(adxLength)
smoothedTR = ta.rma(tr, adxLength)

// Compute +DI and -DI
plusDI = (smoothedPlusDM / smoothedTR) * 100
minusDI = (smoothedMinusDM / smoothedTR) * 100

// Compute DX (Directional Index)
dx = math.abs(plusDI - minusDI) / (plusDI + minusDI) * 100

// Compute ADX by smoothing DX
adx = ta.rma(dx, adxLength)




// === UPDATED TRADE CONDITIONS ===
xlong     = ta.crossover(closeSeriesAlt, openSeriesAlt) and adx > adxfilter
xshort    = ta.crossunder(closeSeriesAlt, openSeriesAlt) and adx > adxfilter
longCond  = xlong
shortCond = xshort


// === STRATEGY ===
slPoints  = input.float(0, title="Initial Stop Loss Points", minval=0)
tpPoints  = input.float(0, title="Initial Target Profit Points", minval=0)
ebar      = input.int(10000, title="Number of Bars for Back Testing", minval=0)

tdays     = (timenow - time) / 60000.0

tdays     := timeframe.ismonthly ? tdays / 1440.0 / 5.0 / 4.3 / timeframe.multiplier :
             timeframe.isweekly ? tdays / 1440.0 / 5.0 / timeframe.multiplier :
             timeframe.isdaily ? tdays / 1440.0 / timeframe.multiplier :
             tdays / timeframe.multiplier

TP = tpPoints > 0 ? tpPoints : na
SL = slPoints > 0 ? slPoints : na

if (ebar == 0 or tdays <= ebar)
    if longCond and tradeType != "SHORT"
        strategy.entry("long", strategy.long)
    if shortCond and tradeType != "LONG"
        strategy.entry("short", strategy.short)
    if shortCond and tradeType == "LONG"
        strategy.close("long")
    if longCond and tradeType == "SHORT"
        strategy.close("short")
    strategy.exit("XL", from_entry="long", profit=TP, loss=SL)
    strategy.exit("XS", from_entry="short", profit=TP, loss=SL)

// === END ===

相关推荐
更多内容