> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mobula.io/llms.txt
> Use this file to discover all available pages before exploring further.

# OHLCV Stream

> Real-time WebSocket stream for retrieving OHLCV (candlestick) data for any asset

<Tip> This endpoint is only available to Growth and Enterprise plans. </Tip>

## Endpoint Details

* **URL**: `wss://api.mobula.io`
* **Event Type**: `ohlcv`

### Pool Mode Subscription

Subscribe to OHLCV data for a specific pool (mode automatically set to `"pair"`):

```json theme={null}
{
  "type": "ohlcv",
  "authorization": "YOUR_API_KEY",
  "payload": {
    "address": "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
    "chainId": "evm:1",
    "period": "1h",
    "subscriptionTracking": true
  }
}
```

### Asset Mode Subscription

Subscribe to OHLCV data for a specific token (mode automatically set to `"asset"`):

```json theme={null}
{
  "type": "ohlcv",
  "authorization": "YOUR_API_KEY",
  "payload": {
    "asset": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
    "chainId": "evm:1",
    "period": "1h",
    "subscriptionTracking": true
  }
}
```

## Parameters

* **`address`** (conditional): Pool address for pool mode - required if not using `asset`
* **`asset`** (conditional): Token address for asset mode - required if not using `address`
* **`chainId`** (required): Blockchain identifier - [See supported chains](/blockchains/intro-blockchains)
* **`period`** (required): Candlestick timeframe - `1s`, `5s`, `15s`, `30s`, `1m`, `5m`, `15m`, `1h`, `4h`, `1d`, `1w`, `1M`
  * Accepted aliases: `1min` or `1` for `1m`, `5min` or `5` for `5m`, `15min` or `15` for `15m`, `60` for `1h`, `1month` for `1M`
