EngineSJS

Working with L3

Add optional higher-level oversight while keeping the main algorithm in SJS.

SJS owns the main strategy: signals, state, entries, and exits. L3 is an optional advanced layer that can observe session evidence, coordinate policies, and approve or reject execution requests.

You do not need to move your algorithm into a policy stack to use L3 oversight. SJS continues to call context.placeOrder and context.closePositions.

For the full hook lifecycle, provider behavior, state, and failure paths, see Advanced L3.

The current integration

SJS app
  → session execution method with source "sjs"
  → automation controls
  → enabled L3 intent hook
  → simulator or broker execution

The ordinary SJS/L2 frame scope does not inject modules.policies. The framework is available to L3, whose script runs its own policy array and returns an aggregate Boolean from its intent export. Exposing policies directly to SJS would be a separate runtime feature, not an existing documentation setup step.

Add the quantity guard

  1. Run the standalone SJS quickstart with L3 disabled and save the baseline results.
  2. Paste Your first policy into the separate L3 editor.
  3. Keep its maximum quantity at two and the SJS quantity at one; the guard should permit an otherwise eligible entry request.
  4. In a fresh experiment, change the SJS quantity to three to exercise rejection on the same signal inputs.
  5. Compare SJS lastAttempt with the L3 stack's lastIntentCheck and actual execution state.

The policy guards the quantity of each request, not total exposure. Its frame hook only observes; the execution check is what rejects the SJS request.

Understand frame timing

L3's app runs before SJS in the shared runner. If it reads context.sjsState.crossoverTutorial.signal, that signal may belong to an earlier frame. Any frame-level use needs an explicit timestamp and freshness rule.

The execution intent hook is different: it runs when SJS calls an execution API. The tutorial attaches its current signal to request metadata, available at args.intent.options?.opt?.metadata?.signal. This gives the check evidence tied to the actual request. That metadata is strategy-supplied evidence, not an independent validation of the market.

Close requests can receive more than one check

In the shared simulated implementation, closePositions first checks a close_position intent and then calls order placement, which checks a place_order intent with the same execution source/options.

Consequently, a policy allowing explicit closes can still reject the delegated order. For example, the quantity guard allows the close-kind check but can reject a closing order whose quantity exceeds its maximum. The stack's lastIntentCheck then describes the most recent check, which can be the delegated placement.

If you need different entry and exit rules, design them using the actual position and request semantics of the target runtime, and test both paths. Do not assume a permissive close-kind branch proves the eventual close will execute. Broker-native implementations can have different paths.

Keep sources accurate

Ordinary SJS requests should identify themselves as sjs. Frame-policy actions submitted by the L3 executor use l3 and bypass the L3 intent hook, while automation controls still apply. Manual requests follow the runtime's manual-override behavior.

These are execution-source contracts, not settings to change to force an order through a gate. See Execution flow for the complete distinction.

Grow the advanced layer deliberately

L3 can add reusable policy checks, shared coordination, or provider-backed analysis when the strategy needs them. Define missing-evidence, stale-evidence, and failure behavior before allowing those decisions to affect execution. Agent Lab's authoring model and an L3 provider call during strategy execution remain separate capabilities.

Continue with Policies, Intents, and Policy debugging.

On this page