Adds BacktestAlpacaSource so saved trade plans for US equities can be
backtested without manual CSV upload. Mirrors the existing Kraken
loader pattern.
Backend:
+ backend/src/backtest/data/alpacaLoader.ts
loadDatasetFromAlpaca({ symbols, fromTs, toTs, feed, adjustment })
- Uses the existing @alpacahq/alpaca-trade-api SDK
- Fetches 15Min bars; normalize.ts aggregates 1h/4h
- 50-day warm-up lookback so ProEngine has enough EMA/RSI history
- Throws cleanly with config guidance if ALPACA_API_KEY missing
- In-memory cache keyed by (symbol, window, feed, adjustment)
~ backend/src/backtest/types.ts
+ BacktestAlpacaSource interface
+ 'alpaca' added to BacktestDataSource and BacktestDataSourceType
~ backend/src/backtest/data/loadHistoricalData.ts
Wires 'alpaca' source into the dispatcher
Frontend:
~ web/src/backtest/types.ts — adds 'alpaca' to BacktestDataSourceType
~ web/src/backtest/components/BacktestConfigurator.tsx
+ 'alpaca' as a SourceType option
+ AUTO_FETCH_SOURCES list — kraken AND alpaca skip the upload-required
validation
+ 'Alpaca (US equities)' option in the source-picker dropdown
+ Source-picker change handler seeds default IEX/raw Alpaca payload
Tests:
+ testBacktestEngine.ts: new "alpaca data source dispatcher" assertion
Verifies the type discriminator + error message without hitting
the network. 11/11 regression checks pass.
Caveats (documented in alpacaLoader inline + ENGINE_READINESS.md §3.4):
- Free IEX feed has limited symbol coverage (~2016+)
- SIP feed (paid) needed for full pre-2017 + full-market historical
- The loader graceful-fails when credentials aren't configured
- Existing Alpaca live-trading connector unchanged — backtest uses
its own SDK instance with a different fetch path
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Adds testBacktestEngine.ts — the minimum viable test set called out in
docs/backtest/ENGINE_READINESS.md §3.1. Codifies behaviors verified
during the readiness audit so they don't silently regress.
Coverage (10 assertions, all passing):
Unit (testable building blocks):
- aggregateCandles 15m→1h: OHLC preserved, volume summed
- aggregateCandles 15m→4h: OHLC preserved, volume summed
- computeSummary: hand-computed PnL/winRate/drawdown match
- computeSummary: empty inputs → all zeros (no NaN/Infinity)
- computeSharpe: single-point timeline → 0 (no divide-by-zero)
- withLogLevel: level restored after success AND after throw
Integration (full runBacktest):
- Determinism: same input → byte-identical JSON output
- Flat-price tape → 0 trades, 0 PnL, 0 drawdown
- Result shape contract: all documented top-level keys present
- Empty candle dataset throws explicitly (no silent 0-trade result)
Conforms to the existing testXxx.ts convention used by the other
check:backtest-* scripts. Wired into package.json:
- "check:backtest-engine": "node --import tsx testBacktestEngine.ts"
- chained into the top-level "test" script
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>