01. Executive Summary
An institutional-grade, real-time derivatives market intelligence and trading system engineered to ingest ticks via WebSocket from the Angel One broker and stream calibrated trade alerts to a Flutter mobile cockpit in under 100ms end-to-end. The entire distributed network runs on resource-constrained commodity hardware (Intel Celeron-class) with a total system memory limit of approximately 531 MB across infrastructure containers.
The system leverages CSnakes to embed CPython directly inside the .NET 8 runtime, eliminating IPC boundaries and enabling microsecond-level options Greeks calculations. It isolates execution-critical fast paths from slow-path AI-driven recommendations, ensuring a fail-safe, non-blocking trading loop.
02. Problem Statement
High-frequency derivative trading systems typically require expensive server instances, high memory allocations, and complex IPC topologies to coordinate .NET execution stacks with Python-based quantitative models (e.g., Options pricing surfaces, implied volatility, Greeks computation).
Spawning external Python subprocesses or calling microservices via HTTP/gRPC introduces:
- Network Hop Latency: Spawning REST/gRPC calls over the loopback network adds 2ms - 10ms per calculation.
- Memory Bloat: Standard Python runtimes and service wrappers easily consume 400MB - 1GB of RAM per instance.
- Execution Blockages: Failure of slow-path sentiment or AI agents can deadlock execution pipelines.
The goal was to engineer a real-time signal pipeline capable of processing 22,450 events/sec, running options Greek calibrations, and broadcasting signals to mobile clients, all while restricted to 1GB total VPS memory and a 100ms tick-to-signal budget.
03. System Architecture
The backend consists of 12 microservices written in .NET 8 and Python, communicating asynchronously over a RabbitMQ event bus managed by WolverineFx, or synchronously via gRPC for low-latency calls.
[ Angel One SmartAPI WebSocket Feed ]
│
(Raw market ticks)
▼
[ TradingBot.MarketFeed Service ]
│
(Normalised tick events)
▼
[ RabbitMQ Event Bus ]
(WolverineFx Broker)
/ │ \
/ │ \
/ │ \
▼ ▼ ▼
[ TradingIntelligenceService ] [OptionFlow Engine] [Execution Engine]
(26-Stage Pipeline / CSnakes) (Implied Vol) (Order Placement)
│ ▲ │ │
│ (In-Process) │ (Reads) │ (Writes) ▼
[ CPython Heap ] └─────► [ Redis Hot Cache ] ──► [ PostgreSQL ]
(Greeks & Models) (Sorted Sets) (Trade Ledger)
│
(Signal Events)
▼
[ RabbitMQ Event Bus ]
│
▼
[ TradingGatewayService ] ──(WebSocket)──► [ Flutter Mobile Cockpit ]
Microservice Topology (12 Services)
| Service | .csproj Location | Operational Role |
|---|---|---|
| TradingGatewayService | src/TradingGatewayService/ | Host for REST endpoints, SignalR hubs, authentication, and SSE streaming. |
| TradingIntelligenceService | src/TradingIntelligenceService/ | Core ingestion coordinator, 26-stage pipeline executor, and CSnakes host. |
| TradingBot.Core | src/TradingBot.Core/ | Domain logic, structural entities, schemas, and rule-engine validators. |
| TradingBot.Execution | src/TradingBot.Execution/ | Order routing, margin validation, broker fill verification, and tracking. |
| TradingBot.MarketFeed | src/TradingBot.MarketFeed/ | Dedicated WebSocket client, tick deserializer, and gap-detection analyzer. |
| TradingBot.OptionFlow | src/TradingBot.OptionFlow/ | Real-time option chain construction and volume-based Greeks accumulator. |
| TradingBot.Lifecycle | src/TradingBot.Lifecycle/ | Health check aggregator, container readiness checks, and circuit-breaker switches. |
| TradingBot.Validation | src/TradingBot.Validation/ | System regression suite, automated mock feeders, and connectivity checks. |
| TradingNimWorker | src/TradingNimWorker/ | Async, out-of-process AI/ML worker built on Nim for slow-path model validations. |
| CommunicationNode | src/CommunicationNode/ | Low-latency gRPC node bridging internal microservices. |
| NotificationWorker | src/NotificationWorker/ | Push alerts provider, email dispatcher, and Telegram status notifier. |
| telegram-sentiment-worker | python/telegram_sentiment_worker/ | Python background script aggregating crowd sentiment from active channels. |
04. Engineering Decisions
CSnakes for In-Process Python Execution
Rather than hosting a separate FastAPI Docker container for Options Greeks analysis, which introduces HTTP serialization overhead and consumes ~300MB of overhead RAM, the system utilizes CSnakes. This library maps the CPython C-API directly into .NET’s native memory space.
- C# models invoke
calculate_greeks()directly via function pointers. - Objects are marshaled across the memory boundary using zero-copy spans.
- Volatile analytics execute in under 40 microseconds vs. 2.4 milliseconds over localhost HTTP.
WolverineFx over MediatR for Queue Decoupling
To scale event processing, WolverineFx was chosen as the mediator and broker. It provides native Outbox pattern execution, message buffering, and dead-letter queues on top of RabbitMQ, without the need for manual boilerplate plumbing.
Flutter Direct to SignalR
By bypassing an intermediate API gateway and letting the mobile cockpit connect directly to the SignalR hub in the gateway service, the system eliminates one serialization cycle, saving 10ms - 15ms on the critical delivery path.
05. Scaling Strategy
Options Chain Index Partitioning
Market data consists of thousands of option strikes. Rather than querying Postgres or parsing massive lists on every tick, the system maps active strikes into Redis Sorted Sets (ZSETs).
- Scores correspond to Option Strike Prices.
- Values store the JSON payload of implied volatility, open interest, and Greeks.
- Services fetch only the relevant strikes (e.g. Near-The-Money range) using
ZRANGEBYSCORE.
Decoupled AI Calibrations (Fast vs Slow Path)
AI models (Gemini-2.5-flash and Groq Llama-3.3) are slow-path components. High-latency LLM calls are executed asynchronously by the TradingNimWorker and telegram-sentiment-worker. If the AI layer experiences lag or API limits, the core .NET pipeline degrades gracefully:
- Core ticks continue generating technical signals (EMA, ATR, VWAP).
- The risk manager processes rules.
- Order execution remains unaffected, ignoring the delayed AI sentiment score.
06. Performance Optimizations
Extreme Memory Tuning for 1GB RAM Limit
Designed for hosting on budget VPS instances ($5-$10/month), the entire multi-container mesh was tuned to operate below 550MB RAM:
- PostgreSQL: Max connections set to
20, shared buffers capped at32MB, work mem capped at2MBvia custom configs. - Redis: Capped at
64MBmaxmemory withallkeys-lrueviction policy. - RabbitMQ: Configured with
vm_memory_high_watermark.relative = 0.2to restrict memory usage to under 160MB. - .NET Services: GC tuned to Workstation mode (
ServerGarbageCollection = false) to reduce heap overhead.
CSnakes Memory Cache
To prevent Python memory leaks from constant allocation/deallocation on the C-API boundary, a Redis cache with 500ms TTL is placed in front of the CSnakes interface. If spot prices have not fluctuated beyond a specific epsilon, cached Greeks are reused:
// Greeks cache routing
await _cache.SetAsync(
key: $"greeks:{symbol}:{expiry}",
value: JsonSerializer.SerializeToUtf8Bytes(greeks),
options: new() { AbsoluteExpirationRelativeToNow = TimeSpan.FromMilliseconds(500) });
07. Challenges Solved
Broker WebSocket Connectivity & Silence Recovery
WebSockets from brokers are notoriously unstable and silent during high-volatility sessions. The solution was the Broker Session Watchdog background service:
- Listens to ticks on the ingestion gateway.
- If no packets arrive for
30 seconds, the Watchdog issues a reconnection request. - If the WebSocket reconnect fails after
3 retries, the watchdog fails over to REST polling (LTP fallback) via Angel One’s REST endpoints, keeping the pipeline alive.
[ Active WebSocket Ingestion ]
│
▼
[ Normal Tick Feed ] ─────► (Updates timestamp)
│
▼ (Silent > 30s)
[ Reconnection Attempt ]
/ \
(Success) (Failure)
/ \
▼ ▼
[ Resume WebSocket ] [ REST LTP Fallback ]
08. Lessons Learned
- CSnakes Thread Safety: Python’s Global Interpreter Lock (GIL) still applies in embedded processes. Spanning parallel C# tasks into CSnakes results in thread blocking. The solution is executing CSnakes calls sequentially inside a dedicated C# worker task, or protecting execution blocks with a fast spinlock.
- Container Boot Dependencies: Under tight memory constraints, booting all services at once causes CPU thrashing and container crash-loops. We introduced strict health check probes (
pg_isready,rabbitmqctl check_port_connectivity) and Docker composedepends_onconditions with startup delay offsets.
09. Infrastructure Diagram
Below is the Docker service network showing memory allocations:
graph TD
subgraph Host ["VPS VM (1GB RAM Core Limit)"]
subgraph Net ["Docker Bridge Network (trading-network)"]
A["feed-ingestion<br/>(45 MB)"] -->|Normalised Events| B["rabbitmq:3.13-alpine<br/>(160 MB)"]
B -->|Queue Messages| C["intelligence-pipeline<br/>(210 MB)"]
C -->|Embedded FFI| CS["CSnakes Runtime<br/>(CPython Heap)"]
C -->|Hot Cache Writes| D["redis:7-alpine<br/>(30 MB)"]
C -->|Persist Logs/Trades| E["postgresql:15-vector<br/>(31 MB)"]
B -->|Signals| F["signalr-gateway<br/>(55 MB)"]
F -->|Read Hot Cache| D
end
end
F -->|SSL WebSocket| G["Flutter Mobile Client"]
10. Technology Stack
- Backend Framework: .NET 8 (C#)
- Embedded Analytics: Python 3.12 (CPython embedded via CSnakes)
- Event Broker: RabbitMQ 3.13-Alpine + WolverineFx 3.5.0
- Caching Database: Redis 7.0-Alpine
- Relational Database: PostgreSQL 15 (with pgvector for backtesting embeddings)
- API Ingestion: Angel One SmartAPI WebSocket Client
- Telemetry Dashboards: Grafana & Prometheus (Custom Gauge metrics exporter)
- Real-time Gateway: ASP.NET Core SignalR
- Mobile Presentation: Flutter SDK 3
11. Future Improvements
- Multi-Broker Adapters: Abstracing
IMarketFeedProviderto dynamically load Zerodha Kite or Dhan WebSocket handlers when Angel One rates limit. - Vectorized Backtester: Utilizing PostgreSQL
pgvectorto store historical tick sequences and perform semantic similarity searches for candlestick patterns.
12. Architecture Decision Records (ADR)
[ADR-01] RabbitMQ over Apache Kafka
- Context: High-throughput tick ingestion pipeline (~22,450 events/sec) requiring decoupling and in-order consumption under a constrained 1GB VPS RAM budget.
- Decision: Selected RabbitMQ + WolverineFx instead of Apache Kafka.
- Rationale: Apache Kafka requires a heavy JVM hosting environment (along with ZooKeeper or KRaft metadata processes) that consumes 250MB+ of base RAM, which would cause immediate OOM triggers on our cheap VPS. RabbitMQ-Alpine runs stably at ~120MB memory and offers low-latency AMQP routing keys and transactional outboxes.
[ADR-02] Embedded Python (CSnakes) over REST/gRPC Loopback
- Context: Low-latency options Greeks calculations require executing Python quantitative libraries (SciPy, NumPy) from .NET microservices.
- Decision: Embedded CPython inside the .NET host process using CSnakes.
- Rationale: Querying Python over standard REST HTTP loopbacks or gRPC adds serialization overhead and 2ms - 10ms network hop latencies. Embedding CPython inside the host assembly enables direct native pointer access, dropping Greeks pricing speeds to 38μs with zero IPC memory bloat.
[ADR-03] PostgreSQL with pgvector for the Ledger
- Context: Storing historical candlestick ticks and trading signals while keeping infrastructure simple.
- Decision: Selected PostgreSQL 15 + pgvector.
- Rationale: PostgreSQL provides robust transactional reliability for trading ledgers. Integrating
pgvectorallows us to perform semantic similarity searches for candlestick patterns and store signal embeddings in the same instance, avoiding the overhead of managing a separate VectorDB cluster.
[ADR-04] Self-Hosted VPS over Cloud Functions
- Context: Deploying services with minimal latency and fixed costs.
- Decision: Deployed via Docker Compose on a fixed-cost $8.50 VPS.
- Rationale: Serverless cloud functions (like AWS Lambda or Azure Functions) suffer from cold-start latencies and connection pooling bottlenecks that degrade high-frequency market feeds. Self-hosting containers provides deterministic thread execution loops at a predictable cost.