Description
Custom levels Rough Draft
Comments (0)
0/2000
Loading comments…
Source code
function calculate(bars, ctx) {
// Scalping strategy for ES/NQ on 1-minute chart
// Level color teams: green 35, red 80, yellow 26 42 58 94, blue 00 10 20 50, black 47 72 86
// Strategy inputs
const qty = ctx.input('Quantity', 1, { min: 1, max: 10 });
const slTicks = ctx.input('Stop Loss (ticks)', 8, { min: 1, max: 20 });
const tpTicks = ctx.input('Take Profit (ticks)', 4, { min: 1, max: 10 });
const useTrailing = ctx.input('Use Trailing Stop', false);
const trailOffset = ctx.input('Trail Offset (ticks)', 6, { min: 1, max: 15 });
const maxTradesPerDay = ctx.input('Max Trades Per Day', 10, { min: 1, max: 50 });
const startHour = ctx.input('Start Hour (ET)', 9, { min: 0, max: 23 });
const endHour = ctx.input('End Hour (ET)', 16, { min: 0, max: 23 });
// Get current price and tick info
const price = ctx.price.last;
const tickSize = ctx.syminfo.tickSize;
const last = bars.length - 1;
// Check trading window
if (!ctx.time.inSession(last, startHour, endHour)) {
ctx.log('Outside trading window');
return;
}
// Check daily trade limit
if (ctx.strategy.account.todayTrades >= maxTradesPerDay) {
ctx.log('Daily trade limit reached');
return;
}
// Calculate key levels based on your color teams
// These repeat every 100 points
const baseLevel = Math.floor(price / 100) * 100;
// Define level values
const greenLevels = [35];
const redLevels = [80];
const yellowLevels = [26, 42, 58, 94];
const blueLevels = [0, 10, 20, 50];
const blackLevels = [47, 72, 86];
// Combine all levels
const allLevels = [
...greenLevels.map(l => baseLevel + l),
...redLevels.map(l => baseLevel + l),
...yellowLevels.map(l => baseLevel + l),
...blueLevels.map(l => baseLevel + l),
...blackLevels.map(l => baseLevel + l),
...greenLevels.map(l => baseLevel + 100 + l),
...redLevels.map(l => baseLevel + 100 + l),
...yellowLevels.map(l => baseLevel + 100 + l),
...blueLevels.map(l => baseLevel + 100 + l),
...blackLevels.map(l => baseLevel + 100 + l),
...greenLevels.map(l => baseLevel - 100 + l),
...redLevels.map(l => baseLevel - 100 + l),
...yellowLevels.map(l => baseLevel - 100 + l),
...blueLevels.map(l => baseLevel - 100 + l),
...blackLevels.map(l => baseLevel - 100 + l)
].sort((a, b) => a - b);
// Find nearest levels above and below current price
let nearestBelow = -Infinity;
let nearestAbove = Infinity;
for (const level of allLevels) {
if (level < price && level > nearestBelow) {
nearestBelow = level;
}
if (level > price && level < nearestAbove) {
nearestAbove = level;
}
}
// Calculate distance to nearest levels
const distanceToBelow = price - nearestBelow;
const distanceToAbove = nearestAbove - price;
// Draw level lines for visualization
for (const level of allLevels) {
// Determine color based on level type
let color = '#787b86'; // default gray
const remainder = level % 100;
if (greenLevels.includes(remainder)) color = '#00e676'; // green
else if (redLevels.includes(remainder)) color = '#ef5350'; // red
else if (yellowLevels.includes(remainder)) color = '#ffeb3b'; // yellow
else if (blueLevels.includes(remainder)) color = '#2196f3'; // blue
else if (blackLevels.includes(remainder)) color = '#212121'; // black
ctx.hline(level, {
color: color,
lineStyle: 'dashed',
lineWidth: 1,
label: remainder.toString()
});
}
// Get current position
const pos = ctx.strategy.position;
// Phase 1: FLAT - look for entry signals near key levels
if (pos.side === 'flat') {
// Check if we're near a key level (within 2 points)
const levelThreshold = 2.0;
// Entry logic: bounce off support (buy) or resistance (sell)
if (distanceToBelow <= levelThreshold) {
// Near support level - look for bullish reversal
const ema9 = ctx.ta.ema(ctx.price.close, 9);
const ema21 = ctx.ta.ema(ctx.price.close, 21);
// Bullish signal: price above EMA9, EMA9 above EMA21, recent bullish candle
if (bars[last].close > ema9[last] &&
ema9[last] > ema21[last] &&
bars[last].close > bars[last].open) {
const entryPrice = price;
const stopLoss = entryPrice - slTicks * tickSize;
const takeProfit = entryPrice + tpTicks * tickSize;
ctx.strategy.entry('long_scalp', 'long', {
qty: qty,
bracket: {
stopLoss: { price: stopLoss },
takeProfit: [{ price: takeProfit }]
}
});
if (useTrailing) {
ctx.strategy.setTrail('long_scalp', {
trailOffset: trailOffset,
unit: 'ticks'
});
}
ctx.log('Long entry at support: ' + entryPrice.toFixed(2));
}
}
if (distanceToAbove <= levelThreshold) {
// Near resistance level - look for bearish reversal
const ema9 = ctx.ta.ema(ctx.price.close, 9);
const ema21 = ctx.ta.ema(ctx.price.close, 21);
// Bearish signal: price below EMA9, EMA9 below EMA21, recent bearish candle
if (bars[last].close < ema9[last] &&
ema9[last] < ema21[last] &&
bars[last].close < bars[last].open) {
const entryPrice = price;
const stopLoss = entryPrice + slTicks * tickSize;
const takeProfit = entryPrice - tpTicks * tickSize;
ctx.strategy.entry('short_scalp', 'short', {
qty: qty,
bracket: {
stopLoss: { price: stopLoss },
takeProfit: [{ price: takeProfit }]
}
});
if (useTrailing) {
ctx.strategy.setTrail('short_scalp', {
trailOffset: trailOffset,
unit: 'ticks'
});
}
ctx.log('Short entry at resistance: ' + entryPrice.toFixed(2));
}
}
// Breakout entry: price breaks through key level with momentum
const atr = ctx.ta.atr(ctx.price.high, ctx.price.low, ctx.price.close, 14);
const atrValue = atr[last] || 5;
// Check for breakout above resistance
if (bars[last].close > nearestAbove && bars[last-1].close <= nearestAbove) {
// Breakout long
const entryPrice = price;
const stopLoss = entryPrice - Math.min(slTicks * tickSize, atrValue * 0.5);
const takeProfit = entryPrice + tpTicks * tickSize;
ctx.strategy.entry('breakout_long', 'long', {
qty: qty,
bracket: {
stopLoss: { price: stopLoss },
takeProfit: [{ price: takeProfit }]
}
});
ctx.log('Breakout long above resistance: ' + entryPrice.toFixed(2));
}
// Check for breakdown below support
if (bars[last].close < nearestBelow && bars[last-1].close >= nearestBelow) {
// Breakdown short
const entryPrice = price;
const stopLoss = entryPrice + Math.min(slTicks * tickSize, atrValue * 0.5);
const takeProfit = entryPrice - tpTicks * tickSize;
ctx.strategy.entry('breakout_short', 'short', {
qty: qty,
bracket: {
stopLoss: { price: stopLoss },
takeProfit: [{ price: takeProfit }]
}
});
ctx.log('Breakdown short below support: ' + entryPrice.toFixed(2));
}
}
// Phase 2: IN POSITION - manage existing trades
if (pos.side !== 'flat') {
// Check if price has reached next key level (potential exit)
const isLong = pos.side === 'long';
const nextLevel = isLong ? nearestAbove : nearestBelow;
const distanceToNextLevel = isLong ? nextLevel - price : price - nextLevel;
// Consider early exit if near next key level and showing reversal signs
if (distanceToNextLevel <= 1.0) {
const rsi = ctx.ta.rsi(ctx.price.close, 14);
const rsiValue = rsi[last] || 50;
// Overbought/oversold at key level - consider exiting
if ((isLong && rsiValue > 70) || (!isLong && rsiValue < 30)) {
ctx.strategy.close();
ctx.log('Early exit at key level with RSI extreme');
}
}
// Check for daily loss limit
if (ctx.strategy.account.dayPnl < -500) {
ctx.strategy.flattenAll();
ctx.log('Daily loss limit reached - flattening all');
}
}
// End of day flattening
if (ctx.time.hour(last) >= 15 && ctx.time.minute(last) >= 45) { // 3:45 PM ET
if (pos.side !== 'flat') {
ctx.strategy.flattenAll();
ctx.log('End of day flattening');
}
}
}