Advertisement IC Markets

Correlation caps for prop candidates: weekly audit

Discuss 1-minute to 15-minute price action setups, fading intraday momentum, key support/resistance zones, and proven short-term trading methodologies.
Post Reply
LondonScalper
Posts: 701
Joined: Sat Sep 05, 2026 7:54 am

Correlation caps for prop candidates: weekly audit

Post by LondonScalper »

Correlation caps for prop candidates: weekly audit

Prop dashboards care about daily loss. Your book can still be secretly concentrated: EURUSD + GBPUSD + gold all expressing the same dollar impulse in one London hour. One ugly print then looks like three unrelated stops and a consistency mess.

Weekly audit I run on challenge weeks:
  • List open-risk themes, not just pairs — dollar, yields, risk-on/off.
  • Cap simultaneous exposure to one theme — for me, two correlated names max during London.
  • If I already took a full stop in that theme, the second pair is blocked for a cooldown window.
Consistency rules punish clusters. Correlation caps are how you stop manufacturing clusters by accident while telling yourself you are “diversified across pairs.” Gut feel pair-by-pair is how the cluster sneaks in.

Do you run any formal correlation cap on prop, or is it still gut feel until the daily loss light blinks?

On review day I literally write the theme names on paper before I open the platform the following Monday. If the paper already shows two dollar-expression tickets planned, the third correlated name is blocked before FOMO invents a reason.
Recommended broker for automated trading & scalping IC Markets
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Correlation caps for prop candidates: weekly audit

Post by PTScalper »

LondonScalper wrote: Sat Sep 19, 2026 7:00 pm Correlation caps for prop candidates: weekly audit

Prop dashboards care about daily loss. Your book can still be secretly concentrated: EURUSD + GBPUSD + gold all expressing the same dollar impulse in one London hour. One ugly print then looks like three unrelated stops and a consistency mess.

Weekly audit I run on challenge weeks:
  • List open-risk themes, not just pairs — dollar, yields, risk-on/off.
  • Cap simultaneous exposure to one theme — for me, two correlated names max during London.
  • If I already took a full stop in that theme, the second pair is blocked for a cooldown window.
Consistency rules punish clusters. Correlation caps are how you stop manufacturing clusters by accident while telling yourself you are “diversified across pairs.” Gut feel pair-by-pair is how the cluster sneaks in.

Do you run any formal correlation cap on prop, or is it still gut feel until the daily loss light blinks?

On review day I literally write the theme names on paper before I open the platform the following Monday. If the paper already shows two dollar-expression tickets planned, the third correlated name is blocked before FOMO invents a reason.
Hi LondonScalper,

Trading EURUSD, GBPUSD, and Gold at the same time isn't diversification; it's just taking out a massive, highly leveraged position on the US Dollar. If a news catalyst or sudden liquidity sweep hits, that "ugly print" will wipe out three trades in a millisecond, and the prop firm's daily drawdown rule won't care that they were technically different tickers.

Since my methodology relies almost entirely on raw price action and liquidity sweeps mapped on D1 and M15 charts, correlated pairs tend to print identical structural setups at the exact same time. It’s incredibly easy for FOMO to trick you into taking all of them. To combat this, I treat the market in themes (USD strength, Risk-On/Off, Euro weakness) rather than individual pairs.

To take the "gut feel" completely out of the equation during a live session, I don't rely on paper alone. I wrote a risk-management overlay in Pine Script that sits on my chart. It calculates real-time correlation against major thematic pairs. If I'm looking at a GBPUSD short but the dashboard is flashing red because it's 90% correlated to a EURUSD trade I'm already in, I know it's a blocked trade.

Here is the Pine Script I use to enforce this mathematically.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Correlation caps for prop candidates: weekly audit

Post by PTScalper »

Correlation Risk Dashboard (Pine Script v5)

This script creates a lightweight, non-lagging dashboard on your chart. You input your currently open trades (or watched themes), and it calculates the Pearson correlation coefficient over your chosen lookback period. If the current chart's price action is too highly correlated (positively or inversely) to your defined themes, the panel highlights it in red to warn you against stacking exposure.

Code: Select all

//@version=5
indicator("Correlation Risk Dashboard - Theme Cap", overlay=true)

