Mithraeum · Agora

The toolkit

Every mining and testing tool, one by one

The two previous sections describe the shape of the search and the shape of the validation. This one is the catalogue: what each tool actually is, how it works, and — the part that matters — which specific way of fooling yourself it exists to prevent.

Click any entry to open it, and the row it sits in opens with it. Nearly every one of these was built after a result turned out to be an illusion, which is why each carries a line naming what it guards against — and now a small set of facts: where it lives in the application, and which other tools it works with. The cross-references are links; a catalogue you can only read top to bottom is a list, and this is a system.

MINING — 30 TOOLS Generate 3 tools Evaluate 2 tools Explore 5 tools Guard, in-loop 4 tools Select 11 tools Record 5 tools only survivors reach the testing lane — most candidates die here TESTING — 28 TOOLS Foundation 1 tool — causal Separation 4 tools Pressure 7 tools Baselines 5 tools Sensitivity 5 tools Diagnosis 6 tools EVERY STAGE EXISTS TO MAKE THE ONE BEFORE IT HARDER TO BELIEVE
Where the 58 sit. The mining lane generates and prunes; the testing lane takes what survived and pushes on it from every remaining angle. The guard stage is lit because it is the unusual part — most search tools filter at the end, and by then the budget is spent. Use the filter below to cut the catalogue by family.

Mining — generating and selecting candidates

30 tools
The grammar assembles logic trees from weighted draw tablesgenerator

Candidates are not random byte soup. A grammar decides the shape of a tree — how many condition groups, how they combine, whether a regime gate is present — and then fills each slot by drawing an indicator, a comparison, an operand and a window from weighted tables.

The default draw tables are deliberately frozen. Absent an explicitly armed option, the generator takes its historical path byte for byte, so a stored seed reproduces the same population it produced when it was recorded.

The draw tables know about your own work too: custom indicators you have written are in the pool alongside the built-ins, so the search can explore around an idea you invented rather than only around the standard library.

Guards against: a search you cannot re-run. A result that cannot be reproduced is an anecdote, and quietly changing a draw weight invalidates every stored run without anyone noticing.

In the app
Under every mining run — the run form chooses its shape
Feeds
Every first-generation candidate, and every immigrant after
Pairs with
ordered window groups · universes
Ordered window groups keep fast and slow parameters coherentgenerator

When a rule compares a fast average to a slow one, drawing both windows independently produces nonsense half the time — a "fast" 200 and a "slow" 20. Window groups draw them as an ordered set instead.

Like most of the search-quality machinery, this is armed per run rather than always on: the historical draw behaviour stays available byte for byte, so old seeds keep replaying exactly.

Guards against: burning most of a search budget evaluating incoherent candidates, which also distorts every population statistic computed over them.

In the app
An armed option on the mining run form
Acts on
Any rule whose windows have a fast/slow meaning
Pairs with
the grammar
The extended grammar writes the newer vocabulary, and the classic one never movesgenerator

A second grammar draws from every one of the 113 indicators and writes what a person can now write by hand — a condition negated on a cross, an at-least-K vote, an exit on the position's own state, a risk gate, an indicator read off a second instrument.

The classic grammar is frozen byte for byte, so every search stored on it still reproduces its population exactly. The extended grammar carries a revision number, and every noise floor measured under it is stamped with that revision — a floor is never read against a search it was not measured for.

Guards against: a vocabulary a person can use and a search cannot, which quietly biases every mined strategy toward the older grammar — and a grammar that changes under stored results, which makes them unrepeatable.

In the app
The grammar switch on the mining form
Pairs with
the grammar · the empirical null
The process pool evaluates candidates in parallelthroughput

Evaluation runs across worker processes whose import surface is deliberately tiny — the engine and the indicator registry, and explicitly not the web application. A worker that had to load a web framework, a machine-learning stack and a large history file would cost a fraction of a second each, which across a large search is the difference between practical and not.

Workers are spawned, never forked. The main process is multithreaded and may be holding a live broker session; forking that produces a child in an undefined state.

Guards against: searches too slow to be worth running, which in practice means searches nobody runs long enough to be meaningful.

In the app
Under every mining run — invisible unless it breaks
Constraint
Workers must stay small; growth here is a regression
Pairs with
the series cache
The series cache computes each indicator once per jobthroughput

Thousands of candidates in one run reference the same indicators over the same data. The cache memoises those series per job and hands them out shared rather than copied.

That makes the read path strictly read-only by contract: a candidate that mutated a series in place would silently corrupt every later candidate that used it. The project treats this as load-bearing rather than an implementation detail.

Guards against: recomputing the same expensive series thousands of times — and, through the read-only rule, against one candidate's evaluation contaminating another's.

In the app
Under every mining run and every engine pass
Contract
Shared, never copied — so never written to
Pairs with
the process pool · the backtest engine
The evolutionary loop breeds from what scored wellsearch

Candidates are scored, better ones become parents, and offspring inherit and mutate structure. Crossover swaps subtrees between two parents, so a good entry condition can meet a good exit condition that was discovered separately.

Because a strategy is a data tree rather than a script, mutation is precise: change one comparison, widen one window, drop one clause. The unit of inheritance is a piece of logic, not a blob of code.

Guards against: the combinatorial impossibility of enumeration. The space of expressible strategies is far too large to sweep, so it has to be explored by something that concentrates effort.

