---
title: "High-Frequency Update"
enterprise: true
framework: vue
version: "14.1.0"
---

# High-Frequency Update

AG Charts is optimised for **high-frequency data updates**, maintaining smooth performance with rapid or real-time data updates on large datasets, while maintaining full functionality.

#### High-Frequency Updates

```ts
import { createApp, defineComponent, ref } from "vue";
import { AgCharts } from "ag-charts-vue3";
import type { AgChartOptions } from "ag-charts-types";
import {
  AreaSeriesModule,
  BarSeriesModule,
  CandlestickSeriesModule,
  CrosshairModule,
  LineSeriesModule,
  ModuleRegistry,
  NumberAxisModule,
  OhlcSeriesModule,
  RangeAreaSeriesModule,
  RangeBarSeriesModule,
  TimeAxisModule,
  ZoomModule,
} from "ag-charts-enterprise";
import { createSeedData, generateNextDatum } from "./data";
import clone from "clone";

let initialPoints = 1000;

let batchSize = 10;

let currentSeriesType = "line";

let currentUpdateMode = "rolling";

const seedResult = createSeedData(initialPoints, currentSeriesType);

let data = seedResult.data;

let nextIndex = data.length;

let lastBasePrice = seedResult.lastBasePrice;

function createSeriesConfig(seriesType) {
  switch (seriesType) {
    case "ohlc":
    case "candlestick":
      return [
        {
          type: seriesType,
          xKey: "timestamp",
          openKey: "open",
          highKey: "high",
          lowKey: "low",
          closeKey: "close",
        },
      ];
    case "stacked-bar":
      return [
        { type: "bar", xKey: "timestamp", yKey: "value", stacked: true },
        { type: "bar", xKey: "timestamp", yKey: "value2", stacked: true },
      ];
    case "stacked-area":
      return [
        {
          type: "area",
          xKey: "timestamp",
          yKey: "value",
          stacked: true,
          marker: { enabled: false },
        },
        {
          type: "area",
          xKey: "timestamp",
          yKey: "value2",
          stacked: true,
          marker: { enabled: false },
        },
      ];
    case "range-area":
      return [
        {
          type: "range-area",
          xKey: "timestamp",
          yLowKey: "low",
          yHighKey: "high",
        },
      ];
    case "range-bar":
      return [
        {
          type: "range-bar",
          xKey: "timestamp",
          yLowKey: "low",
          yHighKey: "high",
        },
      ];
    case "area":
      return [
        {
          type: "area",
          xKey: "timestamp",
          yKey: "value",
          marker: { enabled: false },
          strokeWidth: 1,
        },
      ];
    case "bar":
      return [
        {
          type: "bar",
          xKey: "timestamp",
          yKey: "value",
        },
      ];
    case "line":
    default:
      return [
        {
          type: "line",
          xKey: "timestamp",
          yKey: "value",
          marker: { enabled: false },
          strokeWidth: 1,
        },
      ];
  }
}

let isRunning = false;

let animationFrameId;

function updateBatchSize(value) {
  batchSize = parseInt(value, 10);
}

function updateDataSize(value) {
  const wasRunning = isRunning;
  if (wasRunning) stopUpdates();
  initialPoints = parseInt(value, 10);
  const seedResult = createSeedData(initialPoints, currentSeriesType);
  data = seedResult.data;
  nextIndex = data.length;
  lastBasePrice = seedResult.lastBasePrice;
  options.data = data;
  agCharts.value.chart.update(options);
  if (wasRunning) startUpdates();
}

ModuleRegistry.registerModules([
  AreaSeriesModule,
  BarSeriesModule,
  CandlestickSeriesModule,
  CrosshairModule,
  LineSeriesModule,
  NumberAxisModule,
  OhlcSeriesModule,
  RangeAreaSeriesModule,
  RangeBarSeriesModule,
  TimeAxisModule,
  ZoomModule,
]);

const ChartExample = defineComponent({
  template: `
    <div class="example-controls">
      <div class="controls-row">
        <button id="toggleBtn" v-on:click="toggleUpdates()">Start Updates</button>
        <select id="seriesTypeSelect" v-on:change="updateSeriesType($event.target.value)">
          <option value="line" selected="">Line</option>
          <option value="area">Area</option>
          <option value="bar">Bar</option>
          <option value="stacked-bar">Stacked Bar</option>
          <option value="stacked-area">Stacked Area</option>
          <option value="range-area">Range Area</option>
          <option value="range-bar">Range Bar</option>
          <option value="candlestick">Candlestick</option>
          <option value="ohlc">OHLC</option>
        </select>
        <select id="updateModeSelect" v-on:change="updateMode($event.target.value)">
          <option value="rolling" selected="">Rolling Window</option>
          <option value="append">Append Only</option>
        </select>
      </div>
    </div>
    <ag-charts
      ref="agCharts"
      :options="options"
    />
  `,
  components: {
    "ag-charts": AgCharts,
  },
  setup(props) {
    const options = ref<AgCartesianChartOptions>({
      data,
      title: { text: "High-Frequency Data Updates" },
      subtitle: {
        text: "Rolling Window: removing old points, adding new points",
      },
      animation: { enabled: false },
      zoom: { enabled: true, onDataChange: { strategy: "preserveRatios" } },
      axes: {
        x: {
          type: "time",
          position: "bottom",
          nice: false,
          label: {
            format: "%H:%M:%S",
          },
        },
      },
      series: createSeriesConfig(currentSeriesType),
      legend: { enabled: false },
    });
    const agCharts = ref(null);

    const runUpdate = () => {
      if (!isRunning) return;
      switch (currentUpdateMode) {
        case "rolling":
          performRollingUpdate();
          break;
        case "append":
          performAppendUpdate();
          break;
      }
      animationFrameId = requestAnimationFrame(runUpdate);
    };
    const performRollingUpdate = () => {
      const newPoints = [];
      for (let i = 0; i < batchSize; i++) {
        const result = generateNextDatum(
          nextIndex++,
          currentSeriesType,
          lastBasePrice,
        );
        newPoints.push(result.datum);
        lastBasePrice = result.lastBasePrice;
      }
      const pointsToRemove = data.slice(0, batchSize);
      agCharts.value.chart.applyTransaction({
        remove: pointsToRemove,
        add: newPoints,
      });
      data.splice(0, batchSize);
      data.push(...newPoints);
    };
    const performAppendUpdate = () => {
      const newPoints = [];
      for (let i = 0; i < batchSize; i++) {
        const result = generateNextDatum(
          nextIndex++,
          currentSeriesType,
          lastBasePrice,
        );
        newPoints.push(result.datum);
        lastBasePrice = result.lastBasePrice;
      }
      agCharts.value.chart.applyTransaction({
        add: newPoints,
      });
      data.push(...newPoints);
    };
    const startUpdates = () => {
      if (isRunning) return;
      isRunning = true;
      updateButton();
      animationFrameId = requestAnimationFrame(runUpdate);
    };
    const stopUpdates = () => {
      if (!isRunning) return;
      isRunning = false;
      updateButton();
      if (animationFrameId !== undefined) {
        cancelAnimationFrame(animationFrameId);
        animationFrameId = undefined;
      }
    };
    const updateButton = () => {
      const button = document.getElementById("toggleBtn");
      if (button) {
        button.textContent = isRunning ? "Stop Updates" : "Start Updates";
      }
    };
    const toggleUpdates = () => {
      if (isRunning) {
        stopUpdates();
      } else {
        startUpdates();
      }
    };
    const updateSeriesType = (value) => {
      const optionsCopy = clone(options.value);

      const wasRunning = isRunning;
      if (wasRunning) stopUpdates();
      currentSeriesType = value;
      const seedResult = createSeedData(initialPoints, currentSeriesType);
      data = seedResult.data;
      nextIndex = data.length;
      lastBasePrice = seedResult.lastBasePrice;
      optionsCopy.data = data;
      optionsCopy.series = createSeriesConfig(currentSeriesType);

      if (wasRunning) startUpdates();

      options.value = optionsCopy;
    };
    const updateMode = (value) => {
      const optionsCopy = clone(options.value);

      const wasRunning = isRunning;
      if (wasRunning) stopUpdates();
      currentUpdateMode = value;
      const subtitleText =
        currentUpdateMode === "rolling"
          ? "Rolling Window: removing old points, adding new points"
          : "Append Only: continuously adding new points";
      optionsCopy.subtitle = { text: subtitleText };
      const seedResult = createSeedData(initialPoints, currentSeriesType);
      data = seedResult.data;
      nextIndex = data.length;
      lastBasePrice = seedResult.lastBasePrice;
      optionsCopy.data = data;

      if (wasRunning) startUpdates();

      options.value = optionsCopy;
    };

    return {
      options,
      agCharts,
      toggleUpdates,
      updateSeriesType,
      updateMode,
    };
  },
});

createApp(ChartExample).mount("#app");
```

