这是一个基于开盘价和收盘价移动均线交叉,并结合平均趋向指标(ADX)作为过滤器的量化交易策略。该策略采用多种移动均线类型,包括SMMA、EMA、DEMA等,通过识别均线交叉点来捕捉市场趋势变化,同时使用ADX指标来确认趋势强度,提高交易的可靠性。
策略的核心逻辑是通过计算开盘价和收盘价的移动均线,当收盘价均线向上穿越开盘价均线且ADX值大于设定阈值时,产生做多信号;当收盘价均线向下穿越开盘价均线且ADX值大于设定阈值时,产生做空信号。策略支持多种移动均线计算方法,包括简单移动均线(SMA)、指数移动均线(EMA)、双重指数移动均线(DEMA)等,可根据不同市场特征选择最适合的均线类型。
这是一个将经典的均线交叉策略与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 ===