IC Markets

Gold/Silver Ratio Mean Reversion trading strategy

Share, develop, and backtest custom MQL4/MQL5 Expert Advisors, Python data-scraping scripts, trading bots, and automated market alert systems.
Post Reply
PTScalper
Site Admin
Posts: 1114
Joined: Mon Jul 20, 2026 1:28 pm

Gold/Silver Ratio Mean Reversion trading strategy

Post by PTScalper »

Hi traders/scalpers,

The core of this strategy relies on the historical correlation between gold and silver. Instead of guessing market direction, you are trading the spread between the two metals [1].

The Gold/Silver ratio simply represents how many ounces of silver it takes to buy one ounce of gold [1]. When the ratio reaches historical extremes, it tends to snap back to its historical mean [1].

Hypothetical Setup & Rules:
Assuming standard retail broker conditions and a swing-trading approach.

Timeframe: Daily (D1) or 4-Hour (H4) charts [1].

The Indicator: A custom ratio indicator plotting XAUUSD divided by XAGUSD.

Shorting the Ratio (Gold is Overvalued):

Trigger: The ratio climbs above 80.0 [1].

Action: Sell XAUUSD and Buy XAGUSD [1]. You are betting that silver will catch up to gold, or gold will drop faster than silver.

Longing the Ratio (Silver is Overvalued):

Trigger: The ratio drops below 60.0 (or historically 50.0) [1].

Action: Buy XAUUSD and Sell XAGUSD [1].

Position Sizing (Crucial): You cannot simply trade 1 lot of gold and 1 lot of silver. Brokers have completely different contract sizes for these metals (e.g., 100 oz for Gold vs. 5000 oz for Silver) [2]. You must balance your lot sizes so that a 1% price move in gold yields the exact same dollar profit/loss as a 1% move in silver in your account currency.

Exit / Take Profit: Close both legs simultaneously when the ratio reverts back to the historical mean (typically around 65.0 - 70.0).

Stop Loss: Close both legs if the ratio continues to diverge past a structural extreme (e.g., the ratio hits 95.0), or use a fixed percentage stop (e.g., capping the total floating loss at 2% of your account equity).

MT4 Code (MQL4 Custom Indicator)
Because trading two different symbols simultaneously requires precise, broker-specific contract sizing, running a fully automated multi-currency Expert Advisor (EA) is highly risky for this strategy. If the EA miscalculates the contract size, you could accidentally over-leverage one side of the trade.

The most reliable way to trade this in MT4 is by using a Custom Indicator that plots the ratio, allowing you to manage the dual entries manually.

How to install:

Open MT4, and press F4 to open the MetaEditor.

Click New -> Custom Indicator -> Name it GoldSilverRatio.

Delete the default code, paste the script below, and click Compile.

Drag the indicator from your Navigator panel onto your Gold chart. (Note: Ensure the symbol names in the indicator settings exactly match what your broker uses, e.g., "GOLD" and "SILVER" if they don't use XAUUSD/XAGUSD).

Code: Select all

//+------------------------------------------------------------------+
//|                                              GoldSilverRatio.mq4 |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Educational Purposes"
#property link      ""
#property version   "1.00"
#property strict

// Plot settings
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 clrDodgerBlue
#property indicator_width1 2

// Key Strategy Levels
#property indicator_level1 80.0
#property indicator_level2 60.0
#property indicator_level3 70.0 // Mean reversion target
#property indicator_levelcolor clrDarkGray
#property indicator_levelstyle STYLE_DASHDOT

// User Inputs
input string GoldSymbol = "XAUUSD";   // Exact Gold Symbol on your broker
input string SilverSymbol = "XAGUSD"; // Exact Silver Symbol on your broker

double RatioBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   SetIndexBuffer(0, RatioBuffer);
   SetIndexStyle(0, DRAW_LINE);
   SetIndexLabel(0, "G/S Ratio");
   
   IndicatorShortName("Gold/Silver Ratio (" + GoldSymbol + "/" + SilverSymbol + ")");
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   // Handle missing data or first load
   int limit = rates_total - prev_calculated;
   if(limit > 0)
     {
      limit = rates_total - 1; 
     }

   // Calculate ratio for each candle
   for(int i = limit; i >= 0; i--)
     {
      double goldPrice = iClose(GoldSymbol, 0, i);
      double silverPrice = iClose(SilverSymbol, 0, i);
      
      // Prevent division by zero if a symbol is missing data
      if(silverPrice > 0 && goldPrice > 0)
        {
         RatioBuffer[i] = goldPrice / silverPrice;
        }
      else
        {
         RatioBuffer[i] = 0;
        }
     }
     
   return(rates_total);
  }