In the app
The heart of the mining lab's waves
Steered by
Fitness on training data only, never the held-out window
Pairs with
Pareto ranking · immigrants · lineages
Lineages root a search on a strategy you already havesearch

Rather than starting from nothing, a run can be rooted on an existing strategy and explore around it. Several lineages can run in one job, each tracking back to its own root, so the ancestry of any result is recoverable.

Guards against: losing the thread. Without lineage, an interesting variant arrives with no record of what it was a variant of, and the reasoning that produced it is gone.

In the app
Chosen on the mining run form — point it at a saved strategy
Records
Which root every kept candidate descends from
Pairs with
the evolutionary loop · universes
The cycle alternates searching with pruning, unattendedsearch

A long run proceeds as cycles: search, prune what has been kept, search again from the survivors. The prune is applied against the freshly reloaded stored record rather than a copy held in memory, so a cycle cannot quietly grade yesterday's population. The filters for staying in the population and the filters for graduating out of it are deliberately separate questions with separate thresholds.

An extinction guard watches the arithmetic: if a prune would leave too little alive, the whole prune is skipped rather than applied partially. An empty population is not a rigorous population — it is the end of the experiment by accident.

Guards against: a multi-day search that needed a human to babysit every stage — and one over-strict filter silently ending the run while nobody was watching.

In the app
The mining lab's auto-cycle strip: mine → cut → gauntlet → promote
Two filters
Staying in and graduating out are separate thresholds
Pairs with
held-out fitness · out-of-sample testing
The ML assistant suggests where to look, never what is truesearch

Optionally, a learned model can steer generation: trained on the candidates already evaluated in the run, it nudges the search toward regions that have been producing survivors. The descriptors it learns from travel with the run's configuration, so a steered search is as reproducible as an unsteered one.

What it is never allowed to do is score. Every candidate it points at is evaluated by the same causal engine, under the same held-out discipline and minimum-evidence thresholds as everything else. The model proposes; the backtest disposes.

Guards against: spending a search budget uniformly across a space that is mostly empty — without ever letting the guide become the judge of its own suggestions.

In the app
A toggle on the mining run form
Never
Scores, grades, or touches the held-out window
Pairs with
held-out fitness · the empirical null
The rotation miner searches for ranking rules across a universesearch

Instead of rules on one tape, it mines cross-sectional strategies: rank a universe of instruments through time, hold the leaders, charge the turnover. Every rank is computed from a prefix of history — the same arithmetic the screen uses at that moment — so it is causal by construction.

Guards against: a rotation rule that looked good because its ranks were computed with data from after the date they ranked.

In the app
Mine, beside the single-tape search
Pairs with
basket scoring · the portfolio lab
Immigrants inject fresh random candidates mid-rundiversity

A population left to breed converges. Periodically injecting entirely new random candidates keeps genuinely different material in circulation after the population has started to specialise.

Guards against: premature convergence — the search settling into one basin early and spending the rest of its budget polishing a local maximum it cannot see past.

In the app
Inside the mining loop, drawn from the grammar
Cadence
Every round, not once — convergence is continuous
Pairs with
niche caps
Niche caps limit how many similar candidates survivediversity

A cap on how many structurally similar candidates may occupy the population at once, applied inside the selection loop rather than as a filter at the end.

Guards against: a leaderboard of one idea wearing a thousand hats. Filtering afterwards does not help — by then the search has already spent its whole budget breeding the same thing.

In the app
Inside the selection loop of every armed run
Measures
Structural similarity — the shape of the tree
Pairs with
the correlation cull · basket scoring
The correlation cull removes candidates that move togetherdiversity

Structural difference is not behavioural difference. Two strategies built from entirely different indicators can produce nearly identical return streams. The cull compares candidates by the correlation of their returns, greedily keeping the best of each correlated group.

The same comparison drawn as a picture is the universe map on the Research page — every kept candidate against every other, shaded by how alike they behave. The cull is that heatmap acting instead of showing.

Guards against: a portfolio that looks diversified and is not. This is the failure that makes several "independent" strategies lose money in the same week.

In the app
In the mining loop, and drawn as the universe heatmap
Measures
Behaviour — return streams, not tree shapes
Pairs with
niche caps · the portfolio lab
The curve gate rejects implausible equity shapesdiversity

An in-loop check on the shape of the equity curve itself — not its final value. A curve that is a single vertical step, or flat with one enormous trade, is rejected regardless of how well it scores.

Guards against: a score dominated by one lucky event. Summary statistics are perfectly happy to describe a single trade as an excellent strategy.

In the app
Inside the mining loop, before selection sees a score
Reads
The curve's shape; the number on the end is ignored
Pairs with
minimum evidence thresholds
Pareto parent ranking selects across objectives, not one numberselection

Parents are chosen along a Pareto frontier over several objectives at once — return, robustness, drawdown, trade count — rather than by one blended score.

Blending into a single number is what lets a candidate buy a superb return with terrible robustness and still rank first, because the weights you chose decided the answer before the search began.

Guards against: optimising a weighted sum you made up, and mistaking the result for a discovery about markets.

In the app
How the mining loop picks parents, when armed
Replaces
The single blended fitness number
Pairs with
the evolutionary loop · basket scoring
Basket scoring ranks a candidate by what it addsselection

