FX
FXSOCKET
  • Features
  • How it Works
  • Use Cases
  • Pricing
  • Blog
Sign InGet API Key
Use Case

Historical Forex Data API for Backtesting

Access years of candlestick and tick data from MT4 and MT5 through a single API call. Feed it into your backtesting engine — pandas, backtrader, Zipline, or anything custom. No screen scraping, no CSV downloads, no MQL scripts.

What Data Is Available

  • OHLCV candles. M1, M5, M15, M30, H1, H4, D1, W1, MN — all standard MetaTrader timeframes. Request any date range for any symbol your broker supports.
  • Tick data. Raw bid/ask ticks with millisecond timestamps. Essential for high-frequency strategy testing and spread analysis.
  • Real-time streams. The same WebSocket that powers live trading also streams tick data for paper trading and forward-testing.
  • Clean JSON responses. Every endpoint returns structured JSON. No parsing HTML, no binary formats, no proprietary protocols.

Example: Fetch Daily Candles

import requests
import pandas as pd

API_KEY = "your_api_key"
BASE = "https://api.fxsocket.com/v1"

response = requests.get(
    f"{BASE}/candles/EURUSD",
    headers={"Authorization": f"Bearer {API_KEY}"},
    params={
        "timeframe": "D1",
        "from": "2024-01-01",
        "to": "2024-12-31"
    }
)

candles = response.json()["candles"]
df = pd.DataFrame(candles)
print(df.head())

Example: Complete Moving Average Crossover Backtest

The snippet above fetches data. Here's what a full backtest looks like — fetching H1 candles, computing a fast/slow SMA crossover, generating signals, and calculating returns, all in one script.

import requests
import pandas as pd
import numpy as np

API_KEY = "your_api_key"
BASE = "https://api.fxsocket.com/v1"

# Fetch one year of H1 candles
response = requests.get(
    f"{BASE}/candles/EURUSD",
    headers={"Authorization": f"Bearer {API_KEY}"},
    params={
        "timeframe": "H1",
        "from": "2024-01-01",
        "to": "2024-12-31"
    }
)

df = pd.DataFrame(response.json()["candles"])
df["time"] = pd.to_datetime(df["time"])
df.set_index("time", inplace=True)

# Compute moving averages
df["sma_fast"] = df["close"].rolling(window=20).mean()
df["sma_slow"] = df["close"].rolling(window=50).mean()

# Generate signals: 1 = long, -1 = flat
df["signal"] = np.where(df["sma_fast"] > df["sma_slow"], 1, -1)

# Calculate returns
df["market_return"] = df["close"].pct_change()
df["strategy_return"] = df["signal"].shift(1) * df["market_return"]

# Results
cumulative = (1 + df["strategy_return"].dropna()).cumprod()
print(f"Final equity: {cumulative.iloc[-1]:.4f}")
print(f"Max drawdown: {(cumulative / cumulative.cummax() - 1).min():.4%}")
print(f"Total trades: {(df['signal'].diff() != 0).sum()}")

Example: Tick Data for High-Frequency Strategy Testing

For strategies that depend on spread dynamics, order flow, or sub-minute price movements, candle data isn't enough. The ticks endpoint gives you raw bid/ask prices with millisecond precision.

import requests
import pandas as pd

API_KEY = "your_api_key"
BASE = "https://api.fxsocket.com/v1"

# Fetch tick data for a specific session
response = requests.get(
    f"{BASE}/ticks/EURUSD",
    headers={"Authorization": f"Bearer {API_KEY}"},
    params={
        "from": "2024-06-03T08:00:00",
        "to": "2024-06-03T16:00:00"
    }
)

ticks = response.json()["ticks"]
df = pd.DataFrame(ticks)
df["time"] = pd.to_datetime(df["time"])
df["spread"] = df["ask"] - df["bid"]

print(f"Total ticks: {len(df)}")
print(f"Avg spread: {df['spread'].mean():.5f}")
print(f"Max spread: {df['spread'].max():.5f}")
print(f"Min spread: {df['spread'].min():.5f}")

# Identify spread spikes (e.g., during news events)
spike_threshold = df["spread"].mean() + 3 * df["spread"].std()
spikes = df[df["spread"] > spike_threshold]
print(f"Spread spikes (>3σ): {len(spikes)}")

