TACO LEVELS FOR THE DAY AND BEAN INDICATOR

Description

TACOS AND BEANS YO!

Categories & Tags

Comments (0)

0/2000

Loading comments…

Source code

function calculate(bars, ctx) {
  // === Inputs ===
  const showOpeningRange = ctx.input('Show Opening Range', true);
  const orHighColor = ctx.input('Opening Range High Color', '#f23645');
  const orLowColor = ctx.input('Opening Range Low Color', '#089981');
  const orThickness = ctx.input('Opening Range Line Thickness', 2, { min: 1, max: 5, step: 1 });

  const showVWAP = ctx.input('Show VWAP', true);
  const vwapColor = ctx.input('VWAP Color', '#2962ff');
  const vwapThickness = ctx.input('VWAP Line Thickness', 2, { min: 1, max: 5, step: 1 });

  const showPivots = ctx.input('Show Pivot Points', true);
  const pivotColor = ctx.input('Pivot Color', '#008080');
  const r1Color = ctx.input('R1 Color', '#f23645');
  const s1Color = ctx.input('S1 Color', '#089981');
  const r2Color = ctx.input('R2 Color', '#f23645');
  const s2Color = ctx.input('S2 Color', '#089981');
  const pivotThickness = ctx.input('Pivot Line Thickness', 1, { min: 1, max: 5, step: 1 });

  const showPrevDayLevels = ctx.input('Show Previous Day High/Low/Close', true);
  const prevHighColor = ctx.input('Previous Day High Color', '#f23645');
  const prevLowColor = ctx.input('Previous Day Low Color', '#089981');
  const prevCloseColor = ctx.input('Previous Day Close Color', '#787b86');
  const prevDayThickness = ctx.input('Previous Day Line Thickness', 1, { min: 1, max: 5, step: 1 });

  const showSessionHL = ctx.input('Show Session High/Low', true);
  const sessionHighColor = ctx.input('Session High Color', '#f23645');
  const sessionLowColor = ctx.input('Session Low Color', '#089981');
  const sessionThickness = ctx.input('Session Line Thickness', 1, { min: 1, max: 5, step: 1 });

  // Session time inputs
  const sessionStart = ctx.input('Session Start (ET)', 9, { min: 0, max: 23, step: 1 });
  const sessionEnd = ctx.input('Session End (ET)', 16, { min: 0, max: 23, step: 1 });

  const last = bars.length - 1;
  if (last < 0) return;

  // === Helper: check if bar is in NY session (ET) ===
  function inSession(barIndex) {
    const h = ctx.time.hourIn(barIndex, 'America/New_York');
    if (sessionStart < sessionEnd) return h >= sessionStart && h < sessionEnd;
    return h >= sessionStart || h < sessionEnd; // overnight wrap
  }

  // Track whether we just entered the session (for resetting session-level state)
  let inSessionNow = false;

  // === Opening Range (First 30 minutes after session start) ===
  let openingRangeHigh = null;
  let openingRangeLow = null;
  let orStartBar = -1;

  for (let i = 0; i <= last; i++) {
    const inSess = inSession(i);
    const prevInSess = i > 0 ? inSession(i - 1) : false;

    // Detect session start
    if (inSess && !prevInSess) {
      // New session — figure out the opening range window (first 30 min)
      // We'll find bars where minutes since session start are < 30
    }
  }

  // Simpler approach: find the opening range by scanning session bars
  // First, identify session start bar and count bars for 30 minutes
  let sessionStartBar = -1;
  let openingRangeIdx = -1;
  let orHigh = -Infinity;
  let orLow = Infinity;

  for (let i = 0; i <= last; i++) {
    const inSess = inSession(i);
    const prevInSess = i > 0 ? inSession(i - 1) : false;

    if (inSess && !prevInSess) {
      // New session start
      sessionStartBar = i;
      openingRangeIdx = i;
      orHigh = bars[i].high;
      orLow = bars[i].low;
      continue;
    }

    if (sessionStartBar >= 0 && inSess) {
      // Count minutes since session start
      const startHour = ctx.time.hourIn(sessionStartBar, 'America/New_York');
      const startMin = ctx.time.minuteIn(sessionStartBar, 'America/New_York');
      const currHour = ctx.time.hourIn(i, 'America/New_York');
      const currMin = ctx.time.minuteIn(i, 'America/New_York');
      const startTotalMin = startHour * 60 + startMin;
      let currTotalMin = currHour * 60 + currMin;
      // Handle overnight
      if (currTotalMin < startTotalMin) currTotalMin += 1440;
      const elapsed = currTotalMin - startTotalMin;

      if (elapsed < 30) {
        openingRangeIdx = i;
        if (bars[i].high > orHigh) orHigh = bars[i].high;
        if (bars[i].low < orLow) orLow = bars[i].low;
      }
    }
  }

  // === VWAP (session-anchored) ===
  // Compute VWAP from session start to current bar
  let vwapValues = new Array(bars.length).fill(null);
  let sessionStartIdx = -1;

  for (let i = 0; i <= last; i++) {
    const inSess = inSession(i);
    const prevInSess = i > 0 ? inSession(i - 1) : false;

    if (inSess && !prevInSess) {
      sessionStartIdx = i;
    }

    if (sessionStartIdx >= 0 && inSess) {
      let pv = 0, v = 0;
      for (let j = sessionStartIdx; j <= i; j++) {
        const tp = (bars[j].high + bars[j].low + bars[j].close) / 3;
        pv += tp * bars[j].volume;
        v += bars[j].volume;
      }
      vwapValues[i] = v > 0 ? pv / v : null;
    }
  }

  // === Pivot Points (from previous day's daily data) ===
  // We need to find previous day's high/low/close
  // Detect daily session boundaries
  let prevDayHigh = null, prevDayLow = null, prevDayClose = null;
  let currentDayHigh = -Infinity, currentDayLow = Infinity;

  for (let i = 0; i <= last; i++) {
    const isNewDay = ctx.time.isNewSession(i);
    const h = bars[i].high;
    const l = bars[i].low;

    if (isNewDay && i > 0) {
      // Previous day is completed — store its stats
      prevDayHigh = currentDayHigh;
      prevDayLow = currentDayLow;
      prevDayClose = bars[i - 1].close;
      // Reset for new day
      currentDayHigh = h;
      currentDayLow = l;
    } else {
      if (h > currentDayHigh) currentDayHigh = h;
      if (l < currentDayLow) currentDayLow = l;
    }
  }

  // Calculate pivot levels
  let pivotLevel = null, r1 = null, s1 = null, r2 = null, s2 = null;
  if (prevDayHigh != null && prevDayLow != null && prevDayClose != null) {
    pivotLevel = (prevDayHigh + prevDayLow + prevDayClose) / 3;
    r1 = pivotLevel + (pivotLevel - prevDayLow);
    s1 = pivotLevel - (prevDayHigh - pivotLevel);
    r2 = pivotLevel + (prevDayHigh - prevDayLow);
    s2 = pivotLevel - (prevDayHigh - prevDayLow);
  }

  // === Session High/Low ===
  let sessionHigh = -Infinity;
  let sessionLow = Infinity;
  let currentSessionStartBar = -1;

  for (let i = 0; i <= last; i++) {
    const inSess = inSession(i);
    const prevInSess = i > 0 ? inSession(i - 1) : false;

    if (inSess && !prevInSess) {
      // New session
      currentSessionStartBar = i;
      sessionHigh = bars[i].high;
      sessionLow = bars[i].low;
    } else if (!inSess) {
      // Outside session — reset
      sessionHigh = -Infinity;
      sessionLow = Infinity;
      currentSessionStartBar = -1;
    }

    if (inSess) {
      if (bars[i].high > sessionHigh) sessionHigh = bars[i].high;
      if (bars[i].low < sessionLow) sessionLow = bars[i].low;
    }
  }

  // === Draw everything ===

  // 1. Opening Range
  if (showOpeningRange && openingRangeIdx >= 0 && orHigh > -Infinity && orLow < Infinity) {
    ctx.line(openingRangeIdx, orHigh, last, orHigh, {
      color: orHighColor, lineWidth: orThickness, lineStyle: 'dashed'
    });
    ctx.line(openingRangeIdx, orLow, last, orLow, {
      color: orLowColor, lineWidth: orThickness, lineStyle: 'dashed'
    });
    ctx.label(last, orHigh, 'OR High', { color: orHighColor, textColor: '#fff', size: 10, position: 'at', style: 'none' });
    ctx.label(last, orLow, 'OR Low', { color: orLowColor, textColor: '#fff', size: 10, position: 'at', style: 'none' });
  }

  // 2. VWAP
  if (showVWAP) {
    ctx.plot(vwapValues, 'VWAP', { color: vwapColor, lineWidth: vwapThickness });
  }

  // 3. Pivot Points
  if (showPivots && pivotLevel != null) {
    ctx.hline(pivotLevel, { color: pivotColor, lineWidth: pivotThickness, lineStyle: 'dotted', label: 'Pivot' });
    ctx.hline(r1, { color: r1Color, lineWidth: pivotThickness, lineStyle: 'dotted', label: 'R1' });
    ctx.hline(s1, { color: s1Color, lineWidth: pivotThickness, lineStyle: 'dotted', label: 'S1' });
    ctx.hline(r2, { color: r2Color, lineWidth: pivotThickness, lineStyle: 'dotted', label: 'R2' });
    ctx.hline(s2, { color: s2Color, lineWidth: pivotThickness, lineStyle: 'dotted', label: 'S2' });
  }

  // 4. Previous Day High/Low/Close
  if (showPrevDayLevels && prevDayHigh != null) {
    ctx.hline(prevDayHigh, { color: prevHighColor, lineWidth: prevDayThickness, lineStyle: 'dashed', label: 'Prev High' });
    ctx.hline(prevDayLow, { color: prevLowColor, lineWidth: prevDayThickness, lineStyle: 'dashed', label: 'Prev Low' });
    ctx.hline(prevDayClose, { color: prevCloseColor, lineWidth: prevDayThickness, lineStyle: 'dashed', label: 'Prev Close' });
  }

  // 5. Session High/Low
  if (showSessionHL && currentSessionStartBar >= 0 && sessionHigh > -Infinity && sessionLow < Infinity) {
    ctx.line(currentSessionStartBar, sessionHigh, last, sessionHigh, {
      color: sessionHighColor, lineWidth: sessionThickness, lineStyle: 'solid'
    });
    ctx.line(currentSessionStartBar, sessionLow, last, sessionLow, {
      color: sessionLowColor, lineWidth: sessionThickness, lineStyle: 'solid'
    });
    ctx.label(last, sessionHigh, 'Session High', { color: sessionHighColor, textColor: '#fff', size: 10, position: 'at', style: 'none' });
    ctx.label(last, sessionLow, 'Session Low', { color: sessionLowColor, textColor: '#fff', size: 10, position: 'at', style: 'none' });
  }
}