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