Skip to the content.

Architecture Deep Dive — TTAPI

A comprehensive look at the design decisions, patterns, and trade-offs in a world-class Rust system.


System Overview

TTAPI is a high-performance financial data platform built with Rust, designed to:


Architecture Diagram

┌─────────────────────────────────────────────────────────────────────┐
│                         TTAPI Application                            │
│                                                                       │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐              │
│  │   CLI/UI     │  │   Streaming  │  │   Background │              │
│  │  (Console    │  │   Service    │  │   Tasks      │              │
│  │   Grid)      │  │  (WebSocket) │  │ (Persistence)│              │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘              │
│         │                  │                  │                       │
│         └──────────────────┼──────────────────┘                       │
│                            │                                          │
│  ┌─────────────────────────▼──────────────────────────────────────┐ │
│  │              ttapi-platform (Business Logic)                    │ │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐         │ │
│  │  │ Data         │  │ Processing   │  │ Cache        │         │ │
│  │  │ Collection   │  │ Pipeline     │  │ Manager      │         │ │
│  │  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘         │ │
│  └─────────┼──────────────────┼──────────────────┼─────────────────┘ │
│            │                  │                  │                   │
│  ┌─────────▼──────────────────▼──────────────────▼─────────────────┐ │
│  │              ttapi-polars (Data Processing)                      │ │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐         │ │
│  │  │ LazyFrame    │  │ DataFrame    │  │ Parquet I/O  │         │ │
│  │  │ Utils        │  │ Utils        │  │              │         │ │
│  │  └──────────────┘  └──────────────┘  └──────────────┘         │ │
│  └──────────────────────────────────────────────────────────────────┘ │
│                                                                       │
│  ┌──────────────────────────────────────────────────────────────────┐ │
│  │              ttapi-client (HTTP & WebSocket)                     │ │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐         │ │
│  │  │ Dynamic      │  │ OAuth2       │  │ Circuit      │         │ │
│  │  │ Client       │  │ Manager      │  │ Breaker      │         │ │
│  │  └──────────────┘  └──────────────┘  └──────────────┘         │ │
│  └──────────────────────────────────────────────────────────────────┘ │
│                                                                       │
│  ┌──────────────────────────────────────────────────────────────────┐ │
│  │              ttapi-core (Types & Utilities)                      │ │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐         │ │
│  │  │ Error Types  │  │ Config       │  │ TTL Utils    │         │ │
│  │  │ (TTError)    │  │ (RMS)        │  │              │         │ │
│  │  └──────────────┘  └──────────────┘  └──────────────┘         │ │
│  └──────────────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────────┘

External APIs:
┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│ TastyTrade   │  │ dxFeed       │  │ MetaStock    │
│ REST API     │  │ WebSocket    │  │ CSV Files    │
└──────────────┘  └──────────────┘  └──────────────┘

Crate Responsibilities

ttapi-core

Purpose: Core types, utilities, and configuration
Dependencies: Minimal (std, serde, chrono)
Exports:

Why separate?


ttapi-client

Purpose: HTTP client, authentication, API wrappers
Dependencies: reqwest, tokio, oauth2
Exports:

Why separate?


ttapi-platform

Purpose: Business logic, data processing, caching
Dependencies: ttapi-core, ttapi-client, ttapi-polars
Exports:

Why separate?


ttapi-polars

Purpose: Polars extensions, LazyFrame utilities
Dependencies: polars, ttapi-core
Exports:

Why separate?


ttapi-onboarding (CLI)

Purpose: User-facing interface, console grid
Dependencies: All other crates
Exports:

Why separate?


Data Flow

1. Symbol Data Collection

User runs `tt`
    │
    ▼
CLI parses args (TT_LIST=2 → S&P 500)
    │
    ▼
Platform spawns parallel tasks (507 symbols)
    │
    ├─► Task 1: fetch_market_metrics(symbol_1)
    ├─► Task 2: fetch_market_metrics(symbol_2)
    ├─► ...
    └─► Task 507: fetch_market_metrics(symbol_507)
    │
    ▼
Client makes HTTP requests (max 100 concurrent)
    │
    ├─► Circuit breaker checks state (Closed/Open/Half-Open)
    ├─► Retry with exponential backoff (3 attempts)
    └─► Return Result<Data, ApiError>
    │
    ▼
Platform collects results (graceful degradation)
    │
    ├─► 503 successful (0.7% missing)
    └─► 4 failed (logged, not fatal)
    │
    ▼
Polars builds DataFrame (columnar format)
    │
    ▼
CacheManager persists in background (Parquet + CSV)
    │
    ▼
Console grid updates (in-place progress)

2. EOD Data Processing

User runs `tt` (EOD grid)
    │
    ▼
