Debugging SJS
Trace input validation, signal generation, execution state, and order outcomes.
Investigate the first point where the observed behavior diverges from your expectation. An empty trade list can mean missing data, no crossover, an existing order, a rejected request, or a still-pending fill.
Follow the tutorial state
- Check that saved SJS source defines
appand that frames reach it. Use the observation-only script if necessary. - Inspect the input timestamp and finite close. Invalid observations leave no new sample.
- Inspect
closesandpreviousRelation. Three samples establish a relation; a later crossing produces an actionable signal. - Compare
signal.framewith the current market timestamp. - Check orders and positions before investigating submission behavior.
- Inspect
lastAttempt, thesjs-crossoverlog, and actual trades/positions.
Common symptoms
| Symptom | Next check |
|---|---|
| No state namespace | Wrong source field, compilation error, missing frames, or invalid input |
| Warmup never completes | Input gaps repeatedly exceed the configured limit |
| Price above average but no BUY | The strategy requires a crossover, not merely an above-average value |
| Updated live close is ignored | That timestamp was already consumed under the first-observation rule |
| Crossover but no attempt | Existing orders, unavailable order inspection, multiple positions, or an incompatible position |
| No retry after a rejected entry | The signal is consumed; retry logic is not implemented |
| Accepted request but no trade | Inspect pending orders and the runtime's fill behavior |
| Exit request rejected with L3 enabled | Inspect both close and possible delegated place checks |
| Old error still visible | lastError is the last caught error, not a current-frame status |
Missing modules.policies | That module bag belongs to the L3 scope, not SJS |
Errors versus rejected results
The quickstart catches exceptions from execution-state reads and submission, records the message, and releases its local busy flag. Some shared execution methods catch their own failures and return false or no result, so those appear as not-accepted rather than entering the script's catch block.
A missing required capability is a separate case: the example returns a waiting reason and sends no request. Avoid interpreting a missing getOrders() as an empty list.
Fixed-input checks
Before changing the strategy, reproduce a small set of behaviors: warmup, one upward crossover, one downward crossover, duplicate timestamps, older timestamps, a long gap, pending orders, an existing short, and a rejected request.
The documentation's tests extract the runnable snippets and use deterministic session stubs. They check strategy decisions and API interactions; they do not simulate real broker fills or verify every engine runtime mode.
For historical comparisons, keep the source revision, instrument, input data, interval, and fill settings together. Change one behavior at a time. See Examples.