EngineSJS

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

  1. Check that saved SJS source defines app and that frames reach it. Use the observation-only script if necessary.
  2. Inspect the input timestamp and finite close. Invalid observations leave no new sample.
  3. Inspect closes and previousRelation. Three samples establish a relation; a later crossing produces an actionable signal.
  4. Compare signal.frame with the current market timestamp.
  5. Check orders and positions before investigating submission behavior.
  6. Inspect lastAttempt, the sjs-crossover log, and actual trades/positions.

Common symptoms

SymptomNext check
No state namespaceWrong source field, compilation error, missing frames, or invalid input
Warmup never completesInput gaps repeatedly exceed the configured limit
Price above average but no BUYThe strategy requires a crossover, not merely an above-average value
Updated live close is ignoredThat timestamp was already consumed under the first-observation rule
Crossover but no attemptExisting orders, unavailable order inspection, multiple positions, or an incompatible position
No retry after a rejected entryThe signal is consumed; retry logic is not implemented
Accepted request but no tradeInspect pending orders and the runtime's fill behavior
Exit request rejected with L3 enabledInspect both close and possible delegated place checks
Old error still visiblelastError is the last caught error, not a current-frame status
Missing modules.policiesThat 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.

On this page