Platform checks TTL (is cache fresh?)
    │
    ├─► YES: Load from Parquet (3.978s)
    │        └─► Return DataFrame
    │
    └─► NO: Run hybrid import
         │
         ├─► Scan MetaStock CSV files (15,798 found)
         │
         ├─► Import MetaStock data (27.6M rows, 63s)
         │   └─► Parallel CSV parsing (rayon)
         │
         ├─► Complement with dxFeed (1.7M rows, 63s)
         │   └─► Parallel API calls (tokio)
         │
         ├─► Cleanup & deduplication (130k rows removed)
         │   └─► Polars LazyFrame operations
         │
         ├─► Persist snapshot (Parquet, 16.7s)
         │   └─► Background thread pool
         │
         └─► Return DataFrame

Concurrency Model

Tokio Work-Stealing Scheduler

OS Threads (N=8):
┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
│Thread 1│ │Thread 2│ │Thread 3│ │Thread 4│ ...
└───┬────┘ └───┬────┘ └───┬────┘ └───┬────┘
    │          │          │          │
    ▼          ▼          ▼          ▼
┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
│ Queue  │ │ Queue  │ │ Queue  │ │ Queue  │
│ [T1]   │ │ [T2]   │ │ [T3]   │ │ [T4]   │
│ [T5]   │ │ [T6]   │ │ [T7]   │ │ [T8]   │
│ [T9]   │ │ [T10]  │ │ [T11]  │ │ [T12]  │
└────────┘ └────────┘ └────────┘ └────────┘

Tasks (M=507):
- Each symbol = 1 task
- Tasks distributed across queues
- Idle threads steal from busy threads
- Result: 800% CPU utilization (8 cores)

Semaphore-Based Backpressure

Semaphore (max 100 permits):
┌────────────────────────────────────────┐
│ Available permits: 100                 │
└────────────────────────────────────────┘
         │
         ▼
Task 1 acquires permit (99 available)
Task 2 acquires permit (98 available)
...
Task 100 acquires permit (0 available)
Task 101 WAITS (no permits available)
         │
         ▼
Task 1 completes, releases permit (1 available)
         │
         ▼
Task 101 acquires permit (0 available)

Why 100?


Caching Strategy

TTL-Based Invalidation

Cache Entry:
┌────────────────────────────────────────┐
│ Data Type: symbols                     │
│ Path: /path/to/symbols.parquet         │
│ TTL: 24 hours                          │
│ Modified: 2025-11-13 21:41:18          │
│ Size: 2.3 MB                           │
└────────────────────────────────────────┘

Cache Check (2025-11-14 10:00:00):
    │
    ▼
Age = now - modified = 12h 18m 42s
    │
    ▼
Is age < TTL? (12h < 24h)
    │
    ├─► YES: Load from cache (12.675ms)
    │
    └─► NO: Fetch fresh data (2.596s)
         └─► Persist to cache (background)

Dependency Tracking

Unified Calendar (TTL: 7 days)
    │
    ├─► Modified: 2025-11-13 21:41:22
    │
    ▼
Expiration Series (depends on Unified Calendar)
    │
    ├─► Check: Has Unified Calendar changed?
    │   └─► YES: Rebuild Expiration Series
    │   └─► NO: Use cached Expiration Series
    │
    ▼
Returns StdDev (depends on Expiration Series)
    │
    ├─► Check: Has Expiration Series changed?
    │   └─► YES: Recompute Returns StdDev
    │   └─► NO: Use cached Returns StdDev

Error Handling

Error Hierarchy

TTError (top-level)
├─► ApiError (HTTP/network)
│   ├─► Http { status, message }
│   ├─► Auth(String)
│   ├─► RateLimit { retry_after }
│   └─► Timeout
│
├─► DataError (processing)
│   ├─► InvalidFormat(String)
│   ├─► MissingColumn(String)
│   └─► ParseError(String)
│
├─► ConfigError (configuration)
│   ├─► MissingEnvVar(String)
│   └─► InvalidValue(String)
│
└─► IoError (file I/O)
    └─► std::io::Error

Circuit Breaker State Machine

┌─────────┐
│ Closed  │ ◄─────────────────────────┐
│ (Normal)│                            │
└────┬────┘                            │
     │                                 │
     │ N failures                      │ M successes
     ▼                                 │
┌─────────┐                       ┌────┴────┐
│  Open   │ ──────────────────►   │ Half-   │
│ (Fail   │   Timeout expired     │ Open    │
│  Fast)  │                       │ (Test)  │
└─────────┘                       └─────────┘

Performance Optimizations

1. Lazy Evaluation (Polars)

2. Memory-Mapped Parquet

3. Background Persistence

4. Columnar Format


Conclusion

TTAPI’s architecture demonstrates:

Built with Rust’s safety guarantees and world-class performance.