Page 2 of 2

Re: AUDUSD commodity mood and short gold scalp hedges discussion

Posted: Sun Sep 27, 2026 3:35 pm
by PTScalper
Here is the C# source code for cTrader (cAlgo).

Similar to the MT4 version, this renders in an oscillator subwindow using the PlotType.Histogram overlay. A blue line tracks the rolling Pearson correlation, while green, red, or gray histogram bars fill the space underneath when the specific regime conditions are met.

cTrader's API allows for highly accurate cross-asset data alignment. By using GetIndexByTime(), the script ensures that the exact timestamp on AUDUSD is matched with the corresponding timestamp on Gold, preventing errors if one asset has missing ticks during a quiet session.

Re: AUDUSD commodity mood and short gold scalp hedges discussion

Posted: Sun Sep 27, 2026 3:36 pm
by PTScalper
cTrader (cAlgo) - Commodity Mood Indicator

In cTrader Automate, create a new Indicator, name it CommodityMood, paste the code below, and build it.

cTrader (cAlgo) - Commodity Mood Indicator
In cTrader Automate, create a new Indicator, name it CommodityMood, paste the code below, and build it.

Code: Select all

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

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class CommodityMood : Indicator
    {
        // --- Inputs ---
        [Parameter("Compare Asset (e.g. XAUUSD)", DefaultValue = "XAUUSD")]
        public string CompareAsset { get; set; }

        [Parameter("Correlation Length", DefaultValue = 20, MinValue = 5)]
        public int CorrLen { get; set; }

        [Parameter("Momentum Length (ROC)", DefaultValue = 10, MinValue = 2)]
        public int MomLen { get; set; }

        // --- Outputs ---
        // Render order matters: put histograms first so the line draws on top of them
        [Output("Bullish Theme", LineColor = "MediumSeaGreen", PlotType = PlotType.Histogram, Thickness = 3)]
        public IndicatorDataSeries BullTheme { get; set; }

        [Output("Bearish Theme", LineColor = "Crimson", PlotType = PlotType.Histogram, Thickness = 3)]
        public IndicatorDataSeries BearTheme { get; set; }

        [Output("Divergent Theme", LineColor = "Gray", PlotType = PlotType.Histogram, Thickness = 3)]
        public IndicatorDataSeries DivTheme { get; set; }

        [Output("Correlation", LineColor = "DodgerBlue", PlotType = PlotType.Line, Thickness = 2)]
        public IndicatorDataSeries Correlation { get; set; }

        // Variables
        private Bars _compareBars;

        protected override void Initialize()
        {
            // Load secondary symbol bars for the current timeframe
            _compareBars = MarketData.GetBars(TimeFrame, CompareAsset);
            
            // Draw static reference levels across the subwindow
            Chart.DrawHorizontalLine("hline_70", 0.7, Color.FromArgb(80, Color.Green), 1, LineStyle.Lines);
            Chart.DrawHorizontalLine("hline_minus70", -0.7, Color.FromArgb(80, Color.Red), 1, LineStyle.Lines);
            Chart.DrawHorizontalLine("hline_zero", 0.0, Color.FromArgb(80, Color.Gray), 1, LineStyle.Lines);
        }

        public override void Calculate(int index)
        {
            // Ensure we have enough data to look back on the primary chart
            if (index < Math.Max(CorrLen, MomLen)) return;

            // Align secondary asset's index to current time on primary asset
            int compareIndex = _compareBars.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]);
            
            // If the time doesn't exist on the secondary asset (or lacks history), abort this tick
            if (compareIndex < Math.Max(CorrLen, MomLen)) return;

            // 1. Momentum (Rate of Change) to determine directional agreement
            double roc1 = (Bars.ClosePrices[index] - Bars.ClosePrices[index - MomLen]) / Bars.ClosePrices[index - MomLen] * 100.0;
            double roc2 = (_compareBars.ClosePrices[compareIndex] - _compareBars.ClosePrices[compareIndex - MomLen]) / _compareBars.ClosePrices[compareIndex - MomLen] * 100.0;

            // 2. Pearson Correlation Calculation
            double sumX = 0, sumY = 0;
            for (int k = 0; k < CorrLen; k++)
            {
                sumX += Bars.ClosePrices[index - k];
                sumY += _compareBars.ClosePrices[compareIndex - k];
            }
            double meanX = sumX / CorrLen;
            double meanY = sumY / CorrLen;

            double cov = 0, varX = 0, varY = 0;
            for (int k = 0; k < CorrLen; k++)
            {
                double dx = Bars.ClosePrices[index - k] - meanX;
                double dy = _compareBars.ClosePrices[compareIndex - k] - meanY;
                cov += dx * dy;
                varX += dx * dx;
                varY += dy * dy;
            }

            double r = 0;
            if (varX > 0 && varY > 0)
                r = cov / Math.Sqrt(varX * varY);

            Correlation[index] = r;

            // 3. Directional Agreement
            int agreement = 0;
            if (roc1 > 0 && roc2 > 0) agreement = 1;
            else if (roc1 < 0 && roc2 < 0) agreement = -1;

            // 4. Regime Tagging
            // Using NaN clears the histogram bars when conditions aren't met
            BullTheme[index] = double.NaN;
            BearTheme[index] = double.NaN;
            DivTheme[index] = double.NaN;

            if (r > 0.6 && agreement == 1)       BullTheme[index] = r;
            else if (r > 0.6 && agreement == -1) BearTheme[index] = r;
            else if (r < 0.3 && agreement == 0)  DivTheme[index] = r;
        }
    }
}