A candidate can be scored not on its own record but on what it contributes to the basket of candidates already being kept. The two rankings agree until a newcomer duplicates something the basket already holds — which is exactly the case a solo score cannot see.

It also reaches across data: a candidate can be scored on several tapes at once rather than only the one it was mined from, so something that works purely on its home series shows up as exactly that.

Guards against: a kept set that is five copies of the best idea. The best addition is usually not the best individual, and selecting on individual merit alone guarantees redundancy.

In the app
Extra ranking columns on the mining lab's kept set
Asks
"What does the basket gain?", not "how good is this alone?"
Pairs with
the correlation cull · niche caps
In-loop cost stress varies assumptions during the searchselection

Costs and slippage can be varied while the search runs, so a candidate is scored under a range of assumptions rather than one. Fragility to cost is selected against rather than discovered afterwards.

Guards against: breeding a population of high-frequency candidates that only work at zero cost, then finding out at the validation stage that the entire run was wasted.

In the app
An armed option on the mining run form
Early form of
The full sweep the stress lab runs later
Pairs with
stress sweeps
Held-out fitness with an embargo keeps the search honestselection

The fitness candidates are bred on is computed on training data only. Between the training window and the held-out one sits an embargo — a gap wide enough that an indicator with a long window cannot see across the boundary.

The embargo is the part people skip. Without it, an indicator with a 200-bar window evaluated on the first held-out day is partly computed from training data, and the separation you believe you have is partial.

Guards against: leakage — the search optimising against the very data you were saving to check it with.

In the app
Rides every mining run; the boundary is drawn on the Research page
The detail
The embargo is wider than the longest indicator window
Pairs with
out-of-sample testing · walk-forward
Train-only parents decide who breeds on the training span aloneselection

Which candidates become parents is decided on the training span only. The validation span is where a candidate is judged; it is never where one is bred, because a search that selects parents on a slice slowly learns that slice.

A companion setting rotates the held-out slice between passes, keyed to the first pass's seed, so no single stretch of history does all the judging — and the overfitting estimate reads the training span it was meant to.

Guards against: an out-of-sample slice that became in-sample one generation at a time, and a single fixed holdout — one crash, say — deciding every candidate's fate.

In the app
Armed mining settings; on in the honest preset and in every bot
Pairs with
held-out fitness · overfitting probability
The front cuts on several objectives at once, not one blended numberselection

Ranking a population by a single score forces every trade-off to be decided in advance by whoever chose the weights. The front does not: it keeps the candidates that nothing else beats on every objective at once — return against drawdown, say, or consistency against turnover — and cuts from that set rather than from a sorted column.

Selecting this way is measurably not free, and the number is on the record: taking the front rather than the best single score gave up about a third of the validation-period return for roughly half the drawdown. That is a trade you might want or might refuse, which is exactly why it is stated rather than folded into a formula.

Guards against: a weighting nobody chose deciding what survives. A blended objective always has an implicit exchange rate between risk and return buried in it, and the search will find whatever that rate rewards — including corners you would reject on sight if you saw them separately.

In the app
An arming on the cut, in the mining run form and in a bot's protocol
Feeds
The surviving population at each cycle's cut
Pairs with
Pareto parent ranking · held-out fitness
Robustness at mint asks whether a candidate's neighbours also workselection

A strategy sitting on a knife-edge of its own parameters is a fitted artefact wearing a result's clothes. After each wave of candidates, this stage perturbs the survivors — jitters their windows and thresholds, builds near-twins — and scores those too, so a candidate is judged on the neighbourhood it sits in rather than on its single luckiest point.

The measurements are deliberately not counted as trials: they are stamped over the training span only, and they never enter the tally that the honesty arithmetic divides by. A neighbourhood that comes back perfectly flat — every jitter scoring exactly what the original did — is marked as such and treated as no evidence, because it means the knob being jittered was one the strategy never reads.

Guards against: the fitted peak. The single best parameter set in a search is, by construction, the one that got the most help from noise; its neighbours are the honest estimate.

In the app
A second stage after each mining wave, armed separately from the steering it enables
Feeds
Durability figures usable as the fitness the search steers on
Pairs with
the front · the tape's ceiling
The complexity penalty and a verb that takes conditions awayselection

Every extra condition is another place to fit noise, so fitness can be charged per condition. And an ablation verb removes a candidate's conditions one at a time and re-runs it, to see which were doing any work — at the scale of a whole bank of survivors, not one strategy.

Guards against: rewarding the candidate that fits the most noise because it has the most places to fit it.

In the app
An armed mining setting, and the ablate verb on the kept set
Pairs with
condition quality · the attribution ledger
The tape's ceiling says how good a result this much history can even supportselection

Run enough trials against a fixed stretch of history and the best one will look good whether or not anything is there. How good is not a mystery — it follows from the number of trials and the length of the tape, and it can be computed before the search starts.

So it is. At the moment a run is armed, the app states the score a purely lucky best would be expected to reach given the tape you have pointed it at and the number of candidates you are about to ask for. A result under that line is not a weak result; it is not a result. The figure is also what showed that one early unattended run had been asking for ten times more trials than its history could carry.

Guards against: mining a short tape hard. The number of trials is the thing everyone wants to increase and the thing that most directly inflates the winner, and without this the penalty is invisible.

