main
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4fc53703c6 |
feat(backtest): runtime + per-user feature flags (Option C)
Replaces the build-time VITE_BACKTEST_ENABLED gate with a fully runtime
flow: a global Cosmos-backed default (already shipped in the existing
dynamicConfig system) plus a new per-user override layer. An admin can
now enable backtest for specific users without flipping the global
switch — useful for staged rollout and beta testers.
Resolution order: per-user override > global config > env fallback.
Both /api/feature-flags (FE display) and /api/backtest/run (server
guard) consult the same merge logic.
Backend (backend/src/...):
~ services/profileRepository.ts
+ TradingUserFeatureFlags interface
+ featureFlags?: TradingUserFeatureFlags on TradingUserProfile
+ setUserFeatureFlags(userId, { backtestEnabled, ... })
~ saveCurrentUserProfile() — strip role + featureFlags from input
so non-admins can't elevate via PATCH /api/me/profile
~ mergeTradingUserProfiles() — preserves explicit flag values only
~ services/apiServer.ts
~ /api/feature-flags merges per-user override into the response
+ /api/admin/users/:userId/feature-flags (GET — overrides + effective)
+ /api/admin/users/:userId/feature-flags (PATCH — admin-only writer)
~ /api/backtest/run resolves effective flags before guarding
~ backtest/index.ts
+ RunBacktestOptions.skipGlobalFeatureFlagCheck
~ runBacktest() honors the override (route already gated stricter)
Frontend (web/src/...):
~ backtest/flags.ts — isBacktestBuildEnabled() now returns true.
Kept as a no-op function so existing callers don't break.
+ lib/userFeatureFlagsApi.ts — typed admin client
+ components/admin/UserFeatureFlagsPanel.tsx
Tri-state picker per flag (Default / On / Off), Look up by user id,
Save/Reset, shows the merged "effective" value.
~ tabs/ConfigTab.tsx — mounts <UserFeatureFlagsPanel /> below the
existing global Backtest Access Control section.
~ layout-fixes.css §27 — styles for the per-user panel.
Tests:
+ testBacktestEngine: skipGlobalFeatureFlagCheck enables per-user
override semantics. 12/12 regression checks pass.
Security note: featureFlags + role are explicitly stripped from
saveCurrentUserProfile input. Only the admin-only PATCH endpoint can
set per-user overrides.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
||
|
|
4456873ab4 |
feat(backtest): Alpaca historical data source for equities (Stage C)
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>
|
||
|
|
35efa786bd |
test(backend): backtest engine regression suite (Stage B)
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>
|