Description
Silver Bullet ICT script. created this to show that anything is possible on this platform. free for the community. Feel free to use the code open-source to help you understand and build bigger and better algos or custom indicators to help level up your trading!
Categories & Tags
Comments (0)
0/2000
Loading comments…
Source code
// ICT Silver Bullet (FVG) — SXVNT SDK
// Detect Fair Value Gaps within ICT kill zones with adjustable strictness.
// Adjust all settings via Settings gear icon.
function calculate(bars, ctx) {
// ═══ Kill Zone ═══
const kzStart = ctx.input('KZ Start (ET)', 10, { min: 0, max: 23, step: 1 });
const kzEnd = ctx.input('KZ End (ET)', 11, { min: 0, max: 23, step: 1 });
// ═══ Strictness ═══
const minGapTicks = ctx.input('Min Gap (ticks)', 4, { min: 0, max: 100, step: 1 });
// ═══ Filtering ═══
const maxFVGs = ctx.input('Max FVGs Per Session', 20, { min: 0, max: 200, step: 1 });
const unfilledOnly = ctx.input('Unfilled Only', true);
const direction = ctx.input('Direction (0=both 1=bull 2=bear)', 0, { min: 0, max: 2, step: 1 });
// ═══ Appearance ═══
const bullColor = ctx.input('Bullish Color', '#26a69a');
const bearColor = ctx.input('Bearish Color', '#ef5350');
const showLabels = ctx.input('Show Labels', true);
const tickSize = 0.25;
const fvgs = [];
// Track sessions — detect when we enter a new kill zone
let inKZ = false;
let sessionFVGCount = 0;
for (let i = 2; i < bars.length; i++) {
const currentInKZ = ctx.time.inSession(i, kzStart, kzEnd);
// New kill zone session started
if (currentInKZ && !inKZ) {
sessionFVGCount = 0;
}
inKZ = currentInKZ;
if (!currentInKZ) continue;
if (!ctx.time.inSession(i - 1, kzStart, kzEnd)) continue;
if (!ctx.time.inSession(i - 2, kzStart, kzEnd)) continue;
// Already hit max for this session — skip
if (maxFVGs > 0 && sessionFVGCount >= maxFVGs) continue;
// ═══ Bullish FVG ═══
if (direction !== 2 && bars[i].low > bars[i - 2].high) {
const gapSize = bars[i].low - bars[i - 2].high;
if (gapSize / tickSize < minGapTicks) continue;
fvgs.push({ type: 'bull', start: i - 2, end: i, top: bars[i].low, bottom: bars[i - 2].high });
sessionFVGCount++;
continue;
}
// ═══ Bearish FVG ═══
if (direction !== 1 && bars[i].high < bars[i - 2].low) {
const gapSize = bars[i - 2].low - bars[i].high;
if (gapSize / tickSize < minGapTicks) continue;
fvgs.push({ type: 'bear', start: i - 2, end: i, top: bars[i - 2].low, bottom: bars[i].high });
sessionFVGCount++;
}
}
// ═══ Filter unfilled ═══
let visible = fvgs;
if (unfilledOnly) {
visible = fvgs.filter(fvg => {
for (let j = fvg.end + 1; j < bars.length; j++) {
if (fvg.type === 'bull' && bars[j].low <= fvg.bottom) return false;
if (fvg.type === 'bear' && bars[j].high >= fvg.top) return false;
}
return true;
});
}
// ═══ Render ═══
for (const fvg of visible) {
const isBull = fvg.type === 'bull';
const color = isBull ? bullColor : bearColor;
const r = parseInt(color.slice(1, 3), 16);
const g = parseInt(color.slice(3, 5), 16);
const b = parseInt(color.slice(5, 7), 16);
const gapTicks = ((fvg.top - fvg.bottom) / tickSize).toFixed(0);
const label = showLabels ? ('FVG ' + (isBull ? '▲' : '▼') + ' ' + gapTicks + 't') : '';
ctx.box(fvg.start, fvg.top, fvg.end, fvg.bottom, {
fillColor: 'rgba(' + r + ',' + g + ',' + b + ',0.15)',
borderColor: color,
extend: 'right',
text: label
});
}
}