SDK Comparison: Fetching Data in Python, Node.js, and Go

FxSocket provides official SDKs for Python, JavaScript/Node.js, Go, and Rust. Here's the same candle fetch in three languages so you can pick the one that fits your stack.

Python

import requests

resp = requests.get(
    "https://api.fxsocket.com/v1/candles/GBPUSD",
    headers={"Authorization": "Bearer YOUR_KEY"},
    params={"timeframe": "H4", "from": "2024-01-01", "to": "2024-06-30"}
)
candles = resp.json()["candles"]

Node.js

const resp = await fetch(
  "https://api.fxsocket.com/v1/candles/GBPUSD?" +
    new URLSearchParams({
      timeframe: "H4",
      from: "2024-01-01",
      to: "2024-06-30",
    }),
  { headers: { Authorization: "Bearer YOUR_KEY" } }
);
const { candles } = await resp.json();

Go

req, _ := http.NewRequest("GET",
    "https://api.fxsocket.com/v1/candles/GBPUSD?timeframe=H4&from=2024-01-01&to=2024-06-30",
    nil)
req.Header.Set("Authorization", "Bearer YOUR_KEY")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()

var result struct {
    Candles []Candle `json:"candles"`
}
json.NewDecoder(resp.Body).Decode(&result)

All four SDKs (including Rust) follow the same API structure. Pick whichever language your backtesting pipeline runs in — the data you get back is identical.

Integration with Popular Backtesting Frameworks

FxSocket returns clean JSON that converts directly into the data structures these frameworks expect. Here are quick examples for three popular Python backtesting libraries.

backtrader

import backtrader as bt
import requests
import pandas as pd
from io import StringIO

API_KEY = "your_api_key"
BASE = "https://api.fxsocket.com/v1"

resp = requests.get(
    f"{BASE}/candles/EURUSD",
    headers={"Authorization": f"Bearer {API_KEY}"},
    params={"timeframe": "D1", "from": "2023-01-01", "to": "2024-12-31"}
)

df = pd.DataFrame(resp.json()["candles"])
df["time"] = pd.to_datetime(df["time"])
df.set_index("time", inplace=True)
df = df[["open", "high", "low", "close", "volume"]]

data = bt.feeds.PandasData(dataname=df)

cerebro = bt.Cerebro()
cerebro.adddata(data)
cerebro.addstrategy(YourStrategy)
cerebro.run()

vectorbt

import vectorbt as vbt
import requests
import pandas as pd

API_KEY = "your_api_key"
BASE = "https://api.fxsocket.com/v1"

resp = requests.get(
    f"{BASE}/candles/EURUSD",
    headers={"Authorization": f"Bearer {API_KEY}"},
    params={"timeframe": "H1", "from": "2024-01-01", "to": "2024-12-31"}
)

df = pd.DataFrame(resp.json()["candles"])
df["time"] = pd.to_datetime(df["time"])
close = df.set_index("time")["close"]

# Run a fast/slow MA crossover with vectorbt
fast_ma = vbt.MA.run(close, window=10)
slow_ma = vbt.MA.run(close, window=30)
entries = fast_ma.ma_crossed_above(slow_ma)
exits = fast_ma.ma_crossed_below(slow_ma)

portfolio = vbt.Portfolio.from_signals(close, entries, exits)
print(portfolio.stats())

Zipline

import pandas as pd
import requests

API_KEY = "your_api_key"
BASE = "https://api.fxsocket.com/v1"

# Fetch data and write to a Zipline-compatible CSV bundle
resp = requests.get(
    f"{BASE}/candles/EURUSD",
    headers={"Authorization": f"Bearer {API_KEY}"},
    params={"timeframe": "D1", "from": "2020-01-01", "to": "2024-12-31"}
)

df = pd.DataFrame(resp.json()["candles"])
df["time"] = pd.to_datetime(df["time"])
df = df.rename(columns={"time": "date"})
df = df[["date", "open", "high", "low", "close", "volume"]]

# Save as CSV for Zipline ingestion
df.to_csv("eurusd_daily.csv", index=False)

