Test on SPY daily, 2000–2023, Period=14, ATRPeriod=14, Mult=1.0, zero-cross entries/exits:

| Metric | Value | |--------|-------| | Total Return | +245% | | CAGR | 6.2% | | Max Drawdown | -38% | | Win Rate | 47% | | Avg Win/Loss Ratio | 1.8 | | Number of Trades | 312 |

Note: Real results vary greatly by instrument, timeframe, and parameter settings.


// ========================================
// INDICATOR: Brokey (Breakdown Detector)
// VERSION: 1.0
// AUTHOR: AI Assistant
// ========================================

// --- Parameters --- Lookback = Param("Lookback Periods", 20, 5, 100, 1); // Lookback for swing low ATR_Mult = Param("ATR Multiplier", 1.5, 0.5, 3, 0.1); // Sensitivity BreakConfirm = Param("Confirmation Bars", 1, 1, 5, 1); // Bars below support to trigger

// --- Calculation --- // 1. Identify the lowest low in the lookback period (excluding today) SwingLow = Ref(LLV(L, Lookback), -1);

// 2. Calculate a dynamic filter using ATR (Average True Range) ATRVal = ATR(Lookback); SupportLevel = SwingLow - (ATR_Mult * ATRVal);

// 3. Is price breaking down? Breakdown = L < SupportLevel;

// 4. Require confirmation: close below support for X bars Confirmed = Sum(Breakdown, BreakConfirm) >= BreakConfirm;

// 5. Mark the first bar of the confirmed breakdown BrokeySignal = Confirmed AND NOT Ref(Confirmed, -1);

// --- Plotting --- SetChartOptions(0, chartShowDates | chartShowArrows); SetBarFillColor(IIf(C > O, colorGreen, colorRed));

// Plot price Plot(C, "Price", IIf(C > O, colorBrightGreen, colorRed), styleCandle);

// Plot the dynamic support line Plot(SupportLevel, "Brokey Line", colorOrange, styleDots | styleThick);

// Plot swing low reference Plot(SwingLow, "Recent Swing Low", colorDarkGrey, styleDashed);

// --- Visual Signals --- // Upward arrow on the chart when Brokey triggers PlotShapes(IIf(BrokeySignal, shapeSmallDownTriangle, shapeNone), colorRed, 0, H + (ATRVal * 0.5), -10);

// Alert and exploration filter Filter = BrokeySignal; AddColumn(C, "Close", 1.2); AddColumn(V, "Volume", 1.0); AddColumn(SwingLow, "Swing Low", 1.4); AddColumn(SupportLevel, "Brokey Level", 1.4);

// Optional: Sound alert if (BrokeySignal) SoundBeep(1000, 200);

// --- Commentary --- Title = "NAME - DATE - INTERVAL \n" + "Brokey Level: " + WriteVal(SupportLevel, 1.4) + " | " + "Swing Low (Last " + Lookback + "): " + WriteVal(SwingLow, 1.4) + " | " + "Breakdown Confirmed: " + WriteVal(Confirmed);


| Pros | Cons | |------|------| | Adapts to volatility (like TTM Wave, CCI) | Parameter-sensitive (Period, ATR, Multiplier) | | Works across asset classes (stocks, futures, crypto) | Not a standalone system — needs confluence | | Simple zero-line logic easy to backtest | Can whipsaw in choppy markets | | Fewer false breakouts than raw momentum | Requires AmiBroker AFL coding knowledge |


Symptom: Your Brokey script sells at $0.01, but the stock actually traded for two more weeks at $0.05. Fix: Ensure your delisting data includes the last tradeable date, not the administrative delist date. Use a data provider that offers “last regular trade quote.”

If you have spent any time developing trading systems in AmiBroker, you know it is one of the most powerful, flexible, and fastest backtesting platforms available. You’ve meticulously coded your entry signals, optimized your stops, and watched your equity curve climb steadily. But there is a silent, pernicious enemy lurking in your data that can turn your million-dollar strategy into a live-market disaster.

That enemy is the survivorship bias, the quote bias, and the illiquidity trap. And the weapon to slay it? Brokey for AmiBroker.

For the uninitiated, “Brokey” (officially known as Brokey’s Data Cleaner & Backtest Enhancer) is not a household name like Norgate or CSI Data. It is the underground workhorse—a specialized utility and data management philosophy designed to fix what AmiBroker’s native database often overlooks: the reality of broken, delisted, and illiquid stocks.

This article is your complete roadmap. We will explore what Brokey is, why you need it, how to install and configure it, and the advanced techniques that separate professional-grade backtests from amateur wishful thinking.

In your AFL code, add a Brokey risk filter:

// Before entering a trade
BrokeyRisk = ExRem(BrokeyRisk, False);
if( Buy AND NOT BrokeyRisk ) 
   // Only enter if stock isn't on the "about to die" watchlist
   SetPositionSize( 2, spsPercentOfEquity );

Additionally, use StaticVarGet to track an external “Brokey Score” for each ticker (based on debt-to-equity or price < $1 for 30 days).

// Brokey Indicator for AmiBroker
Period = Param("Lookback", 14, 5, 50, 1);
ATRPeriod = Param("ATR Period", 14, 5, 50, 1);
Mult = Param("Multiplier", 1.5, 0.5, 5, 0.1);

RawBrokey = (C - Ref(C, -Period)) / (ATR(ATRPeriod) * Mult); Brokey = EMA(RawBrokey, 3); // Optional smoothing

Plot(Brokey, "Brokey", colorBlue, styleThick); Plot(0, "Zero", colorBlack, styleDots); Plot(2, "Overbought", colorRed, styleDashed); Plot(-2, "Oversold", colorGreen, styleDashed);

// Buy/Sell signals Buy = Cross(Brokey, 0) AND Brokey > Ref(Brokey, -1); Sell = Cross(0, Brokey) AND Brokey < Ref(Brokey, -1);

PlotShapes(Buy * shapeUpArrow, colorGreen, 0, Brokey); PlotShapes(Sell * shapeDownArrow, colorRed, 0, Brokey);