I Built an AI-Native Trading Engine in Python. 5 Months Later, Here's What Changed A developer built an AI-native trading engine for Bybit futures, evolving from a simple Bollinger Bands scanner to a system with machine learning scoring, backtesting, partial take-profit, and a Telegram bot. After five months, the engine logged 282 real signals and trained a RandomForest classifier to predict trade profitability. The open-source project, bybit-ws, now runs three trading cycles and uses SQLite as a single source of truth. 9 strategies → 12. ML scoring, backtesting, partial take-profit, Telegram bot that survived a 3-echelon audit. Open source, MIT, trading real money. Trading bots come in two flavors: black-box SaaS at $50/month, or GitHub scripts that crash at 3 AM. I wanted neither. Five months ago I shipped v1 of bybit-ws — an AI-native trading engine for Bybit futures. The core loop was simple: scan Bollinger Bands daily, score every signal across 8 metrics, enter when the score passes 5.5/10. It worked. It made money. And then I kept building. This is the v2 story: machine learning on real trade data, a backtesting engine that runs against historical klines, partial take-profit logic, and a Telegram bot that survived 14 production bugs found by three AI agents in parallel. v1 was clean. v2 is battle-tested. ┌──────────────────────────┐ │ Hermes Agent │ │ Voice/chat orchestrator │ └───────────┬────────────────┘ │ MCP / REST port 8766 ┌───────────▼────────────────┐ │ bybit-ws systemd │ │ │ │ main.py — 30s light cycle │ │ — 120s heavy cycle │ │ — 480s x10 cycle │ │ │ │ ┌─ auto sl.py │ │ ├─ trailing sl.py │ │ ├─ trailing sl x10.py ★ │ │ ├─ partial tp.py ★ │ │ ├─ funding rotation.py ★ │ │ ├─ ml scorer.py ★ │ │ ├─ backtest.py ★ │ │ ├─ gridsignal scanner.py │ │ ├─ pump detect.py │ │ ├─ rpc.py JSON-RPC │ │ └─ state db.py SQLite │ └───────────┬────────────────┘ │ WebSocket ┌───────────▼────────────────┐ │ Bybit API v5 │ └────────────────────────────┘ ★ = new in v2 Three cycles instead of two. The new x10 cycle every 8 minutes handles trailing stops for high-leverage positions without touching the 3x positions. The heavy cycle every 2 minutes, down from 7 now includes partial take-profit and funding rotation checks. State is SQLite, period. v1 had a mix of in-memory dicts and JSON snapshots. v2 uses SQLite with WAL mode as the single source of truth. 8 tables, atomic UPDATEs with WHERE clauses, zero race conditions. JSON snapshots are backup-only. | Strategy | Lev | Timeframe | What's New | |---|---|---|---| | Bollinger Grid LONG | 3x | Daily | — | | Bollinger Grid SHORT | 3x | Daily | — | | Junk Short | 3x | Daily | — | | SL Re-entry | 3x | Daily | — | | DCA Ladder | 3x | — | — | | BB Scalping | 10x | M5 | — | | Mean Reversion | 10x | Daily | — | | Funding Momentum | 10x | Daily | — | | ATR Risk Sizing | layer | 15m | — | Partial TP | ★ | dynamic | 20→50% scale-out, no numpy | Trailing SL x10 | ★ | x10 only | Tight trailing on high-lev positions | Funding Rotation | ★ | auto | Closes positions before negative funding hits | The golden rule still applies: every entry passes through scoring across 8+ metrics with a 5.5/10 threshold. But now there's a new layer on top. After 5 months, the system had logged 282 real signals with outcomes — entry price, exit price, PnL, whether it hit take-profit or stop-loss. That's a dataset. I trained a RandomForest classifier on it: features = 'score', 'price vs lower', 'price vs upper', 'volume 24h', 'funding rate', 'rsi 14', 'bb squeeze', 'consecutive down days' target = 'is profitable' 1 if PnL 0, else 0 Results: The model runs every heavy cycle, re-scores open positions, and can veto new entries. It's not a black box — feature importance is logged, so I can see why it made a decision. Is F1=0.69 "AI that prints money"? No. It's a filter that catches bad entries the heuristic would miss. In backtesting, the ML layer improved average PnL per trade by 18% just by rejecting the bottom quartile of signals. You can't trust a strategy you haven't backtested. I built a walk-forward engine that pulls historical klines from Bybit's REST API and replays them day by day: Each day: scan → score → simulate entry → track PnL for day in trading days: klines = fetch klines symbol, start=day.start ms signals = scan klines, strategy='bollinger grid' for sig in signals: trade = simulate sig, klines day:day+30 results.append trade Tested on BTC, ETH, SUI, and ADA with Daily signals: | Symbol | Win Rate | Avg PnL | Best Trade | Worst Trade | |---|---|---|---|---| | SUIUSDT | 42.9% | +6.56% | +27.3% | −12.1% | | ADAUSDT | 38.5% | +4.82% | +19.4% | −11.7% | | BTCUSDT | 35.7% | +3.11% | +14.2% | −9.3% | | ETHUSDT | 33.3% | +1.95% | +11.8% | −10.5% | Not every strategy is a winner. The backtest exposed that ETH is borderline — win rate barely above random, average PnL close to fees. That's valuable information. I'd rather know from backtesting than from a blown account. Most bots close a position all at once. Partial TP scales out gradually: Dynamic split: 20% at first TP → up to 50% at final TP tp levels = calculate partial tp entry price, mark price, unrealized pnl pct First fill: 20% of position, SL moves to breakeven Second fill: 30% more, trailing SL activates 50% left rides with trailing stop No numpy. Pure statistics module. Works on any Python 3.11+ without extra dependencies. High-leverage positions move fast. The new trailing sl x10 module runs every heavy cycle, but only for positions with leverage ≥10 . It tightens the stop-loss when: Negative funding rates eat your margin. The rotation module checks every heavy cycle: The @Gridbolbot formerly @GridSignalBot is a 2,153-line Telegram bot that scans markets, sends alerts, and lets users execute trades inline. Five months in, it went silent. Not "slow" — dead silent. But the logs were clean, the process was running, systemd showed active . Classic Heisenbug. I ran a 3-echelon AI audit — three agents in parallel, each with a different focus: Four minutes later: 14 findings . Five CRITICAL. Highlights: valid symbol — called in 3 places, subprocess.run calls inside async handlers UPDATE ... SET +1 without WHERE check .gitignore blind spotAfter fixes: 45/45 smoke tests green , bot responds instantly. Full story in the separate article https://dev.to/alexey polyakov cfe2095e3/i-built-an-ai-native-trading-engine-in-python-heres-how-it-works-54p0 . Every fix, every feature, every release — the smoke test suite runs: python @pytest.mark.asyncio async def test scan button does not block event loop : """Verify scan handler yields control back to event loop.""" with patch 'subprocess.run' as mock run: mock run.return value = CompletedProcess ... start = time.monotonic await cmd scan update, context assert time.monotonic - start < 0.5 def test race condition scan limit : """Double-tap must not exceed daily limit.""" db.execute "UPDATE users SET scans today = 9 WHERE id = 1" await cmd scan ... 10th — pass with pytest.raises RateLimitExceeded : await cmd scan ... 11th — blocked Tools: pytest , pytest-asyncio , unittest.mock , SQLite :memory: databases. No external services — pure deterministic tests in under 2 seconds. 45 tests. 0 failures. CI green. | Metric | v1 Jan 2026 | v2 Jun 2026 | |---|---|---| | Strategies | 9 | 12 | | Codebase | 2,100 lines | 4,600+ lines | | Test coverage | 0 tests | 45 smoke tests | | ML layer | None | RandomForest F1=0.69 | | Backtesting | None | Walk-forward on REST klines | | Risk management | Basic SL | Partial TP + trailing x10 + funding rotation | | Telegram bot | Working, untested | 45/45 tests, 14 bugs fixed | | Deployment | Manual | systemd + white-label script | | Monitoring | None | Prometheus /metrics + daily health alerts | | Memory | ~200 MB | ~23.5 MB SQLite beats in-memory dicts | The memory drop isn't a typo. Moving from Python dicts to SQLite cut RAM by 88%. git clone https://github.com/poliakarmai/bybit-ws cd bybit-ws cp config.example.yaml config.yaml Insert your Bybit API keys pip install -r requirements.txt python -m bybit-ws Or deploy as a systemd service: sudo cp bybit-ws.service /etc/systemd/system/ sudo systemctl enable --now bybit-ws GitHub: poliakarmai/bybit-ws https://github.com/poliakarmai/bybit-ws Bot: @Gridbolbot https://t.me/Gridbolbot License: MIT The author is a trader and AI engineer. Writes about trading infrastructure, multi-agent systems, and the boring risk management that actually saves accounts.