Python Examples

Install Dependencies

pip install requests websockets pandas

1 — Base Client

A reusable session-based client with automatic error handling:

# forex_client.py
import requests
import time
from typing import Optional


class ForexClient:
    BASE_URL = "https://api.pipdata.net"

    def __init__(self, api_key: str):
        self.session = requests.Session()
        self.session.headers.update({"X-API-Key": api_key})

    def _get(self, path: str, params: dict = None) -> dict:
        resp = self.session.get(f"{self.BASE_URL}{path}", params=params, timeout=15)
        resp.raise_for_status()
        return resp.json()

    def symbols(self, search: Optional[str] = None, limit: int = 100) -> list:
        """List available symbols, optionally filtered by name."""
        params = {"limit": limit}
        if search:
            params["search"] = search
        return self._get("/v1/symbols", params)["symbols"]

    def history(self, symbol: str, resolution: str, countback: int = 500) -> dict:
        """Fetch the latest N OHLCV bars for a symbol."""
        return self._get("/v1/history", {
            "symbol":     symbol,
            "resolution": resolution,
            "countback":  countback
        })

    def history_range(self, symbol: str, resolution: str, from_ts: int, to_ts: int) -> dict:
        """Fetch OHLCV bars between two Unix timestamps."""
        return self._get("/v1/history", {
            "symbol":     symbol,
            "resolution": resolution,
            "from":       from_ts,
            "to":         to_ts
        })

    def coverage(self, symbol: Optional[str] = None) -> dict:
        """Get available data date ranges."""
        params = {"symbol": symbol} if symbol else {}
        return self._get("/v1/coverage", params)

    def status(self) -> dict:
        """Check feed health status."""
        return self._get("/v1/status")

    def usage(self, days: int = 7) -> dict:
        """Get API key usage statistics."""
        return self._get("/v1/usage", {"days": days})


# Quick test
if __name__ == "__main__":
    client = ForexClient("fxd_your_key_here")

    st = client.status()
    print(f"Service: {st['status']}")

    data = client.history("WMMARKETS:ZERO:EURUSD", "60", countback=5)
    if data["s"] == "ok":
        print(f"EUR/USD last close: {data['c'][-1]:.5f}")

2 — Convert to DataFrame + Technical Indicators

import pandas as pd
import numpy as np


def to_dataframe(history: dict) -> pd.DataFrame:
    """Convert API response to a timezone-aware pandas DataFrame."""
    if history.get("s") != "ok":
        return pd.DataFrame()

    df = pd.DataFrame({
        "time":   pd.to_datetime(history["t"], unit="s", utc=True),
        "open":   history["o"],
        "high":   history["h"],
        "low":    history["l"],
        "close":  history["c"],
        "volume": history["v"],
    })
    df.set_index("time", inplace=True)
    return df


def add_ema(df: pd.DataFrame, period: int) -> pd.DataFrame:
    df[f"ema{period}"] = df["close"].ewm(span=period, adjust=False).mean()
    return df


def add_rsi(df: pd.DataFrame, period: int = 14) -> pd.DataFrame:
    delta = df["close"].diff()
    gain  = delta.clip(lower=0).rolling(period).mean()
    loss  = (-delta.clip(upper=0)).rolling(period).mean()
    rs    = gain / loss
    df["rsi"] = 100 - (100 / (1 + rs))
    return df


def add_atr(df: pd.DataFrame, period: int = 14) -> pd.DataFrame:
    hl  = df["high"] - df["low"]
    hpc = (df["high"] - df["close"].shift()).abs()
    lpc = (df["low"]  - df["close"].shift()).abs()
    tr  = pd.concat([hl, hpc, lpc], axis=1).max(axis=1)
    df["atr"] = tr.ewm(span=period, adjust=False).mean()
    return df


# Example
client = ForexClient("fxd_your_key_here")
raw = client.history("WMMARKETS:ZERO:EURUSD", "60", 500)
df  = to_dataframe(raw)
df  = add_ema(df, 20)
df  = add_ema(df, 50)
df  = add_rsi(df, 14)
df  = add_atr(df, 14)

print(df[["close", "ema20", "ema50", "rsi", "atr"]].tail(5))

3 — Download All Symbols to CSV

import csv
import os
import time


