SKILL.md
Create a complete VectorBT backtest script for the user.
Arguments
Parse $ARGUMENTS as: strategy symbol exchange interval
$0= strategy name (e.g., ema-crossover, rsi, donchian, supertrend, macd, sda2, momentum)$1= symbol (e.g., SBIN, RELIANCE, NIFTY). Default: SBIN$2= exchange (e.g., NSE, NFO). Default: NSE$3= interval (e.g., D, 1h, 5m). Default: D
If no arguments, ask the user which strategy they want.
Instructions
- Read the vectorbt-expert skill rules for reference patterns
- Create
backtesting/{strategy_name}/directory if it doesn't exist (on-demand) - Create a
.pyfile inbacktesting/{strategyname}/named{symbol}{strategy}_backtest.py - Use the matching template from
rules/assets/{strategy}/backtest.pyas the starting point - The script must:
- Load .env from the project root using finddotenv() (walks up from script dir automatically) - Fetch data via client.history() from OpenAlgo - If user provides a DuckDB path, load data directly via duckdb.connect(path, readonly=True) instead of OpenAlgo API. Auto-detect format: Historify (marketdata table, epoch timestamps) vs custom (ohlcv table, date+time). See vectorbt-expert rules/duckdb-data.md. - If openalgo.ta is not importable (standalone DuckDB), use inline exrem() fallback. - Use OpenAlgo ta for ALL indicators by default (EMA, SMA, RSI, MACD, BBands, ATR, ADX, STDDEV, MOM, and 90+ more) - from openalgo import ta - Only use TA-Lib if the user explicitly says "talib"/"TA-Lib" in their request; specialty indicators (Supertrend, Donchian, Ichimoku, HMA, KAMA, ALMA, ZLEMA, VWMA) always come from OpenAlgo ta regardless, since TA-Lib has no equivalent - Use ta.exrem() to clean duplicate signals (always .fillna(False) before exrem) - Run vbt.Portfolio.fromsignals() with minsize=1, sizegranularity=1 - Indian delivery fees: fees=0.00111, fixedfees=20 for delivery equity - Fetch NIFTY benchmark via OpenAlgo (symbol="NIFTY", exchange="NSEINDEX") - Print full pf.stats() - Print Strategy vs Benchmark comparison table (Total Return, Sharpe, Sortino, Max DD, Win Rate, Trades, Profit Factor) - Explain the backtest report in plain language for normal traders - Generate the OpenStatz interactive dashboard tearsheet via ostz.dashboard(...) if openstatz is available - a self-contained offline HTML file, no server needed (always use OpenStatz, never QuantStats; never the legacy ostz.reports.html static report). Set strategyreturns.name (e.g. "EMA 20/50 Crossover - SBIN") and benchmark.name before calling dashboard() - that name, not the title= argument, is what the tearsheet shows as the strategy header/column/legend (see the openstatz-tearsheet rule) - Plot equity curve + drawdown using Plotly (template="plotlydark") - Export trades to CSV
- Never use icons/emojis in code or logger output
- For futures symbols (NIFTY, BANKNIFTY), use lot-size-aware sizing:
- NIFTY: minsize=65, sizegranularity=65 (effective 31 Dec 2025) - BANKNIFTY: minsize=30, sizegranularity=30 - Use fees=0.00018, fixed_fees=20 for F&O futures
Available Strategies
| Strategy | Keyword | Template |
|---|---|---|
| EMA Crossover | ema-crossover |
assets/ema_crossover/backtest.py |
| RSI | rsi |
assets/rsi/backtest.py |
| Donchian Channel | donchian |
assets/donchian/backtest.py |
| Supertrend | supertrend |
assets/supertrend/backtest.py |
| MACD Breakout | macd |
assets/macd/backtest.py |
| SDA2 | sda2 |
assets/sda2/backtest.py |
| Momentum | momentum |
assets/momentum/backtest.py |
| Dual Momentum | dual-momentum |
assets/dual_momentum/backtest.py |
| Buy & Hold | buy-hold |
assets/buy_hold/backtest.py |
| RSI Accumulation | rsi-accumulation |
assets/rsi_accumulation/backtest.py |
Benchmark Rules
- Default: NIFTY 50 via OpenAlgo (
symbol="NIFTY", exchange="NSE_INDEX") - If user specifies a different benchmark, use that instead
- For yfinance: use
^NSEIfor India,^GSPC(S&P 500) for US markets - Always compare: Total Return, Sharpe, Sortino, Max Drawdown
Example Usage
/backtest ema-crossover RELIANCE NSE D /backtest rsi SBIN /backtest supertrend NIFTY NFO 5m