Re: Rolling Expectancy: Watching Your Edge Over Time
Posted: Tue Oct 06, 2026 12:01 pm
MQL4: Rolling Expectancy Indicator
This script scans your MT4 OrdersHistoryTotal(), filters out deposits/withdrawals, converts the profits to R-Multiples, and plots the rolling average over the specified window.
This script scans your MT4 OrdersHistoryTotal(), filters out deposits/withdrawals, converts the profits to R-Multiples, and plots the rolling average over the specified window.
Code: Select all
//+------------------------------------------------------------------+
//| RollingExpectancy.mq4 |
//| |
//+------------------------------------------------------------------+
#property copyright "Expectancy Monitor"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 clrDodgerBlue
#property indicator_width1 2
//--- Inputs
input int RollingWindow = 50; // Rolling Window (Trades)
input double RiskPerTrade = 100.0; // Assumed Risk per Trade ($)
//--- Buffers
double ExpectancyBuffer[];
//--- Trade Structure to hold history
struct ClosedTrade {
datetime time;
double profit;
};
ClosedTrade tradeHistory[];
int totalTradesCount = 0;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
SetIndexBuffer(0, ExpectancyBuffer);
SetIndexStyle(0, DRAW_LINE);
IndicatorShortName("Rolling Expectancy (" + IntegerToString(RollingWindow) + ")");
// Create a zero line
SetLevelValue(0, 0.0);
SetLevelStyle(STYLE_DASH, 1, clrGray);
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[])
{
// 1. Refresh Trade History Array on first load or when a new trade closes
int currentHistoryTotal = OrdersHistoryTotal();
static int lastHistoryTotal = -1;
if(lastHistoryTotal != currentHistoryTotal)
{
totalTradesCount = 0;
ArrayResize(tradeHistory, currentHistoryTotal);
for(int i = 0; i < currentHistoryTotal; i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
{
// Filter out deposits, withdrawals, and cancelled orders
if(OrderType() <= OP_SELL && OrderSymbol() == Symbol())
{
tradeHistory[totalTradesCount].time = OrderCloseTime();
tradeHistory[totalTradesCount].profit = OrderProfit() + OrderSwap() + OrderCommission();
totalTradesCount++;
}
}
}
ArrayResize(tradeHistory, totalTradesCount);
lastHistoryTotal = currentHistoryTotal;
}
// 2. Map Rolling Expectancy to Chart Bars
int limit = rates_total - prev_calculated;
if(prev_calculated == 0) limit = rates_total - 1;
for(int i = limit; i >= 0; i--)
{
double sumR = 0;
int tradesFound = 0;
// Look back through our trade history array chronologically
for(int t = totalTradesCount - 1; t >= 0; t--)
{
// Find trades that closed before or exactly on this bar's time
if(tradeHistory[t].time <= time[i])
{
double rMultiple = tradeHistory[t].profit / RiskPerTrade;
sumR += rMultiple;
tradesFound++;
if(tradesFound == RollingWindow) break;
}
}
if(tradesFound == RollingWindow)
ExpectancyBuffer[i] = sumR / RollingWindow;
else
ExpectancyBuffer[i] = EMPTY_VALUE; // Not enough trades yet
}
return(rates_total);
}
//+------------------------------------------------------------------+