- MQL5 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
CSurvival gains SurvivalSE (Greenwood), IncidenceSE and ConditionalIncidenceSE (Aalen), and a free SurvProbCI that puts a log-log interval around a probability so it cannot leave [0,1] on a thin risk set. One IncidenceVar(from,to,cause) worker serves both the unconditional and the conditional figures, since conditioning on survival past a bar only re-bases the same increments. TradeHistory: the comment on the unbounded HistorySelect gave the wrong reason. A position whose only close falls after the cutoff is censored correctly under a narrowed range; the case that actually breaks is a position partially closed before the cutoff and fully closed after, whose partial exit would be read as its final one. SurvivalPanel: the refresh gate watched PositionsTotal() alone, which misses every change that leaves the count intact - a partial close, a netting reversal, a close and an open inside one bar, or a swap of which position is described. LiveKey() folds the count together with the tracked position's ticket, volume and open time. SurvivalCore: ConditionalIncidence's header now states the conditioning convention exactly rather than describing it as the trades that reached the age. SurvivalDemo: the iCustom note now states the input group behaviour positively instead of contrasting it with the documentation. README rewritten to match what the project became: competing risks rather than cumulative hazard, the standard errors, and an honest disclaimer about the demonstration Expert's result. |
||
| Experts/Survival | ||
| Include/Survival | ||
| Indicators/Survival | ||
| README.md | ||
Survival
Survival analysis over your own MetaTrader 5 deal history. Answers what a position that has already survived N bars is likely to do next, which a win rate cannot tell you.
Companion code for the MQL5 article: https://www.mql5.com/en/articles/23928
What it does
A win rate describes every trade a strategy ever opened. The question you actually have while holding a position is conditional: given that this trade has survived ten bars without resolving, what happens over the next ten? The survivors are a different population from the entrants, and only one of those two numbers is about the position in front of you. On the run in the article they differ by roughly a factor of three, 6.28% against 18.18%.
The part most attempts get wrong is what counts as censored. It is tempting to treat "reached target" as the event and everything else as censoring, but censoring means the outcome is unobserved, not impossible. A stopped-out trade is not unobserved; the target can never be reached because there is nothing left to watch. Wins and losses are competing risks, two terminal events racing for the same position, and only a position still open at the moment of measurement is censored. Call a loss "censored" and the estimator hands each dead trade the future of the survivors, so the estimate inflates. The direction is guaranteed by construction, never downward.
CSurvival therefore computes both. The Aalen-Johansen cumulative incidence is
the correct answer; a Kaplan-Meier curve on wins alone, losses called censored,
is the wrong one. On the article's run, at the last bar whose risk set could
support a figure, those two read 17.82% and 50.98%. All four curves plus the
hazard and the risk sets come out of one sweep of a bucket array, so nothing is
sorted and every lookup is an array index.
The estimator also supplies its own error bars. SurvivalSE is Greenwood's
formula for the survival curve; IncidenceSE and ConditionalIncidenceSE are
Aalen's variance for a cumulative incidence under competing risks, which one
routine serves for both the unconditional and the conditional figures because
conditioning on survival past a bar only re-bases the same increments.
SurvProbCI puts a log-log interval around a probability so it cannot run
outside zero and one on a thin risk set. Those numbers are worth having: on the
article's run the naive 50.98% sits about thirteen standard errors above the
correct estimate, so that gap is emphatically not sampling noise, while the
apparent decay in the aging profile past the median is well inside the noise
and should not be read as an established shape.
Two smaller decisions matter more than they look. Durations are measured in
bars rather than clock time, because a position carried over a weekend accrues
hours in which price could not move, and charging the trade for them smears
every curve. And positions are reconstructed from deals on DEAL_POSITION_ID
rather than the order ticket, because one position can be built and dismantled
by any number of orders. The outcome is taken from the sign of net money,
profit plus swap plus commission, so the two competing events are strictly
"closed in profit" and "closed at a loss" rather than "take-profit fired" and
"stop-loss fired". Those coincide for the demonstration Expert and may not for
yours.
The article covers the edge cases, which is where this kind of analysis usually goes wrong: partial closes straddling the cutoff, netting reversals, thin samples in the right-hand tail, and lookback windows that quietly drop the longest-lived trades.
Layout
Include/Survival/SurvivalTypes.mqh three-outcome enum, observation struct, bar-count duration
Include/Survival/TradeHistory.mqh deals joined into positions, censored at a cutoff
Include/Survival/SurvivalCore.mqh Kaplan-Meier, Aalen-Johansen, hazard, naive curve, standard errors
Indicators/Survival/SurvivalPanel.mq5 the chart panel
Experts/Survival/SurvivalDemo.mq5 Donchian breakout that generates a history to read
Start with SurvivalDemo.mq5 in the Strategy Tester with visual mode enabled,
and pause it once some trades have accumulated. The panel is embedded in the
Expert as a resource, so it follows the Expert into the tester agent's sandbox.
To put the panel on your own program, add the #resource line, the iCustom
call in OnInit with a "" placeholder for every input group, and an
IndicatorRelease in OnDeinit. The panel reads your account's own history, so
it shows nothing until deals are present.
Disclaimer
Educational code. The Donchian breakout Expert exists only to generate a trade history for the panel to analyse. It is untuned and it loses money: over EURUSD H4 from January 2021, a 10,000 USD account finishes around 7,545. That is not a defect in the demonstration, since a wide target against a tight stop is precisely the shape that makes these curves worth looking at, but it is not a strategy and should not be run on a live account.
The panel is descriptive. It reports probabilities estimated from history, it never issues a close instruction, and it conditions on the age of a position and on nothing else. The distance left to the stop or target, the unrealised result, the volatility since entry and the market regime are all outside the model by construction, and they are most of what a decision to hold or close would actually need. Past behaviour of any model or dataset says nothing about future results.