Most trading systems I read are shaped like a forecast: compute something, decide up or down, act. The shape is the problem. On a five-minute chart the next candle is close to noise, so a model trained to answer it is being trained on noise, and good accuracy on the training set is a warning rather than a result.
So I changed the question. I no longer ask what the price will do. I ask whether the current moment belongs to the set of moments where my execution rules hold. That is a classification problem on conditions, not a prediction problem on outcome, and the difference matters because conditions are observable now while outcomes are not.
The shape of it
Twelve narrow models look at the same candle from different angles. None of them is smart. Each answers one small question:
- how fast did this candle close, relative to the recent range
- did the move extend or revert
- is volatility expanding or compressing
- is this a liquid hour or a thin one
- is price at a boundary or mid-range
Each model returns a small number. They are fused into one confidence value. That value has to clear a threshold, and only then is anything allowed to happen. Most candles fail. Nothing is taken. This is the intended behaviour, not a dry spell.
def decision(candle, context): parts = [m(candle, context) for m in models] # twelve narrow answers confidence = fuse(parts) # single scalar if confidence < THRESHOLD: return None # no trade, by design return build_order(candle, context) # stop attached at creation Three design rules I would defend
One - no forecast anywhere in the pipeline. Not as an intermediate, not as a feature. If a forecast sneaks in, every downstream layer inherits its error and you lose the ability to tell a bad model from a bad condition.
Two - the stop is part of the hypothesis, not risk hygiene. A trade opens with a boundary. If that boundary is hit, the hypothesis was wrong. Sizing is a separate decision made by a separate layer, because conflating "was I right" with "how much can I lose" makes both unmeasurable.
Three - silence is a valid output. A system that must always be in a trade is a system with no condition filter at all. The threshold is the product.
What this costs you
Honesty about the trade-off: you give up the story. There is no narrative in "conditions did not meet the threshold". Readers want a reason, and the system cannot give one beyond a number. That is why most published strategies are dressed as forecasts - a forecast is a story, a threshold is not.
The compensation is debuggability. When something goes wrong you can ask which of the twelve answers moved, in which direction, and check that against the candle. With a forecast you can only ask whether it was right, after the fact, forever.
If you are building something similar, the test I use is one sentence: can you state the condition under which your system is allowed to act? If you cannot, you have a black box, and a black box cannot be debugged.
