
ZSCORE, RSI, ATR, SMA, EMA
Ini bukan strategi trend-following biasa. Strategi penipuan statistik XAG/XAU adalah berdasarkan pada satu hipotesis utama: harga emas dan perak mempunyai hubungan pulangan nilai purata jangka panjang. Apabila Z-Score menembusi ± 2 standard deviasi, harga menyimpang ke tahap maksimum dalam erti statistik, dan peluang untuk menangkap pulangan masuk.
Inti strategi ini adalah untuk membina model nisbah harga standardisasi. Dengan 20 kitaran SMA untuk XAG dan XAU, kemudian standardisasi dengan 3 kitaran EMA, kemudian mengira nisbah dan melonggarkannya dengan 3 kitaran EMA. Proses ini lebih stabil daripada nisbah harga sederhana dan dapat menyaring kebisingan jangka pendek dengan berkesan. Apabila Z-Score nisbah standardisasi melebihi julat ± 2, yang menunjukkan bahawa harga semasa menyimpang dari rata-rata sejarah lebih dari 2 perbezaan standard, secara statistik merupakan peristiwa kebarangkalian kecil, memberikan peluang untuk kembali ke nilai purata.
Berbeza dengan isyarat RSI over-buy over-sell tradisional, RSI = 50 digunakan sebagai syarat penapisan kosong. RSI <50 dibenarkan untuk melakukan lebih banyak, RSI> 50 dibenarkan untuk melakukan lebih sedikit. Logik reka bentuk ini jelas: membeli menunggu rebound apabila relatif lemah, menjual menunggu pemulihan apabila relatif kuat.
Tetapan berhenti adalah 3 kali ATR, tetapan berhenti adalah 8 kali ATR, nisbah risiko-keuntungan mencapai 1:2.67. Reka bentuk ini adalah berdasarkan ciri-ciri statik: kebarangkalian pulangan rata-rata lebih tinggi, tetapi perlu diberikan ruang kesalahan yang mencukupi. ATR 14 kitaran memastikan tahap stop loss dapat menyesuaikan diri dengan perubahan turun naik pasaran.
Strategi penarikan statistik berfungsi dengan baik dalam keadaan goyah berlawanan arah, kerana pada masa ini ciri-ciri pulangan nilai rata-rata lebih jelas. Dalam pasaran trend unilateral, harga mungkin menyimpang dari nilai rata-rata untuk masa yang lama, menyebabkan strategi menghadapi risiko pulangan yang lebih besar. Ia disyorkan untuk digunakan apabila kadar turun naik pasaran sederhana, tidak ada trend unilateral yang jelas.
Hubungan statistik sejarah tidak menjamin kesinambungan masa depan. Perbandingan harga emas dan perak mungkin mengalami penyimpangan jangka panjang kerana perubahan struktur bekalan dan permintaan, perbezaan dasar monetari dan lain-lain. Strategi mempunyai risiko kerugian berturut-turut, terutamanya semasa perubahan struktur pasaran.
//@version=6
strategy("Stat Arb(xag & xau)")
// ══════════════════════════════════════════════════════════════
// BENCHMARK DATA
// ══════════════════════════════════════════════════════════════
float benchClose = request.security("XAG_USDT.swap", timeframe.period, close)
// ══════════════════════════════════════════════════════════════
// HELPER FUNCTIONS
// ══════════════════════════════════════════════════════════════
f_cov(float src1, float src2, int len) =>
ta.sma(src1 * src2, len) - ta.sma(src1, len) * ta.sma(src2, len)
f_var(float src, int len) =>
ta.sma(src * src, len) - math.pow(ta.sma(src, len), 2)
// ══════════════════════════════════════════════════════════════
// SPREAD ENGINE — NORMALIZED RATIO
// ══════════════════════════════════════════════════════════════
int lookback = 20
float pairSma = ta.sma(close, lookback)
float benchSma = ta.sma(benchClose, lookback)
float pairNorm = pairSma != 0 ? close / pairSma * 100.0 : 100.0
float benchNorm = benchSma != 0 ? benchClose / benchSma * 100.0 : 100.0
float modelRaw = benchNorm != 0 ? pairNorm / benchNorm : 1.0
float model = ta.ema(modelRaw, 3)
float zMean = ta.sma(model, lookback)
float zStd = ta.stdev(model, lookback)
float zScore = zStd != 0 ? (model - zMean) / zStd : 0.0
// ══════════════════════════════════════════════════════════════
// RSI FILTER — BELOW / ABOVE 50
// ══════════════════════════════════════════════════════════════
float rsiVal = ta.rsi(close, 14)
bool rsiLongOk = rsiVal < 50.0
bool rsiShortOk = rsiVal > 50.0
// ══════════════════════════════════════════════════════════════
// ENTRY SIGNALS
// Z crosses below -2 = long, above +2 = short
// ══════════════════════════════════════════════════════════════
bool enterLong = ta.crossunder(zScore, -2.0) and rsiLongOk
bool enterShort = ta.crossover(zScore, 2.0) and rsiShortOk
// ══════════════════════════════════════════════════════════════
// ATR STOP + TAKE PROFIT
// Stop: 8x ATR from entry (hardcoded)
// TP: 3x ATR from entry (hardcoded), stamped at entry
// ══════════════════════════════════════════════════════════════
float atrVal = ta.atr(14)
var float tpLevel = na
var float slLevel = na
var float entryPrice = na
bool isNewEntry = strategy.position_size != 0 and strategy.position_size[1] == 0
if isNewEntry
entryPrice := strategy.position_avg_price
if strategy.position_size > 0
tpLevel := entryPrice + atrVal * 3.0
slLevel := entryPrice - atrVal * 8.0
else
tpLevel := entryPrice - atrVal * 3.0
slLevel := entryPrice + atrVal * 8.0
if strategy.position_size == 0
tpLevel := na
slLevel := na
entryPrice := na
// ══════════════════════════════════════════════════════════════
// EXIT CONDITIONS — high/low for intrabar touch
// ══════════════════════════════════════════════════════════════
bool tpHitLong = strategy.position_size > 0 and not na(tpLevel) and high >= tpLevel
bool tpHitShort = strategy.position_size < 0 and not na(tpLevel) and low <= tpLevel
bool slHitLong = strategy.position_size > 0 and not na(slLevel) and low < slLevel
bool slHitShort = strategy.position_size < 0 and not na(slLevel) and high > slLevel
// ══════════════════════════════════════════════════════════════
// EXECUTION
// ══════════════════════════════════════════════════════════════
if enterLong
strategy.close("Short", comment="Flip")
strategy.entry("Long", strategy.long)
if enterShort
strategy.close("Long", comment="Flip")
strategy.entry("Short", strategy.short)
if tpHitLong
strategy.close("Long", comment="TP")
if tpHitShort
strategy.close("Short", comment="TP")
if slHitLong
strategy.close("Long", comment="SL")
if slHitShort
strategy.close("Short", comment="SL")
// ══════════════════════════════════════════════════════════════
// VISUALS
// ══════════════════════════════════════════════════════════════
hline( 2.0, "+2", color=color.new(color.red, 20), linestyle=hline.style_dashed)
hline(-2.0, "-2", color=color.new(color.teal, 20), linestyle=hline.style_dashed)
hline( 0.0, "Mid", color=color.gray, linestyle=hline.style_solid)
color zCol = zScore >= 0 ? color.new(color.red, 10) : color.new(color.teal, 10)
plot(zScore, title="Z Score", color=zCol, linewidth=3)
bgcolor(zScore > 2.0 ? color.new(color.red, 90) : na, title="Overbought Zone")
bgcolor(zScore < -2.0 ? color.new(color.teal, 90) : na, title="Oversold Zone")
bgcolor(strategy.position_size > 0 ? color.new(color.teal, 93) : na, title="In Long")
bgcolor(strategy.position_size < 0 ? color.new(color.red, 93) : na, title="In Short")
plotshape(enterLong, style=shape.triangleup, location=location.bottom, color=color.teal, size=size.small)
plotshape(enterShort, style=shape.triangledown, location=location.top, color=color.red, size=size.small)
plotshape(tpHitLong or tpHitShort, style=shape.flag, location=location.top, color=color.yellow, size=size.tiny, text="TP")
plotshape(slHitLong or slHitShort, style=shape.xcross, location=location.top, color=color.orange, size=size.tiny, text="SL")