83 lines
3.7 KiB
Markdown
83 lines
3.7 KiB
Markdown
### lowkey_backtest — Supertrend Backtester
|
|
|
|
### Overview
|
|
Backtest a simple, long-only strategy driven by a meta Supertrend signal on aggregated OHLCV data. The script:
|
|
- Loads 1-minute BTC/USD data from `../data/btcusd_1-min_data.csv`
|
|
- Aggregates to multiple timeframes (e.g., `5min`, `15min`, `30min`, `1h`, `4h`, `1d`)
|
|
- Computes three Supertrend variants and creates a meta signal when all agree
|
|
- Executes entries/exits at the aggregated bar open price
|
|
- Applies OKX spot fee assumptions (taker by default)
|
|
- Evaluates stop-loss using intra-bar 1-minute data
|
|
- Writes detailed trade logs and a summary CSV
|
|
|
|
### Requirements
|
|
- Python 3.12+
|
|
- Dependencies: `pandas`, `numpy`, `ta`
|
|
- Package management: `uv`
|
|
|
|
Install dependencies with uv:
|
|
|
|
```bash
|
|
uv sync
|
|
# If a dependency is missing, add it explicitly and sync
|
|
uv add pandas numpy ta
|
|
uv sync
|
|
```
|
|
|
|
### Data
|
|
- Expected CSV location: `../data/btcusd_1-min_data.csv` (relative to the repo root)
|
|
- Required columns: `Timestamp`, `Open`, `High`, `Low`, `Close`, `Volume`
|
|
- `Timestamp` should be UNIX seconds; zero-volume rows are ignored
|
|
|
|
### Quickstart
|
|
Run the backtest with defaults:
|
|
|
|
```bash
|
|
uv run python main.py
|
|
```
|
|
|
|
Outputs:
|
|
- Per-run trade logs in `backtest_logs/` named like `trade_log_<TIMEFRAME>_sl<STOPLOSS>.csv`
|
|
- Run-level summary in `backtest_summary.csv`
|
|
|
|
### Configuring a Run
|
|
Adjust parameters directly in `main.py`:
|
|
- Date range (in `load_data`): `load_data('2021-11-01', '2024-10-16')`
|
|
- Timeframes to test (any subset of `"5min", "15min", "30min", "1h", "4h", "1d"`):
|
|
- `timeframes = ["5min", "15min", "30min", "1h", "4h", "1d"]`
|
|
- Stop-loss percentages:
|
|
- `stoplosses = [0.03, 0.05, 0.1]`
|
|
- Supertrend settings (in `add_supertrend_indicators`): `(period, multiplier)` pairs `(12, 3.0)`, `(10, 1.0)`, `(11, 2.0)`
|
|
- Fee model (in `calculate_okx_taker_maker_fee`): taker `0.0010`, maker `0.0008`
|
|
|
|
### What the Backtester Does
|
|
- Aggregation: Resamples 1-minute data to your selected timeframe using OHLCV rules
|
|
- Supertrend signals: Computes three Supertrends and derives a meta trend of `+1` (bullish) or `-1` (bearish) when all agree; otherwise `0`
|
|
- Trade logic (long-only):
|
|
- Entry when the meta trend changes to bullish; uses aggregated bar open price
|
|
- Exit when the meta trend changes to bearish; uses aggregated bar open price
|
|
- Stop-loss: For each aggregated bar, scans corresponding 1-minute closes to detect stop-loss and exits using a realistic fill (threshold or next 1-minute open if gapped)
|
|
- Performance metrics: total return, max drawdown, Sharpe (daily, factor 252), win rate, number of trades, final/initial equity, and total fees
|
|
|
|
### Important: Lookahead Bias Note
|
|
The current implementation uses the meta Supertrend signal of the same bar for entries/exits, which introduces lookahead bias. To avoid this, lag the signal by one bar inside `backtest()` in `main.py`:
|
|
|
|
```python
|
|
# Replace the current line
|
|
meta_trend_signal = meta_trend
|
|
|
|
# With a one-bar lag to remove lookahead
|
|
# meta_trend_signal = np.roll(meta_trend, 1)
|
|
# meta_trend_signal[0] = 0
|
|
```
|
|
|
|
### Outputs
|
|
- `backtest_logs/trade_log_<TIMEFRAME>_sl<STOPLOSS>.csv`: trade-by-trade records including type (`buy`, `sell`, `stop_loss`, `forced_close`), timestamps, prices, balances, PnL, and fees
|
|
- `backtest_summary.csv`: one row per (timeframe, stop-loss) combination with `timeframe`, `stop_loss`, `total_return`, `max_drawdown`, `sharpe_ratio`, `win_rate`, `num_trades`, `final_equity`, `initial_equity`, `num_stop_losses`, `total_fees`
|
|
|
|
### Troubleshooting
|
|
- CSV not found: Ensure the dataset is located at `../data/btcusd_1-min_data.csv`
|
|
- Missing packages: Run `uv add pandas numpy ta` then `uv sync`
|
|
- Memory/performance: Large date ranges on 1-minute data can be heavy; narrow the date span or test fewer timeframes
|
|
|