Page 1 of 1

System Win/Loss Streak Probability Engine

Posted: Thu Aug 06, 2026 10:00 pm
by FTtrader
Good evening scalpers,

today i decided to share with you another of my indicator, which i use time to time:

Instead of guessing random market directions, this indicator uses Markov chain-style probability based on your actual trading system's performance. It scans your closed trades, tallies the historical frequency of consecutive wins and losses, and calculates the statistical probability of your current streak continuing or reversing on the very next trade.

I've structured this with clean, event-driven C-style logic and included your business and trading channel branding in the dashboard UI.

For MT4 in MQL4:

Code: Select all

//+------------------------------------------------------------------+
//|                             SystemStreakProbabilityEngine.mq4    |
//|                                     Created for Pavel Tuček      |
//|                                          aiprofisolutions.com    |
//+------------------------------------------------------------------+
#property copyright "Pavel Tuček | AI Profi Solutions"
#property link      "https://aiprofisolutions.com"
#property version   "1.00"
#property strict
#property indicator_chart_window

//--- Input Parameters
input string   InpSymbolFilter   = "";          // Filter by Symbol (Empty = All)
input int      InpMagicNumber    = 0;           // Filter by Magic Number (0 = All)
input int      InpHistoryDays    = 0;           // History Days to Analyze (0 = All Time)
input color    InpHeaderColor    = clrWhite;    // Header Text Color
input color    InpDataColor      = clrSilver;   // Data Text Color
input int      InpCorner         = 0;           // Dashboard Corner (0=TopLeft)

//--- Global Variables
string prefix = "StreakEngine_";
int totalTrades = 0;
int totalWins = 0;
int totalLosses = 0;
int currentStreak = 0;
bool isWinStreak = false;

int winStreaks[];
int lossStreaks[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   ArrayResize(winStreaks, 100);
   ArrayResize(lossStreaks, 100);
   
   // Initial Calculation
   CalculateStreaks();
   DrawDashboard();
   
   // Set a timer to refresh the dashboard every 10 seconds
   // This avoids heavy CPU usage on every tick
   EventSetTimer(10);
   
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
   ObjectsDeleteAll(0, prefix);
  }

//+------------------------------------------------------------------+
//| 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[])
  {
   // Relies on OnTimer for trade history updates to save CPU
   return(rates_total);
  }

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
   CalculateStreaks();
   DrawDashboard();
  }

//+------------------------------------------------------------------+
//| Core Logic: Calculate Streaks from Account History               |
//+------------------------------------------------------------------+
void CalculateStreaks()
  {
   totalTrades = 0;
   totalWins = 0;
   totalLosses = 0;
   
   ArrayInitialize(winStreaks, 0);
   ArrayInitialize(lossStreaks, 0);
   
   int currentRun = 0;
   bool lastWasWin = false;
   bool firstTrade = true;
   
   currentStreak = 0;
   
   datetime fromTime = 0;
   if(InpHistoryDays > 0)
      fromTime = TimeCurrent() - (InpHistoryDays * 24 * 60 * 60);

   int ordersTotal = OrdersHistoryTotal();
   
   // Read history from oldest to newest
   for(int i = 0; i < ordersTotal; i++)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
        {
         // Skip non-trading operations (deposits, withdrawals, cancelled limits)
         if(OrderType() > OP_SELL) continue; 
         
         // Apply Filters
         if(InpMagicNumber > 0 && OrderMagicNumber() != InpMagicNumber) continue;
         if(StringLen(InpSymbolFilter) > 0 && OrderSymbol() != InpSymbolFilter) continue;
         if(OrderCloseTime() < fromTime) continue;
         
         double profit = OrderProfit() + OrderCommission() + OrderSwap();
         bool isWin = (profit > 0);
         
         totalTrades++;
         if(isWin) totalWins++;
         else totalLosses++;
         
         if(firstTrade)
           {
            lastWasWin = isWin;
            currentRun = 1;
            firstTrade = false;
           }
         else
           {
            if(isWin == lastWasWin)
              {
               currentRun++;
              }
            else
              {
               // Streak broken, record the completed streak
               if(lastWasWin)
                 {
                  if(currentRun < ArraySize(winStreaks)) winStreaks[currentRun]++;
                 }
               else
                 {
                  if(currentRun < ArraySize(lossStreaks)) lossStreaks[currentRun]++;
                 }
               
               // Reset for the new streak direction
               lastWasWin = isWin;
               currentRun = 1;
              }
           }
        }
     }
     
   // Capture the state of the currently active streak
   if(totalTrades > 0)
     {
      currentStreak = currentRun;
      isWinStreak = lastWasWin;
     }
  }

