GMAN:·paisamaker:TRADING-D19·gex-advisor:POLLING·fetcher:429rps·npm:v0.1.8 (9rel)
$ cd ..

trading systems

0DTE options · gamma advisory · real-time data warehouse

Three coordinated projects: a data warehouse that ingests 429 API calls every 30 seconds, a signal evaluator that scores 62 features per ticker per cycle, and an execution engine with 20+ safety gates. Built in three weeks end-to-end. 2,015 tests across the three repos.

Scope: paper trading on IBKR · personal, not a fund · infrastructure validation over strategy backtest.

── pipeline ─ signal to execution
                                 ingest                              signal                                   execution
                          ┌──────────────────┐              ┌──────────────────┐                    ┌──────────────────┐
GEXBot REST (11 ep/tick) ─│                  │              │                  │                    │                  │
                          │ market-data-     │─── ATTACH ──▶│  gex-advisor     │─── alert_log.db ──▶│  paisamaker      │──▶ IBKR
GEXBot WS (5 hubs)       ─│ fetcher          │   DATABASE   │                  │                    │                  │   paper
                          │                  │   read-only  │                  │                    │                  │   DUP975149
                          │  429 req/30s   │              │  30s poll loop │                    │  24/7 systemd  │
                          │   3-ts provenance │              │   62 feat/tick    │                    │   6s reconnect    │
                          │   22 GB SQLite    │              │   5-force align   │                    │   tolerant        │
                          └──────────────────┘              └──────────────────┘                    └──────────────────┘
                                    │                                  │                                        │
                                    ▼                                  ▼                                        ▼
                           scalar_readings                CASCADE_WATCH   (71% wr)                     discord_signals.db
                           chain_snapshots                CHARM_SQUEEZE   (75% wr)                     (16 tables · WAL)
                           instrument_registry            STRUCTURE_BREAK (filtered)                    EOD flatten 15:45 ET

       ────────────────────────────── shared VM: Hetzner CPX31 · 4 vCPU · 8 GB · Ubuntu 24.04 · $18/mo ──────────────────────────────

       safety plane:   kill switch (L0/L1/L2)   spread gate >30%   bid validation   contract validation   fresh quote re-fetch
                        paper-port fail-closed   exit escalation    EOD flatten       max hold time         position dedup (UNIQUE)

operational degraded — cross-database ATTACH on SQLite WAL, freshness filter data_age_s < 120

── subsystems ─ in execution order
svc-paisamaker[TRADING]uptime 100%

paisamaker · automated 0DTE execution

Python 3.12 · ib_insync · Hetzner VM · 18,387 LOC

Two independent signal sources (a custom GEX evaluator and an external advisor service) feed a unified execution dispatcher. The dual-lane design came from one specific observation: IBKR gateway reconnects take about six seconds, and a single-loop design would miss the next 30-second signal cycle. Separate lanes, independent cooldowns, per-ticker gates. The mode state machine (DATA_ONLY → DEGRADED → WARMUP → FULLY_LIVE) blocks trades during recovery instead of retrying synchronously.

signals / day~100
tests1,327
tickers8
best trade+$410
Python 3.12ib_insyncasyncioSQLite WALsystemdDocker (IB Gateway)
svc-gex-advisor[POLLING]uptime 99.8%

gex-advisor · SPX gamma exposure signal

Python 3.11 · Hetzner VM · ~11,100 LOC

Three alert types built on a five-force alignment model and a conviction ladder. CASCADE (negative gamma acceleration) hits 71% on SPX 0DTE paper trades across 14 days. CHARM SQUEEZE (afternoon theta decay) hits 75%. STRUCTURE BREAK (level break) is filtered down to noise. Every alert is logged with a full feature snapshot plus outcome fields (MFE, MAE, target_hit, stop_hit) — so new signals ship as shadows first, validate against data, then promote.

tests463
alerts (14d)46
features / cycle62
CASCADE win rate71%
Python 3.11SQLite WALpandasDiscord webhookssystemdStreamlit
svc-market-data-fetcher[INGESTING]uptime 99.95%

market-data-fetcher · real-time data warehouse

Python 3.11 · stdlib + asyncio · 8,387 LOC

429 concurrent API calls every 30 seconds against 39 tickers. A three-timestamp provenance model (event_at, fetched_at, stored_at) lets downstream systems filter on freshness with confidence. REST and WebSocket paths run in parallel with failover; exponential backoff into a circuit-breaker into self-kill + systemd restart. No frameworks, no ORM — stdlib sqlite3 and aiohttp only. Framework-free isn't a badge, it's a choice so every millisecond in the fetch path is auditable.

rps (steady)429
tests225
test runtime2.7s
db size22 GB
Python 3.11asyncioaiohttpSQLite WALprotobufzstdsystemd
── safety gates ─ 20 gates, every trade path
/opt/paisamaker-app/safety/20 gates · all tested
gatecategoryfail behavior
kill-switch L0kill-switchsystem running, entries allowed
kill-switch L1kill-switchhalt entries, exits still run
kill-switch L2kill-switchflatten all + no new entries
max positions globalpre-tradereject entry, log reason=max_positions
max positions per-tickerpre-tradereject entry, log reason=ticker_limit
max daily losspre-tradehalt entries for the day
paper-port fail-closedpre-tradereject if IBKR port ≠ 4002
contract validationpre-tradereject if 0DTE expiry or class mismatch
spread gatepre-tradereject if bid-ask spread > 30%
bid > 0 gatepre-tradereject into empty markets
fresh quote re-fetchexecutionre-validate drift + spread at submit
IBKR mode state machinestateDATA_ONLY → DEGRADED → WARMUP → FULLY_LIVE
post-resume warmupstate60s stability before trading resumes
position dedup (UNIQUE)executionDB rejects duplicate contract_id rows
idempotent advisor alertsdataUNIQUE on advisor_alert_id
EOD flattenexitforce close 15:45 ET
EOD panic windowexitMKT escalation from 15:35 ET
max hold timeexit90m SPX / 60m QQQ / 30m singles
exit escalation (3-tier)exitLMT@mid → LMT@bid → MKT
per-source cooldownpre-tradegexwatch doesn't block advisor

Every gate returns a specific reject reason that's logged to discord_signals.db.gex_execution_log. No silent failures. Audit by reading the log.

── planned ─ requires read-only VM API

A live alert feed and live trade feed are planned next. Both require a read-only HTTP API on the Hetzner VM that exposes alert_log.db and gex_execution_log to the public internet. About four hours of FastAPI + systemd config, pending a safer deployment posture (rate limits, read-only contracts enforced at the server layer, not trusted from the client).

  • Live alert feed — tail of the last N alerts with outcome fields
  • Live trade feed (market hours) — current positions + today's fills
  • Week-by-week P&L + fill-rate charts
  • Shadow signal log — signals being validated before promotion
── eof ─