Back to Strategies
SMA Crossover Trend Follower
Code Strategy by 0xsDp5JzBDn·2026-05-12
// Initialize RSI with a period of 14
// Note: In a real persistent strategy, you might want to store the RSI instance
// or feed it historical data via $.Storage if the platform doesn't persist JS objects between runs.
// However, for this simple example, we assume the platform feeds recent prices or we just react to current triggers.
// *Correction based on docs*: The docs show updating values sequentially.
// Since strategies run per event, we likely need to store previous prices or the indicator state in $.Storage
// if the environment doesn't maintain memory between runs.
// Let's assume a stateless run where we might need to Fetch history or just use a simple price check if RSI state isn't persistent.
// BUT, the docs example implies:
// const rsi = new $.Ta.RSI(14);
// rsi.update(30000); ...
// If the environment resets every run, we can't build a proper RSI without history.
// Let's create a more robust example that uses $.Storage to save the indicator state if possible,
// OR stick to a simpler price-based strategy if RSI state persistence is complex.
// Actually, looking at the docs, $.Ta is available. Let's assume we can store the serialized state or
// the platform handles the context. If not, a simple Moving Average Crossover is easier to implement statelessly
// if we store the last MA value.
// Let's do a Simple Moving Average (SMA) Crossover using Storage for state.
const PERIOD = 10;
const FAST_PERIOD = 5;
const SLOW_PERIOD = 15;
async function main() {
// 1. Get current price
if (!$.Price || !$.Price.price) {
return; // No price data available
}
const currentPrice = $.Price.price;
// 2. Retrieve state from storage
let state = await $.Storage.get();
if (!state) {
state = {
fastSMA: null,
slowSMA: null,
prices: [] // Store last N prices to calculate SMA manually if needed
};
}
// 3. Update price history
state.prices.push(currentPrice);
if (state.prices.length > SLOW_PERIOD) {
state.prices.shift(); // Keep only the last SLOW_PERIOD prices
}
// 4. Calculate SMAs if we have enough data
let fastSMA = null;
let slowSMA = null;
if (state.prices.length >= FAST_PERIOD) {
const sumFast = state.prices.slice(-FAST_PERIOD).reduce((a, b) => a + b, 0);
fastSMA = sumFast / FAST_PERIOD;
}
if (state.prices.length >= SLOW_PERIOD) {
const sumSlow = state.prices.reduce((a, b) => a + b, 0);
slowSMA = sumSlow / SLOW_PERIOD;
}
// 5. Trading Logic
let actionTaken = false;
// Golden Cross: Fast SMA crosses above Slow SMA -> LONG
if (fastSMA && slowSMA && state.fastSMA && state.slowSMA) {
if (state.fastSMA <= state.slowSMA && fastSMA > slowSMA) {
// Only enter if not already in a position (or if last action was EXIT)
if ($.Strategy.lastTrigger.action !== $.Action.LONG) {
await $.Strategy.action($.Action.LONG, { id: "GoldenCross" });
actionTaken = true;
}
}
// Death Cross: Fast SMA crosses below Slow SMA -> EXIT
else if (state.fastSMA >= state.slowSMA && fastSMA < slowSMA) {
if ($.Strategy.lastTrigger.action !== $.Action.EXIT) {
await $.Strategy.action($.Action.EXIT, { id: "DeathCross" });
actionTaken = true;
}
}
}
// 6. Save state for next run
state.fastSMA = fastSMA;
state.slowSMA = slowSMA;
await $.Storage.set(state);
}
main();