trader.persistence.simulation module¶
Repository for the shadow-portfolio simulator’s five tables (issue #33).
One session per call, matching every other repository in this package — the simulator is not performance-critical (it steps at most a handful of times per real trading day, per strategy), so consistency with the rest of the codebase’s style matters more than batching writes into fewer transactions.
simulation/step.py reads a value (e.g. a position’s current high_water_mark) via one call, decides what to do with it, then writes the result via a second call — deliberately, so the “test the stop against the prior high-water mark” ordering the design spec requires falls out of the caller’s own control flow rather than needing an in-repository transaction.
- trader.persistence.simulation.ABB_PORTFOLIO_SUFFIX = '::abb'¶
Suffix appended to a real strategy_id to build the Always-be-Buying variant’s portfolio identity (issue #42) — its own SimPortfolio row, reading the same strategy_id’s recorded decisions but with sell signals ignored, so only the trailing stop can ever close a position. sim_portfolios.strategy_id has no format constraint, so this is a convention, not a database rule: “::” cannot appear in a bare YAML scalar id without quoting (config/strategies.yaml’s id: str has no character restriction of its own), and no configured strategy uses it, so in practice this suffix cannot collide with a real strategy id.
- class trader.persistence.simulation.SimulationRepository(session_factory)[source]¶
Bases:
objectWrites and reads the sim_* tables.
- Parameters:
session_factory (sessionmaker[Session])
- get_or_create_portfolio(strategy_id, *, starting_cash)[source]¶
The portfolio for strategy_id, creating it (seeded at starting_cash) on first use. starting_cash is ignored on every call after the first — a config edit must not silently reset an accumulating ledger.
- Parameters:
strategy_id (str)
starting_cash (Decimal)
- Return type:
- update_cash(portfolio_id, cash)[source]¶
- Parameters:
portfolio_id (int)
cash (Decimal)
- Return type:
None
- update_last_bar_ts(portfolio_id, bar_ts)[source]¶
- Parameters:
portfolio_id (int)
bar_ts (datetime)
- Return type:
None
- all_portfolios()[source]¶
- Return type:
list[SimPortfolio]
- get_position(portfolio_id, symbol)[source]¶
- Parameters:
portfolio_id (int)
symbol (str)
- Return type:
SimPosition | None
- all_positions(portfolio_id)[source]¶
- Parameters:
portfolio_id (int)
- Return type:
list[SimPosition]
- open_position(portfolio_id, symbol, *, quantity, entry_price, high_water_mark, last_price, opened_at, entry_confidence=None)[source]¶
entry_confidence (issue #83) defaults to None for every caller that predates it — an intentional “unknown”, never a guessed value — and is read once here, at fill time, from the decision that caused this order (see simulation/step.py’s own lookup at the fill step).
- Parameters:
portfolio_id (int)
symbol (str)
quantity (Decimal)
entry_price (Decimal)
high_water_mark (Decimal)
last_price (Decimal)
opened_at (datetime)
entry_confidence (float | None)
- Return type:
- mark_position(position_id, *, high_water_mark, last_price)[source]¶
Write a new mark. The caller reads the prior value before calling this — this method never returns the old one, on purpose, so there is no temptation to test a breach against a value this same call just overwrote.
- Parameters:
position_id (int)
high_water_mark (Decimal)
last_price (Decimal)
- Return type:
None
- create_order(portfolio_id, symbol, *, decision_id, limit_price, quantity, created_bar_ts)[source]¶
- Parameters:
portfolio_id (int)
symbol (str)
decision_id (int | None)
limit_price (Decimal)
quantity (Decimal)
created_bar_ts (datetime)
- Return type:
- record_round_trip(portfolio_id, symbol, *, decision_id, quantity, entry_price, exit_price, realized_pl, opened_at, closed_at, exit_reason)[source]¶
- Parameters:
portfolio_id (int)
symbol (str)
decision_id (int | None)
quantity (Decimal)
entry_price (Decimal)
exit_price (Decimal)
realized_pl (Decimal)
opened_at (datetime)
closed_at (datetime)
exit_reason (str)
- Return type:
- round_trips(portfolio_id)[source]¶
- Parameters:
portfolio_id (int)
- Return type:
list[SimRoundTrip]
- snapshot_equity(portfolio_id, bar_ts, equity)[source]¶
Insert one equity snapshot. Returns whether it was inserted.
False (not an exception) on the (portfolio_id, bar_ts) unique constraint firing — the second of the step’s two idempotency mechanisms, alongside SimPortfolio.last_bar_ts: a step re-asked to apply an already-applied bar must no-op, not double the curve.
- Parameters:
portfolio_id (int)
bar_ts (datetime)
equity (Decimal)
- Return type:
bool
- equity_curve(portfolio_id)[source]¶
- Parameters:
portfolio_id (int)
- Return type:
list[SimEquitySnapshot]