feature
EMA cross
Fires when a fast EMA crosses above a slow EMA. Uses the public Moving Average indicator as a dependency instead of re-implementing EMA math.
What it defines
Event ema_cross_up on the bar where fast MA crosses from at-or-below slow MA to above it.
Key decisions
Piece | Why it matters |
|---|---|
Two | Same slug ( |
Guard | Deps are empty during warmup — skip, do not emit. |
Read-then-write | Identity read returns last bar’s values; second call stores today’s. |
| At most one emit per session window (optional throttle). |
Full script
meta({
name: "EMA cross up",
kind: "flow",
slug: "ema-cross-up",
shortName: "EmaXUp",
});
indicators.declare({
slug: "ma",
as: "fast",
version: 1,
settings: { period: 9, maType: "EMA" },
});
indicators.declare({
slug: "ma",
as: "slow",
version: 1,
settings: { period: 21, maType: "EMA" },
});
events.declare({
id: "ema_cross_up",
intent: "Fast EMA crosses above slow EMA",
payload: {
fast: { type: "number", description: "Fast EMA" },
slow: { type: "number", description: "Slow EMA" },
close: { type: "number", description: "Close at cross" },
},
paint: "pin",
oncePer: { keys: ["session"], windowBars: 1 },
});
outputs.declare({ id: "fast_line", kind: "line", name: "Fast", color: "#26a69a" });
outputs.declare({ id: "slow_line", kind: "line", name: "Slow", color: "#ef5350" });
export function onBar(ctx) {
const fast = ctx.indicators.fast?.value;
const slow = ctx.indicators.slow?.value;
if (fast == null || slow == null) return;
ctx.plot("fast_line", fast);
ctx.plot("slow_line", slow);
// Identity update returns the stored prior values without changing them.
const prevFast = ctx.accum("prevFast", null, (prev) => prev);
const prevSlow = ctx.accum("prevSlow", null, (prev) => prev);
if (prevFast != null && prevSlow != null && prevFast <= prevSlow && fast > slow) {
ctx.emit(
"ema_cross_up",
{ fast, slow, close: ctx.close },
{
label: "EMA cross ↑",
subtitle: `${fast.toFixed(2)} > ${slow.toFixed(2)}`,
price: ctx.close,
timeStart: ctx.time,
}
);
}
ctx.accum("prevFast", null, () => fast);
ctx.accum("prevSlow", null, () => slow);
}Pin version to the library MA version you resolve in the builder when you can — agents should call resolve_dependency_contract before inventing shapes. See Declaring indicator dependencies.
