Trading Operationsvictorngoma.com

Hi thereRunbook

How-to & procedures

Step-by-step procedures for operating the SPX trading system, server, and website. Click any section to expand it.

Security note: This page contains procedures only — never actual passwords, secrets, or keys. When a step needs a secret (SSH passphrase, dashboard password, webhook secret), it lives in your password manager, not here. Keep this page behind login at all times.
Reference — key facts
Key facts & addresses
  • VPS IP: 165.227.84.78 (DigitalOcean droplet "spx-server", Ubuntu 24.04)
  • SSH user: victor
  • Trading server path: /home/victor/spx-server/
  • Trading service: spx-server.service (port 5005)
  • Dashboard service: spx-dashboard.service (port 5006)
  • Journal file: /home/victor/spx-server/journal/trades_journal_2026.csv
  • URLs: hub = victorngoma.com · dashboard = dashboard.victorngoma.com · webhook = webhook.victorngoma.com · strategies = pine.victorngoma.com · runbook = runbook.victorngoma.com
  • Cloudflare account: vngoma78@gmail.com
  • Secrets location: your password manager (SSH passphrase, dashboard password, webhook secret)
Before going live: revert SPX_0DTE_DAILY_SPEND_CAP_PCT from 100.0 back to 0.02, and verify PAPER_MODE=true until ready to fund.
Connecting to the server
SSH into the VPS

Run this on your Mac (Terminal app), not on the server:

ssh victor@165.227.84.78