//+------------------------------------------------------------------+
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 1114
Joined: Mon Jul 20, 2026 1:28 pm

Re: Gold/Silver Ratio Mean Reversion trading strategy

Post by PTScalper »

Because MT5 and cTrader handle multi-symbol data differently than MT4, both of these scripts map the secondary symbol's prices by the exact timestamp of the current candle. This prevents the ratio from breaking or skewing if there are missing ticks or desynced bars on one of the symbols.

MetaTrader 5 (MQL5)

How to install: Open the MetaEditor (F4), create a new Custom Indicator named GoldSilverRatio, replace the default code with this, and compile.

Code: Select all

//+------------------------------------------------------------------+
//|                                              GoldSilverRatio.mq5 |
//+------------------------------------------------------------------+
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1

#property indicator_label1  "G/S Ratio"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

#property indicator_level1 80.0
#property indicator_level2 60.0
#property indicator_level3 70.0
#property indicator_levelcolor clrDarkGray
#property indicator_levelstyle STYLE_DASHDOT

input string InpGoldSymbol = "XAUUSD";   // Gold Symbol
input string InpSilverSymbol = "XAGUSD"; // Silver Symbol

double RatioBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   SetIndexBuffer(0, RatioBuffer, INDICATOR_DATA);
   IndicatorSetString(INDICATOR_SHORTNAME, "G/S Ratio (" + InpGoldSymbol + "/" + InpSilverSymbol + ")");
   
   // Ensure both symbols are available in Market Watch
   SymbolSelect(InpGoldSymbol, true);
   SymbolSelect(InpSilverSymbol, true);
   
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   if(rates_total < 1) return(0);

   int limit = prev_calculated == 0 ? 0 : prev_calculated - 1;
   
   double goldClose[1], silverClose[1];

   for(int i = limit; i < rates_total; i++)
     {
      // Map prices by the exact bar time to prevent desync errors
      if(CopyClose(InpGoldSymbol, PERIOD_CURRENT, time[i], 1, goldClose) > 0 &&
         CopyClose(InpSilverSymbol, PERIOD_CURRENT, time[i], 1, silverClose) > 0)
        {
         if(silverClose[0] > 0)
            RatioBuffer[i] = goldClose[0] / silverClose[0];
         else
            RatioBuffer[i] = 0;
        }
      else
        {
         // Carry over the previous value if a tick is missing on one symbol
         RatioBuffer[i] = (i > 0) ? RatioBuffer[i-1] : 0; 
        }
     }
   return(rates_total);
  }
//+------------------------------------------------------------------+
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 1114
Joined: Mon Jul 20, 2026 1:28 pm

Re: Gold/Silver Ratio Mean Reversion trading strategy

Post by PTScalper »