def download_all(client: ForexClient, resolution: str = "60", countback: int = 500):
    """
    Download OHLCV history for every accessible symbol and save to individual CSV files.
    """
    os.makedirs("forex_data", exist_ok=True)

    symbols = client.symbols(limit=1000)
    print(f"Downloading {len(symbols)} symbols at {resolution} resolution...")

    for i, sym in enumerate(symbols, 1):
        ticker = sym["symbol"]
        print(f"[{i:3}/{len(symbols)}] {ticker}...", end=" ", flush=True)

        data = client.history(ticker, resolution, countback)

        if data.get("s") != "ok":
            print("no data")
            continue

        fname = f"forex_data/{ticker.replace(':', '_')}_{resolution}.csv"
        with open(fname, "w", newline="") as f:
            writer = csv.writer(f)
            writer.writerow(["time", "open", "high", "low", "close", "volume"])
            for row in zip(data["t"], data["o"], data["h"], data["l"], data["c"], data["v"]):
                writer.writerow(row)

        print(f"{len(data['t'])} bars saved")
        time.sleep(0.05)  # ~20 req/s, well within rate limits

    print("\nDone.")


client = ForexClient("fxd_your_key_here")
download_all(client, resolution="60", countback=500)

4 — Live WebSocket Stream

# live_stream.py
import asyncio
import json
import websockets
from datetime import datetime, timezone

API_KEY = "fxd_your_key_here"
URI     = f"wss://api.pipdata.net/v1/stream?api_key={API_KEY}"

SYMBOLS = [
    "WMMARKETS:ZERO:EURUSD",
    "WMMARKETS:ZERO:GBPUSD",
    "WMMARKETS:ZERO:XAUUSD",
    "WMMARKETS:ZERO:BTCUSD",
]


async def on_bar(symbol: str, bar: dict):
    """Process a newly closed M1 bar."""
    t   = datetime.fromtimestamp(bar["time"], tz=timezone.utc)
    sym = symbol.split(":")[-1]
    print(
        f"[{t.strftime('%H:%M')}] {sym:<8} "
        f"O={bar['open']:.5f} H={bar['high']:.5f} "
        f"L={bar['low']:.5f} C={bar['close']:.5f}"
    )


async def stream():
    reconnect_delay = 5

    while True:
        try:
            async with websockets.connect(URI, ping_interval=30) as ws:
                print("Connected ✓")
                reconnect_delay = 5

                await ws.send(json.dumps({
                    "action":  "subscribe",
                    "symbols": SYMBOLS,
                    "type":    "bar"
                }))

                async for raw in ws:
                    msg = json.loads(raw)

                    if msg["type"] == "connected":
                        print(f"Session: {msg['session_id']} | Max symbols: {msg['limits']['max_symbols']}")

                    elif msg["type"] == "subscribed":
                        print(f"Subscribed: {len(msg['symbols'])} symbols")
                        if msg.get("rejected"):
                            print(f"Rejected: {msg['rejected']}")

                    elif msg["type"] == "bar":
                        await on_bar(msg["symbol"], msg["bar"])

                    elif msg["type"] == "error":
                        print(f"Error: {msg['code']}")
                        if msg["code"] in ("KEY_INVALID", "KEY_INACTIVE", "KEY_EXPIRED"):
                            return  # fatal auth error — stop

        except websockets.exceptions.ConnectionClosed as e:
            print(f"Disconnected ({e}) — reconnecting in {reconnect_delay}s")
            await asyncio.sleep(reconnect_delay)
            reconnect_delay = min(reconnect_delay * 2, 60)

        except Exception as e:
            print(f"Unexpected error: {e}")
            await asyncio.sleep(reconnect_delay)


if __name__ == "__main__":
    asyncio.run(stream())

5 — Latest Price Snapshot

Fetch the most recent close price for every symbol:

def latest_prices(client: ForexClient) -> dict:
    """Return the latest close price for all accessible symbols."""
    symbols = client.symbols(limit=1000)
    prices  = {}

    for sym in symbols:
        ticker = sym["symbol"]
        data   = client.history(ticker, "1", countback=1)
        if data.get("s") == "ok" and data["c"]:
            prices[ticker] = {
                "display": sym["display_symbol"],
                "close":   data["c"][-1],
                "digits":  sym["digits"]
            }

    return prices


client = ForexClient("fxd_your_key_here")
prices = latest_prices(client)

for ticker, info in list(prices.items())[:10]:
    fmt = f"{{:.{info['digits']}f}}"
    print(f"{info['display']:<12} = {fmt.format(info['close'])}")