Skip to main content

Volume-Based Strategy with Custom Indicator

This strategy uses a custom indicator to calculate the ratio between buy and sell volume over a period. It demonstrates:

  • How to create a custom indicator that maintains state per token
  • How to handle rolling windows of data
  • How to use volume data for trading decisions

The VolumeRatio indicator:

  • Maintains a rolling window of buy and sell volumes for each token
  • Calculates the ratio of total buy volume to total sell volume
  • Returns values > 1 when buying pressure is stronger, < 1 when selling pressure is stronger

The strategy:

  • Buys when the ratio > 1.5 (50% more buying than selling)
  • Sells when the ratio < 0.67 (50% more selling than buying)
class VolumeRatio extends BaseIndicator {
constructor(id, params) {
super(id, params);
this.tokenState = new Map();
this.period = params.period || 20;
}

onNewBar(candle, barIndex) {
const token = candle.token_address;
let state = this.tokenState.get(token);
if (!state) {
state = { buyVols: [], sellVols: [] };
this.tokenState.set(token, state);
}

state.buyVols.push(candle.buy_volume);
state.sellVols.push(candle.sell_volume);

if (state.buyVols.length > this.period) {
state.buyVols.shift();
state.sellVols.shift();
}
}

getValue(token) {
const state = this.tokenState.get(token);
if (!state || state.buyVols.length < this.period) return NaN;

const totalBuy = state.buyVols.reduce((a, b) => a + b, 0);
const totalSell = state.sellVols.reduce((a, b) => a + b, 0);
return totalBuy / totalSell;
}
}

// Register the custom indicator
registerIndicator(
"VOLUME_RATIO", // Name for this type of indicator
VolumeRatio, // Class reference
{ period: 20 }, // Parameters
"VOL_RATIO_20" // Custom ID for this instance
);

function onBar(data, indicators, positions, trades) {
const rowCount = data.close.length;
const signals = new Array(rowCount).fill("HOLD");

for (let i = 0; i < rowCount; i++) {
const token = data.token_address[i];
const ratio = indicators.getValue("VOL_RATIO_20", token);

if (ratio > 1.5) { // 50% more buying than selling
signals[i] = "BUY";
} else if (ratio < 0.67) { // 50% more selling than buying
signals[i] = "SELL";
}
}

return signals;
}