EngineSJS

SJS lifecycle

Understand how the engine invokes SJS and how to control work within each frame.

SJS source defines an app function. The shared strategy runner awaits that function with a frame scope containing the current bar, session context, and injected helpers. An invocation is an opportunity to evaluate your strategy, not a guarantee that it should submit an order.

Entry point

This complete observation-only script can replace the quickstart temporarily while checking your data:

export async function app({ bar, log }) {
  log?.("sjs-frame", { date: bar?.date, close: bar?.close });
  return "observed";
}

Use a named app function for inline source as shown here. The inline loader requests that binding. Native-file strategy loading is a separate path; these guides do not require filesystem imports or native module registration.

Where SJS runs

In the shared frame runner, L3's frame hook runs before SJS. SJS is followed by the applicable L2/L1 position or flat/tick branch, then configured native Pine processing. Session preparation and data updates surround that runner.

That order matters when reading evidence from another source. Do not assume an algorithm snapshot or Pine plot already reflects the current frame just because its object exists. See Market data and Execution flow.

Await execution and data reads

Await session methods so you can handle their outcomes before finishing the invocation. Starting background promises inside app can detach errors and decisions from the frame that caused them.

The quickstart sets busy before its first asynchronous execution-state read and clears it in finally. An overlapping invocation waits rather than sending another request against a snapshot already being evaluated. Frames skipped while busy are not queued by this example.

Return versus skip

OperationEffect in the shared runner
returnEnds this SJS invocation; its return value is logged by the runner
skip()Sets flags for subsequent L2 analysis/tick processing
skipall()Sets flags for subsequent L1 and L2 analysis/tick processing

Session L2 algorithms have skip exemptions. The skip flags also influence native Pine's execution skip signal. Neither function cancels an order already submitted, and calling one does not itself return from your JavaScript function.

The quickstart calls skipall() only after an accepted request, then returns. A rejected request leaves those runner flags unchanged.

Cadence and repeated bars

A frame may be a historical bar or a live update, depending on the session. Live cadence can limit heartbeat work without changing what the market-data manager receives. There is no universal “one invocation equals one completed candle” guarantee.

The quickstart therefore defines its own sampling rule: the first valid observation for each strictly increasing timestamp. Later updates with that timestamp are ignored. Use a bar-based historical run to learn this behavior before adapting it to live feeds.

Continue with Context and State.

On this page