Silver Bullet ICT

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

Scalping#ict#silverbullet

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
    });
  }
}