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
| Operation | Effect in the shared runner |
|---|---|
return | Ends 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.