//+------------------------------------------------------------------+
//| Dashboard Rendering                                              |
//+------------------------------------------------------------------+
void DrawDashboard()
  {
   ObjectsDeleteAll(0, prefix); // Clear previous UI
   
   int x = 25;
   int y = 25;
   int yStep = 22;
   
   double winRate = (totalTrades > 0) ? ((double)totalWins / totalTrades) * 100.0 : 0.0;
   
   // UI Headers
   CreateLabel("title", "System Win/Loss Streak Probability Engine", x, y, InpHeaderColor, 12, true); y += yStep * 2;
   
   // Trade Stats
   CreateLabel("stats", StringFormat("Analyzed Trades: %d (W: %d | L: %d)", totalTrades, totalWins, totalLosses), x, y, InpDataColor); y += yStep;
   CreateLabel("winrate", StringFormat("System Win Rate: %.2f%%", winRate), x, y, InpDataColor); y += yStep * 2;
   
   // Current Streak Info
   string streakText = isWinStreak ? "WINS" : "LOSSES";
   color streakColor = isWinStreak ? clrLimeGreen : clrTomato;
   CreateLabel("current", StringFormat("Active Streak: %d %s", currentStreak, streakText), x, y, streakColor, 11, true); y += yStep * 2;
   
   // Probability Math
   double probContinue = 0.0;
   int totalReachedCurrent = 0;
   int totalSurpassedCurrent = 0;
   
   if(isWinStreak && currentStreak > 0)
     {
      for(int i = currentStreak; i < ArraySize(winStreaks); i++)
        {
         totalReachedCurrent += winStreaks[i];
         if(i > currentStreak) totalSurpassedCurrent += winStreaks[i];
        }
     }
   else if(!isWinStreak && currentStreak > 0)
     {
      for(int i = currentStreak; i < ArraySize(lossStreaks); i++)
        {
         totalReachedCurrent += lossStreaks[i];
         if(i > currentStreak) totalSurpassedCurrent += lossStreaks[i];
        }
     }
     
   if(totalReachedCurrent > 0) 
      probContinue = ((double)totalSurpassedCurrent / totalReachedCurrent) * 100.0;
   
   double probReverse = (totalReachedCurrent > 0) ? 100.0 - probContinue : 0.0;
   
   string actionText = isWinStreak ? "LOSS (Reversal)" : "WIN (Reversal)";
   color reverseColor = isWinStreak ? clrTomato : clrLimeGreen;
   
   CreateLabel("prob1", StringFormat("Prob. of extending to %d %s: %.2f%%", currentStreak + 1, streakText, probContinue), x, y, clrGold); y += yStep;
   CreateLabel("prob2", StringFormat("Prob. of next trade being a %s: %.2f%%", actionText, probReverse), x, y, reverseColor, 10, true); y += yStep * 2;
   
   // Footer
   CreateLabel("footer", "Forex, Stocks & Me | AI Profi Solutions", x, y, clrDimGray, 8);
  }

//+------------------------------------------------------------------+
//| Helper: Create Text Label                                        |
//+------------------------------------------------------------------+
void CreateLabel(string nameSuffix, string text, int x, int y, color clr, int size=10, bool bold=false)
  {
   string objName = prefix + nameSuffix;
   if(ObjectFind(0, objName) < 0) ObjectCreate(0, objName, OBJ_LABEL, 0, 0, 0);
   ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, y);
   ObjectSetInteger(0, objName, OBJPROP_CORNER, InpCorner);
   ObjectSetString(0, objName, OBJPROP_TEXT, text);
   ObjectSetString(0, objName, OBJPROP_FONT, bold ? "Arial Bold" : "Arial");
   ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, size);
   ObjectSetInteger(0, objName, OBJPROP_COLOR, clr);
   ObjectSetInteger(0, objName, OBJPROP_BACK, false);
   ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false);
  }
