Description

JOJO

Comments (0)

0/2000

Loading comments…

Source code

function calculate(bars, ctx) {
  // ===== ESSENTIAL SCALPING INPUTS =====
  const showEMA = ctx.input('Show EMA', true);
  const emaFast = ctx.input('EMA Fast', 9, { min: 1, max: 20, step: 1 });
  const emaSlow = ctx.input('EMA Slow', 21, { min: 5, max: 50, step: 1 });
  const emaColor = ctx.input('EMA Color', '#FF6B00');
  
  const showVWAP = ctx.input('Show VWAP', true);
  const vwapColor = ctx.input('VWAP Color', '#2962FF');
  
  const showVolume = ctx.input('Show Volume Profile', true);
  const volumeColor = ctx.input('Volume Color', '#26A69A');
  
  const showRSI = ctx.input('Show RSI', true);
  const rsiPeriod = ctx.input('RSI Period', 14, { min: 5, max: 20, step: 1 });
  
  const showATR = ctx.input('Show ATR Bands', true);
  const atrPeriod = ctx.input('ATR Period', 14, { min: 5, max: 20, step: 1 });
  const atrMultiplier = ctx.input('ATR Multiplier', 2, { min: 1, max: 3, step: 0.5 });
  
  const showSession = ctx.input('Show Session Times', true);
  const asianColor = ctx.input('Asian Session', 'rgba(156,39,176,0.08)');
  const londonColor = ctx.input('London Session', 'rgba(33,150,243,0.08)');
  const nyColor = ctx.input('NY Session', 'rgba(76,175,80,0.08)');
  
  const showOrderFlow = ctx.input('Show Order Flow', true);
  const deltaThreshold = ctx.input('Delta Threshold', 1000, { min: 500, max: 5000, step: 100 });
  
  // ===== CALCULATIONS =====
  const last = bars.length - 1;
  
  // 1. EMA CROSSOVER FOR TREND DIRECTION
  if (showEMA) {
    const emaFastLine = ctx.ta.ema(ctx.price.close, emaFast);
    const emaSlowLine = ctx.ta.ema(ctx.price.close, emaSlow);
    
    ctx.plot(emaFastLine, `EMA ${emaFast}`, { 
      color: emaColor, 
      lineWidth: 2 
    });
    
    ctx.plot(emaSlowLine, `EMA ${emaSlow}`, { 
      color: '#787B86', 
      lineWidth: 2,
      lineStyle: 'dashed'
    });
    
    // Highlight EMA crossovers
    const crossUp = ctx.ta.crossover(emaFastLine, emaSlowLine);
    const crossDown = ctx.ta.crossunder(emaFastLine, emaSlowLine);
    
    for (let i = 0; i < bars.length; i++) {
      if (crossUp[i]) {
        ctx.shape(i, 'arrow_up', {
          position: 'below',
          color: '#26A69A',
          size: 10,
          text: 'EMA↑'
        });
      }
      if (crossDown[i]) {
        ctx.shape(i, 'arrow_down', {
          position: 'above',
          color: '#EF5350',
          size: 10,
          text: 'EMA↓'
        });
      }
    }
  }
  
  // 2. VWAP FOR MEAN REVERSION
  if (showVWAP) {
    const vwma = ctx.ta.vwma(ctx.price.close, 200);
    ctx.plot(vwma, 'VWAP', { 
      color: vwapColor, 
      lineWidth: 2
    });
    
    // Highlight when price is far from VWAP
    const currentPrice = bars[last].close;
    const currentVWAP = vwma[last] || currentPrice;
    const vwapDistance = Math.abs(currentPrice - currentVWAP);
    const atr = ctx.ta.atr(ctx.price.high, ctx.price.low, ctx.price.close, atrPeriod);
    const currentATR = atr[last] || 0;
    
    if (vwapDistance > currentATR * 1.5) {
      ctx.label(last, currentPrice, `VWAP ${(currentPrice > currentVWAP ? '↑' : '↓')}${vwapDistance.toFixed(1)}`, {
        color: 'transparent',
        textColor: currentPrice > currentVWAP ? '#EF5350' : '#26A69A',
        size: 11
      });
    }
  }
  
  // 3. VOLUME PROFILE - SIMPLIFIED
  if (showVolume) {
    const volume = ctx.price.volume;
    const volumeSMA = ctx.ta.sma(volume, 20);
    
    // Highlight high volume bars
    for (let i = Math.max(0, bars.length - 50); i < bars.length; i++) {
      if (volume[i] > (volumeSMA[i] || 0) * 1.5) {
        ctx.barcolor(Array(bars.length).fill(null).map((_, idx) => 
          idx === i ? volumeColor : null
        ));
        
        // Add volume spike label
        if (i === last || i === last - 1) {
          ctx.label(i, bars[i].high + 2, `Vol: ${volume[i]}`, {
            color: 'transparent',
            textColor: volumeColor,
            size: 10
          });
        }
      }
    }
  }
  
  // 4. RSI FOR MOMENTUM - SIMPLIFIED
  if (showRSI) {
    const rsi = ctx.ta.rsi(ctx.price.close, rsiPeriod);
    const currentRSI = rsi[last];
    
    // Plot RSI in separate pane
    ctx.plot(rsi, `RSI ${rsiPeriod}`, { 
      pane: 'separate',
      paneName: 'Momentum',
      color: '#7B1FA2',
      lineWidth: 2
    });
    
    // Highlight overbought/oversold
    if (currentRSI !== null) {
      if (currentRSI > 70) {
        ctx.label(last, bars[last].high + 5, `RSI OB: ${currentRSI.toFixed(1)}`, {
          color: 'transparent',
          textColor: '#EF5350',
          size: 11
        });
      } else if (currentRSI < 30) {
        ctx.label(last, bars[last].low - 5, `RSI OS: ${currentRSI.toFixed(1)}`, {
          color: 'transparent',
          textColor: '#26A69A',
          size: 11
        });
      }
    }
  }
  
  // 5. ATR BANDS FOR VOLATILITY
  if (showATR) {
    const atr = ctx.ta.atr(ctx.price.high, ctx.price.low, ctx.price.close, atrPeriod);
    const currentATR = atr[last] || 0;
    const currentClose = bars[last].close;
    
    // Draw ATR bands only on current bar
    const upperBand = currentClose + (currentATR * atrMultiplier);
    const lowerBand = currentClose - (currentATR * atrMultiplier);
    
    ctx.line(last, upperBand, last, upperBand, {
      color: '#FF9800',
      lineWidth: 1,
      extend: 'right',
      label: `+${atrMultiplier}ATR`
    });
    
    ctx.line(last, lowerBand, last, lowerBand, {
      color: '#FF9800',
      lineWidth: 1,
      extend: 'right',
      label: `-${atrMultiplier}ATR`
    });
    
    // Show ATR value
    ctx.label(last, upperBand + 1, `ATR: ${currentATR.toFixed(1)}`, {
      color: 'transparent',
      textColor: '#FF9800',
      size: 10
    });
  }
  
  // 6. SESSION TIMES - MINIMAL
  if (showSession) {
    const bgColors = [];
    
    for (let i = 0; i < bars.length; i++) {
      if (ctx.time.isAsianKZ(i)) {
        bgColors.push(asianColor);
      } else if (ctx.time.isLondonKZ(i)) {
        bgColors.push(londonColor);
      } else if (ctx.time.isNewYorkKZ(i)) {
        bgColors.push(nyColor);
      } else {
        bgColors.push(null);
      }
    }
    
    ctx.bgcolor(bgColors);
    
    // Add session labels only at session starts
    const sessions = [
      { name: 'ASIA', check: ctx.time.isAsianKZ, color: asianColor },
      { name: 'LONDON', check: ctx.time.isLondonKZ, color: londonColor },
      { name: 'NY', check: ctx.time.isNewYorkKZ, color: nyColor }
    ];
    
    for (const session of sessions) {
      let lastLabelBar = -100;
      for (let i = 0; i < bars.length; i++) {
        if (session.check(i) && (i - lastLabelBar > 30 || lastLabelBar === -100)) {
          ctx.label(i, bars[i].high + 10, session.name, {
            color: 'transparent',
            textColor: session.color.replace('0.08', '0.8'),
            size: 9
          });
          lastLabelBar = i;
        }
      }
    }
  }
  
  // 7. ORDER FLOW / DELTA - FOR SCALPING
  if (showOrderFlow && ctx.footprint.available) {
    const delta = ctx.footprint.delta;
    const currentDelta = delta[last];
    
    // Highlight high delta bars
    if (currentDelta !== null && Math.abs(currentDelta) > deltaThreshold) {
      ctx.shape(last, currentDelta > 0 ? 'arrow_up' : 'arrow_down', {
        position: currentDelta > 0 ? 'below' : 'above',
        color: currentDelta > 0 ? '#26A69A' : '#EF5350',
        size: 12,
        text: `Δ${Math.abs(currentDelta)}`
      });
    }
    
    // Plot cumulative delta in separate pane
    const cumulativeDelta = ctx.footprint.cumulativeDelta;
    ctx.plot(cumulativeDelta, 'Cum Delta', {
      pane: 'separate',
      paneName: 'Order Flow',
      color: '#2962FF',
      lineWidth: 2
    });
  }
  
  // 8. CLEAN STATS TABLE - ONLY ESSENTIALS
  const table = ctx.table('top_right', 2, 6, {
    bgcolor: 'rgba(13,17,28,0.92)',
    borderColor: 'rgba(255,255,255,0.08)',
    fontSize: 11,
    paddingTop: 10
  });
  
  // Current price
  const currentPrice = bars[last].close;
  ctx.cell(table, 0, 0, 'Price', { textColor: '#aaa' });
  ctx.cell(table, 0, 1, currentPrice.toFixed(2), { textColor: '#fff' });
  
  // Volume
  const currentVolume = bars[last].volume || 0;
  ctx.cell(table, 1, 0, 'Volume', { textColor: '#aaa' });
  ctx.cell(table, 1, 1, currentVolume.toString(), { textColor: '#26A69A' });
  
  // Range
  const range = bars[last].high - bars[last].low;
  ctx.cell(table, 2, 0, 'Range', { textColor: '#aaa' });
  ctx.cell(table, 2, 1, range.toFixed(1), { textColor: '#FF9800' });
  
  // RSI
  if (showRSI) {
    const currentRSI = ctx.ta.rsi(ctx.price.close, rsiPeriod)[last];
    if (currentRSI !== null) {
      const rsiColor = currentRSI > 70 ? '#EF5350' : 
                      currentRSI < 30 ? '#26A69A' : '#2196F3';
      ctx.cell(table, 3, 0, 'RSI', { textColor: '#aaa' });
      ctx.cell(table, 3, 1, currentRSI.toFixed(1), { textColor: rsiColor });
    }
  }
  
  // ATR
  if (showATR) {
    const currentATR = ctx.ta.atr(ctx.price.high, ctx.price.low, ctx.price.close, atrPeriod)[last];
    if (currentATR !== null) {
      ctx.cell(table, 4, 0, 'ATR', { textColor: '#aaa' });
      ctx.cell(table, 4, 1, currentATR.toFixed(1), { textColor: '#FF9800' });
    }
  }
  
  // Session
  let currentSession = 'REG';
  if (ctx.time.isAsianKZ(last)) currentSession = 'ASIA';
  else if (ctx.time.isLondonKZ(last)) currentSession = 'LON';
  else if (ctx.time.isNewYorkKZ(last)) currentSession = 'NY';
  
  ctx.cell(table, 5, 0, 'Session', { textColor: '#aaa' });
  ctx.cell(table, 5, 1, currentSession, { textColor: '#9C27B0' });
  
  // 9. PRICE ACTION SIGNALS - SIMPLE
  // Inside bar detection
  if (last > 0) {
    const currentBar = bars[last];
    const prevBar = bars[last - 1];
    
    if (currentBar.high < prevBar.high && currentBar.low > prevBar.low) {
      ctx.label(last, currentBar.high + 3, 'INSIDE', {
        color: 'transparent',
        textColor: '#FF9800',
        size: 10
      });
    }
    
    // Outside bar detection
    if (currentBar.high > prevBar.high && currentBar.low < prevBar.low) {
      ctx.label(last, currentBar.high + 3, 'OUTSIDE', {
        color: 'transparent',
        textColor: '#EF5350',
        size: 10
      });
    }
  }
}