A production-ready, cloud-native algorithmic trading platform built with modern data engineering and ML technologies. Real-time crypto market data processing, strategy backtesting, and automated trading execution.
This platform demonstrates advanced technical skills in:
- Stream Processing: Real-time market data ingestion and processing
- Time-Series Analytics: High-performance OLAP queries on billions of ticks
- Machine Learning: Price prediction and trading signal generation
- Distributed Systems: Event-driven microservices architecture
- Cloud-Native Development: LocalStack for AWS services, managed databases
- DevOps: Infrastructure as Code, local β cloud portability
Tech Stack:
- Streaming & Messaging: Kafka (data streaming), RabbitMQ (task queues), Kinesis (AWS alternative)
- Storage: S3 (LocalStack), ClickHouse (time-series), Redis (cache), PostgreSQL (metadata)
- Application Layer: FastAPI, Python, AsyncIO, MLflow, Jupyter
- Monitoring: Grafana, Prometheus
- Cloud Services (LocalStack): Lambda, DynamoDB, EventBridge, SQS
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DATA STREAMING (Kafka) β
β Exchange WebSockets β Kafka β [S3, ClickHouse, Redis] β
β β’ High throughput (60+ symbols) β
β β’ Message replay for backtesting β
β β’ Multiple consumers (analytics, ML) β
β β’ 24h retention β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β TASK QUEUES (RabbitMQ) β
β Trading API β RabbitMQ β Workers β
β β’ Order execution (priority queues) β
β β’ Backtest jobs (parallel workers) β
β β’ Notifications (email, telegram) β
β β’ Dead letter queues for failures β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Exchange REST API (ccxt) Exchange WebSocket (Binance/Coinbase/Kraken)
β β
Sync Service (every 60s) Market Data Ingestion Service
- Initial backfill: 100 candles - 60+ symbols, real-time trades
- Regular sync: 5 latest candles - Samples ~4% of trades
β β
ClickHouse (candles_1m/5m/1h) Redis (latest_price:{exchange}:{symbol})
ReplacingMergeTree, TTL 90d Real-time signals for Phase 3+
β
Indicator Service (every 60s + 10s delay)
- Catch-up mode: all historical candles on startup
- Calculates: SMA 20/50, EMA 12/26, RSI 14, MACD
- Stores: ClickHouse (indicators) + Redis (60s TTL)
β
Grafana (technical-analysis.json)
βββ 4 panels: Price+Indicators, RSI, MACD, Volume
Trading API (FastAPI) β RabbitMQ β Workers
β
βββ Strategy Engine
βββ ML Pipeline (Jupyter)
βββ Grafana (Docker) - Monitoring
βββ Prometheus - Metrics collection
Replace LocalStack endpoints with real AWS services
- LocalStack S3 β AWS S3
- LocalStack Kinesis β AWS Kinesis
- LocalStack Lambda β AWS Lambda
- Docker ClickHouse β ClickHouse Cloud
- Docker Redis β AWS ElastiCache
DataPlatform/
β
βββ π config/ # Configuration Management
β βββ settings.py # Pydantic Settings (from .env + YAML)
β βββ loader.py # YAML config loaders
β βββ providers/ # Per-service YAML configs
β βββ databases.yaml # ClickHouse, Redis, PostgreSQL
β βββ exchanges.yaml # WebSocket + REST API per exchange
β βββ indicators.yaml # Indicator definitions + service settings
β βββ streaming.yaml # Kafka/Kinesis topics
β βββ storage.yaml # S3/GCS object storage
β βββ sync.yaml # Sync Service timing + REST API config
β
βββ π core/ # Core Abstractions (Cloud-agnostic)
β βββ interfaces/ # Abstract Base Classes
β β βββ cache.py # BaseCacheClient (Redis, Memcached)
β β βββ database.py # BaseTimeSeriesDB (ClickHouse, TimescaleDB)
β β βββ market_data.py # BaseExchangeWebSocket + BaseExchangeRestAPI
β β βββ indicators.py # BaseIndicator
β β βββ storage.py # BaseStorageClient (S3, GCS)
β β βββ streaming_producer.py # BaseStreamProducer (Kafka, Kinesis)
β β βββ streaming_consumer.py # BaseStreamConsumer
β βββ models/
β β βββ market_data.py # Trade, Candle, OrderBook (Pydantic)
β βββ validators/
β β βββ market_data.py # Spike detection, crossed book checks
β βββ utils/
β βββ config.py # load_yaml_safe()
β
βββ π providers/ # Cloud Provider Implementations
β βββ aws/
β β βββ kinesis.py # KinesisStreamProducer
β β βββ s3.py # S3StorageClient
β βββ opensource/
β β βββ clickhouse.py # ClickHouseClient (connection pool)
β β βββ redis_client.py # RedisClient (queued writes)
β β βββ kafka_stream_producer.py # KafkaStreamProducer
β βββ binance/
β β βββ websocket.py # BinanceWebSocket
β β βββ rest_api.py # BinanceRestAPI (ccxt)
β βββ coinbase/
β β βββ websocket.py # CoinbaseWebSocket
β β βββ rest_api.py # CoinbaseRestAPI (ccxt)
β βββ kraken/
β βββ websocket.py # KrakenWebSocket
β βββ rest_api.py # KrakenRestAPI (ccxt)
β
βββ π factory/
β βββ client_factory.py # create_exchange_rest_api(), create_timeseries_db(), etc.
β
βββ π domain/ # Business Logic
β βββ indicators/
β βββ moving_averages.py # SMA, EMA, WMA
β βββ momentum.py # RSI, MACD, Stochastic
β βββ registry.py # Load indicators from config
β
βββ π services/ # Microservices (Phase 2)
β βββ market_data_ingestion/ # WebSocket β Redis (real-time signals)
β β βββ main.py
β β βββ stream_processor.py
β β βββ websocket_client.py
β βββ sync_service/ # REST API β ClickHouse (authoritative candles)
β β βββ main.py # Runs every 60s, backfills 100 candles on startup
β βββ indicator_service/ # ClickHouse β Calculate β Redis + ClickHouse
β βββ main.py # Runs every 60s (+10s delay after sync)
β βββ calculator.py
β βββ persistence.py
β βββ indicator_loader.py
β
βββ π infrastructure/
β βββ docker/
β β βββ docker-compose.yml # ClickHouse, Redis, PostgreSQL, Grafana
β β βββ clickhouse/
β β βββ init-and-migrate.sh # Auto-applies migrations on startup
β β βββ migrations/ # 000β006 SQL migrations
β βββ terraform/ # LocalStack (S3, Kinesis)
β
βββ π monitoring/
β βββ grafana/
β βββ dashboards/
β β βββ technical-analysis.json # Price+Indicators, RSI, MACD, Volume
β βββ provisioning/
β βββ datasources.yml # ClickHouse, Prometheus, PostgreSQL
β
βββ π tests/
β βββ unit/ # 183 tests, no Docker required
β β βββ indicators/ # SMA, EMA, RSI, MACD
β β βββ services/ # stream_processor, websocket_client
β β βββ test_config/ # Settings Phase 2
β β βββ test_providers/ # ClickHouse pool, queued cache/db/streaming, REST API
β β βββ test_services/ # indicator calculator + persistence
β β βββ test_factory.py
β β βββ test_models.py
β βββ integration/ # Requires Docker + Terraform
β βββ pipelines/ # End-to-end pipeline tests
β βββ infrastructure/ # ClickHouse, Redis, Docker readiness
β βββ idempotency/ # Candle/indicator/cache quality
β βββ factory/ # Exchange factory + REST API network
β
βββ π docs/
β βββ DOCKER_SETUP.md
β βββ TERRAFORM_SETUP.md
β βββ KINESIS_VS_KAFKA.md # Architecture decision record
β βββ COMPARISON.md
β βββ WHEN_TO_USE_CLOUD_DB.md
β
βββ .env.example # Environment template
βββ .gitignore
βββ pyproject.toml # uv dependencies
βββ Makefile # docker-up/down, terraform-apply, etc.
βββ CLAUDE.md # AI assistant context + architecture guide
1. Separation of Concerns:
core/interfaces/- Abstract contracts (cloud-agnostic)providers/- Concrete implementations (AWS, GCP, Azure, LocalStack)factory/- Auto-create clients based on configdomain/- Business logic (trading strategies, NOT cloud code)services/- Microservices (API, ingestion, strategy engine)
2. Dependency Flow:
services/ β domain/ β factory/ β providers/ β core/interfaces/
β
config/
3. Cloud Portability:
- Code in
services/anddomain/is 100% cloud-agnostic - Switch clouds by changing
.envfile only - No vendor lock-in
4. Testability:
- Mock implementations of
core/interfaces/for testing - Fixtures in
tests/fixtures/ - Separate unit and integration tests
Mapping hiα»n trαΊ‘ng vΓ o 5 lα»p workflow cα»§a quα»Ή Δα»nh lượng:
Layer 1 β Data Infrastructure ββββββββββ β
Complete
Multi-exchange WebSocket + REST API, ClickHouse OHLCV,
Redis cache, PostgreSQL paper trading, MLflow artifacts
Layer 2 β Feature / Factor Eng. ββββββββββ ~40%
10 regime features + 16 sizing features (price-based only)
Missing: funding rate, open interest, cross-asset, alternative data
β Phase 8C target
Layer 3 β Alpha Validation ββββββββββ ~30%
Backtest engine + walk-forward runner exist
Missing: IC (information coefficient), decay analysis,
factor correlation matrix, signal quality filter
β Phase 8B target
Layer 4 β Portfolio Construction ββββββββββ ~80%
MVO optimizer, regime gates (Layer 1 + Layer 2),
meta-labeling filter, vol overlay, 4-slot MSAPE engine
Layer 5 β Risk & Execution ββββββββββ ~50%
RiskManager, PaperBroker, BacktestBroker
Missing: slippage model, market impact, execution algos
| Strategy | Symbol | Return | Sharpe | MaxDD | Trades |
|---|---|---|---|---|---|
volatility_breakout |
SOLUSDT | +7.11% | 0.580 | 3.50% | 234 |
volatility_breakout |
ETHUSDT | +3.92% | 0.575 | 1.60% | 232 |
volatility_breakout |
BTCUSDT | +0.78% | 0.142 | 2.50% | 248 |
sma_crossover |
ETHUSDT | +1.42% | 0.099 | 9.04% | 830 |
sma_crossover |
BTCUSDT | -1.27% | -0.070 | 7.00% | 862 |
rsi_mean_reversion |
ETHUSDT | -4.68% | -0.224 | 10.90% | 295 |
rsi_mean_reversion |
BTCUSDT | -6.75% | -0.465 | 8.67% | 254 |
ma_trend |
BTCUSDT | -7.89% | -0.678 | 8.38% | 1,561 |
volatility_breakout |
BNBUSDT | -5.56% | -0.884 | 6.16% | 246 |
adaptive_trend |
BTCUSDT | -12.92% | -0.747 | 16.97% | 2,187 |
lower_band_reversion |
BTCUSDT | -15.46% | -1.397 | 16.67% | 1,558 |
fade_breakout |
BTCUSDT | -13.93% | -2.106 | 14.33% | 1,594 |
Portfolio MSAPE β 4 slots, regime filter ON:
| Period | Return | Ann. | Sharpe | MaxDD | AvgLev |
|---|---|---|---|---|---|
| 2022β2026 (4yr) | +2.38% | +0.58%/yr | 0.295 | -2.56% | 1.47Γ |
| 2024 only | +2.58% | +2.90%/yr | 1.20 | -1.60% | 1.36Γ |
Key insight: ma_trend (1,561 trades β $1,512 commission) and adaptive_trend (2,187 trades β $2,082 commission) lose 14β20% of capital to fees. Regime filter cuts them to ~200 trades and turns Sharpe positive.
Goal: Stream live crypto market data into the system
- LocalStack setup (S3, Kinesis, Lambda)
- Docker Compose for stateful services (ClickHouse, Redis, Grafana, Kafka)
- WebSocket connection to Binance (BTC, ETH)
- Stream to Kafka/Kinesis β S3 (raw data backup)
- ClickHouse table:
trades(symbol, price, quantity, timestamp) - Grafana dashboard: Real-time price line chart
- Environment config:
.env+ YAML configs (cloud-agnostic)
- Multi-exchange support (Binance, Coinbase, Kraken)
- 60+ crypto symbols streaming (20+ per exchange)
- Order book depth data with quality validation
- Data quality validation (spike detection, crossed book checks)
- Kafka migration (KRaft mode, dual listeners)
- Cloud-agnostic architecture (factory pattern, generic naming)
- Comprehensive testing (62/62 tests passing: 46 unit, 16 integration)
- Git pre-push hooks (secrets detection, lint, format, tests)
- YAML-based configuration (public) + .env secrets (gitignored)
Services:
- Docker: Kafka, ClickHouse, Redis, PostgreSQL, Grafana, Prometheus
- LocalStack: S3, Kinesis (optional alternative to Kafka)
- Python: Market data ingestion service with async WebSocket clients
Tech Showcase:
- Cloud-Agnostic Design: Factory pattern, swappable providers (Kafka/Kinesis, S3/GCS, ClickHouse/TimescaleDB)
- Multi-Exchange Integration: Binance, Coinbase, Kraken with unified interface
- Kafka Streaming: KRaft mode, dual listeners (Docker + host), 24h retention
- Data Quality: Spike detection, order book validation, data validators
- Testing: 62/62 tests (unit + integration), pytest markers, timezone-aware
- DevOps: Git hooks, ruff linting/formatting, uv dependency management
- Monitoring: Grafana dashboards with multi-exchange metrics
Goal: Transform raw ticks into analytical datasets
- OHLCV candlesticks (1m, 5m, 1h) via REST API
- ClickHouse candle tables (direct inserts, no MVs)
- Technical indicators: SMA(20, 50), EMA(12, 26), RSI, MACD
- Redis caching for latest indicators
- Grafana technical analysis dashboard
- Advanced indicators: RSI, MACD with custom implementations
- Multiple timeframes (1m, 5m, 1h)
- Initial backfill (100 candles on startup)
- Catch-up mode (calculate indicators for all historical candles)
- Sequential processing (avoid ClickHouse connection conflicts)
Services:
- Redis (cache for indicators)
- ClickHouse (candles + indicators storage)
- NEW: Sync Service - Scheduled REST API klines fetching
- NEW: Indicator Service - Scheduled indicator calculation
Architecture: Industry Standard - Scheduled Jobs
Exchange REST API (authoritative OHLCV data)
β
Sync Service (every 60 seconds)
ββ Fetches latest klines via ccxt
ββ Initial backfill: 100 candles on startup
ββ Regular sync: 5 latest candles
ββ Stores in ClickHouse (candles_1m, 5m, 1h)
β
Indicator Service (every 60 seconds + 10s delay)
ββ Reads candles from ClickHouse
ββ Catch-up mode: Process all historical candles on startup
ββ Calculates: SMA 20/50, EMA 12/26, RSI, MACD
ββ Stores in ClickHouse (indicators table)
ββ Caches in Redis (60s TTL)
β
Grafana Dashboard
ββ 4-panel layout: Price+Indicators, RSI, MACD, Volume
Key Design Decisions:
- REST API over WebSocket: Exchange REST API provides authoritative, complete OHLCV data (WebSocket only captures ~4% of trades via sampling)
- Scheduled jobs over event-driven: Simple, predictable, easier to debug than Kafka consumers
- Sequential processing: Avoid ClickHouse single-connection conflicts (clickhouse_driver limitation)
- Catch-up mode: Calculate indicators for all backfilled data on startup
- No Materialized Views: Direct inserts from REST API, simpler schema
Tech Showcase:
- ccxt Integration: Unified exchange REST API abstraction (Binance, Coinbase, Kraken)
- BaseExchangeRestAPI Pattern: Cloud-agnostic REST API abstraction (mirrors WebSocket pattern)
- Scheduled Job Architecture: 60-second intervals, 10-second offset between services
- ClickHouse Optimization: Sequential queries to avoid connection conflicts
- Custom Indicator Implementation: SMA, EMA, RSI, MACD without TA-Lib dependency
- Grafana Advanced Visualization: Candlestick charts with indicator overlays, styled panels
- Initial Backfill + Catch-up: 100 candles fetched on startup, all historical data processed
Goal: Build API and strategy execution engine with paper trading simulator
- FastAPI REST endpoints:
GET /v1/prices/{exchange}/{symbol}- Latest price from RedisGET /v1/candles/{exchange}/{symbol}- OHLCV data from ClickHouseGET /v1/indicators/{exchange}/{symbol}- Technical indicators from RedisGET /v1/orders/POST /v1/orders- Order managementGET /v1/portfolio/GET /v1/positions- Portfolio state
- WebSocket endpoint: Real-time price streaming (
/ws/prices) - Strategy base class/interface (
BaseStrategy,Signalenum) - SMA Crossover strategy (
SMA_20 > SMA_50β BUY,SMA_20 < SMA_50β SELL) - RSI Mean Reversion strategy (
RSI < 30β BUY,RSI > 70β SELL) - Paper trading simulator (
PaperBrokerβ fills at live Redis price) - Risk management (
RiskManagerβ position sizing, daily loss limit) - PostgreSQL:
paper_orders,paper_positions,paper_portfolio_snapshots - Strategy Engine Service (60s polling loop, +20s delay after Indicator Service)
- Kafka audit trail:
trading.signals,trading.orders(write-only, no consumer) - Grafana portfolio dashboard: equity curve, open positions, recent trades, P&L by strategy
- Strategy hot-reload (no restart needed)
- Order types: Limit, Stop-Loss, Trailing Stop (Phase 3: market only)
- Position sizing: Kelly Criterion (Phase 3: flat 10% per position)
- Strategy parameter optimization via grid search (needs backtesting first)
- RabbitMQ task queues (deferred β no value for paper trading, added in Phase 4)
Architecture Decision β No RabbitMQ in Phase 3:
Paper trading has no unreliable external boundary (no real exchange calls, no retries, no burst). A task queue adds zero value. Instead:
InlineTaskQueueβ direct call, zero infra overhead- Phase 4 swaps to
RabbitMQTaskQueueby changing 1 line infactory/client_factory.py
Services:
- PostgreSQL (Docker) β source of truth for all paper trading state
- FastAPI (Python service) β REST + WebSocket, port 8000
- Strategy Engine (Python service) β 60s polling loop
- Kafka (existing) β audit trail only, no new consumers
Tech Showcase:
- Cloud-agnostic factory pattern (
BaseBroker,BaseOrderStore,BaseTaskQueue) - PostgreSQL as source of truth (no in-memory state β crash-safe)
- UUID generated at
OrderManagerβ idempotent retries, no double-fills - Mark-to-market equity curve:
cash + Ξ£(qty Γ live_price_redis)updated every 60s - WebSocket fan-out for real-time price streaming
- Kafka audit trail (fire-and-forget) for Phase 4 backtest replay
Goal: Test strategies against historical data with zero look-ahead bias
-
Backtesterβ fill at next-bar open, equity at current-bar close (intentional 1-bar lag) -
BacktestBroker/BacktestOrderStoreβ in-memory, mirrors paper trading accounting -
BacktestResult+compute_metricsβ Sharpe (annualized β8760), MaxDD, win rate - CLI runner (
services/backtest_runner/main.py) β argparse, ClickHouse only,--debugflag - JSON + CSV reports with per-trade log
-
WalkForwardRunnerβ sliding train/val windows with MLflow child runs -
query_candles_history()β 2-year ClickHouse retention table for ML training data - 36 unit tests (including 4 look-ahead bias tests)
Key design decisions:
candles_1h_historytable (730d TTL) separate fromcandles_1h(90d TTL) β backtests need full history- No Redis/Postgres required β ClickHouse only for speed
limit=Noneinquery_candlesfor full date-range (never mix numeric limit + date range)
Goal: LightGBM regime classifier + volatility sizing model + MLflow tracking
-
FeaturePipelineβ 10 regime features + 16 sizing features (superset) -
LabelGeneratorβ rule-based pseudo-labeling, +1 bar shift (leak-free),train_atr_medianexplicit param -
RegimeClassifierβ LightGBM 3-class (trending/ranging/high_vol), thread-safe predict -
SizingModelβ LightGBM regressor predicting 24h forward realized vol -
MLPositionSizerβ dynamic target_vol, clamped [25%, 150%], fail-safe returns base_qty -
VolatilityBreakoutStrategyβ BUY on bb_position>0.95 + volume + ADX + regime gate -
RegimeAwareStrategyβ circuit breaker p_high_vol>0.60 β HOLD; delegates to breakout or mean_reversion - MLflow Docker service (port 5000, PostgreSQL backend + LocalStack S3)
- New indicators: ATR, ADX, BollingerBands, VolumeRatio, ZScore
- ClickHouse migration 007:
candles_1h_history(730d TTL) - 86 new unit tests
Goal: MVO-based multi-strategy portfolio with two-layer regime gating
Two-layer architecture:
Layer 1 (per-strategy regime gate):
MATrendStrategy: HOLD if regime_trending < 0.55
RSIMeanReversionStrategy: HOLD if regime_ranging < 0.40
VolatilityBreakoutStrategy: HOLD if regime_trending < 0.55
Layer 2 (portfolio MVO weights):
EMA-smoothed Sharpe β SLSQP MVO β MRC cap β weekly rebalance
Vol overlay: leverage = target_vol / port_vol, clamped [0.5, 1.5]
-
domain/portfolio/β pure numpy/scipy computation, no I/Oreturns_matrix.pyβ align N equity curves β forward-filled ReturnsMatrixperformance_engine.pyβ rolling Sharpe/Vol/MaxDD/LedoitWolf covarianceallocation_engine.pyβ stateful EMA-smoothed Sharpe β MVOvol_overlay.pyβ leverage scaling
-
PortfolioBacktesterβ N sequential sub-backtests β bar-by-bar MVO simulation -
PortfolioEngine(live) β reads Redis indicators β MVO weights β paper orders - CLI (
services/portfolio_runner/main.py) β--use-yaml-slots,--regime-filter -
MATrendStrategyβ EMA50/200 crossover; requires "close" key in indicators dict -
create_portfolio_backtester(use_regime_filter=False)β loads classifier from MLflow - Grafana portfolio dashboard
- 46 new unit tests
Goal: Filter strategy signals by trade quality confidence
-
triple_barrier_label()β PT/SL/timeout barriers; entry at next bar's open (look-ahead-free) -
MetaLabelerβ LightGBM binary; drops y==0 (timeout);threshold=0.55; untrained returns 0.5 - Backtester
meta_labelerparam β after signal, if meta_confidence < threshold β HOLD -
--meta-labelerflag inbacktest_runner/main.py -
--train-meta-labeler --strategy <name>inml_trainer/main.py - Factory:
create_meta_labeler(),load_meta_labeler() - Config:
ml.yamlmeta_labeler section (pt_pct=0.015, sl_pct=0.008, max_hold_bars=48) - 17 unit tests
Goal: Long-short capability with ATR trailing stop
-
Signal.SHORT+Signal.COVERadded to signal enum -
BacktestOrderStoreβ SHORT (negative qty, cash+=), COVER (cash-=, PnL=(entry-cover)Γqty-commission) -
BacktestBroker/PaperBrokerβ margin validation for SHORT, position validation for COVER -
RiskManagerβ reject double-short, reject COVER with no short;symbolparam incalculate_quantity -
AdaptiveTrendStrategyβ EMA+ATR long-short; BUY/SHORT on entry, SELL/COVER on ATR trailing stop; stateful; regime gate - 19 unit tests (short selling), 17 unit tests (adaptive trend)
- Total: 470 unit tests passing
Goal: Close real bugs found after Phase 7b code review
-
OrderManager.process_signal()β addsymbol=symboltocalculate_quantitycall (bug: multi-symbol SELL/COVER used wrong position) -
ml_trainer/main.pyβ captureSignal.SHORTin addition toSignal.BUYfor meta-labeler training - Docstring updates:
generate_signal(),validate(),process_signal()
Goal: Move from ~7 alphas to 20-30 validated signals using quant-grade validation
Execution order: B β C β A
Problem diagnosed from backtest: ma_trend (1,561 trades) and adaptive_trend (2,187 trades) lose 14β20% of capital to commission. Signal frequency is too high β not signal direction.
Plan:
- Add
min_confirmation_bars: intparameter toMATrendStrategyandAdaptiveTrendStrategy- Require N consecutive bars of signal confirmation before entry (default: 3)
- Reduces
ma_trendtrades: 1,561 β ~200, commission $1,512 β ~$200
- IC (Information Coefficient) framework in
domain/alpha/ic.pycompute_ic(factor_values, forward_returns, periods=[1,4,8,24])β Spearman rank correlation- IC > 0.02 = weak signal, > 0.05 = usable, > 0.10 = strong
- Decay analysis β IC rolling window to detect when signal loses edge
- Factor correlation matrix β prevent redundant alphas from dominating portfolio
-
services/alpha_lab/β standalone script to evaluate new factors before wiring into strategies
Key files:
domain/alpha/
ic.py # IC + ICIR computation
decay.py # Rolling IC decay analysis
correlation.py # Factor cross-correlation matrix
services/alpha_lab/
evaluate.py # CLI: evaluate a factor against forward returns
Problem: All current features are price-derived. Quant funds use data price cannot provide.
Plan:
- Funding rate β Binance perpetual futures (ccxt:
exchange.fetch_funding_rate)- Negative funding = shorts paying longs = forced short covering imminent
- Extreme positive funding = overleveraged longs = mean reversion setup
- Open interest β
exchange.fetch_open_interestvia ccxt- Rising OI + rising price = trend confirmation
- Rising OI + falling price = capitulation risk
- Cross-asset momentum β BTC 24h return as feature for ETH/SOL/BNB strategies
- BTC leads altcoins by ~1-4 hours on large moves
- Basis β spot vs futures price spread (when futures available)
- Store in
trading.market_contextClickHouse table (hourly snapshots) - Inject into
FeaturePipelineas additional features - Add to
indicators.yamlandconfig/settings.py
Key files:
providers/binance/futures.py # Funding rate + OI fetcher
services/context_service/main.py # Hourly market context collector
domain/ml/features.py # Add FUNDING_FEATURES, OI_FEATURES
infrastructure/docker/clickhouse/migrations/008_market_context.sql
Goal: Expand from 7 alphas to 20-30 using IC-validated factors
Candidate alpha families:
| Family | Examples | IC target |
|---|---|---|
| Momentum | 4h/12h/24h/72h price return, ROC | 0.03β0.06 |
| Seasonality | hour-of-day, day-of-week return patterns | 0.02β0.04 |
| Microstructure | bid-ask spread proxy, trade imbalance | 0.04β0.08 |
| Funding carry | funding rate z-score, cumulative funding | 0.05β0.10 |
| Cross-asset | BTC/ETH relative strength, BTC dominance delta | 0.03β0.07 |
| Volatility regime | realized vol percentile rank, VIX analogue | 0.03β0.06 |
Process for each alpha:
- Compute factor β 2. IC test (needs IC > 0.03) β 3. Decay check (still predictive at 8h+?) β 4. Correlation check (< 0.60 with existing alphas) β 5. Add to strategy or
FeaturePipeline
Key files:
domain/alpha/
momentum.py # Multi-period price momentum factors
seasonality.py # Calendar-based return patterns
carry.py # Funding rate carry factors
cross_asset.py # BTC-relative strength signals
services/alpha_lab/
backtest_alpha.py # Fast vectorized alpha backtest (no strategy overhead)
report.py # IC, decay, correlation summary report
When to use Kafka (Data Streaming):
- β Market data ingestion (trades, order books)
- β Event streaming with replay capability
- β Multiple consumers need same data
- β High throughput (60+ symbols, thousands msg/sec)
- β Message retention (24h+) for backtesting
- β Analytics pipelines
When to use RabbitMQ (Task Queues):
- β Order execution (need acknowledgment)
- β Priority queues (urgent stop-loss first)
- β Dead letter queues (failed task handling)
- β Work distribution (backtest jobs to workers)
- β Notifications (email, telegram)
- β Long-running async jobs
Implementation:
# factory/client_factory.py
def create_stream_client() -> BaseStreamClient:
"""Kafka/Kinesis for data streaming"""
if settings.CLOUD_PROVIDER == "opensource":
return KafkaStreamClient()
elif settings.CLOUD_PROVIDER == "aws":
return KinesisStreamClient()
def create_task_queue() -> BaseTaskQueue:
"""RabbitMQ/SQS for task queues (Phase 3+)"""
if settings.CLOUD_PROVIDER == "opensource":
return RabbitMQClient()
elif settings.CLOUD_PROVIDER == "aws":
return SQSClient()- S3: Object storage for raw data, backups, ML artifacts
- Kinesis: Real-time data streaming (alternative to Kafka)
- Lambda: Serverless compute for event processing
- DynamoDB: NoSQL database for high-throughput data
- EventBridge: Event bus for decoupled architecture
- SQS/SNS: Message queuing and pub/sub
- API Gateway: REST/WebSocket API endpoints
- CloudWatch: Logging and metrics
- Secrets Manager: Secure credential storage
- Step Functions (optional): Workflow orchestration
- ClickHouse: Time-series OLAP database (billions of ticks)
- Local: Docker container
- Cloud: ClickHouse Cloud, Altinity Cloud
- Redis: In-memory caching (latest prices, positions)
- Local: Docker container
- Cloud: Upstash Redis, AWS ElastiCache
- PostgreSQL: Relational metadata (strategies, users, configs)
- Local: Docker container
- Cloud: Supabase, Neon, AWS RDS
- Jupyter: Interactive data exploration
- MLflow: Experiment tracking, model registry
- scikit-learn, XGBoost, LightGBM: Traditional ML
- TensorFlow/PyTorch: Deep learning (LSTM, Transformers)
- Grafana: Real-time operational dashboards (Docker)
- Prometheus: Metrics collection (Docker)
- Python 3.10+: Primary language
- boto3: AWS SDK (works with LocalStack)
- FastAPI: High-performance API framework
- Pydantic: Data validation
- SQLAlchemy: ORM for PostgreSQL
- clickhouse-connect: ClickHouse Python client
- redis-py: Redis Python client
- AWS CDK (recommended): Define LocalStack + AWS resources in Python
- Terraform (alternative): HCL-based IaC
- LocalStack Docker Compose: Service orchestration
LocalStack (unified container):
- All AWS services (S3, Kinesis, Lambda, DynamoDB, etc.) - 512MB
Docker Stateful Services:
- clickhouse (1.5GB)
- redis (256MB)
- postgres (512MB)
- grafana (256MB)
Python Services (run locally, not Docker):
- market-data-ingestion (256MB)
- trading-api (512MB)+ LocalStack Pro features (optional)
+ jupyter (1GB)
+ mlflow (512MB)
+ prometheus (512MB)
+ Additional Lambda functions
+ Step Functions workflowsReplace all with managed services:
- LocalStack β Real AWS (free tier)
- Docker ClickHouse β ClickHouse Cloud ($300 credit)
- Docker Redis β Upstash Redis (free tier)
- Docker Postgres β Supabase (free tier)
- Python services β AWS Lambda or Railway- Docker & Docker Compose
- Python 3.10+
- 8GB+ RAM (minimal), 16GB+ recommended (full stack)
- 20GB+ disk space
git clone <repo-url>
cd DataPlatform
# Copy environment template
cp .env.example .env.local# Start LocalStack + stateful services
docker-compose up -d
# Services started:
# - localstack (all AWS services)
# - clickhouse
# - redis
# - postgres
# - grafana
# Check services health
docker-compose ps
# View logs
docker-compose logs -f localstackRun in this order to ensure proper data flow:
# Terminal 1: Market Data Ingestion (WebSocket β Redis signals)
uv run python services/market_data_ingestion/main.py
# Terminal 2: Sync Service (REST API β ClickHouse candles, every 60s)
uv run python services/sync_service/main.py
# Terminal 3: Indicator Service (ClickHouse β Calculate β Redis/ClickHouse, every 60s)
uv run python services/indicator_service/main.py- LocalStack Dashboard: http://localhost:4566/_localstack/health
- Grafana: http://localhost:3000 (admin/admin)
- ClickHouse: http://localhost:8123
- Redis: localhost:6379
- PostgreSQL: localhost:5432
# Check LocalStack health
curl http://localhost:4566/_localstack/health
# List S3 buckets (LocalStack)
aws --endpoint-url=http://localhost:4566 s3 ls
# Check Kinesis stream (LocalStack)
aws --endpoint-url=http://localhost:4566 kinesis list-streams
# Query ClickHouse
curl "http://localhost:8123/?query=SELECT count() FROM trades"All services use environment variables for endpoints:
# .env.local (LocalStack + Docker)
AWS_ENDPOINT_URL=http://localhost:4566
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=test
AWS_SECRET_ACCESS_KEY=test
CLICKHOUSE_HOST=localhost
CLICKHOUSE_PORT=8123
REDIS_URL=redis://localhost:6379
POSTGRES_URL=postgresql://admin:password@localhost:5432/trading
# .env.cloud (Production AWS)
AWS_ENDPOINT_URL= # Empty = use real AWS
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=<real-key>
AWS_SECRET_ACCESS_KEY=<real-secret>
CLICKHOUSE_HOST=abc123.clickhouse.cloud
REDIS_URL=rediss://username:password@redis.cloud:6379
POSTGRES_URL=postgresql://user:pass@db.supabase.com/postgres# Local development with LocalStack
cp .env.local .env
docker-compose up -d
python services/market-data-ingestion/main.py
# Production (real AWS + managed databases)
cp .env.cloud .env
# Deploy Lambda functions
cd infra
cdk deploy # or terraform apply
# Code remains IDENTICAL - boto3 SDK uses env vars!# On AWS EC2 / GCP Compute / Azure VM
git clone <repo>
docker-compose -f docker-compose.cloud.yml up -d- Kafka: Confluent Cloud, AWS MSK, Aiven
- ClickHouse: ClickHouse Cloud, Altinity.Cloud
- Redis: AWS ElastiCache, Redis Cloud
- PostgreSQL: AWS RDS, Google Cloud SQL, Supabase
- Airflow: Astronomer, Google Cloud Composer
# Using Helm charts
helm install trading ./helm/trading-platform| Phase | Status | Can Demo | Technical Highlights |
|---|---|---|---|
| Phase 1 | β Complete | Real-time prices | WebSocket, multi-exchange, ClickHouse |
| Phase 2 | β Complete | Charts + indicators | REST API sync, scheduled jobs, SMA/EMA/RSI/MACD |
| Phase 3 | β Complete | Paper trading live | FastAPI, strategy engine, PostgreSQL |
| Phase 4 | β Complete | Backtest CLI + reports | Backtester, walk-forward, JSON/CSV output |
| Phase 5 | β Complete | ML regime classifier | LightGBM 3-class, MLflow, vol sizing model |
| Phase 6 | β Complete | Portfolio engine | MSAPE, MVO, two-layer regime gates |
| Phase 7a | β Complete | Meta-labeling | Triple-barrier labels, LightGBM quality filter |
| Phase 7b | β Complete | Long-short trading | SHORT/COVER signals, AdaptiveTrendStrategy |
| Phase 7c | β Complete | Bug fixes | symbol param in calculate_quantity, ml_trainer SHORT capture |
| Phase 8B | π Next | Signal quality | IC framework, confirmation bars, decay analysis |
| Phase 8C | π Planned | Alt data | Funding rate, open interest, cross-asset momentum |
| Phase 8A | π Planned | Alpha factory | 20-30 IC-validated factors, alpha lab CLI |
Current: 470 unit tests passing | 12 strategies backtested | 4-asset portfolio live
By completing this project, you will master:
- Stream processing architectures
- Time-series database optimization
- Data pipeline orchestration
- ETL/ELT patterns
- REST + WebSocket APIs
- Event-driven microservices
- Caching strategies
- Database design
- Time-series forecasting
- Feature engineering
- Model training & evaluation
- MLOps practices
- Containerization (Docker)
- Infrastructure as Code
- Monitoring & alerting
- CI/CD pipelines
- Distributed systems
- Scalability patterns
- Fault tolerance
- Performance optimization
- Market data ingestion β ClickHouse: < 100ms (p99)
- Strategy signal generation: < 50ms
- API response time: < 100ms (p95)
- ML model inference: < 50ms
- Market data ingestion: 10,000+ trades/second
- Strategy evaluations: 1,000+ per second
- API requests: 5,000+ req/second
- 100M+ ticks per day (~1GB/day compressed)
- 1B+ ticks for backtesting (2020-2024)
- Query performance: Sub-second on billions of rows
- Environment variables for secrets
- Docker network isolation
- Read-only API keys (exchange APIs)
- API authentication (JWT)
- Rate limiting
- Input validation
- HTTPS/TLS encryption
- Secrets management (Vault, AWS Secrets Manager)
- Network policies (firewall rules)
- Regular security audits
- Strategy logic
- Technical indicators calculation
- Data validation
- Kafka β ClickHouse pipeline
- API endpoints
- ML model inference
- Load testing (Locust, K6)
- Stress testing (max throughput)
- Latency benchmarks
- Historical strategy validation
- Out-of-sample testing
- Walk-forward analysis
- Binance WebSocket API
- yfinance - Historical stock data
- ccxt - Multi-exchange crypto library
- Kaggle: Crypto/Stock datasets
- QuantConnect: Algorithmic trading tutorials
- TradingView: Technical analysis
This is a learning project showcasing technical skills. Feel free to:
- Fork and customize for your use case
- Submit issues for bugs/improvements
- Share your results and learnings
Educational & Research Purposes Only
This platform is built for:
- Learning data engineering and ML concepts
- Portfolio demonstration
- Academic research
NOT intended for:
- Real money trading without extensive modifications
- Production use without proper risk management
- Financial advice
Trading involves significant risk of loss. Past performance does not guarantee future results.
Phase 1-3 (Development): Use postgres/init.sql (simple, fast iteration)
- Schema is simple and changes infrequently
- Can
docker-compose down -vto recreate database - No production data to preserve
Phase 4+ (Production): Migrate to Alembic (version control, safety)
- Have production data (cannot recreate database)
- Schema changes need to be tracked and reversible
- Team collaboration requires migration history
# Install
pip install alembic psycopg2-binary
# Initialize (creates migrations/ folder)
alembic init migrations
# Configure
# Edit migrations/env.py to use config/settings.pymigrations/env.py:
from config.settings import get_settings
settings = get_settings()
config.set_main_option("sqlalchemy.url", settings.postgres_dsn)Auto-generate from SQLAlchemy models:
# After changing models in domain/models/
alembic revision --autogenerate -m "add phone_number to users"
# Review the generated migration
# Edit migrations/versions/xxx_add_phone_number.py if neededManual migration:
alembic revision -m "add index on orders.symbol"migrations/versions/001_add_phone.py:
from alembic import op
import sqlalchemy as sa
def upgrade():
op.add_column('users',
sa.Column('phone_number', sa.String(20), nullable=True)
)
op.create_index('idx_users_phone', 'users', ['phone_number'])
def downgrade():
op.drop_index('idx_users_phone')
op.drop_column('users', 'phone_number')Local development:
# Apply all pending migrations
alembic upgrade head
# Rollback one migration
alembic downgrade -1
# Check current version
alembic current
# View migration history
alembic historyProduction deployment:
# In Dockerfile or docker-compose
CMD alembic upgrade head && python main.pydocker-compose.yml:
services:
trading-api:
build: .
command: >
sh -c "alembic upgrade head &&
uvicorn main:app --host 0.0.0.0"
depends_on:
postgres:
condition: service_healthy1. Always test migrations:
# Test upgrade
alembic upgrade head
# Test downgrade
alembic downgrade -1
# Test re-upgrade
alembic upgrade head2. Never modify old migrations:
- Create new migration to fix issues
- Old migrations are history (like Git commits)
3. Review auto-generated migrations:
- Alembic may miss some changes
- Check nullable, defaults, indexes
4. Use transactions:
def upgrade():
with op.get_context().autocommit_block():
# DDL statements here
pass5. Data migrations:
def upgrade():
# Schema change
op.add_column('users', sa.Column('status', sa.String(20)))
# Data migration
connection = op.get_bind()
connection.execute(
"UPDATE users SET status = 'active' WHERE is_active = true"
)GitHub Actions:
- name: Run migrations
run: |
alembic upgrade head
- name: Run tests
run: pytestDeployment script:
#!/bin/bash
# deploy.sh
# Backup database
pg_dump $DB_URL > backup_$(date +%Y%m%d_%H%M%S).sql
# Run migrations
alembic upgrade head
# Deploy app
docker-compose up -d --buildStep 1: Initial migration from existing schema
# Start with empty migrations
alembic init migrations
# Create initial migration matching current init.sql
alembic revision -m "initial schema"Step 2: Copy init.sql content to migration:
# migrations/versions/001_initial.py
def upgrade():
# Copy CREATE TABLE statements from init.sql
op.execute("""
CREATE TABLE IF NOT EXISTS users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
...
)
""")Step 3: Mark as applied (don't re-run on existing DB):
# On existing database
alembic stamp head
# On new database
alembic upgrade headStep 4: Future changes use Alembic
# All new schema changes
alembic revision --autogenerate -m "add new column"
alembic upgrade headMigration conflicts:
# Multiple developers created migrations
# Merge and renumber
alembic merge heads -m "merge migrations"Reset migrations (development only!):
# WARNING: Deletes all data!
docker-compose down -v
rm -rf migrations/versions/*
alembic revision -m "initial"
# Recreate schema in migration
alembic upgrade headMIT License - See LICENSE file for details
# Run all strategy backtests (2022β2026)
CLICKHOUSE_HOST=localhost uv run python services/backtest_runner/main.py \
--strategy volatility_breakout --symbol SOLUSDT \
--exchange binance --timeframe 1h \
--start 2022-01-01 --end 2026-02-27
# Run portfolio with regime filter
CLICKHOUSE_HOST=localhost uv run python services/portfolio_runner/main.py \
--use-yaml-slots --exchange binance --timeframe 1h \
--start 2022-01-01 --end 2026-02-27 --regime-filter
# Run unit tests
uv run pytest tests/unit/ -v # 470 tests
# Train meta-labeler
uv run python services/ml_trainer/main.py \
--train-meta-labeler --strategy adaptive_trend \
--symbol BTCUSDT --start 2022-01-01 --end 2024-12-31- Check
CLAUDE.mdfor architecture guide and design decisions - Check
/docsfolder for detailed guides
Built with β€οΈ for learning and showcasing technical expertise
Keywords: #DataEngineering #MachineLearning #AlgorithmicTrading #StreamProcessing #ClickHouse #Kafka #Python #FastAPI #Docker #CloudNative