双极平滑振荡器策略

SMA stdev EMA CROSSOVER CROSSUNDER
创建日期: 2025-10-17 15:20:53 最后修改: 2025-10-17 15:20:53
复制: 0 点击次数: 262
avatar of ianzeng123 ianzeng123
2
关注
323
关注者

双极平滑振荡器策略 双极平滑振荡器策略

🎯 这是什么神仙策略?

你知道吗?这个策略就像是给市场装了一个”情绪探测器”!📡 它通过双极平滑振荡器来感知市场的”喜怒哀乐”,当市场过于兴奋(超买)或过于沮丧(超卖)时,就会发出交易信号。划重点!这不是普通的振荡器,而是经过”双重美颜”处理的高级版本,能有效过滤掉市场噪音,让你看清真正的趋势方向。

💡 工作原理大揭秘

想象一下,这个策略就像一个超级敏感的”市场体温计”🌡️。首先,它计算价格偏离25周期均线的程度,然后进行标准化处理(就像把不同身高的人都换算成标准身高比例)。接下来是关键的”双重平滑”过程,就像给照片连续用两次美颜滤镜,让信号变得更加清晰可靠。当振荡器突破设定阈值时,策略就会果断出手!

⚡ 这个策略的超能力

避坑指南来了!这个策略最厉害的地方是它的”反向信号平仓”机制 - 就像开车时看到红灯就立刻刹车一样聪明!🚦 当出现相反信号时,策略会立即平仓,不会死扛到底。同时还有5周期固定止损保护,就像给你的资金加了一道”安全气囊”。最贴心的是,它还自带完整的交易统计功能,让你随时掌握策略表现!

🚨 风险提醒不能少

划重点!虽然这个策略很优秀,但也不是万能的。在强趋势市场中,振荡器可能会”迷路”,就像在高速公路上用市区导航一样不太合适。固定阈值设置在不同市场环境下可能水土不服,需要你根据实际情况灵活调整。记住,任何策略都需要配合良好的风险管理,不要把所有鸡蛋放在一个篮子里!

策略源码
/*backtest
start: 2025-01-01 00:00:00
end: 2025-10-15 08:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT","balance":500000}]
*/

//@version=6
strategy("Two-Pole Threshold Entries + Opposite-Signal & Stop Exits + Stats",
     overlay=true,
     max_labels_count=500)

// === Inputs ===
length       = input.int(20,    minval=1,    title="Filter Length")
buyTrig      = input.float(-0.8,             title="Buy Threshold (osc ↑)")
sellTrig     = input.float( 0.8,             title="Sell Threshold (osc ↓)")
stopLossPts  = input.int(10,    minval=1,    title="Stop Loss (pts)")

// === Two-Pole Oscillator ===
sma25 = ta.sma(close, 25)
dev   = (close - sma25) - ta.sma(close - sma25, 25)
norm  = dev / ta.stdev(close - sma25, 25)
alpha = 2.0 / (length + 1)

var float s1 = na
var float s2 = na
s1 := na(s1) ? norm : (1 - alpha) * s1 + alpha * norm
s2 := na(s2) ? s1   : (1 - alpha) * s2 + alpha * s1

osc     = s2
prevOsc = osc[4]

// === Trigger Cross Signals ===
isLongSig  = ta.crossover(osc, buyTrig)  and barstate.isconfirmed
isShortSig = ta.crossunder(osc, sellTrig) and barstate.isconfirmed

// === State & Stats Vars ===
var int   tradeDir    = 0      //  1=long, -1=short, 0=flat
var float entryPrice = na
var int   entryBar   = na

var int   buyTotal    = 0
var int   buyFailed   = 0
var float sumMoveB    = 0.0
var int   cntMoveB    = 0
var float sumPLptsB   = 0.0

var int   sellTotal   = 0
var int   sellFailed  = 0
var float sumMoveS    = 0.0
var int   cntMoveS    = 0
var float sumPLptsS   = 0.0

// === Exit Marker Flags ===
var bool longStopHit  = false
var bool shortStopHit = false
var bool longSigExit  = false
var bool shortSigExit = false

longStopHit  := false
shortStopHit := false
longSigExit  := false
shortSigExit := false

// === 1) Opposite-Signal Exit ===
if tradeDir == 1 and isShortSig
    float ptsL = close - entryPrice
    sumMoveB  += ptsL
    sumPLptsB += ptsL
    cntMoveB  += 1
    strategy.close("Long")
    longSigExit := true
    tradeDir    := 0

if tradeDir == -1 and isLongSig
    float ptsS = entryPrice - close
    sumMoveS  += ptsS
    sumPLptsS += ptsS
    cntMoveS  += 1
    strategy.close("Short")
    shortSigExit := true
    tradeDir     := 0

// === 2) 5-Bar, Bar-Close 10-pt Stop Exit ===
inWindow       = (tradeDir != 0) and (bar_index <= entryBar + 5)
longStopPrice  = entryPrice - stopLossPts
shortStopPrice = entryPrice + stopLossPts

if tradeDir == 1 and inWindow and close <= longStopPrice
    buyFailed   += 1
    sumPLptsB   -= stopLossPts
    strategy.close("Long")
    longStopHit := true
    tradeDir    := 0

if tradeDir == -1 and inWindow and close >= shortStopPrice
    sellFailed   += 1
    sumPLptsS    -= stopLossPts
    strategy.close("Short")
    shortStopHit := true
    tradeDir     := 0

// === 3) New Entries (only when flat) ===
if tradeDir == 0 and isLongSig
    buyTotal   += 1
    entryPrice := close
    entryBar   := bar_index
    strategy.entry("Long", strategy.long)
    tradeDir   := 1

if tradeDir == 0 and isShortSig
    sellTotal  += 1
    entryPrice := close
    entryBar   := bar_index
    strategy.entry("Short", strategy.short)
    tradeDir   := -1

// === Stats Computation ===
float avgMoveB    = cntMoveB  > 0 ? sumMoveB  / cntMoveB  : na
float successPctB = buyTotal   > 0 ? (buyTotal - buyFailed) / buyTotal  * 100 : na
float pnlUSD_B    = sumPLptsB * 50.0

float avgMoveS    = cntMoveS  > 0 ? sumMoveS  / cntMoveS  : na
float successPctS = sellTotal  > 0 ? (sellTotal - sellFailed) / sellTotal * 100 : na
float pnlUSD_S    = sumPLptsS * 50.0

string tf = timeframe.period



// === On-Chart Markers ===
plotshape(isLongSig,  title="Long Entry",      style=shape.triangleup,   location=location.belowbar, color=color.green,  size=size.tiny)
plotshape(isShortSig, title="Short Entry",     style=shape.triangledown, location=location.abovebar, color=color.red,    size=size.tiny)
plotshape(longSigExit,  title="Exit on Sell Sig", style=shape.xcross, location=location.abovebar, color=color.orange, size=size.tiny)
plotshape(shortSigExit, title="Exit on Buy Sig",  style=shape.xcross, location=location.belowbar, color=color.orange, size=size.tiny)
plotshape(longStopHit,  title="Stop Exit Long",  style=shape.xcross, location=location.abovebar, color=color.purple, size=size.tiny)
plotshape(shortStopHit, title="Stop Exit Short", style=shape.xcross, location=location.belowbar, color=color.purple, size=size.tiny)


template: strategy.tpl:156:35: executing "strategy.tpl" at <.api.GetStrategyList>: error calling GetStrategyList: Error 1060 (42S21): Duplicate column name 'meta'