
ZSCORE, RSI, ATR, SMA, EMA
이것은 일반적인 트렌드 추적 전략이 아닙니다. XAG/XAU 통계적 거 전략은 하나의 핵심 가정에 기반합니다: 금과 은의 가격이 장기 평균 회귀 관계에 있습니다. Z-Score가 ± 2 표준 차이를 돌파 할 때, 가격이 통계적으로 극한에 도달하여 회귀 기회를 잡습니다.
전략의 핵심은 표준화 가격비율 모델을 구축하는 것이다. XAG와 XAU에 대해 20주기 SMA를 통해 표준화하고, 3주기 EMA를 사용하여 비율을 평형화한다. 이 처리 방식은 간단한 가격비율보다 안정적이며, 단기적 소음을 효과적으로 필터링한다. 표준화 비율의 Z-Score가 ± 2 범위를 초과할 때, 이는 현재 가격이 역사적 평균에서 2 표준 이상 떨어져 있다는 것을 나타냅니다. 통계적으로 작은 확률 사건으로 간주되며, 평균으로 돌아가는 시간을 제공합니다.
기존의 RSI 오버 바이 오버 세 신호와는 달리, RSI=50을 다공간 필터 조건으로 사용한다. RSI<50일 때 더 많이 할 수 있고, RSI>50일 때 더 적게 할 수 있다. 이 설계 논리는 명확하다: 상대적으로 약한 경우 구매하여 반발을 기다리고, 상대적으로 강한 경우 판매하여 재조정을 기다린다. 이 필터 메커니즘은 역경 거래의 위험을 효과적으로 줄이고, 신호 품질을 향상시킨다.
스톱은 3배의 ATR, 스톱로스는 8배의 ATR로 설정되어 있고, 리스크 수익률은 1:2.67에 달한다. 이 디자인은 통계적 배당의 특징을 기반으로 한다. 평균값이 돌아가는 확률이 높지만, 충분한 오류 허용 공간을 부여해야 한다. 14주기 ATR은 스톱로스 레벨이 시장의 변동성에 적응할 수 있도록 보장한다. 역사적인 회귀는 이 비율이 귀금속 쌍 거래에서 긍정적인 기대 수익을 달성할 수 있음을 보여준다.
통계적 중매 전략은 수평 변동 현장에서 가장 잘 작동합니다. 왜냐하면 이 때 평균값 회귀 특성이 더 분명하기 때문입니다. 단방향 시장에서 가격이 평균값에서 오랫동안 벗어날 수 있기 때문에 전략은 더 큰 회수 위험에 직면합니다. 시장의 변동률이 적당하고 명백한 단방향이없는 경우 사용하는 것이 좋습니다. 또한 귀금속 시장은 거시 경제 요인에 의해 영향을 받으며 중요한 사건 동안 신중하게 사용해야합니다.
역사적인 통계적 관계는 미래의 지속을 보장하지 않는다. 금 은 비율은 수요 공급 구조의 변화, 통화 정책의 차이 등과 같은 요인들로 인해 장기적으로 편향될 수 있다. 전략은 연속적인 손실의 위험이 있다. 특히 시장 구조의 변화 기간 동안이다.
//@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")