The premise
Most trading bots ship a strategy and assume it works. This one assumes the opposite and spends its effort on the difference: which strategies survive data they were never fitted to. Research reads real candle history from Binance’s public API; orders and balances come from the Spot Testnet, with fake money. The two are deliberately separate, because the testnet’s own history is shallow and partly synthetic.
market history (Binance public API, up to 5000 candles)
|
v
research sweep -> optimise parameters on the first 65% of history
| score on the held-out 35% (out-of-sample)
v
leaderboard -> only candidates that stay profitable out-of-sample,
| beat buy-and-hold, and earn money across sub-periods
| are marked "aprovada"
v
walk-forward -> the same parameters re-run over eight rolling quarters,
| judged on how many they won, not on the total
v
live engine -> runs the chosen strategies on the testnet,
one position per symbol, acting on closed candles onlyA candidate has to earn the word "approved"
Parameters are fitted on the older 65% of history and ranked only on the 35% the optimiser never touched. On that held-out slice a candidate must:
- be profitable
- hold a Sharpe above 0.3
- contain at least 3 trades
- beat buy-and-hold over the same window
- turn a profit in at least half of eight equal sub-periods
A backtester that refuses to flatter itself
Every assumption is set against the strategy. A signal is filled on the next bar’s open, so it can never see the price it trades at; when a bar touches both the stop and the target, the stop is assumed to hit first; the live engine acts only on closed candles and enters only on a signal transition, so a new allocation never buys a move that started days ago. Fees are read back from the exchange rather than assumed, which matters precisely because the testnet charges none: the 0.2% per round trip would otherwise show up for the first time on real money.
# every simulated trade is charged on both sides
FEE = 0.001 # 0.1%, the same rate paper trading charges
SLIPPAGE = 0.0005 # 0.05% assumption
# and the backtester refuses to flatter itself:
# the position decided at bar t's close is filled at bar t+1's open
# when a bar touches both the stop and the target, the stop hits first
# after a protective exit the strategy stands aside until its signal
# drops and turns long againWalk-forward, then three books
One train/test split tests one regime change, so the survivors are re-run over eight rolling quarters and judged on how many they won rather than on the total. Measured on this project’s live allocations, carrying the deployed parameters beat re-optimising each window on five of six; 365 daily bars cannot support a 500-point grid.
The dashboard runs three books side by side and keeps their ledgers apart: the validated rule-based one, a machine-learning experiment that ranks the universe daily, and an exit experiment that enters identically and exits four different ways, settling by measurement a question usually settled by opinion.
How it reports
- A local dashboard on 127.0.0.1, no build step
- Equity, realised and unrealised P&L, win rate, profit factor, drawdown, Sharpe
- Every entry and exit with the indicator values that triggered it
- Seventeen allocations on 4h and 1d candles, mostly doing nothing, legibly
A Spark pipeline as a JSON document: written, generated, or drawn on a canvas.