Description
VOLUME ON THE CHART CANDLES> MORE TO COME!
Categories & Tags
Comments (0)
0/2000
Loading comments…
Source code
function calculate(bars, ctx) {
// ===== Inputs =====
const sizeScale = ctx.input('Bubble Size Scale', 3, { min: 0.5, max: 10, step: 0.5 });
const minVolume = ctx.input('Min Volume to Show', 0, { min: 0, max: 10000, step: 1 });
const maxBubbles = ctx.input('Max Bubbles', 200, { min: 10, max: 1000, step: 10 });
const lookback = ctx.input('Lookback Bars', 500, { min: 50, max: 5000, step: 50 });
// ===== Check footprint data =====
if (!ctx.footprint.available) {
ctx.label(bars.length - 1, bars[bars.length - 1].high, 'Waiting for tick data...', {
color: '#ff9800', textColor: '#fff', size: 12
});
return;
}
const startIdx = Math.max(0, bars.length - lookback);
// ===== Collect total volumes for global scaling =====
const volumes = [];
let maxTotalVol = 0;
for (let i = startIdx; i < bars.length; i++) {
const fp = ctx.footprint.bar(i);
if (!fp) continue;
const buyVol = fp.askVolume || 0;
const sellVol = fp.bidVolume || 0;
const totalVol = buyVol + sellVol;
if (totalVol > maxTotalVol) maxTotalVol = totalVol;
volumes.push({ barIdx: i, buyVol, sellVol, totalVol });
}
if (maxTotalVol === 0) return;
// ===== Filter and draw bubbles =====
let drawn = 0;
for (const v of volumes) {
if (drawn >= maxBubbles) break;
if (v.totalVol < minVolume) continue;
const isBuy = v.buyVol >= v.sellVol;
const color = isBuy ? '#2196f3' : '#4caf50';
const volRatio = v.totalVol / maxTotalVol;
const bubbleSize = Math.max(4, volRatio * sizeScale * 20);
ctx.shape(v.barIdx, 'circle', {
color: color,
position: 'below',
size: bubbleSize,
text: Math.round(v.totalVol).toString()
});
drawn++;
}
// ===== Legend label =====
const last = bars.length - 1;
ctx.label(last, bars[last].low - (bars[last].high - bars[last].low) * 0.5,
'● Buy ● Sell | Size=Volume | Showing ' + drawn + ' bars', {
color: 'rgba(0,0,0,0.5)', textColor: '#787b86', size: 10
});
}