QuantScript forwardtest strategy: uses a daily SMA trend filter with 15m RSI entries. Demonstrates data.loadCandles() with callback for cross-resolution analysis in a trading context.
// Cross-Resolution Trend Strategy — ETHUSD Paper Trading
//
// Uses a daily SMA as a higher-resolution trend filter:
// - Daily trend UP → only take longs on 15m pullbacks
// - Daily trend DOWN → only take shorts on 15m rallies
mode(mode_type: "forwardtest", script_name: "Cross-TF Trend Strategy");
candles(symbol: "ETHUSD", resolution_type: "15m", bars: 200, adapter: "demotrader.net");
broker(adapter: "mybrokeraccount1");
risk(max_position_pct: 20, daily_loss_limit: 3);
// ── Inputs ───────────────────────────────────────────────────────────────────
const dailySmaLen = input.int(20, "Daily SMA Length", min_value: 5, max_value: 100, group: "Trend");
const rsiLen = input.int(14, "RSI Length", min_value: 5, max_value: 50, group: "Entry");
const rsiOB = input.float(65.0, "RSI Overbought", group: "Entry");
const rsiOS = input.float(35.0, "RSI Oversold", group: "Entry");
const lotSize = input.float(0.1, "Lot Size", min_value: 0.01, step: 0.01, group: "Trade");
// ── Higher timeframe: daily trend filter ─────────────────────────────────────
var dailySma = data.loadCandles(adapter: "demotrader.net", symbol: "ETHUSD", resolution_type: "1D", callback: (c) => ta.sma(c.close, dailySmaLen));
var dailySmaPrev = data.loadCandles(adapter: "demotrader.net", symbol: "ETHUSD", resolution_type: "1D", callback: (c) => {
const sma = ta.sma(c.close, dailySmaLen);
const prev = sma[1];
return prev;
});
// ── Strategy ─────────────────────────────────────────────────────────────────
event.onCandle((candle) => {
const close = candle.close;
const rsi = ta.rsi(close, rsiLen);
// Daily trend: SMA rising = bullish, falling = bearish
let trendUp = false;
let trendDown = false;
if (dailySma !== null && dailySmaPrev !== null) {
trendUp = dailySma > dailySmaPrev;
trendDown = dailySma < dailySmaPrev;
}
chart.plot(close, "ETH Close");
chart.plot(dailySma, "ETH 1D SMA", "#FF9800");
chart.pane("oscillator");
chart.plot(rsi, "RSI", "#9C27B0");
chart.hline(rsiOB, "Overbought", "#f85149");
chart.hline(rsiOS, "Oversold", "#3fb950");
// ── Trade logic (only on live/last candle) ───────────────────────────────
if (!candle.isLive) return;
if (rsi === null) return;
let symbol = frame.symbol ?? "ETHUSD";
let hasLong = false, hasShort = false;
for (const pos of trade.positions()) {
if (pos.side == "long") hasLong = true;
if (pos.side == "short") hasShort = true;
}
let wantLong = trendUp && rsi < rsiOS;
let wantShort = trendDown && rsi > rsiOB;
// Exit on trend flip
if (hasLong && trendDown) {
for (const pos of trade.positions()) {
if (pos.side == "long") trade.closePosition({ positionId: pos.id });
}
}
if (hasShort && trendUp) {
for (const pos of trade.positions()) {
if (pos.side == "short") trade.closePosition({ positionId: pos.id });
}
}
// Entries
if (wantLong && !hasLong) {
trade.buy({
symbol, qty: lotSize,
reason: "Daily uptrend + RSI oversold (" + rsi.toFixed(1) + ")",
tags: ["cross-tf", "trend_pullback"]
});
}
if (wantShort && !hasShort) {
trade.sell({
symbol, qty: lotSize,
reason: "Daily downtrend + RSI overbought (" + rsi.toFixed(1) + ")",
tags: ["cross-tf", "trend_pullback"]
});
}
});