cTrader (C#)

How to install: Open cTrader Automate, click the New Indicator button, name it GoldSilverRatio, paste this code, and click the Build button.

Code: Select all

using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class GoldSilverRatio : Indicator
    {
        [Parameter("Gold Symbol", DefaultValue = "XAUUSD")]
        public string GoldSymbol { get; set; }

        [Parameter("Silver Symbol", DefaultValue = "XAGUSD")]
        public string SilverSymbol { get; set; }

        [Output("G/S Ratio", LineColor = "DodgerBlue", Thickness = 2)]
        public IndicatorDataSeries Ratio { get; set; }

        private Bars _goldBars;
        private Bars _silverBars;

        protected override void Initialize()
        {
            // Fetch historical and live data for both symbols
            _goldBars = MarketData.GetBars(TimeFrame, GoldSymbol);
            _silverBars = MarketData.GetBars(TimeFrame, SilverSymbol);
        }

        public override void Calculate(int index)
        {
            // Get the timestamp of the current chart's candle
            var currentTime = Bars.OpenTimes[index];
            
            // Find the matching candle indices for both symbols
            int goldIndex = _goldBars.OpenTimes.GetIndexByTime(currentTime);
            int silverIndex = _silverBars.OpenTimes.GetIndexByTime(currentTime);

            if (goldIndex >= 0 && silverIndex >= 0)
            {
                double goldPrice = _goldBars.ClosePrices[goldIndex];
                double silverPrice = _silverBars.ClosePrices[silverIndex];

                if (silverPrice > 0)
                {
                    Ratio[index] = goldPrice / silverPrice;
                }
            }
            else
            {
                // Fallback to the previous value if the current time isn't found
                Ratio[index] = index > 0 ? Ratio[index - 1] : 0;
            }
        }
    }
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 1114
Joined: Mon Jul 20, 2026 1:28 pm

Re: Gold/Silver Ratio Mean Reversion trading strategy

Post by PTScalper »

To balance monetary exposure between Gold and Silver, you must equalize their Notional Position Value (Dollar Exposure).

Because contract specifications vary widely between brokers (typically 100 oz per lot for Gold vs. 5,000 oz per lot for Silver), equalizing the total dollar exposure ensures that a 1% move in Gold yields the exact same monetary gain/loss as a 1% move in Silver:

MetaTrader 5 (MQL5 Script)
Save this as a Script in MT5 (MQL5/Scripts/BalanceMetalsExposure.mq5). It calculates the exact balanced lot size, logs the exact dollar values, and can optionally execute both legs simultaneously.

Code: Select all

//+------------------------------------------------------------------+
//|                                     BalanceMetalsExposure.mq5    |
//+------------------------------------------------------------------+
#property copyright "Educational Purposes"
#property script_show_inputs
#property strict

#include <Trade\Trade.mqh>

enum ENUM_TRADE_ACTION
  {
   ACTION_CALCULATE_ONLY = 0,    // Only calculate & print exposure
   ACTION_SELL_GOLD_BUY_SILVER,  // Mean Reversion (Ratio > 80)
   ACTION_BUY_GOLD_SELL_SILVER   // Mean Reversion (Ratio < 60)
  };

//--- Inputs
input group "=== Strategy Parameters ==="
input ENUM_TRADE_ACTION InpAction       = ACTION_CALCULATE_ONLY; // Action to execute
input string            InpGoldSymbol   = "XAUUSD";              // Gold Symbol
input string            InpSilverSymbol = "XAGUSD";              // Silver Symbol
input double            InpGoldLots     = 0.10;                  // Base Gold Lot Size
input ulong             InpDeviation    = 20;                    // Max slippage (points)
input ulong             InpMagicNumber  = 112233;                // Magic Number

CTrade trade;

//+------------------------------------------------------------------+
//| Normalize lots to broker volume step, min, and max limits        |
//+------------------------------------------------------------------+
double NormalizeLots(string symbol, double lots)
  {
   double step   = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
   double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
   double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
   
   if(step <= 0) return lots;
   
   double normalized = MathRound(lots / step) * step;
   if(normalized < minLot) normalized = minLot;
   if(normalized > maxLot) normalized = maxLot;
   
   int digits = (int)MathCeil(MathAbs(MathLog10(step)));
   return NormalizeDouble(normalized, digits);
  }

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   // 1. Verify symbols exist and are available in Market Watch
   if(!SymbolSelect(InpGoldSymbol, true) || !SymbolSelect(InpSilverSymbol, true))
     {
      Print("[ERROR] Could not select symbols in Market Watch.");
      return;
     }

   // 2. Fetch prices and contract specifications
   double goldPrice      = SymbolInfoDouble(InpGoldSymbol, SYMBOL_ASK);
   double silverPrice    = SymbolInfoDouble(InpSilverSymbol, SYMBOL_ASK);
   double goldContract   = SymbolInfoDouble(InpGoldSymbol, SYMBOL_TRADE_CONTRACT_SIZE);
   double silverContract = SymbolInfoDouble(InpSilverSymbol, SYMBOL_TRADE_CONTRACT_SIZE);

   if(goldPrice <= 0 || silverPrice <= 0 || goldContract <= 0 || silverContract <= 0)
     {
      Print("[ERROR] Failed to fetch valid prices or contract sizes.");
      return;
     }

   // 3. Calculate Notional Exposure
   double goldNotional     = InpGoldLots * goldContract * goldPrice;
   double rawSilverLots    = goldNotional / (silverContract * silverPrice);
   double balancedSilverLots = NormalizeLots(InpSilverSymbol, rawSilverLots);
   double silverNotional   = balancedSilverLots * silverContract * silverPrice;
   double currentRatio     = goldPrice / silverPrice;

   // 4. Output sizing breakdown
   Print("------------------------------------------------------------");
   PrintFormat("Gold/Silver Ratio: %.2f", currentRatio);
   PrintFormat("Gold (%s): %.2f Lots | Contract Size: %.0f | Price: %.2f | Exposure: $%.2f", 
               InpGoldSymbol, InpGoldLots, goldContract, goldPrice, goldNotional);
   PrintFormat("Silver (%s): %.2f Lots | Contract Size: %.0f | Price: %.2f | Exposure: $%.2f", 
               InpSilverSymbol, balancedSilverLots, silverContract, silverPrice, silverNotional);
   PrintFormat("Dollar Discrepancy: $%.2f (due to broker lot step)", MathAbs(goldNotional - silverNotional));
   Print("------------------------------------------------------------");

   // 5. Execution (if selected)
   if(InpAction == ACTION_CALCULATE_ONLY)
     {
      Comment(StringFormat("Calculated: %.2f Gold Lots <=> %.2f Silver Lots (Ratio: %.2f)", 
                           InpGoldLots, balancedSilverLots, currentRatio));
      return;
     }

   trade.SetExpertMagicNumber(InpMagicNumber);
   trade.SetDeviationInPoints(InpDeviation);

   if(InpAction == ACTION_SELL_GOLD_BUY_SILVER)
     {
      Print("[EXECUTION] Selling Gold, Buying Silver...");
      trade.Sell(InpGoldLots, InpGoldSymbol, 0, 0, 0, "G/S Ratio Short");
      trade.Buy(balancedSilverLots, InpSilverSymbol, 0, 0, 0, "G/S Ratio Long");
     }
   else if(InpAction == ACTION_BUY_GOLD_SELL_SILVER)
     {
      Print("[EXECUTION] Buying Gold, Selling Silver...");
      trade.Buy(InpGoldLots, InpGoldSymbol, 0, 0, 0, "G/S Ratio Long");
      trade.Sell(balancedSilverLots, InpSilverSymbol, 0, 0, 0, "G/S Ratio Short");
     }
  }
