> For the complete documentation index, see [llms.txt](https://bluegamma.io/documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bluegamma.io/documentation/integrations/api/how-to-guides/streaming-real-time-fx-data.md).

# Streaming Real-Time FX Data

The BlueGamma FX streaming API provides real-time foreign exchange quotes via WebSocket. Use this to power live dashboards, monitor currency exposure, or feed real-time FX rates into pricing engines.

***

## WebSocket Endpoint

```
wss://streaming.bluegamma.io/fx_stream
```

***

## Quick Start

Connect to the stream with your API token and receive real-time quotes:

```python
import asyncio
import json
import websockets

async def stream_fx():
    url = 'wss://streaming.bluegamma.io/fx_stream?s=EURUSD&s=GBPUSD&token=YOUR_API_KEY'
    
    async with websockets.connect(url) as ws:
        async for msg in ws:
            data = json.loads(msg)
            if data.get("type") == "quote":
                print(f"{data['symbol']}: mid={data['mid']}, bid={data['bid']}, ask={data['ask']}")

asyncio.run(stream_fx())
```

```bash
# Using wscat (install with: npm install -g wscat)
wscat -c "wss://streaming.bluegamma.io/fx_stream?s=EURUSD&s=GBPUSD&token=YOUR_API_KEY"
```

**Sample output:**

```
EURUSD: mid=1.16125, bid=1.1612, ask=1.1613
GBPUSD: mid=1.3396, bid=1.3395, ask=1.3397
USDJPY: mid=158.1329, bid=158.125, ask=158.1408
```

***

## Query Parameters

| Parameter | Required | Description                                                                                     |
| --------- | -------- | ----------------------------------------------------------------------------------------------- |
| `s`       | No       | Symbol(s) to subscribe to. Repeat for multiple symbols (e.g., `?s=EURUSD&s=GBPUSD`)             |
| `token`   | Yes      | Your BlueGamma API key. See [Authentication](/documentation/integrations/api/authentication.md) |

***

## Server Messages

The server sends JSON messages to your client. Each message has a `type` field indicating its purpose.

### Connection Confirmation

Sent immediately after connecting:

```json
{
  "type": "connected",
  "client_id": "172.31.33.250_1768555125108",
  "subscribed": ["GBPUSD", "USDJPY", "EURUSD"]
}
```

| Field        | Description                                    |
| ------------ | ---------------------------------------------- |
| `client_id`  | Unique identifier for your session             |
| `subscribed` | List of symbols you're currently subscribed to |

### Real-Time Quote

Sent continuously as prices update:

```json
{
  "type": "quote",
  "symbol": "EURUSD",
  "mid": 1.16125,
  "bid": 1.1612,
  "ask": 1.1613,
  "timestamp": "2026-01-16T09:18:46.749Z"
}
```

| Field       | Description                              |
| ----------- | ---------------------------------------- |
| `symbol`    | Currency pair                            |
| `mid`       | Mid-market rate (average of bid and ask) |
| `bid`       | Best bid price                           |
| `ask`       | Best ask price                           |
| `timestamp` | ISO 8601 timestamp in UTC                |

### Subscription Confirmation

Sent when you subscribe to new symbols:

```json
{
  "type": "subscribed",
  "symbols": ["AUDUSD"]
}
```

### Unsubscription Confirmation

Sent when you unsubscribe from symbols:

```json
{
  "type": "unsubscribed",
  "symbols": ["GBPUSD"]
}
```

### Heartbeat

The server sends periodic pings to keep the connection alive:

```json
{"type": "ping"}
```

If you send a ping, you'll receive:

```json
{"type": "pong"}
```

### Error

Sent when something goes wrong:

```json
{
  "type": "error",
  "error": "Subscription limit of 1000 symbols per connection would be exceeded"
}
```

***

## Client Commands

Send JSON messages to the server to manage your subscriptions.

### Subscribe to Additional Symbols

```json
{"action": "subscribe", "symbols": ["AUDUSD", "NZDUSD"]}
```

**Response:**

```json
{"type": "subscribed", "symbols": ["AUDUSD", "NZDUSD"]}
```

### Unsubscribe from Symbols

```json
{"action": "unsubscribe", "symbols": ["GBPUSD"]}
```

**Response:**

```json
{"type": "unsubscribed", "symbols": ["GBPUSD"]}
```

### Ping

```json
{"action": "ping"}
```

**Response:**

```json
{"type": "pong"}
```

***

## Supported Currency Pairs

The stream supports approximately **1000 currency pairs**, including:

* **Major pairs**: EURUSD, GBPUSD, USDJPY, USDCHF, AUDUSD, USDCAD, NZDUSD
* **Euro crosses**: EURGBP, EURJPY, EURCHF, EURAUD, EURCAD, and more
* **Other crosses**: GBPJPY, CHFJPY, AUDJPY, CADJPY, and more
* **Emerging markets**: USDMXN, USDBRL, USDZAR, USDTRY, USDCNY, and many more

{% hint style="info" %}
For a complete list of available pairs or to verify availability of specific currencies, contact us at <support@bluegamma.io>.
{% endhint %}

***

## Use Cases

| Use Case                  | Description                                           |
| ------------------------- | ----------------------------------------------------- |
| **Real-time dashboards**  | Power live FX rate displays and monitoring screens    |
| **Risk monitoring**       | Track currency exposure in real-time                  |
| **Pricing engines**       | Real-time FX component for multi-asset pricing        |
| **Cash flow forecasting** | Monitor FX rates affecting foreign currency positions |

***

## Complete Example with Reconnection

For production use, implement reconnection logic to handle network interruptions:

```python
import asyncio
import json
import websockets

API_KEY = "your_api_key_here"
SYMBOLS = ["EURUSD", "GBPUSD", "USDJPY"]

async def connect_and_stream():
    """Connect to the FX stream and handle messages."""
    symbol_params = "&".join([f"s={s}" for s in SYMBOLS])
    url = f"wss://streaming.bluegamma.io/fx_stream?{symbol_params}&token={API_KEY}"
    
    async with websockets.connect(url, ping_interval=20, ping_timeout=10) as ws:
        print("Connected to FX stream")
        
        async for message in ws:
            data = json.loads(message)
            msg_type = data.get("type")
            
            if msg_type == "quote":
                symbol = data["symbol"]
                mid = data["mid"]
                bid = data["bid"]
                ask = data["ask"]
                timestamp = data["timestamp"]
                print(f"[{timestamp}] {symbol}: mid={mid:.5f}, bid={bid:.5f}, ask={ask:.5f}")
            
            elif msg_type == "connected":
                print(f"Session ID: {data['client_id']}")
                print(f"Subscribed to: {data['subscribed']}")
            
            elif msg_type == "subscribed":
                print(f"Added subscriptions: {data['symbols']}")
            
            elif msg_type == "unsubscribed":
                print(f"Removed subscriptions: {data['symbols']}")
            
            elif msg_type == "error":
                print(f"Error: {data['error']}")

async def run_with_reconnection():
    """Run the stream with automatic reconnection."""
    while True:
        try:
            await connect_and_stream()
        except websockets.exceptions.ConnectionClosed as e:
            print(f"Connection closed: {e.code} - {e.reason}")
            print("Reconnecting in 5 seconds...")
            await asyncio.sleep(5)
        except Exception as e:
            print(f"Error: {e}")
            print("Reconnecting in 5 seconds...")
            await asyncio.sleep(5)

if __name__ == "__main__":
    asyncio.run(run_with_reconnection())
```

***

## Limits and Best Practices

| Limit                      | Value                                                                     |
| -------------------------- | ------------------------------------------------------------------------- |
| Max symbols per connection | 1000                                                                      |
| Typical update frequency   | \~300ms for major pairs (e.g. EURUSD, GBPUSD), \~1s for less liquid pairs |

**Best practices:**

1. **Implement reconnection logic** — Network interruptions happen; always reconnect automatically
2. **Handle heartbeats** — The server sends periodic pings to keep connections alive
3. **Subscribe dynamically** — Use subscribe/unsubscribe commands rather than reconnecting to change symbols
4. **Process messages asynchronously** — Don't block the message loop with slow operations

***

## Error Handling

| Error                            | Cause                               | Solution                                 |
| -------------------------------- | ----------------------------------- | ---------------------------------------- |
| Connection closed with code 1008 | Invalid or missing API token        | Check your `token` parameter             |
| "Subscription limit exceeded"    | Requested more than 1000 symbols    | Reduce the number of symbols             |
| Connection timeout               | Network issue or server unavailable | Implement retry with exponential backoff |

***

## Related

* [Authentication](/documentation/integrations/api/authentication.md) — How to get and use your API key
* [Fetching FX Forward Rates](/documentation/integrations/api/how-to-guides/fetching-fx-forward-rates.md) — REST API for FX forward rates
* [Rate Limits & Best Practices](/documentation/integrations/api/rate-limits.md) — General API best practices

***

**Need help?**\
📩 <support@bluegamma.io> | 📅 [Book a call](https://app.lemcal.com/@alivohra/website-demo?back=1)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://bluegamma.io/documentation/integrations/api/how-to-guides/streaming-real-time-fx-data.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
