Simulated execution and fills
Understand the generic memory simulator's price checks, market-time delay, and closing behavior.
This page describes the shared execution path used by the generic memory session. Broker-native sessions and specialized simulators can behave differently. Treat the chosen execution path as part of the test configuration.
A request can fill during submission
Shared placeOrder validates basic input, applies automation and L3 checks, and checks execution eligibility and duplicate orders. An accepted order is added to the session's orders and immediately passed to the fill routine.
The replay loop also checks outstanding orders before running strategies on an eligible observation. With zero delay and an available qualifying quote, a newly placed order can therefore fill on the same observation that produced the signal. This is not an automatic next-bar-open model.
The fill routine uses the session quote for the instrument, with the supplied current observation as a fallback. Filled prices use that quote's close.
Price conditions
| Order type | BUY eligibility | SELL eligibility |
|---|---|---|
MARKET | No additional order-type price threshold | No additional order-type price threshold |
LIMIT | Quote close at or below limit | Quote close at or above limit |
STOP | Quote close at or above stop | Quote close at or below stop |
STOP_LIMIT | Quote close satisfies both stop and limit checks | Quote close satisfies both stop and limit checks |
The shared checks do not infer an intrabar path from high and low. A stop touched by a bar's high but not by its available close need not trigger here. The stop-limit implementation checks both thresholds on the current quote; it does not model a separately latched stop activation that persists independently of the later limit check.
When eligible, the fill uses the quote close, not necessarily the submitted limit or stop price. This routine does not model exchange queue position or a volume-based partial-fill process.
Fill delay uses market time
orderFillDelay is measured in seconds. The shared path compares the order timestamp with context.currentTime and keeps it pending until enough simulated time has elapsed. An order without an explicit date is stamped from the session clock when placed.
For an order submitted at 10:00:00 with a 90-second delay and one-minute observations, the 10:01:00 check is too early. The 10:02:00 check is the first scheduled observation old enough to fill it, assuming that observation is processed and all other conditions pass. There is no synthetic 10:01:30 fill event.
Elapsed wall-clock runtime is irrelevant to this delay. A fast replay can represent hours of market time in seconds.
Other reasons an order can remain pending
Missing quotes, capital checks, trade limits, and unmet price conditions can prevent filling. The shared routine also avoids processing a trade ID already recorded. These mechanisms are not a complete broker margin or matching model.
The SJS crossover waits when any order exists. Increasing delay can cause it to consume an EXIT crossover while an entry remains pending. Read SJS state before interpreting this as an exit-policy error.
Closing during and after replay
The shared close path applies a close-kind gate, removes matching existing orders, and delegates to order placement. That delegated request can encounter another gate and the same fill-delay logic. See Working with L3.
After its replay loop finishes, the memory session calls closeAllPositions() and then marks the session completed. This is a close attempt, not proof of a flat final account. A newly delayed closing order may have no later observation on which to fill, and execution controls can also reject the request.
Distinguish strategy exits, session-boundary closes, and run-end close attempts when reading the last trades. Continue with Reading results.