//+------------------------------------------------------------------+

Re: System Win/Loss Streak Probability Engine

Posted: Thu Aug 06, 2026 10:01 pm
by FTtrader
Installation Guide

1.Open the MetaEditor:In your MT4 terminal, press F4 to open the MetaEditor coding environment.

2.Create a new Indicator file:In the Navigator panel on the left, right-click the Indicators folder and select New File. Choose "Custom Indicator", name it StreakProbabilityEngine, and click through to finish.

3.Paste and Compile:Replace all the default template code with the snippet provided above. Press F7 to compile. Ensure there are 0 errors in the terminal at the bottom.

4.Load Account History:Back in the main MT4 terminal, open the Terminal window (Ctrl+T), go to the Account History tab, right-click anywhere inside it, and select All History. (The MQL4 engine can only analyze the history that is actively loaded in this tab).

5.Attach to Chart:Drag the new indicator from the MT4 Navigator onto any chart. You can filter the analysis by a specific Magic Number or Symbol in the indicator input settings.

Re: System Win/Loss Streak Probability Engine

Posted: Thu Aug 06, 2026 10:02 pm
by FTtrader
Here is the completely translated MQL5 version of the System Win/Loss Streak Probability Engine.

MetaTrader 5 handles account history quite differently than MT4—separating Orders, Positions, and Deals. I have rewritten the core engine to specifically filter and analyze Deals that closed a position (DEAL_ENTRY_OUT or DEAL_ENTRY_INOUT), ensuring the mathematical accuracy of your trading history remains perfectly intact in the MT5 environment.

The MQL5 Source Code

Code: Select all

//+------------------------------------------------------------------+
//|                             SystemStreakProbabilityEngine.mq5    |
//|                                     Created for Pavel Tuček      |
//|                                          aiprofisolutions.com    |
//+------------------------------------------------------------------+
#property copyright "Pavel Tuček | AI Profi Solutions"
#property link      "https://aiprofisolutions.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_plots 0

//--- Input Parameters
input string   InpSymbolFilter   = "";          // Filter by Symbol (Empty = All)
input int      InpMagicNumber    = 0;           // Filter by Magic Number (0 = All)
input int      InpHistoryDays    = 0;           // History Days to Analyze (0 = All Time)
input color    InpHeaderColor    = clrWhite;    // Header Text Color
input color    InpDataColor      = clrSilver;   // Data Text Color
input ENUM_BASE_CORNER InpCorner = CORNER_LEFT_UP; // Dashboard Corner

//--- Global Variables
string prefix = "StreakEngine_";
int totalTrades = 0;
int totalWins = 0;
int totalLosses = 0;
int currentStreak = 0;
bool isWinStreak = false;

int winStreaks[];
int lossStreaks[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   ArrayResize(winStreaks, 100);
   ArrayResize(lossStreaks, 100);
   
   // Initial Calculation
   CalculateStreaks();
   DrawDashboard();
   
   // Set a timer to refresh the dashboard every 10 seconds
   EventSetTimer(10);
   
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
   ObjectsDeleteAll(0, prefix);
  }

//+------------------------------------------------------------------+
//| 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[])
  {
   // Relies on OnTimer for trade history updates to save CPU resources
   return(rates_total);
  }

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
   CalculateStreaks();
   DrawDashboard();
  }

