Skip to main content
Supabase provides a PostgreSQL-backed cloud dashboard for NOVOSKY runtime state. All sync writes are live-mode only. In python trading.py --dry, Supabase writes are intentionally disabled.

What gets synced

TableContentsWhen
bot_statusRunning state, equity, risk counters, account identityHeartbeat (~every 2 minutes, upserted)
tradesClosed trade details + P/LOn trade close
open_positionsLive open-position rows keyed by (bot_name, ticket)Upsert on open, delete on close, reconciled on heartbeat
position_eventsOPEN/EXIT/SL_MOVE timeline per positionOn each event
account_snapshotsBalance, equity, marginEvery hour
model_metricsAccuracy, feature count, train dateAfter retrain
news_eventsForexFactory weekly calendar cacheHeartbeat 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.
This matches the table UNIQUE(bot_name, title, event_at) constraint and the sync upsert conflict key.
1

Install and login

npx supabase login
Opens a browser tab — click Authorize. Token saved to ~/.supabase/access-token.
2

Create a project

npx supabase projects create novosky-trading \
  --db-password "YourStrongPassword123!" \
  --region ap-southeast-1
Closest region to most VPS hosts: ap-southeast-1 (Singapore). Save the project ref from the output.
3

Get your API keys

npx supabase projects api-keys --project-ref <your-project-ref>
Copy the service_role key — this is what the bot uses.
4

Add credentials to .env

SUPABASE_URL=https://<your-project-ref>.supabase.co
SUPABASE_KEY=<your-service_role-key>
SUPABASE_BOT_NAME=novosky-vt
SUPABASE_BOT_NAME identifies this instance in the dashboard — useful when running multiple bot instances.
5

Apply the schema

npx supabase link --project-ref <your-project-ref>
npx supabase db push
This applies all migrations from supabase/migrations/ to create the tables.Alternatively, open the Supabase dashboard SQL editor and run the contents of SUPABASE_SETUP.md manually.
6

Verify

python trading.py --dry
Then run live and confirm heartbeats:
python trading.py
Quick checks:
# open positions parity (should usually match broker positions)
curl "$SUPABASE_URL/rest/v1/open_positions?bot_name=eq.<your-bot-name>&select=ticket" \
  -H "apikey: $SUPABASE_KEY" -H "Authorization: Bearer $SUPABASE_KEY"

# recent trades
curl "$SUPABASE_URL/rest/v1/trades?bot_name=eq.<your-bot-name>&select=ticket,closed_at,profit&order=closed_at.desc&limit=20" \
  -H "apikey: $SUPABASE_KEY" -H "Authorization: Bearer $SUPABASE_KEY"

Multiple instances

If you run two bots (e.g. cent + standard accounts), give each a unique SUPABASE_BOT_NAME:
# Instance 1 (.env for cent account)
SUPABASE_BOT_NAME=novosky-cent

# Instance 2 (.env for standard account)
SUPABASE_BOT_NAME=novosky-standard
Both write to the same Supabase project but are identified separately in the bot_status table.

Disabling Supabase

Leave SUPABASE_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.