// =========================================================================
// INPUTS
// =========================================================================
grp1 = "Theme Symbols (e.g., Existing Open Trades)"
sym1 = input.symbol("EURUSD", "Exposure 1", group=grp1)
sym2 = input.symbol("XAUUSD", "Exposure 2", group=grp1)
sym3 = input.symbol("GBPUSD", "Exposure 3", group=grp1)

grp2 = "Risk Parameters"
corrLength = input.int(20, "Correlation Lookback (Bars)", minval=5, group=grp2)
warnThreshold = input.float(0.75, "Correlation Warning Threshold", minval=0.0, maxval=1.0, step=0.05, group=grp2)

// =========================================================================
// DATA REQUESTS
// =========================================================================
// Fetching the close prices for the defined symbols on the current timeframe
src1 = request.security(sym1, timeframe.period, close)
src2 = request.security(sym2, timeframe.period, close)
src3 = request.security(sym3, timeframe.period, close)

// =========================================================================
// CALCULATIONS
// =========================================================================
// ta.correlation compares the current chart's close to the requested symbols
corr1 = ta.correlation(close, src1, corrLength)
corr2 = ta.correlation(close, src2, corrLength)
corr3 = ta.correlation(close, src3, corrLength)

// =========================================================================
// DASHBOARD RENDERING
// =========================================================================
var table riskPanel = table.new(position.bottom_right, 2, 4, border_width=1, border_color=color.new(color.gray, 50))

if barstate.islast
    // Header
    table.cell(riskPanel, 0, 0, "Theme / Pair", bgcolor=color.new(color.black, 20), text_color=color.white, text_size=size.small)
    table.cell(riskPanel, 1, 0, "Correlation", bgcolor=color.new(color.black, 20), text_color=color.white, text_size=size.small)
    
    // Evaluate and color code Symbol 1
    absCorr1 = math.abs(corr1)
    color1 = absCorr1 >= warnThreshold ? color.new(color.red, 60) : color.new(color.green, 60)
    table.cell(riskPanel, 0, 1, sym1, bgcolor=color1, text_color=color.white, text_size=size.small)
    table.cell(riskPanel, 1, 1, str.tostring(corr1, "#.##"), bgcolor=color1, text_color=color.white, text_size=size.small)
    
    // Evaluate and color code Symbol 2
    absCorr2 = math.abs(corr2)
    color2 = absCorr2 >= warnThreshold ? color.new(color.red, 60) : color.new(color.green, 60)
    table.cell(riskPanel, 0, 2, sym2, bgcolor=color2, text_color=color.white, text_size=size.small)
    table.cell(riskPanel, 1, 2, str.tostring(corr2, "#.##"), bgcolor=color2, text_color=color.white, text_size=size.small)
    
    // Evaluate and color code Symbol 3
    absCorr3 = math.abs(corr3)
    color3 = absCorr3 >= warnThreshold ? color.new(color.red, 60) : color.new(color.green, 60)
    table.cell(riskPanel, 0, 3, sym3, bgcolor=color3, text_color=color.white, text_size=size.small)
    table.cell(riskPanel, 1, 3, str.tostring(corr3, "#.##"), bgcolor=color3, text_color=color.white, text_size=size.small)
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Correlation caps for prop candidates: weekly audit

Post by PTScalper »

If you apply this directly to an M15 chart while scanning for setups, the table in the bottom right acts as a hard stop. If the table is glowing red against a pair you already have open, you skip the trade, wait for the cooldown window, and protect your prop drawdown.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Correlation caps for prop candidates: weekly audit

Post by PTScalper »

MetaTrader 5 (MQL5) Implementation

Because MQL5 uses array copies rather than direct time-series access, the calculation explicitly pulls the last N closing prices into arrays using CopyClose before running the Pearson formula. It also utilizes a 1-second timer (EventSetTimer(1)) so the dashboard updates live even when the symbol you are currently watching isn't ticking.

Code: Select all

//+------------------------------------------------------------------+
//| Correlation Risk Dashboard - Theme Cap (MT5)                     |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_plots 0

input string   InpSymbol1     = "EURUSD";      // Exposure 1
input string   InpSymbol2     = "XAUUSD";      // Exposure 2
input string   InpSymbol3     = "GBPUSD";      // Exposure 3
input int      InpCorrLength  = 20;            // Correlation Lookback
input double   InpWarnThresh  = 0.75;          // Warning Threshold

