> the_problem
Most backtesting frameworks are long-only. They assume you buy low and sell high — full stop. But crypto is different: sentiment swings hard, and short-side alpha is real during bearish regimes. The problem was that no off-the-shelf tool could simultaneously:
Raw sentiment signals are noisy. A bearish tweet score doesn't mean the coin is a short — you need ratio context (beta, omega) to confirm conviction. Off-the-shelf tools weren't built for this layered signal logic. Building on vectorbt meant extending it, not forking it.
> my_approach
The design principle was separation of concerns. Strategy files emit signals — they don't know about execution, risk, or portfolio accounting. The engine handles everything downstream.
- Signal Extension Extended vectorbt to support 4-tuple signals: (entry_long, exit_long, entry_short, exit_short). The engine auto-detects whether a strategy returns a 2-tuple or 4-tuple and routes accordingly — no breaking changes to existing strategies.
- Ratio Filter Layer Every sentiment signal passes through a validation gate against FE_RATIOS data (beta/omega ratios). Only signals that meet ratio thresholds proceed to entry. Forward-fill is applied at pipeline start — never inside the signal loop.
- Strategy Separation Strategies live in a strategies/ folder and are discovered automatically via CLI. Adding a new strategy requires zero changes to the engine — just drop a class in the folder.
- MA Baseline Strategies MATimeframes (8h/24h dual crossover) and MAOnlyFast strategies give a non-sentiment baseline to compare against — critical for knowing if sentiment actually adds alpha.
> architecture
┌─────────────────────────────────────────────────────────┐
│ DATA SOURCES │
│ cp_ai (NLP sentiment) cp_backtest_h (OHLCV) │
└──────────────┬──────────────────────┬───────────────────┘
│ │
▼ ▼
┌──────────────────────┐ ┌──────────────────────────┐
│ FE_RATIOS Table │ │ OHLCV Data Loader │
│ beta / omega ratios │ │ (forward-fill aligned) │
└──────────┬───────────┘ └────────────┬─────────────┘
│ │
▼ │
┌──────────────────────┐ │
│ Ratio Filter Gate │◄──────────────┘
│ (validates signals) │
└──────────┬───────────┘
│
▼
┌──────────────────────────────────────────┐
│ STRATEGY SIGNAL GENERATION │
│ SentimentLong / SentimentShort / │
│ SentimentLongShort / MA strategies │
│ (auto-discovered from strategies/) │
└──────────────────┬───────────────────────┘
│ 2-tuple or 4-tuple signals
▼
┌──────────────────────────────────────────┐
│ EXTENDED VECTORBT ENGINE │
│ Portfolio simulation, position sizing, │
│ mutual exclusion enforcement │
└──────────────────┬───────────────────────┘
│
▼
┌──────────────────────────────────────────┐
│ PERFORMANCE ANALYTICS │
│ Sharpe · Profit Factor · Win Rate │
│ Max Drawdown · Period Comparison │
└──────────────────┬───────────────────────┘
│
▼
┌──────────────────────────────────────────┐
│ POSTGRESQL RESULTS │
│ cp_backtest_h — results persisted │
│ + 4 analysis utility scripts │
└──────────────────────────────────────────┘
> hard_challenges
> results
> lessons_learned
vectorbt's portfolio simulation is genuinely fast — backtesting across hundreds of coins and thousands of bars runs in seconds rather than minutes. But the API is dense. The learning curve is steep, and the documentation assumes you already know what a portfolio accessor is. Worth it.
Ratio validation cuts false positives dramatically. Without the beta/omega gate, raw sentiment signals produce a lot of noise entries — especially during sideways markets where sentiment swings but price doesn't follow. The filter is the difference between a signal and a trade.
Auto-discovery of strategy files from a folder was a small engineering decision that paid large dividends — it made experimentation frictionless and kept the engine/strategy boundary clean.