* **`mode`** (optional): Aggregation mode - `pair` or `asset`. Auto-populated based on your query (see below)
* **`subscriptionId`** (optional): Unique identifier for your WebSocket connection. Auto-generated if not provided
* **`subscriptionTracking`** (optional, default: `false`): Include subscription details in response logs for debugging
* **`maxUpdatesPerMinute`** (optional): Limit how often the server sends updates. See [Update Rate Throttling](#update-rate-throttling) below

### Understanding the `mode` Parameter

The `mode` parameter determines how OHLCV data is aggregated and sent:

**Pool Mode (`mode: "pair"`):**

* **Default when:** Using `address` parameter
* **Data scope:** Only trades from the specific pool/pair you subscribed to
* **Use case:** Track a specific trading venue (e.g., Uniswap V3 USDC/ETH pool)
* **Updates:** Real-time updates for that single market only

**Asset Mode (`mode: "asset"`):**

* **Default when:** Using `asset` parameter
* **Data scope:** Aggregated data from the top trading venues for that token
* **Use case:** Track overall token price action across all major liquidity sources
* **Updates:** Real-time updates from multiple pools, filtered to the largest pairs (up to 10 venues)
* **Aggregation:** OHLCV data combines trades from all qualifying pools where the token appears

<Tip>
  The `mode` is automatically set based on your subscription:

  * Use `address` → mode defaults to `"pair"`
  * Use `asset` → mode defaults to `"asset"`

  You can manually override the mode if needed, but the default behavior handles most use cases.
</Tip>

<Note>You can use either **pool mode** (with `address`) or **asset mode** (with `asset`), but not both simultaneously.</Note>

## Response Format

Upon subscribing, you first receive a confirmation message:

```json theme={null}
{
  "event": "subscribed",
  "type": "ohlcv",
  "subscriptionId": "sub_0c1bda43035bab9cbbb18e77246dd4f7"
}
```

Then, each OHLCV update contains the latest candlestick data for the subscribed period:

**Pool Mode Response:**

```json theme={null}
{
  "type": "ohlcv",
  "subscriptionId": "sub_0c1bda43035bab9cbbb18e77246dd4f7",
  "volume": 231222.38341594095,
  "open": 2134.0877566306276,
  "high": 2134.0877566306276,
  "low": 2130.472337069262,
  "close": 2130.4723370692623,
  "time": 1774136880000,
  "period": "1m",
  "tradeTime": 1774136937499,
  "address": "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640"
}
```

**Asset Mode Response:**

```json theme={null}
{
  "type": "ohlcv",
  "subscriptionId": "sub_966400df13443b9a458b2ac6da66f9f0",
  "volume": 111132.93639303978,
  "open": 2152.929326597812,
  "high": 2152.929326597812,
  "low": 2129.6386601659156,
  "close": 2129.6386601659156,
  "time": 1774136940000,
  "period": "1m",
  "tradeTime": 1774136963000,
  "asset": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
}
```

### Response Fields

| Field            | Type             | Description                                              |
| ---------------- | ---------------- | -------------------------------------------------------- |
| `type`           | `string`         | Always `"ohlcv"`                                         |
| `subscriptionId` | `string`         | Unique subscription identifier                           |
| `open`           | `number \| null` | Opening price in USD for the current candle              |
| `high`           | `number \| null` | Highest price in USD during the candle period            |
| `low`            | `number \| null` | Lowest price in USD during the candle period             |
| `close`          | `number \| null` | Latest price in USD (closing price of current candle)    |
| `volume`         | `number`         | Total trading volume in USD for the candle period        |
| `time`           | `number`         | Candle start time in milliseconds, aligned to the period |
| `period`         | `string`         | Candlestick timeframe (e.g., `1s`, `5m`, `1h`, `1d`)     |
| `tradeTime`      | `number`         | Timestamp of the most recent trade in milliseconds       |
| `address`        | `string`         | Pool address (only in pool mode)                         |
| `asset`          | `string`         | Token address (only in asset mode)                       |

<Note>
  The OHLCV candle is updated on every trade internally. Each message you receive contains the latest accurate candle state at the time it was sent.
</Note>

## Implementation Example

**Pool Mode Example (Single Trading Pair):**

```typescript theme={null}
const socket = new WebSocket("wss://api.mobula.io");

socket.addEventListener("open", () => {
  // Subscribe to a specific Uniswap V3 pool
  socket.send(JSON.stringify({
    type: "ohlcv",
    authorization: "YOUR_API_KEY",
    payload: {
      address: "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
      chainId: "evm:1",
      period: "1h",
      subscriptionTracking: true
      // mode: "pair" is automatically set
    }
  }));
});

socket.addEventListener("message", (event) => {
  const data = JSON.parse(event.data);
  
  // Process OHLCV data from this specific pool
  console.log("Pool OHLCV update:", data);
});

socket.addEventListener("error", (error) => {
  console.error("WebSocket error:", error);
});

socket.addEventListener("close", () => {
  console.log("WebSocket connection closed");
});
```

**Asset Mode Example (Aggregated Across Multiple Venues):**

```typescript theme={null}
const socket = new WebSocket("wss://production-api.mobula.io");

socket.addEventListener("open", () => {
  // Subscribe to WETH across all major trading venues
  socket.send(JSON.stringify({
    type: "ohlcv",
    authorization: "YOUR_API_KEY",
    payload: {
      asset: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
      chainId: "evm:1",
      period: "1h",
      subscriptionTracking: true
      // mode: "asset" is automatically set
    }
  }));
});

socket.addEventListener("message", (event) => {
  const data = JSON.parse(event.data);
  
  // Process aggregated OHLCV data from top 10 pools for this token
  console.log("Asset OHLCV update:", data);
});

socket.addEventListener("error", (error) => {
  console.error("WebSocket error:", error);
});

socket.addEventListener("close", () => {
  console.log("WebSocket connection closed");
});
```

<Tip>You can use the Network tab in your browser to see the WebSocket requests and responses in real-time.</Tip>

## Connection Keepalive (Ping/Pong)

To maintain active WebSocket connections and prevent timeouts, you can use the ping/pong mechanism:

**Send ping:**

```json theme={null}
{"event":"ping"}
```

**Receive pong:**
The server will respond with a pong message to confirm the connection is active.

<Tip>Use ping messages periodically (every 30-60 seconds) to keep long-lived connections alive.</Tip>

## Unsubscribing from the Stream

### Unsubscribe from All Streams

To terminate all active subscriptions on the current WebSocket connection:

```json theme={null}
{
  "type": "unsubscribe",
  "authorization": "YOUR_API_KEY",
  "payload": {}
}
```

### Unsubscribe from Specific Subscription

To unsubscribe from a specific subscription using its ID:

```json theme={null}
{
  "type": "unsubscribe",
  "authorization": "YOUR_API_KEY",
  "payload": {
    "subscriptionId": "your-subscription-id"
  }
}
```

### Unsubscribe from All OHLCV Streams

To unsubscribe from all OHLCV streams while keeping other stream types active:

```json theme={null}
{
  "type": "unsubscribe",
  "authorization": "YOUR_API_KEY",
  "payload": {
    "type": "ohlcv"
  }
}
```

<Note>
  If you didn't provide a `subscriptionId` when subscribing, one is auto-generated. To retrieve it, set `"subscriptionTracking": true` in the subscription payload.
</Note>

## Update Rate Throttling

You can control how frequently the server sends update messages using the `maxUpdatesPerMinute` field. This is useful for reducing bandwidth when you don't need every single trade update reflected in real time.

```json theme={null}
{
  "type": "ohlcv",
  "authorization": "YOUR_API_KEY",
  "payload": {
    "asset": "So11111111111111111111111111111111111111112",
    "period": "1m",
    "maxUpdatesPerMinute": 6
  }
}
```

* **Per-subscription throttle**: Each subscription is throttled independently based on its address/asset and period.
* **Candle accuracy preserved**: The OHLCV candle (open, high, low, close, volume) is still updated on every trade internally — only the delivery to your client is throttled. When a message is sent, it contains the latest accurate candle state.
* **Dropped, not buffered**: When an update arrives within the throttle window, it is silently dropped. The next update after the interval elapses will be delivered normally.

| `maxUpdatesPerMinute` | Effective interval | Description                          |
| --------------------- | ------------------ | ------------------------------------ |
| 600                   | 100ms              | Maximum rate (\~10 updates/sec)      |
| 60                    | 1s                 | One update per second                |
| 6                     | 10s                | One update every 10 seconds          |
| 1                     | 60s                | One update per minute (minimum rate) |

<Note>
  When `maxUpdatesPerMinute` is not provided, no throttle is applied and updates are delivered as fast as they arrive.
</Note>

## Support

Can't find what you're looking for? Reach out to us, response times \< 1h.

<CardGroup>
  <Card title="Support" icon="Telegram" href="https://t.me/mobuladevelopers?start=Mobula_API_Support_Key">
    Telegram
  </Card>

  <Card title="Support" icon="Slack" href="https://join.slack.com/t/mobulaapi/shared_invite/zt-29zrrpjnl-I0tyD73sy7zKy8q~KLL3Ug">
    Slack
  </Card>

  <Card title="Need help?" icon="envelope" href="mailto:contact@mobulalabs.org">
    Email
  </Card>
</CardGroup>
