feat: real data pipeline — market data, DB persistence, portfolio sync, signal-trade linkage

Wire the trading bot to real Alpaca market data and persist pipeline
state to the database so the dashboard displays live information.

- Add market-data service fetching OHLCV bars from Alpaca, publishing
  to market:bars Redis Stream; signal generator consumes bars and
  injects current_price into signals for position sizing
- Sentiment analyzer now persists Article + ArticleSentiment rows to
  DB after scoring, with duplicate and error handling
- API gateway runs a background portfolio sync task that snapshots
  Alpaca account state into PortfolioSnapshot/Position DB tables
  during market hours
- TradeSignal carries a signal_id UUID; signal generator and trade
  executor both persist their records to DB with cross-references
- 303 unit tests pass (57 new tests added)
This commit is contained in:
Viktor Barzin 2026-02-22 19:52:45 +00:00
parent 5a6b20c8f1
commit e2a3bd456d
No known key found for this signature in database
GPG key ID: 0EB088298288D958
19 changed files with 2238 additions and 72 deletions

View file

@ -2,6 +2,7 @@
from __future__ import annotations
import asyncio
import logging
from contextlib import asynccontextmanager
from typing import AsyncIterator
@ -43,9 +44,23 @@ def create_app(config: ApiGatewayConfig | None = None) -> FastAPI:
)
app.state.config = config
# Start portfolio sync background task
from services.api_gateway.tasks.portfolio_sync import portfolio_sync_loop
sync_task = asyncio.create_task(
portfolio_sync_loop(config, session_factory)
)
logger.info("API Gateway started")
yield
# Cancel the sync task
sync_task.cancel()
try:
await sync_task
except asyncio.CancelledError:
pass
# Cleanup
await app.state.redis.aclose()
await engine.dispose()