Commit Graph

91 Commits

Author SHA1 Message Date
Devin
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>
2026-05-10 10:59:06 +00:00
Devin
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>
2026-05-10 10:46:45 +00:00
Devin
3c3dce6b73 feat(backend): quiet-mode logging for backtest runs (Stage D)
Backtest runs were emitting ~25k log lines per 5k-candle backtest at
default 'info' level (~5 logs per candle from rule evaluations). At
year-scale that's 80k+ lines per run — operationally disruptive and
likely the reason the production gate was set conservatively.

Changes:
  - utils/logger.ts: respect LOG_LEVEL env override (no behavior change
    when unset). Add `withLogLevel(level, fn)` helper that swaps the
    logger level for the duration of a function and always restores it
    via finally — safe across throws.
  - backtest/index.ts: wrap runBacktestReplay() in withLogLevel('warn').
    New `logLevel?: string` option on RunBacktestOptions lets callers
    override (e.g. 'info' or 'debug' for engine diagnosis).

Verified:
  - 2,000-candle run: 25,000 → 3 log lines at default
  - 500-candle run with logLevel='info': 3,202 lines (verbose still works)
  - Logger.level correctly restored after both successful runs and
    failed runs that throw (assertBacktestMode rejection test)
  - No regression: logger initial level honors LOG_LEVEL env or 'info'

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 10:44:30 +00:00
root
f463ff64de fix(web): global layout fixes for overlap, clipping, responsive reflow
Adds web/src/layout-fixes.css imported once from main.tsx — surgical
overrides applied with !important so they win against the existing
3000+ line index.css without rewriting it.

Issues fixed:
1. Modals/popovers/dropdowns clipped by .dashboard-main { overflow: hidden }
   → now overflow: visible. Stacking context guard for [role=dialog].
2. Right panel (308px fixed) covers main content on laptop/tablet
   → 260px below 1280px, hidden below 1024px.
3. Tables extending off-screen
   → .dashboard-content table wrapped with display:block + overflow-x:auto
   so they scroll inside their column. Also exposes .scroll-x utility.
4. Header search/indices push each other off-screen
   → flex-wrap on .trading-header, search shrinks to 240–360px range,
   indices wrap with smaller column gap on narrow.
5. Long unbreakable strings (commit SHAs, URLs) escaping containers
   → overflow-wrap: anywhere + word-break: break-word + pre-wrap on <pre>.
6. Sidebar 76px doesn't collapse on mobile
   → 56px below 768px with reduced content padding.

Bumps @bytelyst/devops to ^0.1.3 (responsive panel) in backend + web.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 07:14:50 +00:00
root
4763a9a9d1 feat(devops): admin-only info, public version, dep checks, role hardening
Backend:
- /api/devops/info now requires admin role (was: any authenticated user).
  Exposes env keys, dep checks, and socket counts — admin-only by design.
- New /api/devops/version (public, no auth) returns build SHA/branch/image
  for ops/CI rollback verification.
- Dep checks: live ping for Cosmos (trading_users) and platform-service.
- Service version read dynamically via readServiceVersion(import.meta.url)
  — no more hardcoded '0.1.0'.
- extra: socketIoConnections + tradingApiUrl for runtime debugging.
- saveCurrentUserProfile no longer accepts client-supplied role —
  prevents drift with platform JWT (which is authoritative).

Web:
- DevOps tab is now admin-only (gated behind isAdmin like Bot Config and
  Admin Panel). Both the section list and content render are guarded.
- Service version baked into bundle via Vite `define` (__WEB_SERVICE_VERSION__)
  read from web/package.json — no more hardcoded VERSION constant.
- Bumps @bytelyst/devops dep to ^0.1.2.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 05:52:48 +00:00
root
74400fda70 feat: migrate web to Gitea registry, add /api/devops/info, fix role drift
Backend:
- Fix role drift: /api/me/profile now returns JWT role authoritatively (was reading
  drifting role from trading_users). PATCH strips client-supplied role.