In the app
On the mining form at arming time, and on the run's own badge
Feeds
The honesty tiles beside every headline figure
Pairs with
the empirical null · minimum evidence
Fill fidelity judges a candidate on the price it could actually getselection

A signal computed from a bar's close and filled at that same close is a strategy that trades at a price it learned about after the fact. It is a small assumption and it flatters enormously, particularly on the fast, high-turnover shapes a search likes to find.

Candidates are scored on the fill the live path can actually deliver — the next session's open — so the number a search is optimising is the number the product could produce. The excess over the market is computed at the level of each individual fold rather than once over the whole run, so a strategy that beat the market in one era and lost in three cannot report the average as a win.

Guards against: optimising a fill you cannot have. The gap between a close fill and a next-open fill is exactly the size of the edge many mined strategies appear to have.

In the app
The default on the mining form, stated as a fact on the run preview
Feeds
Every fitness number the search ranks on
Pairs with
the backtest engine · the buy-and-hold baseline
Condition quality at mint arrives with every candidate, not afterwardsselection

Every candidate is minted with its own conditions' statistics: how often each clause fired and which never fired at all. The cut can floor on it. The rate of dead clauses turned out to track how many conditions a candidate carries — the complexity a search is prone to reward.

Guards against: a clause that never fired sitting inside a candidate and making it look more considered than it is.

In the app
A column on every mined row, and a floor on the cut
Pairs with
the complexity penalty · edge and redundancy
The condition-attribution ledger shows which rule did the workexplanation

Per condition, per candidate: how often it fired, and what happened when it did. A condition present in every trade is contributing nothing; one that never fires is dead weight the search has not noticed.

The same attribution follows a strategy out of the lab: the logic view on a finished backtest and the records a live deployment keeps are the same question asked later — which clause is actually earning its place?

Guards against: accepting a complicated strategy whose entire result rests on one lucky gate, with four decorative conditions attached.

In the app
The conditions panel in the mining lab; the logic view on runs
Answers
Which clause did the work, and which is decoration
Pairs with
the research lab
Edge and redundancy measured at mint, and deliberately kept report-onlyexplanation

How much each condition adds on its own, and how much two conditions say the same thing, are measured as a candidate is minted. Both were built as filters and measured before either was trusted — and the first one's sign flipped inside its own standard error.

So both stay reports. A gate built on a number that noisy would select on luck while looking rigorous, which is the one kind of filter worse than none.

Guards against: a rigorous-looking gate that is really a coin toss.

In the app
Columns on the mined rows
Pairs with
condition quality · the attribution ledger
Universes store the full result, not a leaderboardrecord

A finished search saves as a universe: the complete logic trees, the statistics, the run configuration that produced them and the seed that reproduces them. Universes can be filtered, re-scored, compared, mapped and mined further.

Guards against: a result you cannot interrogate later. A row in a table tells you a number; it does not tell you what was run, under which assumptions, on which data.

In the app
Saved universes — filterable, mappable, re-minable
Carries
Trees, statistics, configuration, and the reproducing seed
Pairs with
lineages · out-of-sample testing
The bank ranks what a search kept, on validation rather than on the search's own scorerecord

A mining run's leaderboard is ordered by the thing the run was optimising, which is the one ordering guaranteed to be flattered by the search. The bank re-orders what survived by how those strategies did on data the search never touched, then by their worst held-out window, and only then by anything else.

Turning that ranked list into a combined book weights the members by inverse volatility, and refuses by name any curve that does not sit on the same time axis as the rest — two curves of equal length over different dates are not comparable, and silently averaging them is the kind of error that produces a beautiful, meaningless equity line. Ranking on the in-sample score is still possible and takes a confirmation, because occasionally it is what you actually want.

Guards against: reading a leaderboard as a ranking. The order a search produces is a statement about the search, not about the strategies.

In the app
The bank panel on the mining page; rows open in the backtest view
Feeds
The combined book, and the Ordeal's batch runs
Pairs with
held-out fitness · the portfolio lab
The strategy vault keeps the logic of everything the machine has producedrecord

Mining produces far more strategies than any store should keep, and the caps that stop the stores growing without bound will eventually evict something you wanted. The vault is the archive underneath: every distinct piece of strategy logic the system has ever generated, kept whether or not the run that made it still exists.

Entries are deduplicated by what a strategy is rather than what it is called, so renaming one or re-mining the identical logic produces a single entry — while a change to the capital or the cost assumptions, which does not change the logic, deliberately does not fork it. What you marked comes first: anything saved or starred is archived ahead of the rest, and the cap names what it dropped rather than dropping it silently.

Guards against: losing the one you meant to keep. The first version of this ranked by recency alone and was holding 1,899 mined rows while seven strategies that had been saved by hand had already been evicted.

In the app
A background task with its own window, reachable from the top bar
Feeds
Recovery of any strategy by its logic, long after its run is gone
Pairs with
universes · the bank

Testing — trying to prove it was luck

28 tools
The backtest engine is causal by constructionfoundation

Indicator series are computed over a prefix of history — the slice that existed at the moment being decided — so a rule cannot see its own outcome. Costs, slippage, execution delay and warm-up are modelled rather than assumed away, and the result is the full trade list and equity curve rather than a summary.