The pattern is always the same: call the API, convert to a DataFrame, and hand it to whatever framework you prefer. No format conversion, no adapter libraries, no custom data feed classes beyond what the framework itself provides.

Data Quality and Considerations

Historical data quality can make or break a backtest. Here are the things you need to know when working with FxSocket data.

Broker-Specific Data

FxSocket pulls data directly from your broker's MetaTrader server. This means prices, spreads, and available history are specific to your broker. Two brokers will have slightly different bid/ask prices for the same symbol at the same timestamp. This is not a bug — it's how the forex market works. Every broker's liquidity providers and markup are different. The advantage is that you're backtesting on the exact same data feed you'll trade on live, so your fills and slippage estimates are more realistic than with a generic data source.

Handling Gaps: Weekends and Holidays

The forex market closes Friday evening (New York time) and reopens Sunday evening. Between those hours, there are no ticks and no candles. Your backtest needs to account for this. If you request a date range that spans a weekend, the API returns data up to Friday's close and resumes from Sunday's open — there are no artificial fills in between. Similarly, some brokers reduce liquidity or close certain instruments on holidays (e.g., Christmas, New Year). Gaps will appear naturally in the data. When calculating indicators like moving averages, make sure your logic handles these gaps rather than treating them as zero-volume periods.

Timezone Handling

MT4 and MT5 servers each run on the timezone their broker configures — often UTC+2 or UTC+3 (to align daily candles with the New York close). FxSocket returns timestamps exactly as reported by the broker's server. This means a D1 candle's open and close times depend on your broker's timezone setting. If you're comparing data across multiple brokers or merging with external data sources (e.g., economic calendar events in UTC), convert timestamps explicitly. Pandas makes this straightforward:

df["time"] = pd.to_datetime(df["time"])
# Convert from broker time (e.g., UTC+2) to UTC
df["time"] = df["time"].dt.tz_localize("Etc/GMT-2").dt.tz_convert("UTC")

Candle Close Times: MT4 vs MT5

MT4 uses four-digit pricing by default and stores candle timestamps as the candle open time. MT5 also uses the open time but may include additional precision. The more important difference is that MT5 supports more granular timeframes natively and can store tick data with millisecond precision, while MT4 tick history may be more limited depending on the broker. If you're running the same backtest on both MT4 and MT5 data, be aware that minor discrepancies in candle boundaries can occur because of different server configurations and timestamp resolution.

From Backtest to Live — Same Code

The biggest friction in algo trading is the gap between backtesting and live execution. With FxSocket, both use the same API. Pull historical data for backtesting, then switch to live execution by calling the orders endpoint. No rewrite, no adapter layer, no separate data provider.

Common Errors and Troubleshooting

When pulling large amounts of historical data, you may run into a few edge cases. Here's how to handle them.

Handling Large Date Ranges (Pagination)

If you request several years of M1 candles, the response can contain hundreds of thousands of rows. The API paginates large responses automatically. Check for a next_cursorfield in the response and keep fetching until it's absent.

all_candles = []
cursor = None

while True:
    params = {
        "timeframe": "M1",
        "from": "2022-01-01",
        "to": "2024-12-31"
    }
    if cursor:
        params["cursor"] = cursor

    resp = requests.get(
        f"{BASE}/candles/EURUSD",
        headers={"Authorization": f"Bearer {API_KEY}"},
        params=params
    )
    data = resp.json()
    all_candles.extend(data["candles"])

    cursor = data.get("next_cursor")
    if not cursor:
        break

df = pd.DataFrame(all_candles)
print(f"Total candles: {len(df)}")

Symbol Availability

Not every broker offers every symbol. If you request candles for a symbol your broker doesn't support, the API returns a clear error message. You can list all available symbols for your connected account by calling the symbols endpoint. Keep in mind that symbol names can vary between brokers — one broker might use EURUSD, another EURUSDm or EURUSD.r. Always check the symbol list before hardcoding names in your backtest scripts.

Timeframe Availability on Older Data

Some brokers only keep a limited history for smaller timeframes. You might get five years of D1 data but only six months of M1 data. This is a broker-side limitation, not an API one. If you need deep M1 history and your broker doesn't have it, consider fetching the smallest available timeframe and resampling. For example, resample M5 candles into M1-like resolution for rough estimates, or use tick data to reconstruct custom timeframes.