int OnInit() {
    EventSetTimer(1);
    return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason) {
    ObjectsDeleteAll(0, "CorrDash_");
    EventKillTimer();
}

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[]) {
    UpdateDashboard();
    return(rates_total);
}

void OnTimer() {
    UpdateDashboard();
}

double CalculateCorrelation(string symMain, string symTarget, int lookback) {
    if(symMain == symTarget) return 1.0;
    
    double arrMain[], arrTarget[];
    ArraySetAsSeries(arrMain, true);
    ArraySetAsSeries(arrTarget, true);
    
    // Ensure both symbols have enough history loaded
    if(CopyClose(symMain, PERIOD_CURRENT, 0, lookback, arrMain) < lookback) return 0.0;
    if(CopyClose(symTarget, PERIOD_CURRENT, 0, lookback, arrTarget) < lookback) return 0.0;
    
    double sumX = 0, sumY = 0;
    for(int i = 0; i < lookback; i++) {
        sumX += arrMain[i];
        sumY += arrTarget[i];
    }
    
    double meanX = sumX / lookback;
    double meanY = sumY / lookback;
    
    double sumXY = 0, sumX2 = 0, sumY2 = 0;
    for(int i = 0; i < lookback; i++) {
        double devX = arrMain[i] - meanX;
        double devY = arrTarget[i] - meanY;
        sumXY += devX * devY;
        sumX2 += devX * devX;
        sumY2 += devY * devY;
    }
    
    if(sumX2 * sumY2 == 0) return 0.0;
    return sumXY / MathSqrt(sumX2 * sumY2);
}

void DrawPanel(string name, int x, int y, int w, int h) {
    if(ObjectFind(0, name) < 0) {
        ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0);
        ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
        ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
        ObjectSetInteger(0, name, OBJPROP_BGCOLOR, clrBlack);
        ObjectSetInteger(0, name, OBJPROP_BORDER_COLOR, clrGray);
        ObjectSetInteger(0, name, OBJPROP_BACK, true);
        ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
        ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
    }
    ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
    ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
    ObjectSetInteger(0, name, OBJPROP_XSIZE, w);
    ObjectSetInteger(0, name, OBJPROP_YSIZE, h);
}

void DrawCell(string name, string text, int x, int y, color clr) {
    if(ObjectFind(0, name) < 0) {
        ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
        ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
        ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
        ObjectSetString(0, name, OBJPROP_FONT, "Arial");
        ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 9);
    }
    ObjectSetString(0, name, OBJPROP_TEXT, text);
    ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
    ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
    ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
    ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
    ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
}

void UpdateDashboard() {
    double corr1 = CalculateCorrelation(_Symbol, InpSymbol1, InpCorrLength);
    double corr2 = CalculateCorrelation(_Symbol, InpSymbol2, InpCorrLength);
    double corr3 = CalculateCorrelation(_Symbol, InpSymbol3, InpCorrLength);
    
    color c1 = (MathAbs(corr1) >= InpWarnThresh) ? clrRed : clrLimeGreen;
    color c2 = (MathAbs(corr2) >= InpWarnThresh) ? clrRed : clrLimeGreen;
    color c3 = (MathAbs(corr3) >= InpWarnThresh) ? clrRed : clrLimeGreen;
    
    DrawPanel("CorrDash_BG", 10, 10, 160, 90);
    
    int xSym = 90; 
    int xVal = 20; 
    
    DrawCell("CorrDash_Hdr_Sym", "Theme", xSym, 80, clrSilver);
    DrawCell("CorrDash_Hdr_Val", "Corr", xVal, 80, clrSilver);
    
    DrawCell("CorrDash_S1_Sym", InpSymbol1, xSym, 60, c1);
    DrawCell("CorrDash_S1_Val", DoubleToString(corr1, 2), xVal, 60, c1);
    
    DrawCell("CorrDash_S2_Sym", InpSymbol2, xSym, 40, c2);
    DrawCell("CorrDash_S2_Val", DoubleToString(corr2, 2), xVal, 40, c2);
    
    DrawCell("CorrDash_S3_Sym", InpSymbol3, xSym, 20, c3);
    DrawCell("CorrDash_S3_Val", DoubleToString(corr3, 2), xVal, 20, c3);
    
    ChartRedraw();
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Correlation caps for prop candidates: weekly audit

Post by PTScalper »

MetaTrader 4 (MQL4) Implementation

This port leverages iClose to request time-series data directly. It employs manual object deletion loops in the OnDeinit phase to ensure backwards compatibility across all MT4 builds if switching charts rapidly.

Code: Select all

//+------------------------------------------------------------------+
//| Correlation Risk Dashboard - Theme Cap (MT4)                     |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property strict

input string   InpSymbol1     = "EURUSD";      // Exposure 1
input string   InpSymbol2     = "XAUUSD";      // Exposure 2
input string   InpSymbol3     = "GBPUSD";      // Exposure 3
input int      InpCorrLength  = 20;            // Correlation Lookback
input double   InpWarnThresh  = 0.75;          // Warning Threshold

int OnInit() {
    EventSetTimer(1);
    return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason) {
    // Fallback object deletion to ensure clean charts in MT4
    for(int i = ObjectsTotal() - 1; i >= 0; i--) {
        string name = ObjectName(i);
        if(StringFind(name, "CorrDash_") == 0) {
            ObjectDelete(name);
        }
    }
    EventKillTimer();
}

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[]) {
    UpdateDashboard();
    return(rates_total);
}