Because the ranking a screen shows and the ranking a backtest uses are the same implementation given different amounts of data, they cannot drift apart into two versions that agree until they do not.

Guards against: lookahead — the single most common way a backtest lies, and the one that produces the most beautiful curves.

In the app
Under every backtest, every search, every screen
Returns
The full trade list and curve, never just a score
Pairs with
the series cache · the buy-and-hold baseline
Out-of-sample testing withholds data from the searchseparation

A held-out period the search never saw, tested only after a candidate has been selected. With the same embargo the in-loop fitness uses, so the boundary is real rather than nominal.

A universe remembers every out-of-sample window it has been run against, each in its own card — a later gauntlet leg never erases the one before it, so a candidate that thrived in one window and collapsed in another is visible as exactly that.

Guards against: in-sample overfitting — a strategy that describes one specific history perfectly and nothing else.

In the app
The gauntlet stage of the cycle; cards on the kept set
Remembers
Every window separately — evidence is never overwritten
Pairs with
held-out fitness · walk-forward
Walk-forward re-derives the strategy as it marchesseparation

Repeatedly fit on a window, test on the window that follows, advance, repeat. Fold statistics stay confined to their own fold — a fold's result is never computed with knowledge from another.

This answers a different question from a single hold-out. Not "did it work on data I did not look at" but "would it have kept working, being re-derived as you went, all the way along?"

Guards against: a strategy that worked for one era and has been dead for years, which a single split can easily hide.

In the app
Part of the validation battery on a candidate
The rule
Each fold is sealed — no statistic crosses between folds
Pairs with
out-of-sample testing · vintages
The sealed tail the one number selection cannot have touchedseparation

Every number an unattended search produces has been selected on — fitted on the training span, selected on validation, selected on again at the out-of-sample tail. So the final months of the tape are sealed before the search begins: no pass, no gate and no Ordeal may read them. The seal is spent once, when the search is over, and the verdict is a live stamp on each survivor.

Guards against: an out-of-sample result that has quietly become in-sample through being looked at a hundred times.

In the app
Every research bot's tape; visible in the audit trail as the universe is born sealed
Pairs with
out-of-sample testing · the head window
The head window and the bootstrap leg evidence from the oldest months, and a resampled futureseparation

The oldest months of a tape can be held out of the search as a third window with its own question, so out-of-sample evidence is not only ever the most recent stretch. And a bootstrapped continuation — the tape's own returns resampled in blocks — joins the parametric synthetic futures a survivor is judged against.

Guards against: out-of-sample evidence that all comes from one end of history, and synthetic futures that all come from one model of how markets move.

In the app
Optional windows on a bot's protocol and on the out-of-sample gauntlet
Pairs with
the sealed tail · synthetic continuations
The Ordeal re-runs survivors under changed conditionsgauntlet

A structured battery of trials across pillars — different windows, different instruments, degraded assumptions, transferred symbols — with each pillar scored and the whole reported together. There is nothing to configure, deliberately: the same ordeal is applied every time, so two strategies' grades mean the same thing.

Coverage is always reported next to the score. A partial run can score higher than a complete one: if half the trials failed to run and the half that ran happened to be favourable, the average improves. Coverage is the only guard against that, so it is never a footnote.

Guards against: a result that depends on the exact conditions it was found in — and against a broken trial silently flattering the score it was supposed to test.

In the app
Its own panel — one button, one strategy, the whole battery
Reports
A grade, flags, and always the coverage beside them
Pairs with
stress sweeps · synthetic continuations
The gauntlet re-runs a survivor through every window it has not seengauntlet

A candidate that cleared the search cleared it on one arrangement of history. The gauntlet takes the survivors and runs them again across the remaining held-out windows one at a time — including, where it is armed, a synthetic leg on invented continuations — and records each leg separately rather than averaging them.

Separately is the point. A strategy with a strong average and one catastrophic window is a different object from one that is unremarkable everywhere, and an average hides exactly that difference. The synthetic legs are graded only over the invented span, never the real run-in that precedes it, which is a correction that made those numbers drop toward honesty when it was applied.

Guards against: a single lucky era. Most strategies that survive one out-of-sample window do not survive four.

In the app
A stage in the unattended cycle, armed with its own windows
Feeds
The per-window record on each row, and the cycle's keep filters
Pairs with
out-of-sample testing · synthetic continuations
The Adversary finds the mildest world that kills itpressure

Rather than asking whether a strategy survives a crash, this asks how little has to change before it does not. Eleven named worlds run in order from calm to crash, each stated in units calibrated against the strategy's own measured behaviour — so "one and a half times the usual tail volatility" means that, and not a number someone picked.

It is a fixed ladder and deliberately not a search. An optimiser turned loose on this problem wins by discovering a degenerate corner of the world that nobody can interpret, and the deliverable here is a sentence you can act on. The control rung runs first and defines calibrated reality; if it fails to calibrate, the whole run fails rather than letting the other rungs' labels lie. Death is the rung's median drawdown breaching the floor — median, so one unlucky path cannot condemn a strategy.

Guards against: a robustness claim with no scale on it. "It survived a stress test" is meaningless without knowing how hard the test pushed, and this reports the answer as a position on a ladder.

In the app
Its own run on the mining page, against a strategy or a mined row
Feeds
A named rung — the mildest world in which the strategy dies
Pairs with
the Ordeal · synthetic continuations
The noise retest asks whether prices that almost happened would have donepressure

