Detecting meaningful shifts in price trends while filtering out market noise is a challenge many traders face. Inspired by Jakub Polec’s blog, which applies statistical methods like the CUSUM filter, I decided to implement this innovative approach as a trading strategy in AmiBroker. This blog dives into the practicalities of using the CUSUM filter to simplify trend detection and create actionable buy and sell signals.
What is the CUSUM Filter?
The CUSUM (Cumulative Sum) Filter is a statistical method designed to detect significant deviations in data while ignoring small, irrelevant fluctuations. By accumulating price changes over time and comparing them to a threshold, the filter identifies moments when a trend shift becomes statistically meaningful.
Originally used in manufacturing quality control, this method has proven incredibly effective for analyzing financial data, particularly for trend-based strategies.
How the CUSUM Filter Strategy Works
1. Cumulative Sums:
• Tracks upward and downward movements in price separately.
• Resets whenever the cumulative movement surpasses a pre-defined threshold, signaling a trend shift.
2. Threshold-Based Signal Generation:
• Buy Signal: Triggered when cumulative positive price changes exceed the threshold.
• Sell Signal: Triggered when cumulative negative price changes surpass the threshold in the opposite direction.
3. Custom Sensitivity:
• By adjusting the threshold, the filter can adapt to various market conditions, ensuring it captures meaningful trends without reacting to noise.
Key Advantages of Using the CUSUM Filter
• Noise Suppression: Small, insignificant price changes are ignored, focusing only on actionable shifts.
• Flexibility: The threshold can be optimized for different assets or timeframes.
• Clear Signals: The strategy generates unambiguous buy and sell points, simplifying trading decisions.’
Below is the AFL code for implementing the CUSUM filter in AmiBroker. The code identifies significant price movements, generates trading signals, and visualizes them on the chart.
_SECTION_BEGIN("CUSUM Filter Strategy - Percentage Terms");
// Input parameters
Threshold = param("CUSUM Threshold %", 1.5, 0.05, 3, 0.05);
// Initialize arrays
Difference = ROC(C,1);
PositiveSum = 0;
NegativeSum = 0;
Pos_Array =Null;
Neg_Arrray = Null;
BuySignals = Null;
SellSignals = Null;
// Loop to calculate CUSUM
for (i = 1; i < BarCount; i++)
{
diff = Nz(Difference[i], 0);
// Update cumulative sums
PositiveSum = Max(0, PositiveSum + diff);
NegativeSum = Min(0, NegativeSum + diff);
// Check threshold conditions for Buy and Sell signals
if (PositiveSum > Threshold)
{
PositiveSum = 0; // Reset positive sum
BuySignals[i] = 1; // Mark buy signal
}
else
{
BuySignals[i] = Null;
}
if (NegativeSum < -Threshold)
{
NegativeSum = 0; // Reset negative sum
SellSignals[i] = 1; // Mark sell signal
}
else
{
SellSignals[i] = Null;
}
Pos_Array[i] = PositiveSum;
Neg_Arrray[i] = NegativeSum;
}
// Generate Buy/Sell arrays from signals
Buy = ExRem(BuySignals, SellSignals);
Sell = ExRem(SellSignals, BuySignals);
Buy = ExRem(Buy,Sell);
Sell = ExRem(Sell,Buy);
Short = Sell;
Cover = Buy;
SetPositionSize(1*RoundLotSize,spsShares);
// Trade execution settings
SetTradeDelays(0, 0, 0, 0);
BuyPrice = ValueWhen(Buy, close);
SellPrice = ValueWhen(Sell, Close);
ShortPrice = ValueWhen(Short,Close);
CoverPrice = ValueWhen(Cover,Close);
// Plot the chart
SetChartOptions(0, chartShowArrows | chartShowDates);
_N(Title = StrFormat("{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue(ROC(C, 1))));
Plot(Close, "Close", colorDefault, styleCandle);
//Plot(Threshold, "CUSUM Threshold", colorRed, styleDashed);
_SECTION_END();
_SECTION_BEGIN("Trading Signals");
//Plot the trading signals
/* Plot Buy and Sell Signal Arrows */
PlotShapes(IIf(Buy, shapeSquare, shapeNone),colorGreen, 0, L, Offset=-40);
PlotShapes(IIf(Buy, shapeSquare, shapeNone),colorLime, 0,L, Offset=-50);
PlotShapes(IIf(Buy, shapeUpArrow, shapeNone),colorWhite, 0,L, Offset=-45);
PlotShapes(IIf(Sell, shapeSquare, shapeNone),colorRed, 0, H, Offset=40);
PlotShapes(IIf(Sell, shapeSquare, shapeNone),colorOrange, 0,H, Offset=50);
PlotShapes(IIf(Sell, shapeDownArrow, shapeNone),colorWhite, 0,H, Offset=-45);
_SECTION_END();
Customizing the Strategy
1. Threshold Optimization:
• The script includes an optimization parameter to find the ideal threshold value, ensuring the strategy performs well across different assets and market conditions.
2. Position Sizing:
• Adjust position sizes based on your risk tolerance or account size.
3. Visualization:
• Green arrows indicate buy signals, while red arrows mark sell signals. This clear visualization helps traders quickly identify opportunities.
Inspired by Jakub Polec’s Insights
The idea for this strategy stems from Jakub Polec’s excellent breakdown of the CUSUM filter and its applications in financial analysis. He demonstrates how simple statistical techniques can uncover meaningful trends, offering traders a data-driven edge.
👉 Read Jakub’s original blog here: The CUSUM Filter – A Statistical Approach