spb/hfmarketdata
Public
Open high-frequency market data platform — FirstRate full-history downloader, DuckDB/Parquet lake, open REST API and React docs platform (www.hfmarketdata.io)
JavaScript 53.7%
Python 38.3%
CSS 4.6%
TypeScript 3.1%
1---2name: hfmd-quick-backtest3description: Backtest a moving-average crossover (or adapt the template to another signal) on HF Market Data bars with an honest walk-forward (parameters chosen on a training window, evaluated on the next out-of-sample window), transaction costs, and a full metrics report. Use when the user wants to "test a strategy", "backtest", or compare signal parameters on a symbol.4---56# hfmd-quick-backtest78A small, honest backtest template on top of v1 bars. It exists to give a *defensible* first answer9(walk-forward, costs, benchmark, no look-ahead) — not to be a full trading framework.1011## When to use1213- "Backtest a 50/200 MA crossover on SPY", "does a 20/100 cross work on CL?", "which MA pair worked best on BTC — and did it hold out of sample?"14- Any quick strategy sanity check on daily or intraday bars1516## Method (what the script does)17181. Fetch bars (`/v1/bars/{asset}/{ticker}`), keep `close`, compute daily/bar returns.192. **Walk-forward**: split time into consecutive blocks (`--test-years`, default 1). For each test block, select the (fast, slow) pair with the best Sharpe over the preceding `--train-years` (default 3) of data from the `--grid`; apply *that* pair to the test block. Concatenate the out-of-sample test blocks → the reported equity curve.203. Signal: long when `MA_fast > MA_slow`, flat otherwise (`--allow-short` for ±1). Position is applied to the **next bar** (no look-ahead).214. Costs: `--cost-bps` per side per change of position (default 5 bps).225. Report: CAGR, annualised volatility, Sharpe, max drawdown, exposure, number of trades, turnover, vs buy-and-hold on the same out-of-sample span; per-block table of the chosen parameters and the block's Sharpe (this is where you see whether the choice was stable).236. Optional chart: equity vs benchmark + drawdown + the chosen pair over time.2425## Steps2627```bash28python3 scripts/ma_crossover.py --asset etf --ticker SPY --start 2010-01-01 \29 --grid 10,20,50 --grid-slow 100,150,200 --train-years 3 --test-years 1 --cost-bps 5 --plot spy_wf.png30```3132Then explain: (a) the out-of-sample numbers *only*, (b) the stability of the selected parameters across blocks, (c) the in-sample vs out-of-sample gap (`--show-insample` prints the best in-sample pair on the full history for contrast), (d) what is not modelled (slippage beyond bps, borrow, dividends if UNADJUSTED, intraday fills).3334## Examples3536```bash37# Crude oil vendor continuous (ratio-adjusted so returns are meaningful across rolls)38python3 scripts/ma_crossover.py --asset futures --ticker CL --adjustment contin_adj_ratio --start 2012-01-01 --allow-short3940# Bitcoin, hourly bars, 6-month train / 2-month test41python3 scripts/ma_crossover.py --asset crypto --ticker BTCUSD --timeframe 1hour --start 2024-01-01 --train-years 0.5 --test-years 0.17 --grid 12,24,48 --grid-slow 96,168,3364243# Single fixed pair, no optimisation (pure evaluation)44python3 scripts/ma_crossover.py --asset stock --ticker AAPL --fixed 50,200 --start 2015-01-0145```4647## Adapting the template4849`signal_ma_cross(close, fast, slow)` returns a position series in {0,1} (or {-1,0,1}). Replace it with any function of past data only; keep the `.shift(1)` when applying positions and keep the walk-forward loop untouched.5051## Gotchas5253- For futures use `contin_adj_ratio` (multiplicative back-adjustment): `contin_UNadj` has roll jumps that fake returns; `contin_adj_absolute` can go negative in long histories.54- Intraday bars are US/Eastern and include only the sessions the vendor covers; annualisation uses bars/year inferred from the median bar spacing — check the printed `periods_per_year`.55- Keyless mode (low hourly limits, 30 req/h) is enough for daily history; hourly since 2010 needs a free API key (`HFMD_API_KEY`).56- A Sharpe above ~1.5 out-of-sample on a plain MA cross is a red flag for a bug or a tiny sample, not a discovery.57