Every bar is nudged by a draw scaled to its own true range — so quiet days wobble less than violent ones — highs and lows re-bracket the result, and the strategy runs again. The close is deliberately not re-chained: this is a wobble around the path history actually took, never a drift away into a different history.

It answers a question none of the neighbouring tools do. Perturbing the strategy asks whether the parameters are on a knife-edge; destroying the structure entirely asks what luck scores. This perturbs the tape, and asks whether the result depended on prices landing exactly where they did. A nudge of zero is an exact no-op, which is what makes the whole thing checkable.

Guards against: a result that rests on precise price coincidences — a stop grazed by a fraction, an entry that needed one particular tick.

In the app
A run on the mining page, and a pillar of the Ordeal's score
Feeds
A distribution of outcomes over almost-histories
Pairs with
robustness at mint · the empirical null
Stress sweeps vary assumptions across rangesstress

Costs, slippage, execution delay, volatility shocks and price jumps swept across ranges rather than checked at one value. The question is not "does it survive my assumption" but "at what assumption does it stop surviving, and is that anywhere near reality?"

Guards against: a strategy whose edge is entirely inside the margin of error of your cost model.

In the app
The stress lab — scenarios, waves, deterministic seeds
Asks
Where the edge stops, not whether it survives one guess
Pairs with
in-loop cost stress · stress history
Stress history keeps every sweep for later re-gradingstress

Finished sweeps are saved whole, with the objective they were graded against stamped on them. Re-grading against a different threshold is a client-side operation on stored results rather than a re-run.

Guards against: moving the goalposts without noticing. If the threshold is stamped, a later comparison cannot quietly use a friendlier one.

In the app
The stress lab's history tab, per account
Stamps
The objective a sweep was graded against, permanently
Pairs with
stress sweeps
Synthetic continuations test on data that did not existsynthetic

Price paths generated beyond the end of real history, carrying the statistical character of the real series but none of its specific sequence. A strategy tested on these provably cannot have been fitted to them.

Synthetic results are held in memory and never written into stored history as though they were real runs. Evidence about robustness is not a track record, and the two must not be confusable later.

Guards against: the limits of having one history. There is only one actual past, and every test on it shares its idiosyncrasies.

In the app
Grown in the stress lab, off a real base series
Never
Stored as history — robustness evidence is not a track record
Pairs with
stress sweeps · the empirical null
The empirical null establishes what luck scoresbaseline

The same search, at the same size, run against deliberately meaningless data. Whatever it returns is what a good result looks like when there is definitively nothing to find.

This is the most important number in the whole system and the one most often missing elsewhere. A Sharpe ratio means nothing without knowing what a search of that size produces from noise.

Guards against: multiple-comparison self-deception — the mathematical certainty that a large enough search returns something spectacular from pure noise.

In the app
The mining lab's null panel, run beside any search
The rule
Same grammar, same size, same filters — only the data is noise
Pairs with
the grammar · minimum evidence thresholds
The buy-and-hold baseline takes the market's credit awaybaseline

Any result can be read as the difference against simply holding the same instrument for the same span — the same window, never a different one, because a baseline computed over a friendlier period is not a baseline, it is a thumb on the scale.

The difference is expressed in percentage points against that matched span. It is a deliberately humbling view: in a long rising market, most strategies are revealed to be an expensive way of owning the market.

Guards against: crediting a strategy for a bull market it merely sat in — the most common illusion in backtesting after lookahead, and the more flattering of the two.

In the app
A reading available on every result's charts
The rule
Always the same span — a friendlier window is a thumb on the scale
Pairs with
the backtest engine · scenario windows
The market question, per block asked every six months, not oncebaseline

A candidate is compared with simply holding the tape in six-month calendar blocks, and the share of blocks it beat is its own column. One block reads as a number, never as a share; a tape too short for two blocks gets no verdict rather than a flattering one.

Guards against: one good year carrying a whole comparison, so that a strategy which lost to the market in most of its history reads as having beaten it.

In the app
Columns on every mined row, and a statistic the cut can use
Pairs with
the buy-and-hold baseline · per regime
The market question, per regime because one regime can carry twobaseline

The comparison with holding is also made regime by regime. A strategy that beats the market only while it is rising is identified as a leveraged opinion about the market rather than an edge, however good its total looks.

Guards against: a bull-market strategy presented as an all-weather one.

In the app
The regime section of a backtest, and the Ordeal's regime pillar
Pairs with
per block · scenario windows
Overfitting probability and a reality check on the whole populationbaseline

Two published statistics, run against a search's own results. The first splits the trial record combinatorially and asks how often the configuration that looked best in one half failed to stay above median in the other — an estimate of the probability that the selection procedure itself is overfitting, rather than that any single strategy is.

The second asks whether the best result in a population is better than the best you would expect from that many attempts at nothing — the multiple-testing correction that a per-strategy significance test cannot make, because by the time you are looking at one strategy the selection has already happened. It is read as a floor and ties count against the candidate.

Guards against: testing the winner instead of the procedure. A search over ten thousand candidates produces a wonderful best one from pure noise, and no amount of testing that best one in isolation reveals it.

