Chiến lược chênh lệch giá vàng và bạc


Ngày tạo: 2026-03-12 11:50:47 sửa đổi lần cuối: 2026-03-12 11:50:47
sao chép: 0 Số nhấp chuột: 22
2
tập trung vào
413
Người theo dõi

Chiến lược chênh lệch giá vàng và bạc Chiến lược chênh lệch giá vàng và bạc

ZSCORE, RSI, ATR, SMA, EMA

Z-Score Statistical Arbitrage: Trò chơi toán học về giá vàng và bạc

Đây không phải là một chiến lược theo dõi xu hướng thông thường. Chiến lược đánh giá thống kê XAG/XAU dựa trên một giả định cốt lõi: giá vàng và bạc có mối quan hệ quay trở về giá trị trung bình trong thời gian dài. Khi Z-Score phá vỡ chênh lệch tiêu chuẩn ± 2, giá sẽ đi lạc đến cực điểm theo nghĩa thống kê, khi đó bắt đầu cơ hội quay trở lại. Dữ liệu đánh giá lại cho thấy phương pháp đánh giá thống kê này có lợi thế rõ ràng về lợi nhuận sau khi điều chỉnh rủi ro trong thị trường kim loại quý.

Tỷ lệ chuẩn hóa 20 chu kỳ: chính xác hơn so với phân tích liên quan truyền thống

Cốt lõi của chiến lược là xây dựng mô hình tỷ lệ giá chuẩn hóa. Định chuẩn hóa cho XAG và XAU theo 20 chu kỳ SMA, sau đó tính tỷ lệ và làm mịn bằng 3 chu kỳ EMA. Cách xử lý này ổn định hơn tỷ lệ giá đơn giản và có thể lọc hiệu quả tiếng ồn ngắn hạn. Khi tỷ lệ chuẩn hóa Z-Score vượt quá khoảng ± 2, cho thấy giá hiện tại lệch khỏi trung bình lịch sử hơn 2 điểm chuẩn, theo thống kê là một sự kiện xác suất nhỏ, cung cấp thời gian để quay trở lại trung bình.

Bộ lọc RSI: Sử dụng khéo léo đường phân chia 50

Khác với tín hiệu mua quá bán RSI truyền thống, RSI = 50 được sử dụng như một điều kiện lọc nhiều không gian. RSI <50 cho phép làm nhiều, RSI> 50 cho phép làm rỗng.

3:8 ATR: Hy vọng toán học là tích cực

Đặt dừng là 3 lần ATR, đặt dừng là 8 lần ATR, tỷ lệ lợi nhuận rủi ro đạt 1:2.67. Thiết kế này dựa trên tính chất của tỷ lệ rủi ro thống kê: xác suất trở lại trung bình cao hơn, nhưng cần phải cho phép đủ không gian cho lỗi. ATR 14 chu kỳ đảm bảo mức dừng lỗ có thể thích nghi với sự thay đổi biến động của thị trường.

Trường hợp áp dụng: Thị trường chấn động tốt hơn thị trường xu hướng

Chiến lược đánh giá thống kê hoạt động tốt nhất trong tình huống biến động ngang, vì tính năng quay trở lại của giá trị trung bình rõ ràng hơn. Trong thị trường xu hướng đơn phương, giá có thể lệch khỏi giá trị trung bình trong một thời gian dài, dẫn đến chiến lược đối mặt với rủi ro rút lui lớn hơn.

Dấu hiệu rủi ro: giới hạn của mô hình thống kê

Các mối quan hệ thống kê lịch sử không đảm bảo sự tiếp tục trong tương lai. Giá vàng và bạc có thể bị lệch lâu dài do các yếu tố như thay đổi cấu trúc cung cầu, sự khác biệt về chính sách tiền tệ. Chiến lược có nguy cơ mất mát liên tục, đặc biệt là trong thời gian thay đổi cấu trúc thị trường.

Mã nguồn chiến lược
//@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")