- Add /api/devops/info endpoint backed by @bytelyst/devops/server.
- Dockerfile: bake BYTELYST_COMMIT_SHA / BYTELYST_BUILT_AT / etc. as build args.

Web:
- Migrate from vendor/ + .pnpmfile.cjs to Gitea npm registry (consistency with backend).
- Replace file: refs in web/package.json with semver ranges resolved from Gitea.
- Drop vendor/bytelyst/* tree and .pnpmfile.cjs.
- Add DevOpsTab in Settings using @bytelyst/devops/ui (tabbed: Build/Runtime/Config/Deps/Raw).
- Vite alias: restrict @bytelyst/* catch-all to single-segment names so subpath
  imports (@bytelyst/devops/ui) resolve via package exports map.
- Bake BYTELYST_* metadata into the bundle as VITE_BYTELYST_* env.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 04:57:09 +00:00
root
15d9eeef12 fix(docker): use shared docker-prep.sh, add UI components, remove pnpmfile
Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 01:50:55 +00:00
root
127be5755c revert(docker): revert to vendor approach for trading repo
The base image approach was reverted for notes and clock due to workspace
complexity. The trading repo was still using the base image approach
which is causing build failures. Reverting to the vendor approach
which works reliably for the monorepo structure.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 00:55:54 +00:00
root
a586d3e158 refactor(docker): use shared base images for @bytelyst/* packages
Update Dockerfiles to use bytelyst-common-base-backend and bytelyst-common-base-web
images instead of installing @bytelyst/* packages via vendor directory.

Benefits:
- Smaller final images (~50MB vs ~250MB)
- Faster builds (base image cached)
- Consistent package versions across products
- No need for vendor/ directory maintenance

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-10 00:27:17 +00:00
4c658694f0 chore: enforce local ByteLyst package resolution 2026-05-08 21:09:14 -07:00
root
b4f68725ef chore(chat): harden pipeline and deploy flow 2026-05-07 08:24:44 +00:00
root
1a794d2365 feat(chat): add structured copilot insights 2026-05-07 08:03:08 +00:00
root
8fd5fbae3c test(chat): add copilot contract coverage 2026-05-07 07:42:05 +00:00
root
8adc27004d feat(chat): add copilot quick links 2026-05-07 07:40:20 +00:00
root
73db534d7d feat(chat): add guided next actions 2026-05-07 07:25:00 +00:00
root
3f73310b4e feat(chat): explain waiting trade signals 2026-05-07 06:59:40 +00:00
root
f3dfe31d1f feat(chat): add runtime copilot explanations 2026-05-07 06:58:11 +00:00
root
a1a63cc945 feat(simple): add long-term hold mode 2026-05-06 17:37:04 +00:00
root
0b526f3499 feat(simple): add setup activity history 2026-05-06 17:23:45 +00:00
root
e853ffc0c5 fix(api): reconcile simple setup state on order sync 2026-05-06 17:07:13 +00:00
root
62804ed4e5 feat(simple): add lifecycle toast notifications 2026-05-06 16:56:01 +00:00
root
d8941c5ad0 fix(api): auto-close dust exit remainders 2026-05-06 16:39:21 +00:00
root
92747b76a7 fix(simple): support concurrent symbol setups 2026-05-06 07:56:03 +00:00
root
e50e906866 fix(simple): dedupe exit retries per scan 2026-05-06 07:36:09 +00:00
root
349cdae4a6 fix(simple): support crypto fallback and scale-in entries 2026-05-06 07:33:52 +00:00
root
e92236b764 fix(simple): rebind armed buys to existing holdings 2026-05-06 07:23:03 +00:00
root
f57f0fc205 test(api): align market data contract checks 2026-05-06 07:08:18 +00:00
root
3d505db8d8 feat(simple): add amount sizing and runtime status 2026-05-06 07:04:48 +00:00
root
dad47fc13d fix(simple): prefer available user alpaca creds 2026-05-06 06:40:49 +00:00
root
b690f26a28 fix(simple): refresh user keys for profile sync 2026-05-06 06:35:07 +00:00
root
e01f38c883 fix(simple): allow immediate buy triggers 2026-05-06 06:09:16 +00:00
root
90e733b46c feat(simple): save dip-buy and profit-exit setups 2026-05-06 02:14:32 +00:00
root
0bd46ab43b feat(simple): auto-create dedicated execution profile 2026-05-06 01:29:45 +00:00
root
0f74d7b292 fix(portfolio): tighten bootstrap and manual position handling 2026-05-05 23:31:33 +00:00
root
160920ea07 fix(api): migrate fmp routes to stable endpoints 2026-05-05 23:21:27 +00:00
root
0c0cc93f57 fix(api): require user fmp api key 2026-05-05 23:14:04 +00:00
root
39456473cb feat(settings): add per-user fmp api key 2026-05-05 23:08:31 +00:00
root
adfadd824b fix(api): prefer paper alpaca keys for market data 2026-05-05 22:47:13 +00:00
root
351412423f fix(api): use user alpaca keys for market data 2026-05-05 22:40:06 +00:00
root
3867b6b296 fix(api): return 503 for missing fmp config 2026-05-05 22:20:10 +00:00
root
2db27ef686 fix(auth): handle null platform token verification 2026-05-05 21:19:28 +00:00
root
2a510ded83 fix(docker): vendor platform packages for container builds 2026-05-05 20:31:48 +00:00
root
1bd0297066 chore(build): add switchable bytelyst package source 2026-05-05 19:47:41 +00:00
e2e189eede fix(C7): mitigate FMP key exposure 2026-05-04 17:07:52 -07:00
1377bf2453 fix(C6): require explicit FMP API key
Remove the silent shared demo-key fallback for FMP-backed research and screener routes, document the required key, and make backend/.env.example trackable so setup guidance has one source of truth.

Refs: docs/AUDIT_REDESIGN.md item C6.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
2026-05-04 17:01:00 -07:00
7c4b08cdd5 fix(C4): validate news symbol filters
Normalize and limit /api/news symbols before proxying to Alpaca so only bounded, expected symbol characters reach the upstream news endpoint.

Refs: docs/AUDIT_REDESIGN.md item C4.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
2026-05-04 16:47:24 -07:00
c173aeb87a fix(C3): validate screener sector filters
Reject unsupported /api/screener sector values before building the FMP query so only known sector labels reach the upstream stock screener.

Refs: docs/AUDIT_REDESIGN.md item C3.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
2026-05-04 16:44:33 -07:00
6aa001a530 fix(C1): refuse unsafe code strategy backtests
Reject inline JavaScript strategy payloads before backtest execution, both at the API boundary and inside runBacktest, so saved profiles and direct internal calls cannot route unsandboxed code into replay handling.

Refs: docs/AUDIT_REDESIGN.md item C1.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
2026-05-04 16:31:04 -07:00
e2806b28c1 test(F6): cover market data proxy endpoints
Add static contract coverage for the dashboard market data and research proxy routes so auth, upstream URL construction, response normalization, and FMP cache usage stay guarded by the backend test gate.

Refs: docs/AUDIT_REDESIGN.md item F6.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
2026-05-04 16:25:44 -07:00
412fa5ad7c fix(audit): close agent follow-up gaps
Centralize the HomeView research profile fetch so the ticker header and research cards share one FMP profile request, preserving the B3 company-name behavior without doubling profile traffic. Wire the FMP cache regression into the backend test script and fix the stale API-contract shared import so backend tests can run through the new cache check.

Refs: docs/AUDIT_REDESIGN.md items B2, B3, and C2.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
2026-05-04 16:18:21 -07:00