Re: AUDUSD commodity mood and short gold scalp hedges discussion

Posted: Sun Sep 27, 2026 3:37 pm
by PTScalper
To elevate this into a production-grade cTrader tool, we need to move past basic scripting and treat it like an enterprise C# component.

Here is the "Pro" version. It introduces:

Parameter Grouping: Clean UI organization in the cTrader instance panel.

Strong Typing: Replaces magic numbers (1, -1, 0) with a dedicated MarketRegime enum.

Signal Smoothing (Optional): Raw tick correlation is noisy. Added an EMA signal line to smooth the correlation output and prevent regime flickering.

Graceful Error Handling: Validates the secondary symbol on initialization to prevent silent crashes.

Subwindow HUD: Renders a clean text display in the subwindow showing live metrics (Current Correlation, XAU ROC, AUD ROC) for instant readability.

Re: AUDUSD commodity mood and short gold scalp hedges discussion

Posted: Sun Sep 27, 2026 3:37 pm
by PTScalper
cTrader (cAlgo) - Pro Commodity Mood

Code: Select all

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

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class CommodityMoodPro : Indicator
    {
        private enum MarketRegime
        {
            BullishAgreement,
            BearishAgreement,
            Divergence,
            Neutral
        }

        // --- Parameters: Symbols ---
        [Parameter("Compare Asset", DefaultValue = "XAUUSD", Group = "Data Sources")]
        public string CompareAsset { get; set; }

        // --- Parameters: Periods ---
        [Parameter("Correlation Length", DefaultValue = 20, MinValue = 5, Group = "Calculations")]
        public int CorrLen { get; set; }

        [Parameter("Momentum Length (ROC)", DefaultValue = 10, MinValue = 2, Group = "Calculations")]
        public int MomLen { get; set; }

        [Parameter("Smooth Correlation (EMA)", DefaultValue = 3, MinValue = 1, Group = "Calculations")]
        public int SmoothLen { get; set; }

        // --- Parameters: Thresholds ---
        [Parameter("High Correlation Level", DefaultValue = 0.6, Step = 0.1, Group = "Thresholds")]
        public double HighCorrLevel { get; set; }

        [Parameter("Low Correlation Level", DefaultValue = 0.3, Step = 0.1, Group = "Thresholds")]
        public double LowCorrLevel { get; set; }

        // --- Outputs ---
        [Output("Bullish Theme", LineColor = "MediumSeaGreen", PlotType = PlotType.Histogram, Thickness = 4)]
        public IndicatorDataSeries BullTheme { get; set; }

        [Output("Bearish Theme", LineColor = "Crimson", PlotType = PlotType.Histogram, Thickness = 4)]
        public IndicatorDataSeries BearTheme { get; set; }

        [Output("Divergent Theme", LineColor = "DimGray", PlotType = PlotType.Histogram, Thickness = 4)]
        public IndicatorDataSeries DivTheme { get; set; }

        [Output("Raw Correlation", LineColor = "FromArgb(80, 30, 144, 255)", PlotType = PlotType.Line, Thickness = 1)]
        public IndicatorDataSeries RawCorrelation { get; set; }

        [Output("Smoothed Correlation", LineColor = "DodgerBlue", PlotType = PlotType.Line, Thickness = 2)]
        public IndicatorDataSeries SmoothedCorrelation { get; set; }

        // --- Internal State ---
        private Bars _compareBars;
        private ExponentialMovingAverage _emaSmoothing;
        private string _errorMessage;

        protected override void Initialize()
        {
            try
            {
                _compareBars = MarketData.GetBars(TimeFrame, CompareAsset);
            }
            catch (Exception)
            {
                _errorMessage = $"ERROR: Cannot load symbol '{CompareAsset}'. Check naming convention.";
                PrintError(_errorMessage);
                return;
            }

            _emaSmoothing = Indicators.ExponentialMovingAverage(RawCorrelation, SmoothLen);

            // Subwindow structural lines
            Chart.DrawHorizontalLine("hline_upper", HighCorrLevel, Color.FromArgb(60, Color.Green), 1, LineStyle.Dots);
            Chart.DrawHorizontalLine("hline_lower", -HighCorrLevel, Color.FromArgb(60, Color.Red), 1, LineStyle.Dots);
            Chart.DrawHorizontalLine("hline_zero", 0.0, Color.FromArgb(100, Color.Gray), 1, LineStyle.Lines);
        }

        public override void Calculate(int index)
        {
            if (!string.IsNullOrEmpty(_errorMessage))
            {
                Chart.DrawText("ErrorMsg", _errorMessage, index, 0, Color.Red);
                return;
            }

            if (index < Math.Max(CorrLen, MomLen)) return;

            int compareIndex = _compareBars.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]);
            if (compareIndex < Math.Max(CorrLen, MomLen)) return;

            // 1. Momentum 
            double primaryPast = Bars.ClosePrices[index - MomLen];
            double comparePast = _compareBars.ClosePrices[compareIndex - MomLen];

            if (primaryPast == 0 || comparePast == 0) return; // Prevent division by zero

            double rocPrimary = (Bars.ClosePrices[index] - primaryPast) / primaryPast * 100.0;
            double rocCompare = (_compareBars.ClosePrices[compareIndex] - comparePast) / comparePast * 100.0;

            // 2. Pearson Correlation
            double r = CalculatePearsonCorrelation(index, compareIndex, CorrLen);
            RawCorrelation[index] = r;

            // Wait for EMA to seed properly
            if (index < Math.Max(CorrLen, MomLen) + SmoothLen) return;
            double smoothedR = _emaSmoothing.Result[index];
            SmoothedCorrelation[index] = smoothedR;

            // 3. Determine Regime
            MarketRegime regime = DetermineRegime(smoothedR, rocPrimary, rocCompare);

            // 4. Render Histograms
            BullTheme[index] = regime == MarketRegime.BullishAgreement ? smoothedR : double.NaN;
            BearTheme[index] = regime == MarketRegime.BearishAgreement ? smoothedR : double.NaN;
            DivTheme[index] = regime == MarketRegime.Divergence ? smoothedR : double.NaN;

            // 5. Update HUD on the last tick
            if (IsLastBar)
            {
                UpdateHUD(regime, smoothedR, rocPrimary, rocCompare);
            }
        }

        private double CalculatePearsonCorrelation(int primaryIndex, int compareIndex, int length)
        {
            double sumX = 0, sumY = 0;
            for (int k = 0; k < length; k++)
            {
                sumX += Bars.ClosePrices[primaryIndex - k];
                sumY += _compareBars.ClosePrices[compareIndex - k];
            }
            
            double meanX = sumX / length;
            double meanY = sumY / length;

            double cov = 0, varX = 0, varY = 0;
            for (int k = 0; k < length; k++)
            {
                double dx = Bars.ClosePrices[primaryIndex - k] - meanX;
                double dy = _compareBars.ClosePrices[compareIndex - k] - meanY;
                cov += dx * dy;
                varX += dx * dx;
                varY += dy * dy;
            }

            return (varX > 0 && varY > 0) ? cov / Math.Sqrt(varX * varY) : 0;
        }

        private MarketRegime DetermineRegime(double correlation, double rocPrimary, double rocCompare)
        {
            bool bullishAgreed = rocPrimary > 0 && rocCompare > 0;
            bool bearishAgreed = rocPrimary < 0 && rocCompare < 0;

            if (correlation > HighCorrLevel && bullishAgreed)
                return MarketRegime.BullishAgreement;
            
            if (correlation > HighCorrLevel && bearishAgreed)
                return MarketRegime.BearishAgreement;
            
            if (correlation < LowCorrLevel && (!bullishAgreed && !bearishAgreed))
                return MarketRegime.Divergence;

            return MarketRegime.Neutral;
        }

        private void UpdateHUD(MarketRegime regime, double correlation, double rocPrimary, double rocCompare)
        {
            string hudText = $"Regime: {regime}\n" +
                             $"Corr: {Math.Round(correlation, 2)}\n" +
                             $"{SymbolName} ROC: {Math.Round(rocPrimary, 3)}%\n" +
                             $"{CompareAsset} ROC: {Math.Round(rocCompare, 3)}%";

            Color hudColor = regime switch
            {
                MarketRegime.BullishAgreement => Color.MediumSeaGreen,
                MarketRegime.BearishAgreement => Color.Crimson,
                MarketRegime.Divergence => Color.DimGray,
                _ => Color.DarkGray
            };

            Chart.DrawText("MoodHUD", hudText, Chart.FirstVisibleBarIndex, Chart.TopY, hudColor);
        }
    }
}

Re: AUDUSD commodity mood and short gold scalp hedges discussion

Posted: Sun Sep 27, 2026 9:41 pm
by LondonScalper
Your copper-versus-haven explanation matches what I see most of the time. When AUD fades and gold holds its bid mid-London, it is usually two separate stories that happen to share a morning.

I would put the rule more bluntly than "trade pure microstructure": once they diverge for more than a couple of M5 bars, I stop using one as a filter for the other. Before that point, gold firming is a small plus for an AUD long. After it, the correlation is noise, and AUDUSD gets judged on its own levels and spread.

The trap I fell into years ago was the opposite — reading the divergence as a sign that AUD would "catch up". Sometimes it does, but not on a scalp horizon, and not reliably enough to pay the spread on a cross-asset hunch.

The day-type tag stays in the journal. Over a quarter it shows which mornings AUD trades like a commodity currency and which it trades like a China proxy, and that is more use to me than any hedge ratio.