void OnTimer() {
    UpdateDashboard();
}

double CalculateCorrelation(string symMain, string symTarget, int lookback) {
    if(symMain == symTarget) return 1.0;
    
    double sumX = 0, sumY = 0;
    for(int i = 0; i < lookback; i++) {
        double cX = iClose(symMain, Period(), i);
        double cY = iClose(symTarget, Period(), i);
        // Abort calculation if history for target pair is not fully synchronized yet
        if(cX == 0 || cY == 0) return 0.0; 
        
        sumX += cX;
        sumY += cY;
    }
    
    double meanX = sumX / lookback;
    double meanY = sumY / lookback;
    
    double sumXY = 0, sumX2 = 0, sumY2 = 0;
    for(int i = 0; i < lookback; i++) {
        double devX = iClose(symMain, Period(), i) - meanX;
        double devY = iClose(symTarget, Period(), i) - meanY;
        sumXY += devX * devY;
        sumX2 += devX * devX;
        sumY2 += devY * devY;
    }
    
    if(sumX2 * sumY2 == 0) return 0.0;
    return sumXY / MathSqrt(sumX2 * sumY2);
}

void DrawPanel(string name, int x, int y, int w, int h) {
    if(ObjectFind(name) < 0) {
        ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0);
        ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
        ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
        ObjectSetInteger(0, name, OBJPROP_BGCOLOR, clrBlack);
        ObjectSetInteger(0, name, OBJPROP_BORDER_COLOR, clrGray);
        ObjectSetInteger(0, name, OBJPROP_BACK, true);
        ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
        ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
    }
    ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
    ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
    ObjectSetInteger(0, name, OBJPROP_XSIZE, w);
    ObjectSetInteger(0, name, OBJPROP_YSIZE, h);
}

void DrawCell(string name, string text, int x, int y, color clr) {
    if(ObjectFind(name) < 0) {
        ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
        ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
        ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
        ObjectSetString(0, name, OBJPROP_FONT, "Arial");
        ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 9);
    }
    ObjectSetString(0, name, OBJPROP_TEXT, text);
    ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
    ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
    ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
    ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
    ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
}

void UpdateDashboard() {
    double corr1 = CalculateCorrelation(Symbol(), InpSymbol1, InpCorrLength);
    double corr2 = CalculateCorrelation(Symbol(), InpSymbol2, InpCorrLength);
    double corr3 = CalculateCorrelation(Symbol(), InpSymbol3, InpCorrLength);
    
    color c1 = (MathAbs(corr1) >= InpWarnThresh) ? clrRed : clrLimeGreen;
    color c2 = (MathAbs(corr2) >= InpWarnThresh) ? clrRed : clrLimeGreen;
    color c3 = (MathAbs(corr3) >= InpWarnThresh) ? clrRed : clrLimeGreen;
    
    DrawPanel("CorrDash_BG", 10, 10, 160, 90);
    
    int xSym = 90; 
    int xVal = 20; 
    
    DrawCell("CorrDash_Hdr_Sym", "Theme", xSym, 80, clrSilver);
    DrawCell("CorrDash_Hdr_Val", "Corr", xVal, 80, clrSilver);
    
    DrawCell("CorrDash_S1_Sym", InpSymbol1, xSym, 60, c1);
    DrawCell("CorrDash_S1_Val", DoubleToString(corr1, 2), xVal, 60, c1);
    
    DrawCell("CorrDash_S2_Sym", InpSymbol2, xSym, 40, c2);
    DrawCell("CorrDash_S2_Val", DoubleToString(corr2, 2), xVal, 40, c2);
    
    DrawCell("CorrDash_S3_Sym", InpSymbol3, xSym, 20, c3);
    DrawCell("CorrDash_S3_Val", DoubleToString(corr3, 2), xVal, 20, c3);
    
    ChartRedraw();
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Correlation caps for prop candidates: weekly audit

Post by PTScalper »

Let's build a cTrader (cAlgo) custom indicator.

Requirements:

1.) Inputs for 3 theme symbols.

