Hydre: automated algorithmic trading
An autonomous system that decides and commits real money on a prediction market, built alone, on free data, and net positive since it went live.
- Python 3.12
- asyncio
- PostgreSQL
- Docker
- Prometheus
- Grafana
- What it is
A system that decides on its own and commits real money on a prediction market, with no decision reviewed before it goes out.
- What was hard
No paid data, no purchased quota, no one on call. What is freely available has to be enough, and the system has to hold without me.
- What it proves
It runs, it is net positive, and every decision it makes carries the reason that produced it.
A personal project, built and operated alone, with my own money. Designed in February 2026. 2out of threeproductionStrategies committed with real money: 2 out of three (production). run on real money, and the system is live as I write this.
The wager
The price is already a probability. A prediction market sells shares whose price, between zero and one, is the probability the market assigns to an event. On resolution, the winning share is worth one, the losing share zero.
Which leaves one question, and only one: can I produce a probability better calibrated than the market’s, over some subset of markets, using data nobody charges for?
What makes it hard
No budget for data. Public ensemble weather forecasts, live sports scores from an open API, the market’s public transaction feed. No paid feed, no purchased quota.
The system decides alone, with no continuous supervision. It runs around the clock, it commits money, and nobody reviews its decisions before they go out. More importantly, an order that has gone out produces a side effect nothing can replay: there is no enclosing transaction that would put the outside world back as it was. That is what forces the intent to be persisted before sending rather than after.
External sources are unstable and outside my control. Data providers, the market’s interface, the network, the settlement chain: any of them can fail, stutter, or return a wrong answer.
A single operator. No one on call, no one to notice a silence.
How the system decides
From probability to decision
- Probability
- from the model
- Market price
- as a prior
Blend
- Calibration cascade
- hierarchical Bayesian, then post-model, then conformal prediction
- Validation gate
- pass, fail, or insufficient data
- never passed to date
- A range, not a single number
- the system can say how sure it is
- Bet only if the edge holds in the worst case
- the more it hesitates, the less it commits
Three independent prediction sources, and that independence is not declared: it is established by a check replayable in one command, with no database and no network, whose verdict appears further down. An ensemble weather forecast corrected by statistical post-processing, an ensemble of live sports outcome models, and an agent rating built on a Bayesian rating system with uncertainty.
One decision chain, shared by all three. No strategy calibrates on its own: a raw probability travels through a common cascade, hierarchical Bayesian correction, post-model calibration, then conformal prediction, which yields an interval rather than a point. The output is not a probability, it is a probability together with its uncertainty.
The commitment rule fits in one sentence: the system only bets when the edge survives even in the worst credible scenario. If it hesitates between “good deal” and “trap”, it stands aside. By design, the more uncertain the model, the less it acts, and uncertainty by itself shrinks the amount committed. A bankroll cap bounds the rest.
An operations layer: task supervision, stall detection, an external watchdog, reconciliation against the chain, and full logging of decisions, refusals included.
reproducible artefactOrder idempotence through an intent persisted before sending, with a refusal to emit if the trace cannot be written.
What I settled along the way
Calibrate before looking for an edge
A badly calibrated probability makes every commitment decision wrong, whatever model produced it. On the sports family, partial pooling of thin segments towards the global mean takes the calibration error from 0.132calibration errortest setCalibration error before hierarchical correction: 0.132 calibration error (test set). to 0.061average gaptest setWhen the system says "70% likely", reality lands on average within six points of the claim, compared with thirteen before the fix: the gap was cut in half., measured out of sample, at identical protocol and identical data. Only the calibrator changes.
That is a real gain, and it is also a lesson: better calibration makes probabilities honest, it does not make them better than the price.
Respond to a failure by its nature, not by how bad it looks
After three incidents from the same family, the point was hard to miss: a safeguard designed for a permanent danger, applied to a transient one, with an irreversible consequence. A provider stuttering for a few seconds triggered the same freeze as a capital leak.
| Nature of the danger | Response | Resumption |
|---|---|---|
| Transient, a third party hiccuping | in-memory pause | automatic, as soon as the cause clears |
| Permanent, real loss, confirmed divergence | persisted freeze | human, always |
The pause does not survive the process, and that is deliberate: on restart the condition is assessed afresh, never inherited. It blocks every entry. It never blocks exits: a third-party outage must not trap capital in an open position.
Never credit what is not confirmed
A gain is not credited until settlement is actually confirmed on chain, and the amount credited is the one read from the receipt, never a computed amount.
A corollary learned the hard way: the divergence between internal accounting and the real balance is signed. A shortfall is a danger, money is missing. An excess bounded by expected gains is a bookkeeping lag. At first both had the same threshold, and the system was cutting itself off because it was winning.
Turn down an edge that looks too good
The system can also turn down a bet whose apparent edge is too large. A huge gap between my probability and the market’s is almost never an opportunity: it is a sign that my model is wrong, or that the market knows something I do not.
documented trade-offA response proportionate to third-party outages: a reversible, automatic pause for transient failures, a freeze requiring human resumption for permanent ones, and never a block on exits.
What it delivers
It runs, and it is net positive
785predictionsproductionThat many times the system staked money on its own, with nobody reviewing the decision. have been placed with real money, none of them reviewed before going out. As of 27 August 2026 the account is net positive, fees deducted, over its whole active period.
It is a dated fact, not a projection, and it is stated without an amount. No capital figure, no profit figure and no return is published, here or anywhere else: the scale is given in kind, a few hundred dollars committed. This is not coyness, it is that the amount proves nothing. And a few months do not tell an edge from a lucky run. Over a few hundred bets, a positive result remains perfectly compatible with having no real edge at all, which the limits section spells out.
So what stands up here is not the profit: an autonomous system made eight hundred financial decisions unsupervised, and the account is in the black at the end of it.
What had to be built to get there
12.2mdecisionsproductionDecisions logged with their reason: 12.2m decisions (production)., each carrying the reason that produced it, refusals included. That is what makes the system analysable: without a log of refusals, the question “do my filters actually screen out the bad cases?” cannot be answered.
1,004testsproductionTests run, all green: 1,004 tests (production). before every deployment, and I cannot say what they cover: coverage is not measurable in the current environment. Counting tests without knowing what they reach is exactly the objection I raise elsewhere against a number published with no reference point. Here it counts against me.
1out of twoproductionArchitecture contracts upheld: 1 out of two (production).: the independence of the three strategies is guaranteed mechanically, the layering contract is not. The check runs on every deployment and the return to compliance is under way: the internal audit concluded that part of the breaches describe the intended architecture rather than debt, so the contract is being rewritten before it is enforced again. A stale contract left failing teaches you to ignore your own tooling.
Output of the checking tool, replayable in one command, with no database, no network and no money at stake.
135files
323dependencies
Hydre layered architectureBROKENWorkers mutually independentKEPT
1 contract upheld · 1 contract broken
Reliability was built by post-mortem
The system is not robust by design, it became robust one incident at a time, and it took three failures from the same family before I drew the right rule from them.
In July 2026, the longest outage: 4.5daysproductionThe service stayed down for four and a half days without anything alerting me: this is the outage I recount because it slipped past me.. That is where I stopped fixing the path that had broken and catalogued every path in the same family: 21pathsproductionShutdown paths catalogued after the last incident: 21 paths (production).. The earlier failures had each received a one-off fix, and the next one had simply walked in through the door beside it.
In August, the most recent: three network failures of a few seconds each froze the live strategies for more than a day. 0euro lostproductionThirty hours frozen with real money on the line, and not a euro lost: the freeze blocks entries, never exits.. A freeze blocks entries and never exits, and no position was exposed. Nor was the outage detected, and it is that defect, not the failure, that produced the next fix.
What is still fragile
It is the project’s most solid result, and it counts against it. Across the traded universe, the observed success rate equals the entry price for all three strategies, one of which never left simulation, and a regression of the outcome on my probability and on the price keeps only the price. The structural ceiling is therefore break-even, minus fees, and the net gain observed does not contradict it: it is consistent with a favourable run over a short window.
The context is measured: 77.9mbetsbacktestSettled bets replayed over the market's history: 77.9m bets (backtest). over 41monthsbacktestSpan covered by the replay: 41 months (backtest). establish that this market’s price is already calibrated, to within one percentage point and at every price level. That is the bar to beat.
The statistical gate I built has never given the green light. It rules in three states, pass, fail, or insufficient data, and requires four independent checks to pass together. 0green lightbacktestGreen lights issued by the validation gate: 0 green light (backtest).. The real-money strategies therefore run without its approval, at small scale and knowingly. I can defend the trade-off, I do not present it as daring.
Three weaknesses remain open, none is an oversight, and each carries its follow-up. The alerting setup rests on a single channel, identified as the highest remaining risk: doubling that channel is the first job of the next version, ahead of any further work on the models. None of the three strategies emits a sign of life towards the stall detector, a one-line fix per file, written and waiting for the deployment window. And degraded calibration passes unnoticed by the decision: an unreadable artefact drops the layer concerned into pass-through, and the system keeps committing money on an uncalibrated probability; that pass-through fallback has to become a refusal rather than a silent defect, and it is the next fix in line.
A known units mismatch between the fee computation and the edge computation is not fixed yet, and deliberately so. The reason is not technical: fixing it would increase the amounts committed, and I do not want to raise the exposure before the alerting channel is doubled. The correction is written, its rollout is conditioned on that doubling. It is a risk decision held in that order, not a defect left aside.
If I started over
I would build the gate before the models. I built three families of models, then the instrument able to say whether they were worth anything. Built first, it would have forced the question that matters, what could beat a market price, and why?, before I wrote tens of thousands of lines answering it by default.
I would duplicate the alerting channel before anything else. The channel stayed silent for a full month without anyone noticing, and that is what produced the only countermeasure that works: a daily heartbeat expected at a fixed hour, which turns the absence of an alert into a signal. A single channel is still a single channel.
I would treat the class, not the case, from the first incident. The rule cost three failures before it was learned. The same reflex produced the anti-degeneracy safeguard, born of a degenerate calibrator that had silently killed the signals of an entire competition: a one-off fix would have replaced that calibrator, the general rule now refuses any degenerate calibration.
Evidence
measurementThe system has been net positive since it started trading real money. Recorded on 27 August 2026, from the tally the market itself keeps for that account. No amount is published.measurementA three-state statistical validation gate, pass, fail or insufficient data, over a purged out-of-sample split with a per-event embargo.measurementAcross the traded universe, the realised success rate equals the entry price for all three strategies; a joint regression assigns all the weight to price and none to the models.documented trade-offA response proportionate to third-party outages: a reversible, automatic pause for transient failures, a freeze requiring human resumption for permanent ones, and never a block on exits.reproducible artefactOrder idempotence through an intent persisted before sending, with a refusal to emit if the trace cannot be written.constraint metA known units mismatch is not fixed yet because fixing it would increase the amounts committed: the correction is written, its rollout is conditioned on doubling the alerting channel. A risk decision held in that order, not a technical one.Numbers and method
15 numbers and how each one was measured
- Predictions placed with real money
- 785predictionsproductionThat many times the system staked money on its own, with nobody reviewing the decision.Counter on the account's public dashboard, read on 27 August 2026. Each prediction is a real financial commitment on an event's outcome, decided and placed by the system without intervention.A platform counter, read from a dated screenshot: I do not recompute it from the production database.
- Decisions logged with their reason
- 12.2mdecisionsproductionCount of the decisions recorded by the system, refusals included, each carrying the reason that produced it. It is a number I read off my production database.Read once, not tracked continuously. The count aggregates my three strategies, one of which never left simulation.
- Settled bets replayed over the market's history
- 77.9mbetsbacktestA replay of the market's public history, covering forty-one months, to establish empirically that the quoted price is already calibrated: over that universe the observed success rate departs from the price by about one percentage point, at every price level.Measured over the market's history, not over the system's own bets: it describes what has to be beaten, not what the system achieves. The gap of about one point is an order of magnitude reported by the analysis, not a confidence interval.
- Span covered by the replay
- 41monthsbacktestTime span of the replayed history, bounded by the depth of the public data available on the market.
- Calibration error before hierarchical correction
- 0.132calibration errortest setExpected calibration error, measured over an out-of-sample temporal split, before the hierarchical correction is applied. It measures the average gap between the stated probability and the frequency actually observed.Measured on a single market family, the sports one. It says nothing about how the two others are calibrated.
- Gap between stated probabilities and reality, after correction
- 0.061average gaptest setWhen the system says "70% likely", reality lands on average within six points of the claim, compared with thirteen before the fix: the gap was cut in half.The same measure, over the same out-of-sample split, after partial pooling of the thin segments towards the global mean. Protocol and data are identical to the before measurement: only the calibrator changes.Better calibration creates no edge: it makes the probabilities honest, it does not make them better than the price.
- Loss during the thirty-hour outage
- 0euro lostproductionThirty hours frozen with real money on the line, and not a euro lost: the freeze blocks entries, never exits.Recorded after the incident of 19 and 20 August 2026: three network failures of a few seconds each froze the strategies running with real money for thirty hours. No position was exposed when the freeze landed, and a freeze blocks entries without ever blocking exits.The absence of loss owes as much to the state of the book at that moment as to how the freeze is designed. The outage itself went unnoticed by the alerting.
- Tests run, all green
- 1,004testsproductionThe full suite run before deployment. The count is of executed cases: parameterised tests expand into several cases from a single function.The associated coverage figure cannot be measured as things stand, and is therefore not published.
- Green lights issued by the validation gate
- 0green lightbacktestThe gate applies a three-state conjunctive rule over a purged out-of-sample split with a per-event embargo, combining four independent checks: probability of backtest overfitting by combinatorial cross-validation, deflated Sharpe ratio, Romano-Wolf correction of the family-wise error rate, and minimum backtest length. A green light requires all four to pass.Including for the two strategies committed with real money: they went live without a green light, at small scale and knowingly.
- Strategies committed with real money
- 2out of threeproductionSwitched over strategy by strategy since 8 July 2026; the third remains in simulation. The system is running as this is written.
- Architecture contracts upheld
- 1out of twoproductionStatic check of the dependencies between modules, run with no database, no network and no money at stake. The contract requiring the three strategies to stay independent of one another holds; the layering contract does not.The internal audit concludes that part of what the second contract flags reflects the intended architecture rather than debt: the contract is partly out of date and was never rewritten. No count of breaches is published.
- Files traversed by the architecture check
- 135filesproductionCount reported by the output of the contract-checking tool, run with no database, no network and no money at stake.
- Inter-module dependencies traversed
- 323dependenciesproductionCount reported by the same run as the file count: these are the edges of the import graph over which both contracts are evaluated.
- Longest service outage
- 4.5daysproductionThe service stayed down for four and a half days without anything alerting me: this is the outage I recount because it slipped past me.Measured between the service stopping and resuming, on 30 July 2026. Triggered by a system update, a start-up check stricter than the running regime, and the service manager exhausting its restart quota.The evidence sheet carries two diverging readings for this same incident, five days and four and a half. The second, given by the author, is the one published; the divergence is not settled.
- Shutdown paths catalogued after the last incident
- 21pathsproductionAn inventory produced in response to the last incident: rather than fixing the one path that had broken, the whole class of the problem was catalogued.