[Live example: High-Frequency Updates](https://www.ag-grid.com/charts/vue3/high-frequency-data/examples/high-frequency-showcase)

In the above example:

- Use the controls to select different series types.
- Choose between update modes: **Rolling Window** (remove old, add new) or **Append Only** (continuously add).
- Updates run at `requestAnimationFrame` speed for maximum throughput.
- The zoom functionality is available during the updates.

> **Note**
>
> Performance may vary based on your specific use case, environment and hardware.

## How it works

The `applyTransaction()` API provides efficient incremental updates to chart data. Instead of replacing the entire dataset on each update, transactions specify only the changes: items to add, remove, or update. This dramatically reduces processing overhead for real-time scenarios.

```js
// Rolling window: remove old points, add new ones
chart.applyTransaction({
    remove: oldPoints,
    add: newPoints,
});
```

For detailed information on transaction operations and best practices, see [Transactions](https://www.ag-grid.com/charts/vue/transactions/).

## Financial Charts

High-frequency updates also work with Financial Charts.

The following example simulates real-time candlestick trading data:

- Starts with 365 days of historical data.
- Every 2 seconds, a new candle is created representing a new trading day.
- Between new candles, price ticks update the current candle's high, low, and close values at `requestAnimationFrame` speed.

#### High-Frequency Financial Chart

```ts
import { createApp, defineComponent, ref } from "vue";
import { AgFinancialCharts } from "ag-charts-vue3";
import type { AgChartOptions } from "ag-charts-types";
import { FinancialChartModule, ModuleRegistry } from "ag-charts-enterprise";
import { MS_PER_DAY, PriceSimulator, getHistoricalData } from "./data";
import { random } from "./seededRandom";
import clone from "clone";

const CANDLE_INTERVAL_MS = 2000;

const TICKS_PER_CANDLE = 100;

const INITIAL_POINTS = 365;

const VISIBLE_POINTS = 25;

const data = getHistoricalData(INITIAL_POINTS);

let currentCandle;

let simulator;

let candleIntervalId;

let animationFrameId;

let isRunning = false;

ModuleRegistry.registerModules([FinancialChartModule]);

const ChartExample = defineComponent({
  template: `
    <div class="example-controls">
      <div class="controls-row">
        <button id="toggleBtn" v-on:click="toggleUpdates()">Start</button>
      </div>
    </div>
    <ag-financial-charts
      ref="agCharts"
      :options="options"
    />
  `,
  components: {
    "ag-financial-charts": AgFinancialCharts,
  },
  setup(props) {
    const options = ref<AgFinancialChartOptions>({
      title: { text: "High-Frequency Update" },
      data,
      volume: true,
      navigator: false,
      rangeButtons: false,
      statusBar: true,
      toolbar: false,
      zoom: true,
      initialState: {
        zoom: {
          ratioX: { start: 1 - VISIBLE_POINTS / data.length, end: 1 },
        },
      },
    });
    const agCharts = ref(null);

    const startNewCandle = () => {
      const lastCandle = data[data.length - 1];
      const newTimestamp = lastCandle.date + MS_PER_DAY;
      const openPrice = lastCandle.close;
      simulator = new PriceSimulator(openPrice, TICKS_PER_CANDLE);
      currentCandle = {
        date: newTimestamp,
        open: openPrice,
        high: openPrice,
        low: openPrice,
        close: openPrice,
        volume: Math.round(1000000 + random() * 500000),
      };
      data.push(currentCandle);
      agCharts.value.chart.applyTransaction({ add: [currentCandle] });
    };
    const processTick = () => {
      if (!currentCandle || !simulator) return;
      const newPrice = simulator.tick();
      currentCandle.close = newPrice;
      currentCandle.high = Math.max(currentCandle.high, newPrice);
      currentCandle.low = Math.min(currentCandle.low, newPrice);
      agCharts.value.chart.applyTransaction({ update: [currentCandle] });
    };
    const scheduleNextTick = () => {
      if (isRunning) {
        animationFrameId = requestAnimationFrame(() => {
          processTick();
          scheduleNextTick();
        });
      }
    };
    const stopAllUpdates = () => {
      if (candleIntervalId) {
        clearInterval(candleIntervalId);
        candleIntervalId = undefined;
      }
      if (animationFrameId) {
        cancelAnimationFrame(animationFrameId);
        animationFrameId = undefined;
      }
    };
    const updateButton = () => {
      const button = document.getElementById("toggleBtn");
      if (button) {
        button.textContent = isRunning ? "Stop" : "Start";
      }
    };
    const toggleUpdates = () => {
      if (isRunning) {
        isRunning = false;
        stopAllUpdates();
      } else {
        isRunning = true;
        startNewCandle();
        scheduleNextTick();
        candleIntervalId = setInterval(
          () => startNewCandle(),
          CANDLE_INTERVAL_MS,
        );
      }
      updateButton();
    };

    return {
      options,
      agCharts,
      toggleUpdates,
    };
  },
});

createApp(ChartExample).mount("#app");
```

[Live example: High-Frequency Financial Chart](https://www.ag-grid.com/charts/vue3/high-frequency-data/examples/high-frequency-financial-chart-showcase)