In the app
Its own run over a universe's trial record, and a deflation card beside the headline stat
Feeds
The honesty tiles and the badge gates on a mined row
Pairs with
the empirical null · the tape's ceiling
Vintages re-run anchored at different start datessensitivity

The same strategy, re-run from a range of start dates, to measure how much of the result depends on when you happened to begin.

This is deliberately distinct from slicing an existing curve. Slicing shows a segment of one run; re-running produces a different run, with different compounding and different warm-up. The gap between those two is exactly the effect being measured.

Guards against: start-date luck, which silently flatters or ruins a result and is invisible in a single run.

In the app
The vintage lab — one strategy, many anchored starts
Not
Curve slicing; every vintage is a genuine re-run
Pairs with
walk-forward · scenario windows
Scenario windows isolate specific historical periodssensitivity

Behaviour restricted to a chosen period — a crash, a squeeze, a long grind — computed server-side on the full-resolution equity rather than on the sampled curve the browser draws, because the statistics of a drawdown are not preserved by sampling.

Guards against: a strategy that is fine on average and catastrophic in exactly the conditions you care about surviving.

In the app
A window tool on any stored run's equity
The detail
Full-resolution arithmetic — a sampled curve hides the drawdown
Pairs with
vintages · the buy-and-hold baseline
The stop lab prices an exit rule instead of optimising onesensitivity

This tool was asked for as an optimiser — mine the best stops, apply them, make mined strategies beat the market — and the measurement taken before building it said that could not be done honestly. A stop's effect on return did not transfer out of sample by any method tried: per-row, pooled, on a risk-adjusted basis, at the plateau rather than the peak, on the worst fold, and walk-forward on the parameter itself. All empty, with the relationship between in-sample and out-of-sample gain running firmly negative.

Its effect on drawdown transfers reliably — in 33 of 40 cases by one measure and 40 of 40 by another, and it correctly declines to claim a benefit where there is none. So the tool ships as a price list: every candidate exit is shown as an insurance line — what it costs in return, what it buys in drawdown, how many more trades it causes, and how often it actually fired — and the recommended pick is a constrained one, minimising cost subject to a protection requirement. It refuses to choose at all below a floor on how many times the stop was genuinely tested.

Guards against: optimising a knob whose gains are not portable. The first version stated both its budgets in risk-adjusted terms, which let a take-profit that cost 140 points of return win because it bought a fraction of a point of drawdown — a constraint stated on the wrong axis is not a constraint.

In the app
A panel on the mining page; applying a pick mints the variant as its own row
Feeds
A frontier of priced exits, and a stated refusal where evidence is thin
Pairs with
the stop bench · stress sweeps
Pictured
on the research page
The stop bench puts a strategy you already have onto the same price listsensitivity

The lab prices exits for the rows a search produced. The bench is its inverse: it takes a strategy you saved yourself and re-runs it into the same comparison, so a hand-built strategy can be measured against the same insurance lines rather than only against itself.

It re-runs rather than copies, because a stored result carries the assumptions of the run that produced it. An import is deliberately not counted as a trial — it did not come out of a search, so it must not inflate the arithmetic that divides by how many things were tried. The bench needs a held-out span to report against; without one every premium it quoted would be measured over the same window it was chosen on.

Guards against: comparing a mined exit against a hand-built one on different terms.

In the app
An import control on the stop lab panel
Feeds
The same priced frontier, with your own strategy in it
Pairs with
the stop lab · vintages
The seed check does the search reproduce under another seed?sensitivity

The same search configuration is re-mined under a different seed and the two top-K lists are compared. A search that reproduces less than half of its best candidates was describing its seed, not the tape.

Guards against: treating a result as a property of the market when it is a property of the random number generator.

In the app
A report on any stored universe
Pairs with
the empirical null · overfitting probability
Minimum evidence thresholds reject thin resultshygiene

Minimum trade counts and minimum coverage ride on every run rather than being applied as an afterthought. A candidate with nine trades is not a strategy; it is a coincidence with a chart.

Guards against: statistics computed on samples too small to support them, which is where the most confident wrong numbers come from.

In the app
Rides every run, mined or hand-built
Refuses
Results whose sample could not support their statistics
Pairs with
the curve gate · the empirical null
The research lab measures breadth, carry, sizing and lagdiagnosis

A set of diagnostics that ask where a result actually came from: how many positions contributed versus how many were carried, what the sizing scheme contributed as opposed to the signal, and how sensitive the whole thing is to acting a day later than assumed.

The lag question deserves its own sentence, because it is the one that catches real deployments: a strategy whose entire result evaporates when you act one day later than the model assumed was never a strategy you could have run.

Guards against: attributing to a clever signal what was actually produced by position sizing, by holding through, or by an unrealistic assumption about how fast you can act.

In the app
The research tab's diagnostics over any stored run
Separates
Signal from sizing from carry from execution speed
Pairs with
the attribution ledger · the portfolio lab
The portfolio lab is the last test, not the first productdiagnosis

Blending survivors into a book is itself a test: correlated legs reveal themselves, turnover costs become visible, and a strategy that looked additive turns out to be a duplicate. The lab is modelling only and cannot place an order or alter a deployment.

Guards against: assuming that several individually-validated strategies combine into something better. Often they combine into the same strategy, three times, at three times the cost.

