Estrategia de arbitraje de oro y plata


Fecha de creación: 2026-03-12 11:50:47 Última modificación: 2026-03-12 11:50:47
Copiar: 0 Número de Visitas: 22
2
Seguir
413
Seguidores

Estrategia de arbitraje de oro y plata Estrategia de arbitraje de oro y plata

ZSCORE, RSI, ATR, SMA, EMA

Arbitraje estadístico Z-Score: el juego matemático de la relación entre el precio del oro y la plata

Esta no es una estrategia de seguimiento de tendencias ordinaria. La estrategia de arbitraje estadístico XAG/XAU se basa en una hipótesis central: el precio de la plata y el oro tiene una relación de retorno a la media a largo plazo. Cuando el Z-Score supera la diferencia estándar de ± 2, el precio se desvía hasta alcanzar un límite en sentido estadístico, en ese momento entra en juego la oportunidad de capturar una reversión.

Ratio de estandarización de 20 ciclos: más preciso que el análisis de correlación tradicional

El núcleo de la estrategia es la construcción de un modelo de proporción de precios estandarizado. Se estandariza a través de 20 ciclos de SMA para XAG y XAU respectivamente, luego se calcula la proporción y se suaviza con 3 ciclos de EMA. Este tratamiento es más estable que la simple proporción de precios y filtra eficazmente el ruido a corto plazo.

El filtro RSI: el uso ingenioso de la línea divisoria 50

A diferencia de las señales de sobreventa y sobreventa de RSI tradicionales, se utiliza el RSI = 50 como condición de filtro de la brecha. Se permite hacer más cuando el RSI es <50 y se permite hacer menos cuando el RSI es >50. La lógica de diseño es clara: comprar y esperar un rebote cuando el RSI es relativamente débil y vender y esperar un repunte cuando el RSI es relativamente fuerte. Este mecanismo de filtración reduce efectivamente el riesgo de operaciones en contraposición y mejora la calidad de la señal.

3:8 ATR riesgo-beneficio: las matemáticas esperan ser positivas

El stop-loss es de 3 veces el ATR, el stop-loss es de 8 veces el ATR, y la relación entre el riesgo y el beneficio es de 1:2.67. El diseño se basa en el arbitraje estadístico: la probabilidad de que el promedio regrese es alta, pero se debe dar suficiente margen de error. El ATR de 14 períodos asegura que el nivel de stop-loss se adapte a los cambios en la volatilidad del mercado.

Escenario de aplicación: el mercado de la oscilación es mejor que el mercado de tendencia

Las estrategias de arbitraje estadístico funcionan mejor en situaciones de oscilación horizontal, ya que la característica de regreso al valor promedio es más evidente en este momento. En un mercado de tendencia unilateral, los precios pueden desviarse del valor promedio durante un largo tiempo, lo que hace que la estrategia se enfrente a un mayor riesgo de retorno. Se recomienda su uso cuando la volatilidad del mercado es moderada y no hay una tendencia unilateral evidente.

Sugerencias de riesgo: las limitaciones de los modelos estadísticos

Las relaciones estadísticas históricas no garantizan la continuidad en el futuro. La relación entre el precio del oro y el de la plata puede desviarse a largo plazo debido a cambios en la estructura de la oferta y la demanda, diferencias en la política monetaria, etc. La estrategia presenta un riesgo de pérdidas continuas, especialmente durante los cambios estructurales en el mercado. Se recomienda aplicar estrictamente la gestión de riesgos, controlar el riesgo de una sola transacción no más del 2% de los fondos de la cuenta y evaluar periódicamente la eficacia de la estrategia.

Código Fuente de la Estrategia
//@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")