2.) Inputs for Correlation Lookback (Bars) and Warning Threshold.

3.) Access historical data for these 3 symbols on the current timeframe.
In cTrader, we can use MarketData.GetBars(TimeFrame, symbol_name).

4.) Calculate Pearson correlation.
We can calculate this manually over the lookback or use built-in functions. Wait, there's no built-in PearsonCorrelation indicator in basic cAlgo, but we can write a simple method.

5.) Display a dashboard panel on the chart.
cTrader has an excellent GUI API (Controls, ChartPanel, StackPanel, TextBlock, etc.).
We can use Canvas, Grid, or StackPanel placed on the chart via IndicatorArea.AddControl() or Chart.AddControl().
Let's create a nice custom control table using a Grid or nested StackPanels.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: Correlation caps for prop candidates: weekly audit

Post by PTScalper »

Let's write the C# code for the cTrader custom indicator.

Code: Select all

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

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class CorrelationRiskDashboard : Indicator
    {
        [Parameter("Theme 1 Symbol", DefaultValue = "EURUSD", Group = "Themes")]
        public string Symbol1 { get; set; }

        [Parameter("Theme 2 Symbol", DefaultValue = "XAUUSD", Group = "Themes")]
        public string Symbol2 { get; set; }

        [Parameter("Theme 3 Symbol", DefaultValue = "GBPUSD", Group = "Themes")]
        public string Symbol3 { get; set; }

        [Parameter("Correlation Lookback", DefaultValue = 20, MinValue = 5, Group = "Risk Parameters")]
        public int Lookback { get; set; }

        [Parameter("Warning Threshold", DefaultValue = 0.75, MinValue = 0.0, MaxValue = 1.0, Group = "Risk Parameters")]
        public double WarningThreshold { get; set; }

        private Bars _bars1;
        private Bars _bars2;
        private Bars _bars3;

        private Grid _dashboardGrid;
        private TextBlock _tbSym1, _tbVal1;
        private TextBlock _tbSym2, _tbVal2;
        private TextBlock _tbSym3, _tbVal3;

        protected override void Initialize()
        {
            // Request the bars for the specified symbols on the current timeframe
            _bars1 = MarketData.GetBars(TimeFrame, Symbol1);
            _bars2 = MarketData.GetBars(TimeFrame, Symbol2);
            _bars3 = MarketData.GetBars(TimeFrame, Symbol3);

            DrawDashboard();
        }

        public override void Calculate(int index)
        {
            // Sync current chart index with the external symbol series
            UpdateCorrelationDisplay(index, _bars1, Symbol1, _tbSym1, _tbVal1);
            UpdateCorrelationDisplay(index, _bars2, Symbol2, _tbSym2, _tbVal2);
            UpdateCorrelationDisplay(index, _bars3, Symbol3, _tbSym3, _tbVal3);
        }

        private void UpdateCorrelationDisplay(int index, Bars targetBars, string symName, TextBlock tbSym, TextBlock tbVal)
        {
            if (targetBars.Count < Lookback || Bars.Count < Lookback)
                return;

            // Get current time of the bar being evaluated
            DateTime currentTime = Bars.OpenTimes[index];
            int targetIndex = targetBars.OpenTimes.GetIndexByTime(currentTime);

            // If we don't have a matching time or enough history, skip
            if (targetIndex < Lookback - 1)
                return;

            double correlation = CalculatePearsonCorrelation(index, targetIndex, targetBars);

            // Format UI
            tbVal.Text = Math.Round(correlation, 2).ToString("0.00");
            
            var color = Math.Abs(correlation) >= WarningThreshold ? Color.Red : Color.LimeGreen;
            tbSym.ForegroundColor = color;
            tbVal.ForegroundColor = color;
        }

        private double CalculatePearsonCorrelation(int mainIndex, int targetIndex, Bars targetBars)
        {
            double sumX = 0, sumY = 0;
            
            for (int i = 0; i < Lookback; i++)
            {
                sumX += Bars.ClosePrices[mainIndex - i];
                sumY += targetBars.ClosePrices[targetIndex - i];
            }

            double meanX = sumX / Lookback;
            double meanY = sumY / Lookback;

            double sumXY = 0, sumX2 = 0, sumY2 = 0;
            
            for (int i = 0; i < Lookback; i++)
            {
                double devX = Bars.ClosePrices[mainIndex - i] - meanX;
                double devY = targetBars.ClosePrices[targetIndex - i] - meanY;
                
                sumXY += devX * devY;
                sumX2 += devX * devX;
                sumY2 += devY * devY;
            }

            if (sumX2 * sumY2 == 0)
                return 0;

            return sumXY / Math.Sqrt(sumX2 * sumY2);
        }

        private void DrawDashboard()
        {
            // Create the main Grid layout
            _dashboardGrid = new Grid(4, 2)
            {
                BackgroundColor = Color.FromArgb(200, 20, 20, 20),
                HorizontalAlignment = HorizontalAlignment.Right,
                VerticalAlignment = VerticalAlignment.Bottom,
                Margin = new Thickness(0, 0, 10, 10),
                ShowGridLines = true
            };

            // Header
            _dashboardGrid.AddChild(new TextBlock { Text = "Theme", Margin = 5, ForegroundColor = Color.Silver, FontWeight = FontWeight.Bold }, 0, 0);
            _dashboardGrid.AddChild(new TextBlock { Text = "Corr", Margin = 5, ForegroundColor = Color.Silver, FontWeight = FontWeight.Bold }, 0, 1);

            // Row 1
            _tbSym1 = new TextBlock { Text = Symbol1, Margin = 5 };
            _tbVal1 = new TextBlock { Text = "0.00", Margin = 5 };
            _dashboardGrid.AddChild(_tbSym1, 1, 0);
            _dashboardGrid.AddChild(_tbVal1, 1, 1);

            // Row 2
            _tbSym2 = new TextBlock { Text = Symbol2, Margin = 5 };
            _tbVal2 = new TextBlock { Text = "0.00", Margin = 5 };
            _dashboardGrid.AddChild(_tbSym2, 2, 0);
            _dashboardGrid.AddChild(_tbVal2, 2, 1);

            // Row 3
            _tbSym3 = new TextBlock { Text = Symbol3, Margin = 5 };
            _tbVal3 = new TextBlock { Text = "0.00", Margin = 5 };
            _dashboardGrid.AddChild(_tbSym3, 3, 0);
            _dashboardGrid.AddChild(_tbVal3, 3, 1);

            Chart.AddControl(_dashboardGrid);
        }
    }
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
LondonScalper
Posts: 701
Joined: Sat Sep 05, 2026 7:54 am

Re: Correlation caps for prop candidates: weekly audit

Post by LondonScalper »

PTScalper wrote:Trading EURUSD, GBPUSD, and Gold at the same time isn't diversification; it's a massive leveraged position on the US Dollar. I treat the market in themes rather than individual pairs, and I use a real-time correlation overlay so a 90% linked second ticket is blocked before FOMO fills it.
Agreed — three "different" tickers expressing one dollar impulse is how a single ugly print becomes a consistency mess on a prop dashboard. Theme thinking (USD strength, risk-on/off, euro weakness) is the right unit of risk. Your live overlay removing gut feel mid-session is stronger than my paper weekly audit alone; the audit still catches the pattern after the fact, but the block needs to happen before the second click.

Desk rule I keep even without scripts: one theme, one risk unit — a second pair in the same theme only replaces, never stacks, while the first is open. If EURUSD is already expressing USD strength, GBPUSD and gold wait or I flatten and switch. The firm's daily loss does not care that the stops had different symbols.

When your overlay flashes a high correlation mid-trade, do you force a flatten of the weaker ticket, or only refuse new adds and let the first runner work alone?
Post Reply