//+------------------------------------------------------------------+
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 1114
Joined: Mon Jul 20, 2026 1:28 pm

Re: Gold/Silver Ratio Mean Reversion trading strategy

Post by PTScalper »

cTrader (C# cBot Execution Script)

In cTrader, position sizes are handled directly in Volume in Units. This script calculates unit volumes, normalizes them to broker volume step constraints, and outputs the quantities in both units and standard lots.

Save this in cTrader Automate as a cBot named

Code: Select all

using System;
using cAlgo.API;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    public enum StrategyAction
    {
        CalculateOnly,
        SellGoldBuySilver,
        BuyGoldSellSilver
    }

    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class MetalsExposureBalancer : Robot
    {
        [Parameter("Action", DefaultValue = StrategyAction.CalculateOnly)]
        public StrategyAction Action { get; set; }

        [Parameter("Gold Symbol", DefaultValue = "XAUUSD")]
        public string GoldSymbolName { get; set; }

        [Parameter("Silver Symbol", DefaultValue = "XAGUSD")]
        public string SilverSymbolName { get; set; }

        [Parameter("Base Gold Lots", DefaultValue = 0.10, MinValue = 0.01, Step = 0.01)]
        public double BaseGoldLots { get; set; }

        [Parameter("Max Slippage (Pips)", DefaultValue = 5)]
        public double MaxSlippage { get; set; }

        protected override void OnStart()
        {
            var goldSymbol = Symbols.GetSymbol(GoldSymbolName);
            var silverSymbol = Symbols.GetSymbol(SilverSymbolName);

            if (goldSymbol == null || silverSymbol == null)
            {
                Print("[ERROR] One or both symbols could not be found.");
                Stop();
                return;
            }

            // 1. Convert Gold lots into units and calculate notional exposure
            double goldUnits = goldSymbol.QuantityToVolumeInUnits(BaseGoldLots);
            double goldPrice = goldSymbol.Ask;
            double silverPrice = silverSymbol.Ask;

            if (goldPrice <= 0 || silverPrice <= 0)
            {
                Print("[ERROR] Market data currently unavailable.");
                Stop();
                return;
            }

            double goldNotional = goldUnits * goldPrice;

            // 2. Calculate required Silver units to match notional exposure
            double rawSilverUnits = goldNotional / silverPrice;
            double balancedSilverUnits = silverSymbol.NormalizeVolumeInUnits(rawSilverUnits, RoundingMode.ToNearest);
            double balancedSilverLots = silverSymbol.VolumeInUnitsToQuantity(balancedSilverUnits);
            double silverNotional = balancedSilverUnits * silverPrice;
            double currentRatio = goldPrice / silverPrice;

            // 3. Log results
            Print("============================================================");
            Print($"Current Gold/Silver Ratio: {currentRatio:F2}");
            Print($"Gold ({GoldSymbolName}): {BaseGoldLots:F2} Lots ({goldUnits:N0} units) @ ${goldPrice:F2} | Exposure: ${goldNotional:N2}");
            Print($"Silver ({SilverSymbolName}): {balancedSilverLots:F2} Lots ({balancedSilverUnits:N0} units) @ ${silverPrice:F2} | Exposure: ${silverNotional:N2}");
            Print($"Exposure Difference: ${Math.Abs(goldNotional - silverNotional):N2}");
            Print("============================================================");

            // 4. Trade Execution
            if (Action == StrategyAction.CalculateOnly)
            {
                Stop();
                return;
            }

            if (Action == StrategyAction.SellGoldBuySilver)
            {
                Print("[EXECUTION] Executing: Sell Gold / Buy Silver");
                ExecuteMarketOrder(TradeType.Sell, GoldSymbolName, goldUnits, "G/S Ratio Short", null, null, MaxSlippage);
                ExecuteMarketOrder(TradeType.Buy, SilverSymbolName, balancedSilverUnits, "G/S Ratio Long", null, null, MaxSlippage);
            }
            else if (Action == StrategyAction.BuyGoldSellSilver)
            {
                Print("[EXECUTION] Executing: Buy Gold / Sell Silver");
                ExecuteMarketOrder(TradeType.Buy, GoldSymbolName, goldUnits, "G/S Ratio Long", null, null, MaxSlippage);
                ExecuteMarketOrder(TradeType.Sell, SilverSymbolName, balancedSilverUnits, "G/S Ratio Short", null, null, MaxSlippage);
            }

            // Stop the bot after single execution
            Stop();
        }
    }
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 1114
Joined: Mon Jul 20, 2026 1:28 pm

Re: Gold/Silver Ratio Mean Reversion trading strategy

Post by PTScalper »

Key Execution ConsiderationsContract Size Discrepancies:

On standard accounts, 1 lot of Gold ($2,500/oz) is 100 oz ($250,000 notional), whereas 1 lot of Silver ($30/oz) is 5,000 oz ($150,000 notional). For 0.10 lots of Gold ($25,000 exposure), the script will calculate approximately 0.17 lots of Silver ($25,500 exposure).Financing & Swaps: Overnight holding costs (financing swap rates) apply separately to long and short legs. When holding spread positions over several days/weeks, check your broker's triple-swap days (typically Wednesday or Friday) to account for carry drag.Lot Step Rounding: Minor dollar exposure discrepancies occur because retail brokers enforce volume steps (e.g., $0.01\text{ lots} = 50\text{ oz}$ of silver).
The scripts automatically round to the nearest valid increment.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 1114
Joined: Mon Jul 20, 2026 1:28 pm

Re: Gold/Silver Ratio Mean Reversion trading strategy

Post by PTScalper »

Here is the complete Pine Script (v5) implementation for TradingView.

This script plots the real-time Gold/Silver Ratio, marks the historical mean reversion bands, and includes a live Position Sizing & Exposure Table directly in the indicator sub-window so you can see the balanced lot sizes in real time.

TradingView Pine Script (v5)
How to use:

Open any chart on TradingView and click on the Pine Editor tab at the bottom.

Clear any placeholder code, paste the script below, and click Save -> Add to chart.

In the indicator settings (⚙), you can adjust the broker symbol tickers (e.g., OANDA:XAUUSD or TVC:GOLD), contract sizes, and base lot size.

Pine Script

Code: Select all

//@version=5
indicator("Gold/Silver Ratio & Position Sizer", shorttitle="G/S Ratio & Sizer", overlay=false)

// ==========================================
// 1. INPUTS
// ==========================================
grp_sym   = "Symbol Configuration"
goldSym   = input.symbol("OANDA:XAUUSD", "Gold Symbol", group=grp_sym)
silverSym = input.symbol("OANDA:XAGUSD", "Silver Symbol", group=grp_sym)

grp_spec  = "Contract & Sizing Specifications"
goldLots  = input.float(0.10, "Base Gold Lot Size", minval=0.01, step=0.01, group=grp_spec)
goldOz    = input.float(100.0, "Gold Contract Size (oz per lot)", minval=1.0, group=grp_spec)
silverOz  = input.float(5000.0, "Silver Contract Size (oz per lot)", minval=1.0, group=grp_spec)
lotStep   = input.float(0.01, "Silver Volume Step", minval=0.001, step=0.01, group=grp_spec)

grp_lvl   = "Strategy Ratio Thresholds"
levelOver = input.float(80.0, "Overvalued Gold (Sell Gold / Buy Silver)", group=grp_lvl)
levelMean = input.float(70.0, "Mean Reversion Target", group=grp_lvl)
levelUnder= input.float(60.0, "Undervalued Gold (Buy Gold / Sell Silver)", group=grp_lvl)

// ==========================================
// 2. DATA RETRIEVAL & RATIO
// ==========================================
goldClose   = request.security(goldSym, timeframe.period, close)
silverClose = request.security(silverSym, timeframe.period, close)

ratio = (silverClose > 0) ? (goldClose / silverClose) : na

// ==========================================
// 3. EXPOSURE & SIZING MATH
// ==========================================
// Dollar notional exposure for base gold leg
goldNotional   = goldLots * goldOz * goldClose

// Calculate balanced silver lots needed to match dollar exposure
silverLotsRaw  = (silverClose > 0 and silverOz > 0) ? (goldNotional / (silverOz * silverClose)) : 0.0
silverLots     = math.round(silverLotsRaw / lotStep) * lotStep
silverNotional = silverLots * silverOz * silverClose

// ==========================================
// 4. PLOTS & SIGNALS
// ==========================================
plot(ratio, "G/S Ratio", color=color.new(#2962FF, 0), linewidth=2)

h_upper = hline(levelOver, "Upper Threshold (80)", color=color.red, linestyle=hline.style_dashed)
h_mean  = hline(levelMean, "Mean Target (70)", color=color.gray, linestyle=hline.style_dotted)
h_lower = hline(levelUnder, "Lower Threshold (60)", color=color.green, linestyle=hline.style_dashed)
fill(h_upper, h_lower, color=color.new(color.blue, 95), title="Mean Range Fill")

// Signal Triggers
signalShort = ta.crossover(ratio, levelOver)
signalLong  = ta.crossunder(ratio, levelUnder)
signalExit  = ta.cross(ratio, levelMean)

plotshape(signalShort, title="Sell Gold / Buy Silver", style=shape.triangledown, location=location.top, color=color.red, size=size.small, text="SHORT RATIO")
plotshape(signalLong, title="Buy Gold / Sell Silver", style=shape.triangleup, location=location.bottom, color=color.green, size=size.small, text="LONG RATIO")

// ==========================================
// 5. ON-CHART SIZING DASHBOARD
// ==========================================
var table dash = table.new(position.top_right, 4, 4, bgcolor=color.new(#1e222d, 10), border_color=color.gray, border_width=1)

if barstate.islast
    // Header
    table.cell(dash, 0, 0, "Asset", bgcolor=color.new(color.gray, 40), text_color=color.white, text_size=size.small)
    table.cell(dash, 1, 0, "Required Lots", bgcolor=color.new(color.gray, 40), text_color=color.white, text_size=size.small)
    table.cell(dash, 2, 0, "Price", bgcolor=color.new(color.gray, 40), text_color=color.white, text_size=size.small)
    table.cell(dash, 3, 0, "Notional Exposure", bgcolor=color.new(color.gray, 40), text_color=color.white, text_size=size.small)

    // Gold Row
    table.cell(dash, 0, 1, "Gold (XAU)", text_color=color.white, text_size=size.small)
    table.cell(dash, 1, 1, str.tostring(goldLots, "#.##"), text_color=color.white, text_size=size.small)
    table.cell(dash, 2, 1, "$" + str.tostring(goldClose, "#.##"), text_color=color.white, text_size=size.small)
    table.cell(dash, 3, 1, "$" + str.tostring(goldNotional, "#,###.##"), text_color=color.yellow, text_size=size.small)

    // Silver Row
    table.cell(dash, 0, 2, "Silver (XAG)", text_color=color.white, text_size=size.small)
    table.cell(dash, 1, 2, str.tostring(silverLots, "#.##"), text_color=color.white, text_size=size.small)
    table.cell(dash, 2, 2, "$" + str.tostring(silverClose, "#.##"), text_color=color.white, text_size=size.small)
    table.cell(dash, 3, 2, "$" + str.tostring(silverNotional, "#,###.##"), text_color=color.yellow, text_size=size.small)

    // Status / Signal Row
    string statusText = ratio >= levelOver ? "Ratio Overbought: Sell Gold / Buy Silver" : ratio <= levelUnder ? "Ratio Oversold: Buy Gold / Sell Silver" : "Ratio in Neutral Zone"
    color statusBg = ratio >= levelOver ? color.red : ratio <= levelUnder ? color.green : color.navy
    table.cell(dash, 0, 3, "Ratio: " + str.tostring(ratio, "#.##") + " | " + statusText, bgcolor=statusBg, text_color=color.white, text_size=size.small)
    table.merge_cells(dash, 0, 3, 3, 3)

// ==========================================
// 6. TRADINGVIEW ALERTS
// ==========================================
alertcondition(signalShort, title="Ratio > 80 (Sell Gold / Buy Silver)", message="Gold/Silver ratio exceeded 80. Look to short Gold and long Silver.")
alertcondition(signalLong, title="Ratio < 60 (Buy Gold / Sell Silver)", message="Gold/Silver ratio dropped below 60. Look to long Gold and short Silver.")
alertcondition(signalExit, title="Ratio Reverted to Mean (70)", message="Gold/Silver ratio reverted to 70. Look to close spread positions.")
Features in this Pine ScriptLive Multi-Ticker Sync: Pulls synchronized close prices for both Gold and Silver from your selected provider via request.security.Automatic Exposure Balancer: Uses the exact formula $\text{Lots}_{\text{Silver}} = \frac{\text{Lots}_{\text{Gold}} \times \text{Size}_{\text{Gold}} \times \text{Price}_{\text{Gold}}}{\text{Size}_{\text{Silver}} \times \text{Price}_{\text{Silver}}}$ and rounds to your broker's volume step.Live On-Screen Dashboard: Shows your exact dollar exposure for each leg and highlights current setup status (Overbought/Oversold/Neutral).Native Alert Hooks: Pre-configured alertcondition events for upper threshold crossovers, lower threshold crossunders, and mean reversion exits.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Post Reply