python trading.py --dry, Supabase writes are intentionally disabled.
What gets synced
| Table | Contents | When |
|---|---|---|
bot_status | Running state, equity, risk counters, account identity | Heartbeat (~every 2 minutes, upserted) |
trades | Closed trade details + P/L | On trade close |
open_positions | Live open-position rows keyed by (bot_name, ticket) | Upsert on open, delete on close, reconciled on heartbeat |
position_events | OPEN/EXIT/SL_MOVE timeline per position | On each event |
account_snapshots | Balance, equity, margin | Every hour |
model_metrics | Accuracy, feature count, train date | After retrain |
news_events | ForexFactory weekly calendar cache | Heartbeat fetch + upsert by unique key |
news_events duplicate policy
news_events is idempotent by key: (bot_name, title, event_at).
- Existing events are upserted (updated), not duplicated.
- New weekly events are inserted once.
- Re-pushing the same FF weekly payload does not create extra rows.
UNIQUE(bot_name, title, event_at) constraint and the sync upsert conflict key.
Setup (CLI method — recommended)
Create a project
ap-southeast-1 (Singapore). Save the project ref from the output.Add credentials to .env
SUPABASE_BOT_NAME identifies this instance in the dashboard — useful when running multiple bot instances.Apply the schema
supabase/migrations/ to create the tables.Alternatively, open the Supabase dashboard SQL editor and run the contents of SUPABASE_SETUP.md manually.Multiple instances
If you run two bots (e.g. cent + standard accounts), give each a uniqueSUPABASE_BOT_NAME:
bot_status table.
Disabling Supabase
LeaveSUPABASE_URL and SUPABASE_KEY blank in .env. The bot runs fine without cloud sync — Supabase is optional.
Operational note: stale open_positions
If the bot is stopped/crashed for a while, stale open_positions rows can remain temporarily.
When the bot is running again, the heartbeat reconciliation removes rows that are no longer present on the broker.