EMA cross
Fires when a fast EMA crosses above a slow EMA. It reads the library Moving Average indicator twice instead of computing EMAs itself.
What it defines
An event ema_cross_up on the bar where the fast EMA moves from at or below the slow EMA to above it.
Key decisions
Piece | Why it matters |
|---|---|
Two | Same indicator, different |
| Reads are always nested by the dependency's output key: |
| The MA plots every bar, so |
Guard | The MA has no value until its period has filled. Skip those bars. |
No | A cross is already one bar. Every cross is its own event. |
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: "signal",
payload: {
fast: { type: "number", description: "Fast EMA on the cross bar" },
slow: { type: "number", description: "Slow EMA on the cross bar" },
close: { type: "number", description: "Close on the cross bar" },
},
paint: "pin",
});
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.ma.value;
const slow = ctx.indicators.slow.ma.value;
if (fast == null || slow == null) return;
ctx.plot("fast_line", fast);
ctx.plot("slow_line", slow);
const prevFast = ctx.indicators.fast.ma.at(1);
const prevSlow = ctx.indicators.slow.ma.at(1);
if (prevFast == null || prevSlow == null) return;
if (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,
}
);
}
}version pins the Moving Average version the definition reads. Set it to the version the indicator library shows: pinning a version that does not exist fails lint with indicators/version-not-found. See Declaring indicator dependencies.
Next, Session OR break keeps its own state across bars.
