Weighted Average of Standard Deviations
Master the advanced statistical technique to improve risk assessment across different market conditions and trading systems.
Improved Accuracy
Weight volatility by trade count for truer risk estimates
Multi-System Comparison
Fairly compare EAs with different trade frequencies
Smarter Risk Models
Build position sizing based on reliable volatility data
Core Formula
Where nᵢ = trades in period i and σᵢ = standard deviation in period i
What Is the Weighted Average of Standard Deviations?
When evaluating Forex Expert Advisors (EAs), a simple average of standard deviations across multiple periods or systems can be dangerously misleading. If one period contains far more trades than another, treating both equally distorts your overall volatility estimate. The Weighted Average of Standard Deviations (also called the pooled standard deviation) solves this by weighting each period's volatility contribution according to its sample size—giving you a far more accurate picture of true risk.
Why a Simple Average Fails
Suppose your EA produced trades across two distinct market regimes. In a quiet consolidation period you recorded 20 trades with a standard deviation of 15 pips. In a high-volatility trending period you recorded 200 trades with a standard deviation of 80 pips. A naive average gives σ = (15 + 80) / 2 = 47.5 pips. But that number is dominated by the small, unrepresentative quiet period—your real risk exposure is far closer to 80 pips because the vast majority of your trade history lived there.
Key insight: Standard deviations should be weighted by the number of observations (trades) they are based on, not treated as equals regardless of sample size.
The Pooled Standard Deviation Formula:
Step-by-Step Worked Example
Let's walk through the calculation with three distinct market periods to see exactly how the weighting changes the result.
| Period | Trades (nᵢ) | Std Dev σᵢ (pips) | nᵢ · σᵢ² |
|---|---|---|---|
| Low volatility | 20 | 15 | 20 × 225 = 4,500 |
| Medium volatility | 80 | 45 | 80 × 2,025 = 162,000 |
| High volatility | 200 | 80 | 200 × 6,400 = 1,280,000 |
| Totals | 300 | Simple avg: 46.7 pips | 1,446,500 |
Calculating σw:
5 Practical Applications for EA Traders
1. Comparing EAs with Different Trade Frequencies
A scalping EA with 500 trades and a swing EA with 40 trades cannot be compared on simple standard deviations alone. The weighted pooled approach gives you a common, fairly scaled volatility figure regardless of trade count differences.
2. Robust Position Sizing Across Regimes
Many traders use standard deviation to set stop-loss distances or lot sizes. Using a simple average underestimates risk in high-trade-count, high-volatility regimes. The weighted standard deviation provides the correct denominator for volatility-adjusted position sizing.
Example: A risk-of-ruin model using σ = 46.7 pips would over-leverage the account. Using σw = 69.4 pips leads to appropriately reduced lot sizes and a more conservative, realistic equity curve.
3. Backtesting Across Multiple Currency Pairs
When your EA runs on EURUSD, GBPUSD, and USDJPY simultaneously, each pair contributes a different number of trades and a different volatility profile. The weighted average of standard deviations gives you a portfolio-level σ that accurately represents blended risk.
4. Walk-Forward Analysis Aggregation
Walk-forward testing splits your history into multiple out-of-sample windows. Each window will have a different number of trades. Weighting the standard deviations from each window ensures that longer, more representative windows dominate the overall risk estimate when you aggregate results.
5. Detecting Volatility Regime Changes
By splitting your history into rolling windows and tracking σw over time, you can detect when market conditions are shifting. A rising weighted standard deviation signals increasing risk before your equity curve or drawdown metrics catch it.
Example: If σw across your last three rolling windows reads 42 → 51 → 68 pips, this upward trend is an early warning to reduce lot sizes before a large drawdown materialises.
MQL5 Implementation
Here's how to calculate the weighted standard deviation across multiple defined periods directly inside MetaTrader 5:
struct PeriodStats
{
int trades; // sample size for this period
double stdDev; // standard deviation of returns
};
double WeightedStdDev(PeriodStats &periods[], int count)
{
double sumWeightedVariance = 0.0;
int totalTrades = 0;
for(int i = 0; i < count; i++)
{
sumWeightedVariance += (double)periods[i].trades
* MathPow(periods[i].stdDev, 2);
totalTrades += periods[i].trades;
}
if(totalTrades == 0) return 0.0;
return MathSqrt(sumWeightedVariance / totalTrades);
}
void OnStart()
{
// Define three market regime periods
PeriodStats periods[3];
periods[0].trades = 20; periods[0].stdDev = 15.0; // Low vol
periods[1].trades = 80; periods[1].stdDev = 45.0; // Medium vol
periods[2].trades = 200; periods[2].stdDev = 80.0; // High vol
double simpleAvg = (15.0 + 45.0 + 80.0) / 3.0;
double weightedSD = WeightedStdDev(periods, 3);
Print("Simple average σ : ", DoubleToString(simpleAvg, 2), " pips");
Print("Weighted σ (σ_w) : ", DoubleToString(weightedSD, 2), " pips");
Print("Difference : ", DoubleToString(weightedSD - simpleAvg, 2), " pips");
// Interpret risk level
string riskLabel = "";
if(weightedSD < 30) riskLabel = "Low volatility — normal sizing";
else if(weightedSD < 60) riskLabel = "Moderate volatility — consider reduced sizing";
else if(weightedSD < 90) riskLabel = "High volatility — reduce lot size significantly";
else riskLabel = "Extreme volatility — minimal sizing or pause trading";
Print("Risk assessment: ", riskLabel);
}
Interpreting Your Weighted Standard Deviation
| σw Range (pips) | Volatility Regime | Position Sizing Action |
|---|---|---|
| σw < 30 | Low volatility | Standard lot sizing |
| 30 ≤ σw < 60 | Moderate volatility | Consider 10–25% reduction |
| 60 ≤ σw < 90 | High volatility | Reduce sizing 25–50% |
| σw ≥ 90 | Extreme volatility | Minimal sizing or pause |
These thresholds will vary by instrument and strategy. Calibrate them against your EA's historical equity curve to identify the σw levels at which drawdowns historically escalated.
Practical Steps for Applying This to Your EA
- Segment your trade history — Split results by time period, market regime, or currency pair to create distinct groups. Common splits: monthly, quarterly, by session (London/New York/Asia), or by detected volatility regime (ATR-based).
- Calculate σᵢ per group — Compute the standard deviation of trade returns (in pips or R-multiples) within each segment. Ensure you use population standard deviation (÷ n) rather than sample standard deviation (÷ n−1) for consistency across groups.
- Record nᵢ per group — Note the number of trades in each segment; this becomes your weighting factor. Groups with fewer than 10 trades should be flagged as low-confidence and handled with caution.
- Apply the formula — Compute Σ(nᵢ · σᵢ²) / Σnᵢ, then take the square root to get σw.
- Use σw in your risk model — Feed this value into position sizing, stop-loss width, and drawdown projections instead of any simple average or single-period estimate.
- Monitor rolling σw — Recalculate every 20–50 new trades to detect volatility regime shifts early, before they register as drawdown on your equity curve.
- Set σw alert thresholds — Define your personal upper limit. When rolling σw crosses it, trigger an automated lot-size reduction or send a MetaTrader alert to review manually.
- Document and review quarterly — Keep a log of σw readings over time alongside your equity curve. This gives you a volatility-adjusted lens to explain drawdown periods and identify when conditions suit your EA best.
How σw Compares to Other Volatility Measures
EA traders have several volatility tools available, and each answers a different question. Understanding when to use σw versus the alternatives prevents both under- and over-estimating risk.
| Measure | What It Captures | Key Weakness | Best Used For |
|---|---|---|---|
| σw (Pooled SD) | Weighted spread of returns across multiple periods or systems | Requires segmenting data into meaningful groups first | Multi-period EA evaluation, multi-pair comparison |
| Simple SD | Return dispersion from a single homogeneous dataset | Treats all periods equally regardless of trade count | Single-period analysis with consistent market conditions |
| ATR (Average True Range) | Recent candlestick range — price-level volatility | Reflects market volatility, not EA return volatility | Setting stop-loss distances dynamically |
| Rolling SD (20-trade window) | Short-term regime shifts in real time | Small window makes it noisy; can overreact to single outliers | Live monitoring dashboards and alerts |
| Maximum Drawdown | Worst peak-to-trough loss in history | Backward-looking; cannot predict future drawdown magnitude | Stress testing account size and risk of ruin |
| Sharpe Ratio | Return per unit of total volatility | Uses simple SD in denominator — inherits its weaknesses | Ranking EAs of similar trade frequency |
Pro tip: Use σw as your primary volatility input to the Sharpe ratio denominator when aggregating across multiple test windows. This gives you a more honest risk-adjusted performance figure than the one MetaTrader's strategy tester reports by default.
Applying σw to R-Multiple Distributions
Pip-based standard deviations are instrument-dependent — a σw of 60 pips means very different things on USDJPY versus EURUSD. A more transferable approach is to work in R-multiples: expressing each trade's outcome as a multiple of your initial risk (1R = 1× the amount risked on that trade). R-multiples let you compare EAs across instruments, account sizes, and time periods on a level playing field.
Converting to R-Multiples:
A well-behaved EA should have a σw(R) close to 1.0–2.0. Here's what different ranges signal:
| σw(R) Range | What It Means | Action |
|---|---|---|
| < 1.0 | Very consistent outcomes — tight clustering around mean R | Excellent — check for curve-fitting |
| 1.0 – 2.0 | Normal dispersion for a trend-following or S&D strategy | Healthy — proceed with live trading |
| 2.0 – 3.5 | Wide outcome dispersion — occasional large wins/losses | Caution — reduce position size |
| > 3.5 | Unpredictable returns — strategy lacks consistency | Review strategy logic before live use |
Example: EA Alpha trades EURUSD with σw(R) = 1.4 across 300 trades. EA Beta trades GBPJPY with σw(R) = 3.8 across 300 trades. Despite both having a positive expectancy, Alpha is far more predictable and manageable — a direct, instrument-agnostic comparison you cannot make with pip-based standard deviations.
Rolling Window σw: Monitoring Volatility in Real Time
A static σw calculated over your entire trade history tells you about the past. To manage risk prospectively, you need a rolling calculation that updates with every new trade. The idea is to divide your trade history into consecutive non-overlapping windows of equal size, compute σ for each window, then pool those standard deviations using the weighted formula.
Recommended Window Sizes by EA Type:
The MQL5 implementation below maintains a circular buffer of the last WINDOW_SIZE trade profits, computes standard deviation per window, and outputs a rolling σw that updates every time a trade closes:
#define WINDOW_SIZE 50 // trades per rolling window
#define MAX_WINDOWS 10 // how many windows to pool
double g_tradeBuffer[WINDOW_SIZE * MAX_WINDOWS]; // circular buffer
int g_bufferIndex = 0;
int g_totalTrades = 0;
// Call this after every trade closes, passing the R-multiple result
void UpdateRollingWeightedSD(double rMultiple)
{
g_tradeBuffer[g_bufferIndex % (WINDOW_SIZE * MAX_WINDOWS)] = rMultiple;
g_bufferIndex++;
g_totalTrades++;
if(g_totalTrades < WINDOW_SIZE) return; // not enough data yet
int completedWindows = MathMin(g_totalTrades / WINDOW_SIZE, MAX_WINDOWS);
double sumWeightedVar = 0.0;
int totalUsed = 0;
for(int w = 0; w < completedWindows; w++)
{
// Gather trades for this window
int startIdx = w * WINDOW_SIZE;
double sum = 0.0;
for(int t = 0; t < WINDOW_SIZE; t++)
sum += g_tradeBuffer[startIdx + t];
double mean = sum / WINDOW_SIZE;
double variance = 0.0;
for(int t = 0; t < WINDOW_SIZE; t++)
{
double diff = g_tradeBuffer[startIdx + t] - mean;
variance += diff * diff;
}
variance /= WINDOW_SIZE; // population variance
sumWeightedVar += WINDOW_SIZE * variance;
totalUsed += WINDOW_SIZE;
}
double rollingWeightedSD = MathSqrt(sumWeightedVar / totalUsed);
Print("Rolling σ_w (R-multiple): ", DoubleToString(rollingWeightedSD, 3),
" | Windows pooled: ", completedWindows,
" | Total trades: ", g_totalTrades);
// Trigger alert if volatility exceeds threshold
double alertThreshold = 2.5;
if(rollingWeightedSD > alertThreshold)
{
Alert("⚠ Elevated volatility detected! σ_w = ",
DoubleToString(rollingWeightedSD, 2),
" — consider reducing lot size.");
}
}
Hook UpdateRollingWeightedSD() into your EA's OnTrade() or post-close handler, passing the closed trade's R-multiple. The function automatically pools the last MAX_WINDOWS complete windows and fires a MetaTrader alert the moment σw exceeds your defined threshold.
Using σw to Build a More Honest Sharpe Ratio
The standard Sharpe ratio divides average return by standard deviation. When your EA has operated across multiple market regimes or been tested across multiple walk-forward windows, the standard deviation in the denominator should be σw rather than a single-period SD — otherwise you're dividing by a number that doesn't accurately represent the risk your account actually experienced.
Standard vs. Weighted Sharpe Comparison:
- ✗ Uses simple average of all SDs
- ✗ Small quiet periods inflate the ratio
- ✗ Flatters EAs tested in low-volatility windows
- ✓ Uses pooled SD weighted by trade count
- ✓ High-trade-count periods dominate correctly
- ✓ Survives walk-forward aggregation faithfully
The same logic extends to the Sortino ratio, which replaces σ with downside deviation (only counting losing trades in the variance calculation). Simply apply the weighted pooling formula to downside deviations instead of total standard deviations, and you get a weighted Sortino that is equally robust across regimes.
5 Common Mistakes When Using Weighted Standard Deviations
Even traders who know the formula fall into these traps. Avoid them to ensure your σw calculations are genuinely informative rather than just statistically sophisticated-looking noise.
Mixing population and sample standard deviation
Some tools output sample SD (÷ n−1) while others output population SD (÷ n). Pooling a mix of the two produces a σw that is technically incorrect. Pick one convention — population SD is generally preferred for backtesting — and apply it consistently across all segments.
Using overlapping windows
If your windows share trades (e.g. a rolling 50-trade window shifted by 10 trades each time), the same trade contributes to multiple σᵢ values. When you pool those, you double-count those trades' variance. Always use non-overlapping, consecutive windows when computing σw.
Weighting by time instead of trades
It's tempting to weight by calendar duration (e.g. Q1 = 90 days). But the statistical power of a period comes from trade count, not time elapsed. A 90-day window with 5 trades should carry far less weight than a 30-day window with 80 trades. Always use nᵢ (number of trades) as your weight.
Treating σw as a fixed risk parameter
Setting your position size once using a historical σw and never updating it is a common mistake. Markets evolve, and so does your EA's volatility profile. σw should be recalculated on a rolling basis and your lot size should adjust with it — not remain static for months.
Ignoring outlier trades within segments
A single extreme outlier trade (e.g. a 20R winner due to a news event) can massively inflate σᵢ for one window, which then propagates into σw. Before pooling, identify and flag outliers (trades beyond ±3σ of the segment mean). You may choose to Winsorise them rather than exclude them entirely, preserving the data while limiting their distorting influence.
Quick-Reference Cheat Sheet
Bookmark this summary for fast reference when reviewing EA backtests or live trade logs.
- ✓σw(R) < 2.0 → healthy, proceed
- ⚠σw(R) 2.0–3.5 → reduce lot size 25%
- ✗σw(R) > 3.5 → pause and review strategy
- ↑Rising rolling σw → cut size preemptively
- ⊗n < 10 per window → exclude from pooling
- ≠Never mix population & sample SD formulas
- Scalper: 20 trades
- Day / S&D: 50 trades
- Swing: 30 trades
Key Takeaways
-
A simple average of standard deviations ignores sample size and can severely underestimate risk
-
The pooled formula σw = √(Σnᵢσᵢ² / Σnᵢ) gives each period's volatility a weight proportional to its trade count
-
Use σw when comparing EAs, aggregating multi-pair results, or summarising walk-forward windows
-
Feed σw into your position sizing model instead of any single-period standard deviation for more conservative, realistic risk management
-
Track rolling σw over time to detect rising volatility regimes before they damage your equity curve