Quant Trading for Programmers 24: Persist Paper-Trading Account State
· 12 min read · Views --
Last updated on

Quant Trading for Programmers 24: Persist Paper-Trading Account State

Author: Alex Xiang


Quant Trading for Programmers 24: Persist Paper-Trading Account State

Article 23 linked the daily paper-trading flow. But if the account state disappears after a program restart, that flow is only a demo.

Article 24 first saves and restores the paper-trading account state with a JSON file. It is not the final production storage plan, but it is enough to let the local practice project keep running across days.

A ZiCode engineer saving paper-trading account state

Persist Only Base State

Chapter 24 adds app/paper_state_store.py.

It saves only cash and positions. It does not save derived results such as snapshots, daily reports, or recommendation summaries.

The advantage is that after restore, the system can recompute snapshots and risks from the latest market data instead of mistaking old derived state for current state.

Paper-trading state can roughly be split into two categories: base state and derived state. Base state includes cash, position shares, average cost, and realized PnL. Derived state includes market value, weights, risk level, recommendation action, and daily report body. Base state should be persisted. Derived state should usually be recalculated.

Convert To A Dictionary

def paper_account_to_dict(account: PaperAccountState) -> dict[str, Any]:
    return {
        "cash": account.cash,
        "positions": {
            symbol: {
                "symbol": position.symbol,
                "shares": position.shares,
                "avg_cost": position.avg_cost,
                "realized_pnl": position.realized_pnl,
            }
            for symbol, position in sorted(account.positions.items())
        },
    }

The implementation deliberately sorts by symbol so the same account writes stable JSON across multiple saves. That makes diffs and debugging easier.

Save And Restore

save_paper_account(account, "data/paper-account.json")
account = load_paper_account("data/paper-account.json")

The implementation only uses standard-library json and pathlib. When paper-trading state becomes more complex, migrating to a database can happen later.

Current Integrated Run

The paper-ops command saves the account state once in a temporary directory, restores the account from JSON, and then continues running the daily flow:

uv run python -m scripts.chapter_examples paper-ops

Account state save-and-restore output generated by the paper-ops command

This example intentionally saves only cash and positions. Trade date, latest prices, risk conclusions, and recommendation summaries are not written into the account state file because they should be recalculated as daily market data changes. This also makes it easier to replace JSON with SQLite or PostgreSQL later: the domain object does not need to change with the storage medium.

Chapter Update And Repository

This chapter adds:

  • app/paper_state_store.py.
  • Conversion from a paper-trading account to a dictionary.
  • JSON file save and restore functions.
  • Backward compatibility for old payloads missing realized_pnl.
  • An integrated paper-ops example showing account state persistence, restore, and continued daily flow execution.
  • Context for separating base state from derived state in persistence design.
  • tests/test_paper_state_store.py, covering in-memory round trips, file save/read, and old-format compatibility.

Repository:

https://github.com/ax2/zi-quant-platform

Code for this chapter:

git clone https://github.com/ax2/zi-quant-platform.git
cd zi-quant-platform
git checkout chapter-24
uv sync --extra dev
uv run pytest tests/test_paper_state_store.py

Chapter 24 is commit 3c3c52b, tagged as chapter-24.

Summary

Being able to calculate one day does not mean the system can run continuously.

Article 24 lets the paper-trading account state be written to disk and restored. The next article adds production checks so missing prices, target-weight errors, or empty daily reports do not silently enter the daily flow.