Rate Limits and Timeouts

FxSocket does not throttle data requests under normal use. However, if you're hitting the API in a tight loop with thousands of requests per minute, you may see occasional 429 responses. Add a simple retry with exponential backoff and you'll be fine. For bulk data pulls, use larger date ranges per request and let the pagination handle the rest rather than making many small requests.

Why Traders Use FxSocket for Backtesting

  • One API for everything. Historical data, live data, and trade execution all through the same endpoints and authentication.
  • Broker-accurate data.Data comes directly from your broker's MetaTrader server — the same prices you'll trade on live.
  • No rate limits on data requests. Download large date ranges without throttling. Perfect for bulk backtests.
  • Works with any analysis tool. JSON output drops into pandas, R, Excel, or any data pipeline.
  • Sub-30ms execution. When you move from backtest to live, orders execute in under 30 milliseconds with 99.99% uptime.
  • No MQL required. No need to write Expert Advisors or MQL scripts. Your Python, Node.js, Go, or Rust code talks directly to the API.
  • No VPS needed. Run your backtests on your local machine, a cloud VM, or a CI pipeline. The API is accessible from anywhere.

Supported Symbols

Any symbol available on your broker's MT4 or MT5 server. Forex pairs, indices, commodities, crypto CFDs, stocks — if your broker offers it on MetaTrader, you can pull data for it.

Pricing

FxSocket starts at €11 per account per month on the Starter plan, which includes full access to historical data endpoints, real-time WebSocket streams, and trade execution. Pro plans are available for teams and higher-volume use cases. Every plan includes access to all supported timeframes (M1 through MN), tick data, and unlimited data requests.

Frequently Asked Questions

How far back does historical data go?

It depends on your broker. FxSocket pulls data directly from your broker's MetaTrader server, so the available history matches what your broker stores. Most brokers keep several years of D1 and H1 data, often going back 10+ years for major forex pairs. Smaller timeframes like M1 and M5 typically have shorter history — anywhere from a few months to a few years. Tick data availability varies the most and is generally limited to the most recent months. If deep history is critical for your strategy, check your broker's data retention before you start.

Is the data the same as what I'd see on the MT4/MT5 chart?

Yes. FxSocket reads directly from the same MetaTrader server that feeds your charts. The OHLCV values, timestamps, and tick prices are identical to what the MT4 or MT5 terminal displays. If you open the same symbol and timeframe in your MetaTrader client and compare it to the API response, the numbers will match. This is by design — it means your backtest results reflect the actual prices you would have traded on.

Can I get tick data for all symbols?

Tick data is available for any symbol your broker provides on MetaTrader, but the depth of tick history varies. Major pairs like EURUSD typically have deeper tick history than exotic pairs or CFD instruments. MT5 brokers generally store more tick history than MT4 brokers. If the tick endpoint returns no data for a specific date range, try a more recent range or check with your broker about their tick data retention policy.

How do I handle weekends and gaps in the data?

The API returns no data for periods when the market is closed. Weekend gaps (Friday close to Sunday open) are the most common, but you'll also see gaps on holidays depending on your broker. Your backtesting code should handle these naturally — don't interpolate or fill gaps with synthetic data, as that will distort your results. When computing rolling indicators, use the actual available bars rather than assuming a fixed number of bars per day or week.

Can I use FxSocket data with live trading on a different platform?

Absolutely. While FxSocket offers its own trade execution endpoints, you can use the data API purely for backtesting and analysis without placing any trades through it. Many developers pull historical data from FxSocket, run their backtests locally, and then deploy their live strategy on a different execution platform. The data is yours to use however you like once you've fetched it.

Start BuildingView API Docs
FX
FXSOCKET

Cloud-hosted MT4 & MT5 terminals with REST APIs and real-time WebSocket streams. No VPS required.

Product
  • Features
  • Pricing
  • Documentation
  • Status
Use Cases
  • Algo Trading
  • Copy Trading
  • Backtesting
  • Prop Firms
Company
  • Contact
  • Terms
  • Privacy
  • info@fxsocket.com
Connect
  • Telegram
  • WhatsApp

© 2026 Quantum Performance Labs LLC. All rights reserved.