//+------------------------------------------------------------------+
//| Core Logic: Calculate Streaks from MT5 Deal History              |
//+------------------------------------------------------------------+
void CalculateStreaks()
  {
   totalTrades = 0;
   totalWins = 0;
   totalLosses = 0;
   
   ArrayInitialize(winStreaks, 0);
   ArrayInitialize(lossStreaks, 0);
   
   int currentRun = 0;
   bool lastWasWin = false;
   bool firstTrade = true;
   
   currentStreak = 0;
   
   datetime fromTime = 0; // 1970.01.01
   if(InpHistoryDays > 0)
      fromTime = TimeCurrent() - (InpHistoryDays * 24 * 60 * 60);

   // Request history for the specified period
   if(!HistorySelect(fromTime, TimeCurrent())) return;

   int dealsTotal = HistoryDealsTotal();
   
   // Read history from oldest to newest deal
   for(int i = 0; i < dealsTotal; i++)
     {
      ulong ticket = HistoryDealGetTicket(i);
      if(ticket > 0)
        {
         // In MT5, only look at deals that CLOSE a position
         long entryType = HistoryDealGetInteger(ticket, DEAL_ENTRY);
         if(entryType != DEAL_ENTRY_OUT && entryType != DEAL_ENTRY_INOUT) continue; 
         
         // Apply Filters
         if(InpMagicNumber > 0 && HistoryDealGetInteger(ticket, DEAL_MAGIC) != InpMagicNumber) continue;
         if(StringLen(InpSymbolFilter) > 0 && HistoryDealGetString(ticket, DEAL_SYMBOL) != InpSymbolFilter) continue;
         
         // Calculate total net profit for the deal
         double profit = HistoryDealGetDouble(ticket, DEAL_PROFIT) + 
                         HistoryDealGetDouble(ticket, DEAL_COMMISSION) + 
                         HistoryDealGetDouble(ticket, DEAL_SWAP) + 
                         HistoryDealGetDouble(ticket, DEAL_FEE);
                         
         bool isWin = (profit > 0);
         
         totalTrades++;
         if(isWin) totalWins++;
         else totalLosses++;
         
         if(firstTrade)
           {
            lastWasWin = isWin;
            currentRun = 1;
            firstTrade = false;
           }
         else
           {
            if(isWin == lastWasWin)
              {
               currentRun++;
              }
            else
              {
               // Streak broken, record the completed streak tally
               if(lastWasWin)
                 {
                  if(currentRun < ArraySize(winStreaks)) winStreaks[currentRun]++;
                 }
               else
                 {
                  if(currentRun < ArraySize(lossStreaks)) lossStreaks[currentRun]++;
                 }
               
               // Reset for the new streak direction
               lastWasWin = isWin;
               currentRun = 1;
              }
           }
        }
     }
     
   // Capture the state of the currently active streak
   if(totalTrades > 0)
     {
      currentStreak = currentRun;
      isWinStreak = lastWasWin;
     }
  }

//+------------------------------------------------------------------+
//| Dashboard Rendering                                              |
//+------------------------------------------------------------------+
void DrawDashboard()
  {
   ObjectsDeleteAll(0, prefix); // Clear previous UI
   
   int x = 25;
   int y = 25;
   int yStep = 22;
   
   double winRate = (totalTrades > 0) ? ((double)totalWins / totalTrades) * 100.0 : 0.0;
   
   // UI Headers
   CreateLabel("title", "System Win/Loss Streak Probability Engine (MT5)", x, y, InpHeaderColor, 12, true); y += yStep * 2;
   
   // Trade Stats
   CreateLabel("stats", StringFormat("Analyzed Deals: %d (W: %d | L: %d)", totalTrades, totalWins, totalLosses), x, y, InpDataColor); y += yStep;
   CreateLabel("winrate", StringFormat("System Win Rate: %.2f%%", winRate), x, y, InpDataColor); y += yStep * 2;
   
   // Current Streak Info
   string streakText = isWinStreak ? "WINS" : "LOSSES";
   color streakColor = isWinStreak ? clrLimeGreen : clrTomato;
   CreateLabel("current", StringFormat("Active Streak: %d %s", currentStreak, streakText), x, y, streakColor, 11, true); y += yStep * 2;
   
   // Probability Math
   double probContinue = 0.0;
   int totalReachedCurrent = 0;
   int totalSurpassedCurrent = 0;
   
   if(isWinStreak && currentStreak > 0)
     {
      for(int i = currentStreak; i < ArraySize(winStreaks); i++)
        {
         totalReachedCurrent += winStreaks[i];
         if(i > currentStreak) totalSurpassedCurrent += winStreaks[i];
        }
     }
   else if(!isWinStreak && currentStreak > 0)
     {
      for(int i = currentStreak; i < ArraySize(lossStreaks); i++)
        {
         totalReachedCurrent += lossStreaks[i];
         if(i > currentStreak) totalSurpassedCurrent += lossStreaks[i];
        }
     }
     
   if(totalReachedCurrent > 0) 
      probContinue = ((double)totalSurpassedCurrent / totalReachedCurrent) * 100.0;
   
   double probReverse = (totalReachedCurrent > 0) ? 100.0 - probContinue : 0.0;
   
   string actionText = isWinStreak ? "LOSS (Reversal)" : "WIN (Reversal)";
   color reverseColor = isWinStreak ? clrTomato : clrLimeGreen;
   
   CreateLabel("prob1", StringFormat("Prob. of extending to %d %s: %.2f%%", currentStreak + 1, streakText, probContinue), x, y, clrGold); y += yStep;
   CreateLabel("prob2", StringFormat("Prob. of next trade being a %s: %.2f%%", actionText, probReverse), x, y, reverseColor, 10, true); y += yStep * 2;
   
   // Footer
   CreateLabel("footer", "Forex, Stocks & Me | AI Profi Solutions", x, y, clrDimGray, 8);
  }

