Live Trading Portfolio

How strategies trade real money: dollar amounts, automatic reconciliation, close-all, and the kill switch.

Last updated 2026-08

Overview

The trading portfolio is the set of strategies allowed to place real orders. Each strategy in it gets a fixed dollar amount; the reconciler daemon then keeps the positions the strategies themselves opened converged to the combined target — you never place these orders yourself. It only manages its own orders: a position you opened by hand is invisible to it and never touched.

strategy.py ──► state.json ──────────────┐
   (cron)                                ├──► reconciler.py ──► exchange
amounts     ──► portfolio_config.json ───┘

Amount-Based Sizing

Each strategy in the portfolio is assigned an amount in account currency (e.g. USD) — what the strategy trades with when its signal is at full size. The target position per symbol is the sum across strategies:

target[symbol] = Σ ( amount × position )

position is the strategy's signal and can be fractional (a vol-scaled strategy may emit 0.5 or 1.8). The amount you set is exactly what sizes positions — it does not drift with account equity. Exception: for Capital (群益) Taiwan futures strategies the amount is a lot count (number of contracts), not a dollar figure.

Never edit manager/portfolio_config.json by hand. Set amounts from the workspace Trading setup page or ask the agent; optimizer weights are applied only through manager.py, which is dry-run by default and writes the config only with --apply after you confirm.

The Reconciler

The reconciler is a daemon that polls every 5 seconds and reconciles whenever:

  • a strategy updates its signal (state.json changes)
  • you save new amounts in Trading setup
  • the kill switch is tripped or cleared
  • 5 minutes passed without a reconcile — a safety net that catches position drift and dead exchange keys
  • a TWAP or custom execution finishes — so the residual gap converges within one poll instead of waiting for the 5-minute safety net

Each pass compares the target against the bot's own book — the reconciler keeps its own ledger, a running total of every order it has placed (manager/orders.jsonl), rather than reading the account's raw exchange positions, so a position you opened by hand is never read as "already held" and never added to or closed. Orders are then placed to close the gap — market orders by default; each strategy can be set to market, TWAP, chase limit, or a custom execution style in Trading setup (Capital (群益) TW futures support market only). Differences under $10 are ignored (TW futures reconcile in whole lots instead). A position flip (long → short) is split into a reduce-only close plus a fresh open, so hedge-mode accounts never hold both sides at once.

When positions cannot be read from the exchange: a temporary exchange fault (timeout, busy, maintenance) only skips those rounds, and trading resumes by itself once reads succeed; after 30 minutes in a row you are notified. The reconciler trips the kill switch only for an invalid key, missing permissions, an IP not on the whitelist, 3 unrecognized errors in a row, or an account mismatch found at startup, on reconnect, or after a key change — and that switch never clears itself; you decide when to resume.

Close All Positions

Press Pause trading in the workspace and the dialog offers two choices: Pause new positions only trips the kill switch; Pause and close positions (or python3 manager/flatten.py) market-closes the positions the strategies opened — only what is on the bot's own book, so a position you opened by hand is left alone, and spot sells only the coins under strategy management, never your other holdings. It is a panic button, not portfolio management:

  • The kill switch is tripped first, so nothing re-opens after the flatten — trading stays paused until you press Start trading.
  • Positions below the exchange minimum can't be closed — the dust is logged and left.
  • Every close is written to the order history with its exchange-confirmed fill.

Kill Switch (HALT)

While the kill switch is on, any order that would add exposure is refused at the code level. Closing positions, stop-loss / take-profit, and cancels still go through — a halt never traps a position you are trying to reduce.

It is set by Pause trading in the workspace (including Pause and close positions), by telling the agent to stop trading, or automatically on a key or permission error, 3 unrecognized errors in a row, or an account mismatch found at startup, on reconnect, or after a key change (a temporary exchange fault does not trip it — trading resumes by itself once the exchange is back). It is never cleared automatically — trading resumes only when you press Start trading or explicitly ask the agent to resume. Start trading offers two choices as well: Start and catch up positions places market orders immediately to match each strategy's current signal; Start, wait for new signals places no orders now — each strategy starts trading only at its next entry, exit, or flip. Every order attempt and denial is written to an audit log.

Order History & Fills

Every executed order is appended to manager/orders.jsonl with its legs — the exchange-confirmed fill price and executed quantity of each individual leg. A position flip records two legs: the closing leg carries the exit price, the opening leg the entry price.

Partial failures are recorded too: if a flip's closing leg filled but the opening leg failed, the entry is kept and marked failed — the history never hides an order that moved real money. The workspace Order History tab renders this file.