alpha-forge live¶
Live trading event ingestion (VPS → local), raw event → trade record conversion, performance analysis, and backtest comparison. Integrates with alpha-forge journal to surface live results.
About sample output
Sample outputs in this page are based on the formats read from the alpha-forge source. Actual values and formatting depend on the format_* functions in live/formatter.py.
Typical operation flow¶
1. alpha-forge live sync-events Pull raw events from VPS
2. alpha-forge live convert-check Verify conversion readiness
3. alpha-forge live import-events Generate trades from fill / close events
4. alpha-forge live summary Show live performance summary
5. alpha-forge live compare Compare with the latest backtest run
Subcommands¶
| Command | Description |
|---|---|
alpha-forge live list |
List strategies that have live trading records |
alpha-forge live events |
List raw trading events |
alpha-forge live convert-check |
Check readiness to convert raw events to trade records |
alpha-forge live import-events |
Generate and save trade records from fill / close events |
alpha-forge live trades |
List individual trade records for a strategy |
alpha-forge live summary |
Show live performance summary for a strategy |
alpha-forge live compare |
Compare the latest backtest run with live summary |
alpha-forge live doctor |
Check the setup status of live trading analysis |
alpha-forge live sync-events |
Sync event logs from VPS to local via rsync |
alpha-forge live replay |
Reconstruct position-based live metrics from a combine portfolio's alert log |
alpha-forge live list¶
Walk <journal_path>/../live/ to find strategies that have live records (trade records or event logs).
Synopsis¶
Arguments and options¶
None.
Sample output¶
Formatting is delegated to format_live_list.
alpha-forge live events¶
List raw events emitted by brokers (e.g., fill, close). Without filters, the latest --limit records are shown.
Synopsis¶
Arguments and options¶
| Name | Kind | Default | Description |
|---|---|---|---|
--strategy |
option | - | Filter by strategy_id (renamed from --strategy-id in epic #1083 D) |
--event-type |
option | - | Filter by event_type (e.g., fill, close) |
--broker |
option | - | Filter by broker |
--limit |
int | 20 |
Number of records to display |
--json |
flag | false | Emit the result as JSON ({events: [...], count}) |
Sample output¶
=== live events ===
2026-04-15T09:31:00+00:00 | fill | spy_sma_v1 | SPY | buy | filled | sig_0042
2026-04-15T14:02:00+00:00 | trade_closed | spy_sma_v1 | SPY | sell | closed | sig_0042
Formatting is delegated to format_live_events. Each row is pipe (|) delimited in the order timestamp (ISO format) / event_type / strategy_id / symbol (ticker) / side (action) / status / signal_id. There are no broker / qty / price columns. You can still filter with --broker, but the broker value itself is not shown in the rows.
alpha-forge live convert-check¶
Check whether raw events can be converted to trade records (whether fill and close pairs are matched, etc.). Recommended as a pre-step to import-events.
Synopsis¶
Arguments and options¶
| Name | Kind | Default | Description |
|---|---|---|---|
--strategy |
option | - | Filter by strategy_id (renamed from --strategy-id in epic #1083 D) |
Sample output¶
=== event conversion report ===
strategy_id : spy_sma_v1
total_events : 96
total_signals : 20
total_orders : 18
total_fills : 16
total_trade_closed : 16
accepted_orders : 18
failed_orders : 0
live_events : 80
paper_events : 16
signals_without_orders : 2
accepted_missing_strategy_meta : 0
accepted_missing_snapshot_id : 0
accepted_missing_fill_data : 2
accepted_missing_close_data : 2
fill_events_missing_trade_id : 0
trade_closed_missing_pnl : 0
conversion_ready : yes
Formatting is delegated to format_event_conversion_report (the EventConversionReport model). The header is === event conversion report === and each field is printed as key : value. conversion_ready is yes / no. When there are conversion blockers, a blockers : section and the list follow at the end. There are no matched / pending / status (ready/partial/missing) columns.
alpha-forge live import-events¶
Generate trade records from fill / close events and save them to a SQLite DB (backtest_results.db under config.report.output_path). Trades and summaries were migrated from JSON files to SQLite in v0.12.0; no JSON is written to <live_path>/trades/ or <live_path>/summaries/.
Synopsis¶
Arguments and options¶
| Name | Kind | Default | Description |
|---|---|---|---|
STRATEGY_ID |
argument (required) | - | Target strategy ID |
Prerequisites for raw event → trade records conversion¶
- Event logs for the
strategy_idmust exist under<live_path>/events/(fetched viaalpha-forge live sync-events, or placed manually) - Each entry must have a paired
fillevent andcloseevent - Verify with
alpha-forge live convert-checkfirst thatconversion_ready : yes - Running once per
strategy_idpersists the trade records to SQLite (re-runs overwrite)
Sample output¶
Only three fields are printed: imported_trades / strategy_id / db_path (no trades_file / summary_file). The trade records are stored in the SQLite DB referenced by db_path.
Common errors¶
| Message | Cause | Fix |
|---|---|---|
Failed to generate trade records: <id> |
Unmatched fill / close pairs or missing events |
Diagnose with alpha-forge live convert-check --strategy <id> |
alpha-forge live trades¶
List individual trade records for a strategy.
Synopsis¶
Arguments and options¶
| Name | Kind | Default | Description |
|---|---|---|---|
STRATEGY_ID |
argument (required) | - | Strategy ID |
--limit |
int | 50 |
Number of records. 0 = show all |
--side |
choice | - | Filter by long / short |
--exit-reason |
option | - | Filter by exit_reason |
--json |
flag | false | Emit the result as JSON ({strategy_id, trades: [...], count}) |
Trades are sorted newest-first (entry_at descending). When the strategy exists but has zero trades, --json returns status: "no_trades_yet" plus an empty envelope (exit code 0), treating it as a normal case.
Sample output¶
=== live trades ===
entry_at symbol side qty entry exit net_pnl ret% hold_m exit_reason
──────────────────────────────────────────────────────────────────────────────────────────────────────────────
2026-04-15 09:31 SPY long 100.00 452.3000 458.1200 +582.00 +1.29% 271 take_profit
2026-04-12 10:05 SPY long 100.00 451.0000 449.1000 -190.00 -0.42% 343 stop_loss
Formatting is delegated to format_live_trades. Columns are entry_at / symbol / side / qty / entry / exit / net_pnl / ret% / hold_m (holding minutes) / exit_reason. There are no trade_id or exit_at columns.
Common errors¶
| Message | Cause | Fix |
|---|---|---|
No live trade records found: <id> |
No trade records for the strategy in SQLite | Generate via alpha-forge live import-events <id> |
alpha-forge live summary¶
Show the live performance summary. If the summary has not yet been built, it is constructed from trade records on the fly.
Synopsis¶
Arguments and options¶
| Name | Kind | Default | Description |
|---|---|---|---|
STRATEGY_ID |
argument (required) | - | Strategy ID |
--json |
flag | false | Emit the result as JSON (dumps StrategyLiveSummary; zero trades returns summary: null + status: "no_trades_yet" with exit code 0) |
Sample output¶
=== spy_sma_v1 live summary ===
version : v1.1.0
snapshot_id : snap_20260415
broker : ibkr
symbols : SPY
total_trades : 16
win_rate_pct : 56.25
gross_pnl : 1280.00
net_pnl : 1184.50
profit_factor : 1.92
avg_win : 185.30
avg_loss : -112.40
avg_slippage_bps : 1.80
total_commission : 95.50
max_drawdown_pct : -4.20
Formatting is delegated to format_live_summary (the StrategyLiveSummary model). Fields are version / snapshot_id / broker / symbols / total_trades / win_rate_pct / gross_pnl / net_pnl / profit_factor / avg_win / avg_loss / avg_slippage_bps / total_commission / max_drawdown_pct. There is no total_pnl_pct, sharpe_ratio, or period. avg_win / avg_loss are absolute amounts (P/L in the position currency), not percentages.
Common errors¶
| Message | Cause | Fix |
|---|---|---|
No live summary found: <id> |
Cannot build (no trade records) | Run alpha-forge live import-events <id> first |
alpha-forge live compare¶
Compare the latest backtest run with the live summary side by side to evaluate whether live behavior matches expectations.
Synopsis¶
The two meanings of compare
live compare is a read-only command that merely references the saved latest backtest run and live summary (it does not run a new backtest). Running a fresh backtest for comparison is the distinct, heavyweight backtest compare.
Arguments and options¶
| Name | Kind | Default | Description |
|---|---|---|---|
STRATEGY_ID |
argument (required) | - | Strategy ID |
--json |
flag | false | Emit the result as JSON ({strategy_id, backtest_run, backtest: {...}, live: {...}}) |
Sample output¶
=== spy_sma_v1 live vs backtest ===
backtest_run : run_20260410181522
backtest_symbol : SPY
live_symbols : SPY
snapshot_id : snap_20260415
metric backtest live delta
──────────────────────────────────────────────────────────────
total_trades 18 16 -2
win_rate_pct 58.30% 56.25% -2.05%
profit_factor 2.10 1.92 -0.18
total_return_pct +12.40% - -
max_drawdown_pct -3.80% -4.20% -0.40%
net_pnl - 1184.50 -
avg_slippage_bps - 1.80 -
Formatting is delegated to format_live_compare. The header is === <id> live vs backtest ===, followed by backtest_run / backtest_symbol / live_symbols / snapshot_id metadata lines and then a metric / backtest / live / delta table. The rows are total_trades / win_rate_pct / profit_factor / total_return_pct / max_drawdown_pct / net_pnl / avg_slippage_bps. There is no sharpe_ratio row. Metrics available only on the backtest side (total_return_pct) or only on the live side (net_pnl / avg_slippage_bps) render - on the missing side.
Common errors¶
| Message | Cause | Fix |
|---|---|---|
No live summary found: <id> |
Live summary missing | Run alpha-forge live import-events <id> |
No backtest run found: <id> |
No backtest run in journal | Run alpha-forge backtest run and let it record |
alpha-forge live doctor¶
Diagnose the setup status of live trading analysis. With STRATEGY_ID, also checks trade and summary readiness for that strategy.
Synopsis¶
Arguments and options¶
| Name | Kind | Default | Description |
|---|---|---|---|
STRATEGY_ID |
argument (optional) | - | Strategy ID (enables detailed checks) |
--json |
flag | false | Emit the diagnostics as JSON (same data as the text output) |
Sample output (no strategy ID)¶
=== live trading doctor ===
live_path : data/live
events_path : data/live/events
db_path : data/results/backtest_results.db
events_exists : yes
event_files : 24
hint : pass a strategy_id to validate trades/summary readiness
There are no trades_path / summaries_path lines. Because trades and summaries are stored in SQLite (the backtest_results.db referenced by db_path), db_path is shown instead.
Sample output (with strategy ID)¶
=== live trading doctor ===
live_path : data/live
events_path : data/live/events
db_path : data/results/backtest_results.db
events_exists : yes
event_files : 24
strategy_id : spy_sma_v1
trades_exists : yes
summary_exists : yes
rollout_status : ready
When trades exist but the summary has not been built, it is constructed on the spot and a summary_built : yes line is added. rollout_status is ready when events_exists is true, event_files > 0, and either trades_exists or summary_exists is true; otherwise incomplete.
alpha-forge live sync-events¶
Sync event logs from VPS to local via rsync.
Synopsis¶
Arguments and options¶
| Name | Kind | Default | Description |
|---|---|---|---|
--dry-run |
flag | false | Show file list only without actual transfer |
rsync configuration (forge.yaml)¶
forge.yaml requires a remote section like:
remote:
enabled: true
user: <SSH_USER>
host: <VPS_HOST>
events_path: /var/log/alpha-strike/events # VPS-side event log directory
local_events_path: ./data/live/events # Local destination (optional, default ./data/live/events)
ssh_key_path: ~/.ssh/id_ed25519 # SSH key (optional, falls back to default)
| Key | Required | Description |
|---|---|---|
remote.enabled |
✓ | Set to true |
remote.host |
✓ | VPS hostname or IP |
remote.user |
✓ | SSH login user |
remote.events_path |
✓ | Event log directory on VPS (absolute path recommended) |
remote.local_events_path |
- | Local destination (defaults to ./data/live/events) |
remote.ssh_key_path |
- | SSH key path (uses default key when omitted) |
rsync command executed¶
rsync -avz --progress -e "ssh -i <ssh_key_path>" \
<user>@<host>:<events_path>/ <local_events_path>/
With --dry-run, rsync --dry-run -avz ... runs without actually transferring. The timeout is 300 seconds.
Sample output¶
Syncing: ubuntu@vps.example.com:/var/log/alpha-strike/events/ → ./data/live/events/
sending incremental file list
events_20260415_093021.json
2,318 100% 12.45MB/s 0:00:00
events_20260415_140215.json
1,842 100% 15.20MB/s 0:00:00
sent 4,312 bytes received 78 bytes total size 4,160
Common errors¶
| Message | Cause | Fix |
|---|---|---|
Error: remote is disabled. Set remote.enabled to true in forge.yaml. |
remote.enabled is false |
Set enabled: true in forge.yaml |
Error: Set remote.host, remote.user, and remote.events_path. |
Required key missing | Complete the remote section |
Error: rsync timed out (300s). Check your VPS connection. |
Network or SSH issue | Verify connectivity, key, and firewall |
Exit codes¶
- Success:
0 - Missing config:
1 - rsync timeout:
1 - rsync own error: propagates rsync's exit code as is
alpha-forge live replay¶
Reconstruct position-based live metrics from a combine portfolio's alert log. Intended for always-in-market combine overlays: it rebuilds position transitions from synced alpha-strike events (alpha-forge live sync-events) and computes Sharpe / CAGR / MaxDD from the portfolio equity curve. order_reconciled receipts are preferred as the authoritative source.
Synopsis¶
alpha-forge live replay <PORTFOLIO_ID> --combine-strategies <ID1,ID2,...> [--since <ISO>] [--compare]
Arguments and options¶
| Name | Kind | Default | Description |
|---|---|---|---|
PORTFOLIO_ID |
argument (required) | - | Combine portfolio ID |
--combine-strategies |
option (required) | - | Comma-separated combine strategy IDs (2 or more required) |
--since |
option | - | Lower bound of the period (ISO format; UTC assumed when no timezone) |
--compare |
flag | false | Also run the backtest combine and show it side by side |
Sample output¶
=== live replay (position-based) — combo_spy_qqq ===
receipts: 128
| Metric | Live | Backtest |
|------------------|-----------|-----------|
| sharpe_ratio | 1.21 | 1.38 |
| cagr_pct | 14.30 | 16.80 |
| max_drawdown_pct | -5.40 | -4.90 |
| total_return_pct | +9.85 | +11.20 |
The Backtest column appears only when --compare is passed. When no receipts match the portfolio_id, a warning is shown prompting you to confirm alpha-forge live sync-events has been run.
Common errors¶
| Message | Cause | Fix |
|---|---|---|
--combine-strategies must list 2 or more strategies (comma-separated) |
Fewer than 2 strategy IDs provided | Pass at least two IDs, e.g. --combine-strategies spy_sma_v1,qqq_hmm_v1 |
Failed to parse --since as ISO: ... |
Invalid ISO datetime | Use an ISO 8601 value, e.g. 2026-03-01 or 2026-03-01T00:00:00Z |
Common behavior¶
- Storage location:
- raw event logs:
<journal_path>/../live/events/(JSON on the filesystem) - trade records / summary: a SQLite DB (
backtest_results.dbunderconfig.report.output_path). Migrated from JSON files intrades//summaries/to SQLite in v0.12.0
- raw event logs:
forge.yaml: All paths above are determined by theforge.yamlreferenced by theFORGE_CONFIGenvironment variable- VPS integration:
sync-eventsreads theremote.*section offorge.yaml - Exit codes:
0on success; argument errors return Click's2; missing config or records typically1 --jsonoutput rules:list/events/trades/summary/compare/doctorsupport--json. When--jsonis set, stdout contains pure JSON only; decoration, progress, and save messages go to stderr. List commands return{<plural>: [...], "count": n}(empty array + exit code0when absent), while single-record commands return a{error, code, id}JSON to stdout with exit code1on not-found.