//+------------------------------------------------------------------+
//| Helper: Create Text Label                                        |
//+------------------------------------------------------------------+
void CreateLabel(string nameSuffix, string text, int x, int y, color clr, int size=10, bool bold=false)
  {
   string objName = prefix + nameSuffix;
   if(ObjectFind(0, objName) < 0) 
     {
      ObjectCreate(0, objName, OBJ_LABEL, 0, 0, 0);
     }
   ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, y);
   ObjectSetInteger(0, objName, OBJPROP_CORNER, InpCorner);
   ObjectSetString(0, objName, OBJPROP_TEXT, text);
   ObjectSetString(0, objName, OBJPROP_FONT, bold ? "Arial Bold" : "Arial");
   ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, size);
   ObjectSetInteger(0, objName, OBJPROP_COLOR, clr);
   ObjectSetInteger(0, objName, OBJPROP_BACK, false);
   ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false);
  }
//+------------------------------------------------------------------+

Re: System Win/Loss Streak Probability Engine

Posted: Thu Aug 06, 2026 10:02 pm
by FTtrader
Installation Guide for MT5:

1.Open MetaEditor 5:In your MT5 terminal, press F4 to launch the MetaEditor environment.

2.Create a new Indicator:In the Navigator on the left, right-click the Indicators folder, select New File, choose "Custom Indicator", and name it StreakProbabilityEngine_MT5.

3.Paste and Compile:Highlight and delete the default template code, paste the entire MQL5 code provided above, and press F7 to compile. Ensure there are 0 errors.

4.Attach to Chart:Drag the compiled indicator from the MT5 Navigator onto your chart. You can adjust the anchor corner, filter by magic number, or specify a particular symbol directly in the indicator inputs.

Re: System Win/Loss Streak Probability Engine

Posted: Thu Aug 06, 2026 10:04 pm
by FTtrader
Here is the complete C# source code adapted for IC Trader (cTrader).

