Three free sources, one validated pipeline

Everything runs on public, no-key data: Bybit perpetual futures via ccxt, traditional-market OHLCV via yfinance, and the CFTC Commitment of Traders report. Every pull is cached to parquet, validated against a shared schema, and re-fetched incrementally.

The data layer

SourceAccessWhat's pulledUniverseHistoryNotes
Bybit perps ccxt v5, public market-data endpoints, no key OHLCV (1h, 1d) + funding-rate history BTC, ETH, SOL + BNB, XRP, LINK, AVAX, DOGE (8 perps) 2020-03-25 → present (BTC perp listing date) Paginated with exponential backoff; incremental cache refresh
yfinance yfinance package (Yahoo Finance) Daily OHLCV SPY, QQQ, IWM, TLT, IEF, GLD, USO, DBC, DX-Y.NYB, ^VIX, HYG (11 tickers) 2010-01-01 → present tz-aware UTC index enforced; used for traditional-market tools (macro filter, implied vol, yield valuation)
CFTC COT cot_reports package (scrapes cftc.gov public bulk files), no auth Legacy Futures-Only report: open interest + noncommercial/commercial long & short All COT markets (FX, commodities, financials); project used EUR/USD CME futures 1986 → present (weekly) Publication-lag shift baked in (as-of Tuesday → public Friday) to avoid lookahead; built 2026-09-04 specifically for COT Positioning

What every backtest pays

ItemValueWhere
Bybit taker fee5.5 bpsAssumed 100% taker on turnover for sweep signals
Bybit maker fee2.0 bpsBlended cost model for multi-asset books
Perp fundingreal historyApplied from fetched funding-rate history (BTC mean ≈ 0.0001175/8h ≈ 12.9%/yr)
Traditional-market proxy1.5 bps1.0 bps spread + 0.5 bps commission, flat, for yfinance instruments

Costs matter enormously at this horizon — the funding-cycle seasonality tool (flips position 3×/day) produced Sharpe −5.46 almost entirely from transaction-cost drag, and holding-period analysis showed costs collapse the shortest (intraday) bucket's net Sharpe from +0.13 to −1.90.

A parquet cache with a validation gate

Incremental parquet cache

Every fetch lands in data/cache/ as parquet, keyed by (symbol, timeframe). Re-runs only pull bars newer than the last cached bar — a full BTCUSDT 1h history is a ~10-minute one-time pull against Bybit rate limits, then everything is local.

Shared schema validation

Every source passes through validate_ohlcv: a sorted, deduplicated, UTC-timezone DatetimeIndex with the exact OHLCV columns. Corrupted or partial frames fail loudly at load time instead of silently poisoning a backtest.

Three bugs found, fixed, and re-verified

1 · Funding-history fetch bug major

fetch_funding_rate_history silently returned an empty frame for BTC/USDT:USDT for the entire project: the requested start (2020-01-01) predates the perp's listing (2020-03-25), and the funding endpoint returns nothing when since predates data — so every earlier backtest ran with zero funding cost applied (mean funding ~12.9%/yr, not trivial). A second bug would truncate fetches to ~6 weeks mid-history. Both fixed; the corrupted cache was deleted, full real history re-fetched (7,056 obs), and all 16 affected tools re-run — zero conclusion changes.

2 · yfinance timezone-concat bug

Caching concatenated a tz-aware cached index with a tz-naive fresh yf.download() index, corrupting the index and crashing validation. Fixed by localizing new data to UTC before concat. Caught while building the Macro Filter; earlier runs were BTC-only and unaffected.

3 · Sortino sign-inversion bug

evaluate_risk_input's comparison divided two negative Sortinos, inverting the direction of "improvement" and wrongly failing the ≥0.9 bar. Guarded in the ATR and Realized-Vol runners. This flipped Realized Vol from a false Rejected to the correct Validated — and is why "always inspect the underlying numbers" is a project rule.

What is NOT in the pipeline

17 of 62 tools are data-blocked. The gaps fall into four families — each with the fix that would unblock it. The Results table lists every blocked tool with its specific gap; the Findings page has the taxonomy.

Tick / L2 order-book data

Order Book Depth Analysis, Tick-Rule Trade Classification, Order Book Imbalance, VPIN / Kyle's Lambda, and the honest test of the Market Impact Model all need historical quote/tick/fill data. A vendor (Tardis.dev / Kaiko / CryptoTick) or a forward-collection polling process would close this.

Point-in-time fundamentals

Price-to-Book, P/E, NVT/MVRV, and the entire Quality element need historical, point-in-time cross-sectional fundamentals (EPS, book value, ROE, margins, debt/equity). yfinance only exposes current snapshots — except dividends, which is exactly why Yield-Based Valuation was testable.

Rates, curves & event calendars

FX interest-rate differential carry, dividend-yield carry, futures roll yield, and earnings-cycle seasonality are rate/fundamental/event-calendar quantities with no price-only proxy.

Options & news

Put/Call Ratio needs options market data; News/Social NLP Sentiment needs a news corpus + NLP infra; Analyst Revision Tracking needs analyst estimates.