FilterAttribution/README.md
ayantrader ayantrader 75d005141a Add FilterAttribution sources and README
Attribution engine, the six-filter opening-range breakout test bed with
its record and enforce modes, and the report and dashboard script.
2026-10-27 19:39:53 +05:00
99 lines
6.1 KiB
Markdown
# FilterAttribution
Shapley attribution of strategy filters in native MQL5: one unfiltered
backtest that records every filter's verdict on every trade already contains
the result of every filter combination, exactly, and the report shares the
gain out among the filters without depending on the order they were added in.
Companion code for the MQL5 article: https://www.mql5.com/en/articles/25617
## What it does
Filters are usually judged one at a time: add one, rerun the backtest, and
credit the filter with the change. That credit depends on what was already in
the stack when the filter went in. On the six-filter test bed here, the daily
trend filter can be credited with anything from -14.7 R to +65.8 R depending
on the order, so the one-at-a-time story is mostly a story about the order of
the experiment. Settling it by brute force takes 2^n backtests, 64 for six
filters and 4,096 for twelve.
None of them is needed when filters only veto trades. Run the strategy once
with every filter evaluated and none enforced, and store each trade's verdicts
as a bit mask in its entry comment, together with the money risked. The result
of any combination is then a sum over the trades whose mask contains it. Three
conditions make that sum exact rather than approximate: a vetoed signal must
consume whatever the taken one would have (here, the day's first breakout),
risk must be a fixed money amount rather than a share of equity, and positions
must not overlap. The Expert Advisor's enforce mode exists to prove the
conditions hold: optimising the filter mask over all 64 values runs 64 real
backtests, and `OnTesterDeinit` compares each against the recorded table.
All 64 matched in trade count and total R, with a largest difference of zero.
`CFilterAttribution` turns the coalition values into Moebius dividends, and
everything else is read off that one decomposition: the Shapley value (each
filter's average marginal gain over every order), the leave-one-out cost (what
the full stack loses without it) and the pairwise interaction index (positive
when two filters work together, negative when they duplicate each other). A
moving-block bootstrap gives each number an interval, the sample is split at a
date to see which credit survives, and a rolling Shapley value over a trailing
window of trades shows when it was earned. An independent brute-force average
over all 720 orderings agrees with the library to within 1e-13.
The most important number in the report is the chance level. When the base
strategy loses, any veto earns credit simply by trading less, so the library
computes exactly what a random veto at each filter's own pass rate would have
earned, and the same for every pair's interaction. On the test bed that chance
credit runs from 1.8 R to 16.3 R depending on the filter, and a third of the
two trend filters' raw overlap, and half or more of two other pairs', was
chance. Only the part above it is
credit for choosing which trades to block.
The test bed is a London opening-range breakout on GBPUSD M5, 2023 to
2026.09, with six filters: daily and H4 trend, narrow range, midweek, strong
close and active market. Unfiltered it loses 81.6 R over 955 trades; all six
filters make 11.0 R on 42 trades. Read against chance, removal cost and the
split, the attribution keeps only the H4 trend filter, which takes the
strategy to 7.0 R on 461 trades, close to breakeven, and its margin over
chance was the same before and after the split. The daily trend, midweek and
active-market filters earn positive credit but cost almost nothing to remove,
because other filters in the stack already do their work. Re-checking the dropped
filters against the kept one finds a single candidate, the strong-close
filter, which adds on both sides of the split and takes the pair to 21.4 R on
356 trades. That window has now been used to choose it, so only later data can
confirm it. The method found which filter carries the edge there is; it did
not create a larger one.
## Layout
```
Include/FilterAttribution/FilterAttribution.mqh verdict table, coalition values, Moebius dividends, Shapley value, leave-one-out and interaction with chance levels, block bootstrap, rolling credit
Experts/FilterAttribution/ORB_FilterLab.mq5 London opening-range breakout with six filters; records verdicts, or enforces a mask and verifies the table against every enforced backtest
Scripts/FilterAttribution/FilterAttribution.mq5 loads a saved table or the account's tagged history, prints the report with the split, selection and kept-stack checks, and draws the dashboard
```
Run `ORB_FilterLab.mq5` once in the Strategy Tester in `LAB_RECORD` mode. When
the test ends it rebuilds the table from its own deal history and saves it to
the terminal's common data folder. Then, once, set `InpMode` to `LAB_ENFORCE`
and optimise `InpMask` from 0 to 63 with the slow complete algorithm; the
summary line printed to the Experts log must report zero mismatches before the
table is trusted. Finally run `FilterAttribution.mq5` on a chart to print the
report and draw the dashboard. Set `InpKeep` to the mask of the filters you
plan to keep to see what each dropped filter adds back to them.
To attribute your own filters, nothing in the library needs to change. In your
Expert Advisor, evaluate every filter at entry, open the trade regardless,
write the pass mask and the money risked into the order comment with
`CFilterAttribution::Tag`, make sure a vetoed signal is spent exactly as a
taken one would be, and size from a fixed money amount. Add an enforce mode
and run the verification once before reading any attribution.
## Disclaimer
Educational code. The opening-range breakout is a test bed for the
attribution method, not a trading strategy: unfiltered it loses money, and the
best verified result is close to breakeven, with one candidate filter that has
not been tested on unseen data. The method applies only to filters that veto
trades; filters that resize or reshape trades break the subset property, and
the verification will report it. Past performance in the Strategy Tester does
not guarantee future results. Test on your own data and broker conditions
before drawing conclusions.