Enter your SSH passphrase when prompted (it's in your password manager). You'll land at a prompt that reads victor@spx-server:~$ — that confirms you're on the VPS.

If the prompt still says victorngoma@Victors-MacBook-Pro, you're still on your Mac — the SSH didn't connect. Re-run the command.

Never run server commands while the prompt shows your Mac name — they'll run on the wrong machine.
Download the full journal CSV to your Mac

Run this on your Mac (NOT on the VPS — open a fresh Mac terminal, do not SSH in first):

scp victor@165.227.84.78:/home/victor/spx-server/journal/trades_journal_2026.csv ~/Downloads/

Enter your SSH passphrase. The file lands in your Mac's ~/Downloads/ folder.

This must run on the Mac. If your prompt says victor@spx-server, you're on the VPS — the command will fail (the VPS can't SSH to itself). Open a new Mac terminal instead.
Server operations (run after SSH'ing in)
Check if the trading server is running
sudo systemctl status spx-server

Look for Active: active (running) in green. Press q to exit the view.

Restart the trading server
sudo systemctl restart spx-server

Then confirm it came back up:

sudo systemctl status spx-server
Avoid restarting during market hours unless necessary — it briefly interrupts the webhook listener.
View the trading server log (live)

Tail the log to watch incoming webhooks in real time:

sudo tail -f /var/log/spx-server.log

Press Ctrl + C to stop watching.

To see just the last 50 lines:

sudo tail -50 /var/log/spx-server.log
Check / restart the dashboard
sudo systemctl status spx-dashboard

Restart if needed:

sudo systemctl restart spx-dashboard
Trading watchlist & strategy operations
Weekly watchlist update (fool.com → strategy)

The Stocks Strategy trades the Stock Advisor Aggressive + Moderate "Buy" lists. Do this check about once a week:

  1. Open the Stock Advisor scorecard page on fool.com (Active tab).
  2. Select the whole page with Cmd+A, copy with Cmd+C. (Copy-paste beats screenshots — nothing gets misread or cut off.)
  3. Paste it to Claude with the message: "Weekly watchlist update — here is the fool.com paste."
  4. Claude runs stocks_strategy/update_universe.py against it and reports three lists: ADD (new recommendations), REMOVE (dropped ones), UNCHANGED.
  5. You approve. Rules Claude follows: a stock with an open position is never removed until it closes; multi-symbol rows (spinoffs, share classes) are flagged for your call, never auto-added.
  6. Claude updates the universe file, the trading server (deploy + restart), and regenerates the three TradingView scripts if tickers changed.
  7. Your only manual step: if scripts changed, re-paste them into TradingView (see the TradingView procedure below). New stocks only trade once their script group is updated there.

Master file: Local_Server/stocks_strategy/stocks_universe.json — every ticker with its sector fund, strategy (S1/S3/S6), and script group (A/B/C).

TradingView scripts & alerts (Stocks A / B / C)

TradingView limits one script to 40 watched symbols, so the stocks universe is split into three generated scripts: A = technology, B = consumer/financial/industrial, C = everything else. Each needs exactly one alert.

To update a script (after a watchlist change):

  1. Find the files in Finder → Dropbox → Mac → Downloads → Local_Server → pine: stocks_multi_strategy_A.pine, _B, _C.
  2. Open the changed file in TextEdit, Cmd+A, Cmd+C.
  3. In TradingView: Pine Editor (bottom of window) → open your saved script of the same letter → Cmd+A, Cmd+VSave. The chart updates itself; the existing alert keeps working.

Creating an alert from scratch: alarm-clock icon → Create alert → Condition = the script → "Any alert() function call" → Notifications tab → tick Webhook URL and paste the webhook address (ends in ?secret=… — it's in your password manager, never in the script).

Each script also draws a small table on the chart's right edge showing its open positions. Settings → Inputs has checkboxes to hide it or show all stocks.

Restart a trading brain or panel (the safe way)

All four brains and the panels restart automatically only if they die "by accident". A polite stop looks intentional, so the supervisor leaves them dead.

Always use kill -9 (or sudo systemctl restart …) — never a plain kill. A plain kill takes the brain down and nothing brings it back.

After SSH'ing in (prompt must say victor@spx-server), restart the stocks brain like this:

kill -9 $(pgrep -f "stocks-server/.venv/bin/python stocks_server.py" | head -1)

Then confirm it came back (should print "ok":true):

sleep 8; curl -s http://127.0.0.1:5109/health

Ports: SPX brain 5005 · ETF brain 5107 · stocks brain 5109 · panels 5106/5108/5110/5111 · dashboard 5006.

Change position size or max open positions

Each brain reads a config file at startup. Current settings (2026-07-27): stocks = $1,000/position, max 15 open; ETF = $1,000/position, max 5 open.

  • Stocks brain: /home/victor/stocks-server/stocks_config.json
  • ETF brain: /home/victor/etf-server/etf_config.json

Edit the number (position_value or max_concurrent_positions), then restart that brain with the kill -9 procedure above. Changes affect new positions only — anything already open keeps its original size until it exits.

Easiest: just ask Claude — "set the stocks brain to $2,000 per position" — and it will edit, restart, and verify.

Manage member plans (tiers) in /admin

Members have a plan: Observer (Home, Strategies, Advisory) → Member (adds Live Dashboard, the four strategy pages, Backtests, Documentation, live positions) → Pro (adds Runbook). Owner and admin accounts always see everything.

  1. Go to victorngoma.com/admin.
  2. In the user table, use the Plan dropdown next to a member — it saves instantly.
  3. When inviting someone, pick their plan in the invite form.

The same page shows Recent visits: who opened the site, when (Chicago time), roughly how long, and how many pages.

Website & access management (Cloudflare)
Add a new user to a locked tool
  1. Go to Cloudflare dashboard → Zero Trust
  2. Access controls → Policies
  3. Click the policy for the tool (e.g. pine-allowed-users) — pick the one with Used by applications = 1
  4. Click Configure
  5. Under Include → Value, type the new email and add it
  6. Click Save policy

The new person can now log in to that tool via email PIN code. Each tool has its own policy/allowlist — add someone to one tool without affecting others.

To remove someone: same steps, click the × on their email chip, then Save.

Update a hub or subdomain page
  1. Edit the index.html file in the matching Mac folder (e.g. victorngoma-hub, victorngoma-pine)
  2. Cloudflare dashboard → Workers & Pages → click the project (e.g. victorngoma-pine)
  3. Create deployment (or drag-and-drop the updated folder)
  4. Upload the new index.html → Deploy

Keep the filename index.html — Cloudflare serves that as the page automatically. Keep each project's files in its own folder.

Add a brand-new locked subdomain

Part 1 — deploy the page:

  1. Make a new Mac folder with an index.html inside
  2. Cloudflare → Workers & Pages → Create application → Pages → "Get started" next to "Drag and drop your files"
  3. Project name (e.g. victorngoma-docs) → Create project → upload folder → Deploy
  4. Custom domains tab → Set up a custom domain → enter the subdomain (e.g. docs.victorngoma.com) → Activate

Part 2 — lock it:

  1. Zero Trust → Access controls → Applications → Add an application
  2. Self-hosted and private → Public DNS → Continue
  3. Destinations: Subdomain = the subdomain, Domain = victorngoma.com, Path = empty
  4. Access policies → Create new policy → name it, Action = Allow, Include → Selector = Emails → add emails → Save policy
  5. Authentication: "Accept all available identity providers" = ON
  6. Details: Name it, Session Duration 24h → Create
After clicking Create, confirm the app appears in the Applications list ("Showing 1-1 of 1" etc). If it doesn't show, the save failed — redo it. A silent save-failure leaves the page unprotected.

Test in a fresh Incognito window (or phone) — you should hit the Cloudflare Access email login. If it loads straight through, the lock isn't active.

Verify a locked page is actually protected
  1. Open a fresh Incognito window, or use your phone
  2. Visit the subdomain
  3. You should see the Cloudflare Access email login page
  4. An email NOT on the allowlist should be denied; an allowed email gets a PIN code by email

If the page loads with no login prompt, the lock isn't working — check the Application exists and its DNS record is orange-clouded (proxied).

Restricted access · Operations runbook · victorngoma.com