feat: Tradier parallel-stack compose template

Self-contained shakeout stack beside the paper stack: own postgres (host
5434, disposable pgdata-tradier volume), own dashboard (host 8768), loop
with BROKER=tradier (sandbox). Data plane stays Alpaca; Telegram/deadman
disabled so main-stack alerts stay unambiguous; main data dir mounted
read-only (inherits learned_params/overrides.env). Filled local copy is
git-excluded; bootstrap_live_db.sh playbook reused for DB parity.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
momentum devandClaude Fable 5 committed 2026-07-27 08:07:32 -05:00
1 parent 1cefb51c63
commit df85201c45
2 files changed
+131

No files matched your search

+111
View File
@@ -0,0 +1,111 @@
# TRADIER PARALLEL STACK — template (fill <FILL-ME-*>, save as
# truenas-compose.tradier.local.yaml, never commit the filled copy).
#
# Runs the SAME image/strategy as the paper stack but executes through the
# Tradier mirror (BROKER=tradier, sandbox by default). Fully self-contained:
# own postgres (host 5434), own dashboard (host 8768). Market data stays on
# Alpaca (keys still required). Telegram + deadman are OFF here so the main
# stack's alerts stay unambiguous.
#
# Shares the main stack's data dir READ-ONLY: the loop inherits the nightly
# learned_params.json and overrides.env without being able to clobber them.
#
# Fresh-DB bootstrap (same playbook as live staging), run on cube:
# ./bootstrap_live_db.sh <nightly-backup.sql.gz> <this-stack-postgres-container>
# or skip it and let the loop start from an empty DB (research baselines absent,
# config knobs at code defaults — fine for a first shakeout).
#
# Requires an image built from >= 1cefb51 (tradier_broker in image).
#
# Sandbox caveat: Tradier sandbox fills are simulated and can be slow/absent —
# an order parked in 'pending_new' is usually the sandbox, not the code.
services:
postgres:
image: postgres:18
environment:
PGDATA: /var/lib/postgresql/data/pgdata
POSTGRES_DB: momentum
POSTGRES_PASSWORD: <FILL-ME-PG-PASSWORD>
POSTGRES_USER: momentum
TZ: America/New_York
healthcheck:
interval: 10s
retries: 5
test:
- CMD-SHELL
- pg_isready -U momentum -d momentum
timeout: 5s
ports:
- 5434:5432
restart: unless-stopped
volumes:
- /mnt/Volume/Storage/Apps/momentum/pgdata-tradier:/var/lib/postgresql/data
loop:
image: docker.io/fez5587/momentum-app:latest
command:
- python
- -u
- run_live_paper.py
- --no-dashboard
depends_on:
postgres:
condition: service_healthy
environment: &tradier-env
BROKER: tradier
TRADIER_ACCESS_TOKEN: <FILL-ME-TRADIER-TOKEN>
TRADIER_ACCOUNT_ID: <FILL-ME-TRADIER-ACCOUNT>
TRADIER_ENV: sandbox
ALPACA_API_KEY: <FILL-ME-ALPACA-KEY>
ALPACA_SECRET_KEY: <FILL-ME-ALPACA-SECRET>
ALPACA_BACKFILL_FEED: sip
ALPACA_BASE_URL: https://paper-api.alpaca.markets
ALPACA_PAPER_SYNC_ENABLED: '1'
DATABASE_URL: postgresql://momentum:<FILL-ME-PG-PASSWORD>@postgres:5432/momentum
# alerts stay with the MAIN stack — no double Telegram / deadman pings
TELEGRAM_BOT_TOKEN: ''
TELEGRAM_CHAT_ID: ''
DEADMAN_DAILY_PING: '0'
DEADMAN_STALE_MIN: '5'
INGEST_STALE_BLOCK: '0'
INGEST_STALE_SECONDS: '180'
ORB_BARS: '5'
PG_SKIP_SCHEMA: '0'
QUOTE_SNAPSHOT_INTERVAL_SECONDS: '8'
STRATEGY_SETUPS: opening_range_break
DEPTH_RECORD_ENABLED: '0'
TZ: America/New_York
healthcheck:
interval: 60s
retries: 5
start_period: 180s
test:
- CMD
- python
- -c
- import os; os.environ['PG_SKIP_SCHEMA']='1'; import datetime,sys; from research.multi_schema import open_research_db; r=open_research_db('market').execute('SELECT max(timestamp) FROM events').fetchall()[0][0]; sys.exit(0 if r and (datetime.datetime.now()-r).total_seconds()<300 else 1)
timeout: 20s
restart: unless-stopped
volumes:
- /mnt/Volume/Storage/Apps/momentum/data:/app/data:ro
dashboard:
image: docker.io/fez5587/momentum-app:latest
command:
- python
- -u
- dashboard_api.py
depends_on:
postgres:
condition: service_healthy
environment:
<<: *tradier-env
COMMAND_BUS_ENABLED: '1'
DASHBOARD_HOST: 0.0.0.0
DASHBOARD_PORT: '8765'
DASHBOARD_TOKEN: <FILL-ME-DASHBOARD-TOKEN>
ports:
- 8768:8765
restart: unless-stopped
volumes:
- /mnt/Volume/Storage/Apps/momentum/data:/app/data:ro
+20
View File
@@ -44,6 +44,26 @@ Smoke refuses order exercises against the live base URL.
filters are client-side; the live loop only queries today + held symbols, so
behavior matches.
## Parallel shakeout stack (TrueNAS)
`deploy/docker/truenas-compose.tradier.yaml` is the committed template; the
filled copy lives (git-excluded) at `truenas-compose.tradier.local.yaml`.
Runs beside the paper stack, fully isolated:
- own postgres (host **5434**, fresh `pgdata-tradier` volume), own dashboard
(host **8768**), loop with `BROKER=tradier` against the sandbox account
- market data still Alpaca; Telegram + deadman OFF (main stack keeps alerts)
- main data dir mounted **read-only** — inherits nightly
`learned_params.json` / `overrides.env`, cannot clobber them; if a service
ever crashes on a read-only-filesystem error, switch that mount to a
writable copy
- fresh DB starts empty (knobs at code defaults). For research-baseline +
knob parity with the paper stack, reuse the live-staging playbook:
`./bootstrap_live_db.sh <nightly-backup.sql.gz> <tradier-postgres-container>`
- needs an image built from >= 1cefb51 (`tradier_broker/` in image)
- sandbox fills are simulated and can be slow or absent — an order parked in
`pending_new` is usually the sandbox, not the code
## Before flipping live money to Tradier
1. Rotate the sandbox token (it transited chat) and mint a live token.