Because cTrader runs on a completely different architecture than MetaTrader (using C# and the cAlgo API instead of MQL), there are a few important platform-specific changes:

Labels over Magic Numbers: cTrader uses text Labels to group automated trades rather than integer Magic Numbers, so I've updated the filter parameter accordingly.

Net Profit Calculation: The cTrader History API automatically bundles commissions and swaps into the NetProfit property, which streamlines the math.

WPF-Style UI: cTrader allows for beautiful native UI panels instead of drawing raw text on the chart canvas. I've built the dashboard using a modern StackPanel layout so it renders cleanly.

The cTrader C# Source Code:

Code: Select all

//+------------------------------------------------------------------+
//|                        SystemStreakProbabilityEngine.cs          |
//|                                     Created for Pavel Tuček      |
//|                                          aiprofisolutions.com    |
//+------------------------------------------------------------------+

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

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class StreakProbabilityEngine : Indicator
    {
        [Parameter("Symbol Filter (Empty = All)", DefaultValue = "")]
        public string SymbolFilter { get; set; }

        [Parameter("Label Filter (Empty = All)", DefaultValue = "")]
        public string LabelFilter { get; set; }

        [Parameter("History Days (0 = All Time)", DefaultValue = 0)]
        public int HistoryDays { get; set; }

        // Core calculation variables
        private int[] winStreaks = new int[100];
        private int[] lossStreaks = new int[100];
        private int totalTrades, totalWins, totalLosses, currentStreak;
        private bool isWinStreak;

        // UI Elements
        private StackPanel _mainPanel;
        private TextBlock _titleText;
        private TextBlock _statsText;
        private TextBlock _winRateText;
        private TextBlock _currentStreakText;
        private TextBlock _probContinueText;
        private TextBlock _probReverseText;
        private TextBlock _footerText;

        protected override void Initialize()
        {
            InitializeUI();
            
            // Initial calc
            CalculateStreaks();
            
            // Set a timer to refresh the dashboard every 10 seconds (avoids tick-by-tick lag)
            Timer.Start(TimeSpan.FromSeconds(10));
        }

        protected override void OnTimer()
        {
            CalculateStreaks();
        }

        public override void Calculate(int index)
        {
            // Calculation logic is intentionally handled by OnTimer() to save CPU.
        }

        private void CalculateStreaks()
        {
            totalTrades = 0;
            totalWins = 0;
            totalLosses = 0;
            Array.Clear(winStreaks, 0, winStreaks.Length);
            Array.Clear(lossStreaks, 0, lossStreaks.Length);

            int currentRun = 0;
            bool lastWasWin = false;
            bool firstTrade = true;
            currentStreak = 0;

            DateTime fromTime = DateTime.MinValue;
            if (HistoryDays > 0)
                fromTime = Server.Time.AddDays(-HistoryDays);

            // Fetch and filter historical trades
            var historicalTrades = History.Where(t => t.ClosingTime >= fromTime);

            if (!string.IsNullOrEmpty(SymbolFilter))
                historicalTrades = historicalTrades.Where(t => t.SymbolName == SymbolFilter);

            if (!string.IsNullOrEmpty(LabelFilter))
                historicalTrades = historicalTrades.Where(t => t.Label == LabelFilter);

            // Process oldest to newest
            var sortedTrades = historicalTrades.OrderBy(t => t.ClosingTime).ToList();

            foreach (var trade in sortedTrades)
            {
                // NetProfit includes swap and commissions in cTrader
                bool isWin = trade.NetProfit > 0;

                totalTrades++;
                if (isWin) totalWins++;
                else totalLosses++;

                if (firstTrade)
                {
                    lastWasWin = isWin;
                    currentRun = 1;
                    firstTrade = false;
                }
                else
                {
                    if (isWin == lastWasWin)
                    {
                        currentRun++;
                    }
                    else
                    {
                        // Streak broken
                        if (lastWasWin)
                        {
                            if (currentRun < winStreaks.Length) winStreaks[currentRun]++;
                        }
                        else
                        {
                            if (currentRun < lossStreaks.Length) lossStreaks[currentRun]++;
                        }

                        lastWasWin = isWin;
                        currentRun = 1;
                    }
                }
            }

            if (totalTrades > 0)
            {
                currentStreak = currentRun;
                isWinStreak = lastWasWin;
            }

            UpdateDashboardUI();
        }

        private void InitializeUI()
        {
            _mainPanel = new StackPanel
            {
                Orientation = Orientation.Vertical,
                Margin = new Thickness(25, 25, 0, 0),
                HorizontalAlignment = HorizontalAlignment.Left,
                VerticalAlignment = VerticalAlignment.Top
            };

            _titleText = new TextBlock { Text = "System Win/Loss Streak Probability Engine", Foreground = Color.White, FontSize = 14, FontWeight = FontWeight.Bold, Margin = new Thickness(0, 0, 0, 15) };
            _statsText = new TextBlock { Foreground = Color.Silver, FontSize = 12, Margin = new Thickness(0, 0, 0, 5) };
            _winRateText = new TextBlock { Foreground = Color.Silver, FontSize = 12, Margin = new Thickness(0, 0, 0, 15) };
            _currentStreakText = new TextBlock { FontSize = 13, FontWeight = FontWeight.Bold, Margin = new Thickness(0, 0, 0, 15) };
            _probContinueText = new TextBlock { Foreground = Color.Gold, FontSize = 12, Margin = new Thickness(0, 0, 0, 5) };
            _probReverseText = new TextBlock { FontSize = 13, FontWeight = FontWeight.Bold, Margin = new Thickness(0, 0, 0, 15) };
            _footerText = new TextBlock { Text = "Forex, Stocks & Me | AI Profi Solutions", Foreground = Color.Gray, FontSize = 10 };

            _mainPanel.AddChild(_titleText);
            _mainPanel.AddChild(_statsText);
            _mainPanel.AddChild(_winRateText);
            _mainPanel.AddChild(_currentStreakText);
            _mainPanel.AddChild(_probContinueText);
            _mainPanel.AddChild(_probReverseText);
            _mainPanel.AddChild(_footerText);

            Chart.AddControl(_mainPanel);
        }

        private void UpdateDashboardUI()
        {
            double winRate = totalTrades > 0 ? ((double)totalWins / totalTrades) * 100.0 : 0.0;
            string streakText = isWinStreak ? "WINS" : "LOSSES";
            string actionText = isWinStreak ? "LOSS (Reversal)" : "WIN (Reversal)";
            
            Color streakColor = isWinStreak ? Color.LimeGreen : Color.Red;
            Color reverseColor = isWinStreak ? Color.Red : Color.LimeGreen;

            double probContinue = 0.0;
            int totalReachedCurrent = 0;
            int totalSurpassedCurrent = 0;

            if (isWinStreak && currentStreak > 0)
            {
                for (int i = currentStreak; i < winStreaks.Length; i++)
                {
                    totalReachedCurrent += winStreaks[i];
                    if (i > currentStreak) totalSurpassedCurrent += winStreaks[i];
                }
            }
            else if (!isWinStreak && currentStreak > 0)
            {
                for (int i = currentStreak; i < lossStreaks.Length; i++)
                {
                    totalReachedCurrent += lossStreaks[i];
                    if (i > currentStreak) totalSurpassedCurrent += lossStreaks[i];
                }
            }

            if (totalReachedCurrent > 0)
                probContinue = ((double)totalSurpassedCurrent / totalReachedCurrent) * 100.0;

            double probReverse = totalReachedCurrent > 0 ? 100.0 - probContinue : 0.0;

            // Apply text and colors
            _statsText.Text = $"Analyzed Trades: {totalTrades} (W: {totalWins} | L: {totalLosses})";
            _winRateText.Text = $"System Win Rate: {winRate:F2}%";
            
            _currentStreakText.Text = $"Active Streak: {currentStreak} {streakText}";
            _currentStreakText.Foreground = streakColor;

            _probContinueText.Text = $"Prob. of extending to {currentStreak + 1} {streakText}: {probContinue:F2}%";
            
            _probReverseText.Text = $"Prob. of next trade being a {actionText}: {probReverse:F2}%";
            _probReverseText.Foreground = reverseColor;
        }
    }
}

Re: System Win/Loss Streak Probability Engine

Posted: Thu Aug 06, 2026 10:05 pm
by FTtrader
Installation Guide for cTrader

1.Open cTrader Automate:In your cTrader platform, look at the left sidebar and click on the Automate tab (the icon looks like a gear or robot).

2.Create a New Indicator:At the top of the Automate panel, click the dropdown menu for Indicators, then click New Indicator. Name it StreakProbabilityEngine.

3.Paste and Build:Delete all the default code in the code editor window that appears, and paste the entire C# block provided above.

4.Compile the Code:Click the Build button at the top of the code editor (or press Ctrl+B). Look at the "Build Result" window at the bottom to ensure it says "Build Succeeded".5.Attach to Chart:Go back to the Trade tab (your standard charts), right-click on any chart, select Indicators -> Custom -> StreakProbabilityEngine.

I hope you will like it.
Take a care and have a nice night :-)

Have a great trades.