Simulation and Replay¶
TL;DR
Use a paper executor to test order and accounting behavior without sending orders to a live venue. Use REPLAY mode to rerun recorded events through your strategy. Always validate with paper before going live.
Paper execution¶
Paper accounts use the same executor and receipt interfaces as live accounts. The difference is where fills come from: a live executor gets fills from an exchange; a paper executor simulates fills from a configured data source.
device::BoundExecutor paper_;
paper_ = bind<device::BoundExecutor>(paper::Account{
.id = "paper",
.balances = {
{.asset = "USDT", .amount = Notional{100'000}},
{.asset = "BTC", .amount = Notional{0}},
},
.instruments = {
Instrument::Spot("BTCUSDT", "BTC", "USDT"),
},
.simulation = paper::fromBar{
.topic = "bar://okx/BTCUSDT@1m",
.latency = time::milliseconds(100),
},
});
Note
fromBar fills from the configured bar stream — each bar close becomes a
fill price. This is a simplified fill model suitable for strategy logic
validation. It is not a substitute for exchange queue simulation, which
would model individual order matching against a limit order book. Choose the
simulation model that matches what you are testing.
Replay mode¶
sdk::Application({
.mode = sdk::RuntimeMode::REPLAY,
.replay = ReplayConfig{.speed = 0.0},
})
speed = 0 processes eligible events without wall-clock pacing. A positive
speed maps logical event time to wall time.
Decision tree: Which mode should I use?¶
What are you trying to do?
Test strategy logic with fake fills?
→ LIVE mode + paper::Account
Run historical data through your strategy?
→ REPLAY mode
Paper trade with real-time market data?
→ LIVE mode + paper::Account
Trade with real money?
→ LIVE mode + venue executor (see live-trading)
Tip
A common workflow: develop in LIVE + paper, replay historical data to validate the strategy across a broader date range, then switch to LIVE + venue executor for production. Each mode catches different classes of bugs.
Runtime controls¶
Installed replay projects support pause and resume:
aurum pause replay-demo
aurum resume replay-demo
Runtime controls currently operate on the selected local Aurum home and do not
accept --server. Use the Forge environment’s operator surface when the
instance runs remotely.
Validate before live trading¶
Confirm at least the following before replacing a paper executor with a live venue executor:
[ ] expected resource keys appear in the runtime catalog
[ ] rejected and partially filled receipts are handled
[ ] balances and positions converge after fills
[ ] replay completes without dropped lossless events
[ ] strategy identity and version are ready for an immutable push
Warning
A strategy that works perfectly in paper can fail in live trading for reasons unrelated to fill accuracy: network latency, exchange rate limits, credential expiration, partial fills at unexpected prices, or venue-specific order rejection rules. Paper validates your strategy logic. It does not validate your operational readiness.
Common mistakes¶
- Treating paper fills as identical to live fills.
fromBarfills every market order at the bar close price. A live venue fills at the prevailing bid/ask, which may be far from the bar close during volatile periods. Paper tells you if your logic is correct; it does not tell you if your execution quality will be good.- Not handling rejected receipts in paper mode.
Even paper executors can reject orders (e.g., insufficient balance). If your strategy only handles
acceptedand ignoresrejected, you may not notice that your paper account ran out of funds.- Using REPLAY speed=0 for real-time-sensitive logic.
speed=0processes events as fast as the CPU allows. If your strategy has wall-clock-dependent behavior (timeouts, rate limiters), it will behave differently at speed=0 than at speed=1.0. Test at multiple speeds.
Next steps¶
To switch to live trading, read Live Trading.
For the executor API, read C++ SDK Reference.
To understand the determinism guarantees for replay, read Reactive Application Model.