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:
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 Timestampshould be UNIX seconds; zero-volume rows are ignored
Quickstart
Run the backtest with defaults:
uv run python main.py
Outputs:
- Per-run trade logs in
backtest_logs/named liketrade_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): taker0.0010, maker0.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; otherwise0 - 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:
# 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 feesbacktest_summary.csv: one row per (timeframe, stop-loss) combination withtimeframe,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 tathenuv sync - Memory/performance: Large date ranges on 1-minute data can be heavy; narrow the date span or test fewer timeframes
Description
Languages
Python
100%