Three Bots, One Mission: How TIYlab’s Algorithmic Stack Survived 30 Days of Live Trading
--
A technical breakdown of Macro Phase 11, DCA v3c, and Funding v1.1 — including the production incident that taught us humility
Thirty days ago, I pushed our trading stack live. Today, I’m publishing the recalibration story.
This is not a marketing piece.
This is what 6 weeks of parameter tuning, one production incident, and 1,466 unit tests look like when the bots are running on real money.
The Setup
TIYlab is a portfolio automation platform for Bitcoin. Three bots, one strategy, fixed allocation.
- Macro Bot (60%) — Reads market regimes, goes long in bull, hedges in bear, de-risks at extremes.
- DCA Bot (10%) — Accumulates Bitcoin intelligently based on macro regime, with crash recovery.
- Funding Bot (30%) — Captures funding rate differentials between spot and futures, market-neutral.
Each client runs the stack on their own exchange account. We never touch the funds. API keys are trade-only. Withdrawals are mathematically impossible from our infrastructure.
The product is not “set it and forget it.” The product is continuous iteration under fire.
Part 1 — The Macro Bot, Phase 11
The Macro Bot is the brain. It reads SMA200, RSI, and momentum to classify the market into one of three regimes: BULL, BEAR, or TRANSITION.
- In BULL: long position with adaptive trailing stop and an intra-trade stop loss.
- In BEAR: cash + dynamic dual-position hedging.
- In TRANSITION: progressive de-risking.
The strategy is conceptually simple. The execution is hard.
The Two Failure Modes
Every trend-following bot dies one of two deaths:
Death by tight stops. Aggressive trailing stops cut winners too early. The asymmetric profile of Bitcoin (rare massive winners, frequent small losses) means cutting a winner three months early kills the entire backtest.
Death by no stops. A Bitcoin position with no protective stop can hand back 80% of unrealized gains in a 6-week drawdown. The 2021 → 2022 cycle taught us that one.
Phase 11 was 6 weeks of work to thread that needle.
What Phase 11 Actually Changed
Seven parameters were recalibrated through walk-forward optimization on 8 years of hourly BTC data (March 2018 — February 2026). Plus one new feature: an intra-trade stop loss that activates separately from the trailing stop.
The trailing stop lets winners breathe. The intra-trade stop limits damage during severe crashes (the kind where price drops 25% in 48 hours and a slow trailing stop hasn’t tightened yet).
Two stops. Two purposes. They don’t compete — they complement.
The Numbers
After Phase 11, on the full backtest (2018–2026):
- Simulated return: +2,036%
- Sharpe ratio: 1.14
- Max drawdown: -42%
- Buy & Hold over the same period: +757%
These numbers are from a backtest. They include realistic fees (0.1% per trade) and slippage (0.02%). No look-ahead bias. Train/test splits balanced across BULL and BEAR phases.
Past performance does not predict future performance. The bot you don’t recalibrate today is the bot that breaks in 2 years.
Phase 12 will come too.
The Live Test
Phase 11 was deployed live on May 5, 2026. The bot is currently in BEAR regime, sitting in cash.
That’s working as designed. In BEAR, the right move is no move. Capital preservation > forced trading.
Part 2 — The DCA Bot, v3c
The DCA Bot is where most “smart” Bitcoin accumulation strategies fail.
The naive version is everywhere: buy a fixed amount of BTC every X days, regardless of price. It’s psychologically appealing. It’s mathematically lazy. And it has two terminal flaws.
Flaw 1: It buys the top.
A blind DCA bot doesn’t know that BTC just hit $108k three days ago. It sends the same buy order it would have sent at $20k. You accumulate at the worst possible price.
Flaw 2: It runs out of cash exactly when it should be deploying it.
After 18 months of disciplined buying, your cash envelope is empty. Then BTC drops 40% — the moment you should be accumulating aggressively — and the bot is frozen. No recycling logic. No exit. No re-entry.
DCA v3c was built to fix both, plus a third problem nobody talks about.
Layer 1: Regime-Aware Adaptive Accumulation
The DCA Bot reads the same regime signal as the Macro Bot. Then it modulates its buy size accordingly.
- In BULL stable: moderate accumulation. Steady but slow.
- In TRANSITION: cautious. Tighter ATH guard.
- In BEAR with deep drawdown: accelerated buying. The deeper the discount, the bigger the buy.
The ATH guard is the safety lock. If the price is too close to the most recent peak, the bot abstains. Threshold adjusts to regime: more permissive in BULL (you can’t wait forever for a 30% pullback in a strong uptrend), stricter in BEAR (where every rally is a potential trap).
Discipline beats FOMO. Mechanically, every time.
Layer 2: Capital Recycling
This is what fixes the “dead bot after 2 years” problem.
When the DCA portfolio reaches a comfortable profit, or when the buying envelope is saturated, the bot can take partial profit and recycle the capital for future opportunities.
Three distinct triggers ensure the bot is never stuck:
- Big TP: triggers on large unrealized profit. Reset cycle.
- Soft TP: triggers when the buying envelope is full AND the position is in decent profit. Frees capital before the next opportunity.
- Wake-up trigger: activates in BEAR when the bot has been idle too long. Forces a partial recycle to keep capital active.
At least one trigger can fire in every market regime. Structural guarantee. Mathematical impossibility for the bot to die.
Layer 3: Crash Recovery (The Story)
This layer is what nobody else has, because it was built in response to a real production incident.
April 30, 2026. A watchdog cron restarted the runtime during an ImportError crash-loop.
The root cause: a missing import path on the VPS Python environment (from kubot.bots.base import BaseBot — should have been from kubot.core.base_bot). The bot crashed on startup. The watchdog saw the process down. The watchdog restarted it. The bot crashed again. The watchdog restarted it. And so on, every 5 minutes, for several hours.
Each restart called DCABot._setup(), which loaded state from the database. But the in-memory state was corrupted by the crash-loop. cost_basis got reset to 0.0 while total_btc remained at the previously-accumulated value.
The bot now thought it had acquired BTC for free.
If we hadn’t caught it, the next sell signal would have computed an absurd realized PnL. The client’s equity would have been corrupted in the database. Reconciliation would have been a nightmare.
We caught it because Laurent noticed an inconsistency in the /equity Telegram output during a routine check.
The fix took the rest of the day:
- Fixed the import path on VPS (sed patch on all affected files).
- Manual SQL reconciliation:
UPDATE runtime_bot_state SET state_json = jsonb_set(...) WHERE client_id = 56 AND bot_type = 'dca';— recomputing the correctcost_basisfrom the trade history. - Added a state machine recovery layer to the DCA Bot.
- Added an invariant check in
DCABot._setup():
python
if self.state.cost_basis == 0 and self.state.total_btc > 0:
raise InvariantViolation(
f"cost_basis is 0.0 but total_btc is {self.state.total_btc} — "
"database state is corrupted. Manual reconciliation required."
)Fail loudly. Refuse to trade. Alert the admin.
DCA v3c was the result. 92 unit tests. Zero incident since.
Lessons from April 30
Production teaches humility. No amount of unit testing catches “watchdog restarts during ImportError crash-loop.” That edge case wasn’t in our test suite because we didn’t know it could happen. We learned it the hard way.
Watchdog crons are double-edged swords. They prevent downtime, but they can amplify crash-loops by restarting the process before the root cause is addressed. We added a 30-second grace period to our watchdog to give crashed processes time to be diagnosed before re-launch.
Fail loudly, never silently. A bot trading on corrupted data is worse than a bot that refuses to trade. The invariant check is now the first line of every _setup() method.
Part 3 — The Funding Bot, v1.1
Funding rate arbitrage is one of the cleanest crypto strategies. It’s also where most bots blow up.
The setup is elegant:
- Long spot BTC.
- Short perpetual futures BTC.
- Equal notional value on both legs.
When BTC moves +10%, your spot position gains 10% and your short loses 10%. They cancel. You’re delta-neutral. Direction doesn’t matter.
What you collect: the funding rate. Perpetual futures pay a small fee every 8 hours from longs to shorts when funding is positive (which happens most of the time when BTC is in contango). You’re short. You collect that fee. 24/7.
Conceptually simple. Operationally, three failure modes kill 90% of naive bots.
Failure Mode 1: Entering Every Window
The naive bot enters every 8h funding window. But not all funding rates cover the round-trip transaction fees.
If the funding rate is +0.001% over 8 hours and your spot+futures fees per cycle are 0.04%, you’ve just opened a position that will close at a loss before funding has time to compensate.
Funding v1.1 only opens a position when the predicted average rate exceeds a threshold that covers fees with margin.
Failure Mode 2: No Exit Logic
The naive bot stays in position regardless of how funding evolves. When funding flips negative for an extended period (which happens during sharp crashes or capitulation events), the strategy bleeds.
Funding v1.1 exits on a confirmed streak of negative funding rates. Short-term noise (one or two negative prints) is filtered out. A confirmed streak signals a regime change worth respecting.
Failure Mode 3: Excessive Leverage
The naive bot uses high leverage on the futures leg to amplify yield. Then a sharp BTC move creates temporary deviation between the legs, the futures leg gets liquidated, and the strategy is dead.
Funding v1.1 uses moderate leverage, calibrated to stay well clear of liquidation even on sharp moves. Continuous monitoring of the spread between legs. Position reduction if needed.
The Calibration
Phase 1.3 of the Funding Bot was a parameter grid search on 6 years of historical data (2020–2026, ~3,767 funding rate prints).
The single most impactful change: the exit_negative_streak threshold went from 6 to 8.
Translation: the bot now waits for 8 consecutive negative funding prints before exiting (versus 6 in the previous version).
This sounds minor. The impact wasn’t:
- Sharpe ratio: 8.46 → 9.16 (+8%)
- Maximum drawdown: -1.73% → -1.01% (divided by 1.7)
- Total fees: $402 → $140 (-65%)
- Number of cycles: 23 → 8
Pareto-superior. Every metric improved.
Why That Matters
Strategy decay is real. A parameter that was optimal in 2022 may not be optimal in 2026. Markets evolve. Liquidity profiles change. Exchange dynamics shift.
The discipline of revisiting parameters quarterly — not for vanity, but for survival — is what separates a 5-year-old strategy from one that broke in year 3.
We also briefly considered a v2 redesign with multi-exchange aggregation. We backtested it. The ROI was negative. The added complexity wasn’t worth the marginal improvement.
We abandoned 8 days of work and shipped v1.1. Sometimes the right engineering decision is to throw away the new and harden the old.
What 30 Days Live Actually Looks Like
Here’s the unvarnished version:
- Day 1 (April 6): Deployment to production. Heart in throat.
- Day 14: First real trade. A small DCA buy in BEAR regime. Worked as designed.
- Day 24 (April 30): The crash-recovery incident. 6 hours of debugging. Manual SQL reconciliation. Hard lesson logged.
- Day 26: DCA v3c shipped with full crash-recovery state machine.
- Day 28: Funding v1.1 calibration validated and deployed.
- Day 30 (May 5): Macro Bot Phase 11 calibration deployed. Seven parameters changed. 1,416 tests passing.
- Day 30+1 (May 6): This article.
Capital is intact. Bots are nominal. Zero IllegalTransitionError errors. Zero data corruption since the April 30 fix. The bot is currently in BEAR regime, sitting in cash, doing exactly what it should do — nothing.
That’s the boring outcome. Boring is success.
What This Approach Costs
6 weeks of recalibration work. Not glamorous. Not a “10x feature.” Just disciplined backtesting, parameter sweeps, walk-forward validation, and version control.
Public documentation of failures. The April 30 incident is on this Medium article. It’s also in our public changelog. We document our incidents because that’s how we earn trust.
No promise of returns. Past performance does not predict future results. The crypto market remains highly volatile. The strategy can go through prolonged loss periods. The maximum simulated drawdown is -42%.
If you’re looking for a bot that promises 10% per month, this isn’t it. We promise discipline, transparency, and a strategy that survives bear markets.
What’s Next
Continuous iteration. Specifically:
- DCA v2 comparative backtest — A research project I’ve been postponing. Comparing the current buy-only DCA v1.1 baseline against HODL, Smart Timing variants, an Accumulator + TP Ladder strategy, and Rolling Cycles. Decision-by-data, not decision-by-intuition.
- Funding Bot multi-exchange aggregation — Already explored, currently shelved. Will revisit if exchange dynamics change.
- Macro Bot Phase 12 — Whenever the data suggests it. We don’t recalibrate on a fixed schedule. We recalibrate when there’s evidence of decay.
I’ll publish the next monthly track record on June 6.
Disclaimers
The performance numbers in this article come from historical backtests and live trading on a single account (operator capital, ~2,000 USDT). Past performance is not an indicator of future results. Cryptocurrency trading involves substantial risk of loss. The maximum drawdown observed in backtest is -42%. Live results may differ from backtest results due to slippage, latency, exchange API instability, and market conditions not present in historical data.
TIYlab is a software automation tool. It does not constitute financial advice, investment management, or a recommendation to buy or sell any asset. Users remain solely responsible for their portfolio decisions and associated risks.
The Funding Bot strategy includes liquidation risk on futures markets, even though the strategy aims for market neutrality.
Follow Along
- Live track record: tiylab.com (updated automatically from production data)
- X: @TIYlab_btc — weekly threads, regime change alerts, monthly recaps
- Bluesky: @tiylab.bsky.social
- Telegram signals channel: @TIYlabSignals (read-only, public)
- Code: closed-source. Audit available on request to qualified parties.
If this approach (transparency + rigor + humility) resonates with you, follow along. If it doesn’t, that’s fine too — there are plenty of bots that promise the moon. We promise discipline.
This article describes real production work on TIYlab’s algorithmic trading platform. All numbers are sourced from internal backtests and live monitoring. Written by Laurent, founder of TIYlab. Feedback welcome via [email protected] or @TIYlab_btc on X.