Description
Build a complete market data subsystem for FinAlly supporting both a GBM simulator (default) and Massive API (real market data) via a unified interface.
Status: Architecture complete. Production-ready implementation required.
Components to Build
1. Massive API Interface (backend/app/market/massive_client.py)
Implement a REST client for the Massive (Polygon.io) API that:
- Polls the snapshot endpoint for all watched tickers in a single API call
- Handles rate limits (free tier: 5 req/min → poll every 15s; paid tiers: faster)
- Runs synchronously in
asyncio.to_thread() to avoid blocking the event loop
- Implements the
MarketDataSource abstract interface
- Includes error handling for invalid API keys, rate limits, and malformed responses
- Gracefully recovers from failures without stopping the poller
Key methods:
start(tickers) - Begin polling with initial tickers
stop() - Stop polling and clean up
add_ticker(ticker) - Add ticker to active set
remove_ticker(ticker) - Remove ticker from active set
get_tickers() - Return current list of tracked tickers
Configuration:
- API key via
MASSIVE_API_KEY environment variable
- Poll interval: 15s for free tier (configurable for paid tiers)
2. Unified Market Interface (backend/app/market/)
Implement a complete abstraction layer with:
Data Model (models.py):
PriceUpdate - Immutable frozen dataclass with ticker, price, previous_price, timestamp, change, direction
- Computed properties for change percentage and direction
- Serialization method for SSE transmission
Abstract Interface (interface.py):
MarketDataSource ABC defining start/stop/add_ticker/remove_ticker/get_tickers
- Enables both simulator and Massive implementations to be source-agnostic
Price Cache (cache.py):
- Thread-safe in-memory store for latest prices per ticker
- Version counter for efficient SSE change detection
- Methods: update, get, get_all, get_price, remove
Factory (factory.py):
create_market_data_source() - Selects simulator or Massive based on MASSIVE_API_KEY env var
- Lazy imports to avoid unnecessary dependencies
SSE Streaming (stream.py):
create_stream_router() - FastAPI router factory for /api/stream/prices endpoint
- Version-based change detection to avoid redundant sends
- Auto-reconnection support via EventSource retry directive
Package Export (__init__.py):
- Clean public API:
PriceUpdate, PriceCache, MarketDataSource, create_market_data_source, create_stream_router
3. Market Data Simulator (backend/app/market/simulator.py)
Implement a Geometric Brownian Motion (GBM) simulator with:
Seed Prices & Parameters (seed_prices.py):
- Realistic starting prices for 10 default tickers (AAPL, GOOGL, MSFT, AMZN, TSLA, NVDA, META, JPM, V, NFLX)
- Per-ticker GBM drift (mu) and volatility (sigma) parameters
- Sector-based correlation groups (tech, finance)
- Correlation coefficients for intra-group and cross-group moves
GBM Simulator Engine (simulator.py):
- Geometric Brownian Motion:
S(t+dt) = S(t) * exp((mu - sigma²/2)*dt + sigma*sqrt(dt)*Z)
- Cholesky decomposition of correlation matrix for realistic correlated moves
- Random shock events (~0.1% per tick) for 2-5% sudden moves (visual drama)
- Time step: 500ms ticks; 252 trading days/year normalization
- Supports dynamic ticker add/remove with automatic correlation recalculation
SimulatorDataSource Implementation:
- Implements
MarketDataSource interface
- Background asyncio loop stepping the simulator every 500ms
- Seeds cache with initial prices on startup
- Exception resilience (one bad tick doesn't kill the feed)
- Graceful cancellation and cleanup
Architecture
PriceCache (Thread-safe In-Memory Store)
↑ ↑ ↓
Writes Writes Reads
│ │ │
┌─────────────┐ ┌────────────────┐ ┌──────────────┐
│ Simulator │ │ Massive Client │ │ SSE Endpoint │
│ (GBM) │ │ (REST Poller) │ │ (Generator) │
└─────────────┘ └────────────────┘ └──────────────┘
Both data sources implement MarketDataSource ABC and write to a shared PriceCache. The SSE endpoint reads from the cache and streams to connected clients.
Environment Variables
| Variable |
Default |
Description |
MASSIVE_API_KEY |
"" (empty) |
If set, use Massive; otherwise use simulator |
Testing Requirements
Unit Tests (73 tests target, 84% coverage):
test_models.py - PriceUpdate dataclass and properties
test_cache.py - PriceCache thread safety and version counter
test_simulator.py - GBM math, price positivity, correlation matrix
test_simulator_source.py - SimulatorDataSource lifecycle and ticker management
test_factory.py - Environment-based source selection
test_massive.py - Massive API client with mocked responses
Integration Tests:
- SSE endpoint with mock client
- Cholesky decomposition for all 10 default tickers
- Error cases (invalid API key, malformed responses, network failures)
- Ticker add/remove during runtime
Demo (Optional):
backend/market_data_demo.py - Rich terminal dashboard showing live prices, sparklines, and event log
Deliverables
Related Documentation
Description
Build a complete market data subsystem for FinAlly supporting both a GBM simulator (default) and Massive API (real market data) via a unified interface.
Status: Architecture complete. Production-ready implementation required.
Components to Build
1. Massive API Interface (
backend/app/market/massive_client.py)Implement a REST client for the Massive (Polygon.io) API that:
asyncio.to_thread()to avoid blocking the event loopMarketDataSourceabstract interfaceKey methods:
start(tickers)- Begin polling with initial tickersstop()- Stop polling and clean upadd_ticker(ticker)- Add ticker to active setremove_ticker(ticker)- Remove ticker from active setget_tickers()- Return current list of tracked tickersConfiguration:
MASSIVE_API_KEYenvironment variable2. Unified Market Interface (
backend/app/market/)Implement a complete abstraction layer with:
Data Model (
models.py):PriceUpdate- Immutable frozen dataclass with ticker, price, previous_price, timestamp, change, directionAbstract Interface (
interface.py):MarketDataSourceABC defining start/stop/add_ticker/remove_ticker/get_tickersPrice Cache (
cache.py):Factory (
factory.py):create_market_data_source()- Selects simulator or Massive based onMASSIVE_API_KEYenv varSSE Streaming (
stream.py):create_stream_router()- FastAPI router factory for/api/stream/pricesendpointPackage Export (
__init__.py):PriceUpdate,PriceCache,MarketDataSource,create_market_data_source,create_stream_router3. Market Data Simulator (
backend/app/market/simulator.py)Implement a Geometric Brownian Motion (GBM) simulator with:
Seed Prices & Parameters (
seed_prices.py):GBM Simulator Engine (
simulator.py):S(t+dt) = S(t) * exp((mu - sigma²/2)*dt + sigma*sqrt(dt)*Z)SimulatorDataSource Implementation:
MarketDataSourceinterfaceArchitecture
Both data sources implement
MarketDataSourceABC and write to a sharedPriceCache. The SSE endpoint reads from the cache and streams to connected clients.Environment Variables
MASSIVE_API_KEY""(empty)Testing Requirements
Unit Tests (73 tests target, 84% coverage):
test_models.py- PriceUpdate dataclass and propertiestest_cache.py- PriceCache thread safety and version countertest_simulator.py- GBM math, price positivity, correlation matrixtest_simulator_source.py- SimulatorDataSource lifecycle and ticker managementtest_factory.py- Environment-based source selectiontest_massive.py- Massive API client with mocked responsesIntegration Tests:
Demo (Optional):
backend/market_data_demo.py- Rich terminal dashboard showing live prices, sparklines, and event logDeliverables
backend/app/market/module structure (8 files, ~500 lines)backend/pyproject.toml(numpy, massive).env.exampleupdated withMASSIVE_API_KEYbackend/app/main.py(lifespan context manager)Related Documentation
planning/PLAN.md- Full project specificationplanning/MARKET_DATA_DESIGN.md- Complete implementation guide with code examplesplanning/archive/MASSIVE_API.md- Massive API referenceplanning/archive/MARKET_INTERFACE.md- Interface design patterns