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