In the app
The portfolio lab — weights, rebalancing, turnover charged
Cannot
Place an order or touch a deployment, by construction
Pairs with
the correlation cull · the research lab
The almanac reports calendar structure with its sample size showingdiagnosis

Day of the week, month of the year, and position within the month — the seasonal patterns the strategy grammar has been able to trade for a hundred rounds, finally measured rather than assumed. Every cell reports how many observations it rests on, always, next to the number itself.

Below a floor set from real measurements, the verdict fields are simply absent and the cell reads as a hint rather than evidence. That is the whole design: a two-year tape genuinely does not have enough turn-of-month observations to say anything, and a calendar tool that prints a confident number for a cell holding twenty-six samples is worse than no calendar tool.

Guards against: seasonal folklore. Calendar effects are the easiest thing in finance to find by accident, because the number of ways to slice a year is large and the number of years is small.

In the app
A panel you open per question, from the research page
Feeds
Per-cell counts, returns and up-rates with intervals where they are earned
Pairs with
minimum evidence · scenario windows
The deviance monitor watches a live strategy for drift from its own tested behaviourdiagnosis

Every test on this page is a statement about a strategy at a moment. Once it is running, the useful question changes: not "was it real" but "is it still behaving like the thing that was tested". The monitor compares live behaviour against the distribution the strategy produced under test — trade frequency, holding period, the shape of its returns — and reports the divergence.

It reports and never acts. Nothing here closes a position or disarms a rule; the deviation is evidence for a decision that stays yours, which is the same rule every safeguard in this project follows.

Guards against: a strategy that quietly stopped being the strategy you tested — a regime it never saw, a data change, or a broker filling it differently than modelled.

In the app
A panel you open per question, alongside the live controls
Feeds
A divergence report against the tested distribution
Pairs with
the research lab · the live controls
Execution quality what the orders did against what the plan saiddiagnosis

On a running deployment, the replay splits the delay from signal to fill into the application's leg and the broker's, measures price drift on a named basis, matches round trips first-in-first-out on the size actually executed, and flags a trip opened by an exit order as a trade nobody meant.

Guards against: blaming the market or the broker for a delay the machine caused, and a position nobody intended hiding inside a book that looks fine in total.

In the app
The Replay page's execution-quality and ledger sections
Pairs with
the deviance monitor · fill fidelity
The pattern across all 46. Almost none of these make a strategy better. They make it harder to believe in one, which is the only service a research tool can honestly provide. A system that only helped you find things would be a machine for generating confidence, and confidence is the one thing this domain supplies for free.

Nothing on this page is investment advice or a performance claim. No figures, returns or results appear here and none are implied. Passing any or all of these tests is not evidence that a strategy will work in future — robustness testing reduces the chance of self-deception, it does not establish that a pattern will persist. Trading involves risk of loss.

A personal project. Not advice. Nothing for sale.

This site describes a personal engineering project, written and run by one person in their own time and published under the name Mithraeum Agora. There is no company behind it, no team and no other contributor. It is not a product and not a business. Nothing here is for sale — there is no account to open, nothing to buy, no subscription, no waiting list, and no service is being offered or solicited. Sending a message through the note form creates no customer, client or contractual relationship of any kind. The note form on the contact page is the way to reach me, and it is the only one.

Nothing on this site is investment advice, financial advice, tax advice, or a recommendation, solicitation or offer to buy or sell any security or financial instrument. I am not a financial adviser, a broker, an investment manager or a regulated firm, and nothing here should be relied on as though I were. If you are making decisions about money, take advice from someone qualified and regulated to give it.

Figures do appear on this site, inside screenshots, and none of them is a performance claim. Every one is a demonstration instance's own arithmetic over price series the application generated itself — synthetic data, with no real market behind it — shown to illustrate what the tools display. They are hypothetical and simulated: no capital was at risk, no orders were placed, and a result computed over history with the benefit of hindsight carries limitations that live trading does not forgive. Hypothetical results are not indicative of future returns, and past performance — real or simulated — predicts nothing.

No brokerage, market-data vendor or other company is named anywhere on this site, and where a name appeared inside a screenshot it has been redacted out of the image. Nothing here states or implies that any company is associated with this project, endorses it, sponsors it, supplies it or has reviewed it. None is, and none has.

What this site collects. Nothing, unless you write to me. There is no analytics, no tracking, no advertising, and nothing at all is loaded from another domain. If you use the note form it takes the name, address and message you type, stores them privately where only I can read them, and keeps them for up to a year before they are deleted — sooner if you ask, and you do not have to give a reason. Your IP address is not kept. One thing is stored on your own device: the colour theme you pick, remembered by your browser so the site does not change appearance every time you arrive. It is written only when you choose a theme, and it identifies nothing and nobody. The preference itself never leaves your browser, but the screenshots follow it, so the pictures your browser fetches from this site are the ones drawn in that palette. The contact page answers all of this in more detail.

Terms of use. This site is provided as is and as available, with no warranty of any kind, express or implied. It describes software under active development: anything here may be incomplete, out of date or simply wrong, and it may change or disappear without notice. Nothing on it is a contract, a term of service for any product, or a promise that anything described will be built, released or kept running. To the fullest extent the law allows, I accept no liability for any loss or damage arising from use of this site or from reliance on anything it says. Nothing here excludes or limits any liability that cannot lawfully be excluded or limited.

Trading involves risk of loss.