adona-robot — market data by capacity

A forex one-minute history API

One-minute OHLC bars by REST, up to 5 000 a page, paged back with a cursor: what a backtest or a chart reads, through the metered API rather than a file.

How far back
Since 16.05.2025 for EURUSD, GBPUSD, USDJPY, XAUUSD; since 17.03.2026 or 17.05.2026 for the others, each symbol's page giving its own date. The trial reads the last 7 days, on EURUSD · XAUUSD.
Paging back
Ask for M1 bars with a limit of up to 5 000. Each page comes oldest first with next_before, the cursor to the page before it, which is null when there is nothing older for your account. The newest page ends with the bar still forming. Prices are strings, exactly as served.
What a bar is made of
Before 21.05.2026 (22.05.2026 for EURUSD), the one-minute history comes from a different price feed than the live series, and so do some one-minute bars filled in afterwards, until 04.06.2026 at the latest; /symbols.json gives each symbol's dates. The volume is a tick volume: the number of price updates in the bar; bars from the other feed, on any timeframe until 05.06.2026 at the latest, carry its tick volume, not counted the same way.
What it costs
Billed in slices of 1 000 bars, rounded up per response, so ask for what you need: a day of one-minute bars (1 440 at most) read in one response is 2 slices, and an empty page costs nothing. A page that carries the bar still forming counts as following the symbol live: past 80% of its open hours in a month, that symbol adds CHF 150. Plans from CHF 500 a month.

Facts as of 03.10.2026.

The code: one-minute history, paged back

history_m1.py
# pip install requests
# One-minute history, paged back with the cursor: ADONA_API_KEY=... python history_m1.py EURUSD 3
import os
import sys
from datetime import datetime, timedelta, timezone

import requests

API = "https://api.adona-robot.com"
symbol = sys.argv[1] if len(sys.argv) > 1 else "EURUSD"
days = int(sys.argv[2]) if len(sys.argv) > 2 else 3


def get(path, bearer, **kwargs):
    r = requests.request(kwargs.pop("method", "GET"), API + path, headers={"Authorization": f"Bearer {bearer}"}, timeout=30, **kwargs)
    if not r.ok:
        raise SystemExit(f"refused: {r.status_code} {r.text}")
    return r.json()


# your server exchanges the key for a token
token = get("/v1/tokens", os.environ["ADONA_API_KEY"], method="POST", json={"end_user_id": "u-42"})["access_token"]

# pages of up to 5000 bars, newest first; next_before is the page before.
# Every bar served is billed, so each page asks only for the minutes it can still need.
start = datetime.now(timezone.utc) - timedelta(days=days)
since = start.strftime("%Y-%m-%dT%H:%M:%SZ")
bars, before, until = [], None, datetime.now(timezone.utc)
while True:
    minutes = int((until - start).total_seconds() // 60) + 1
    params = {"symbol": symbol, "timeframe": "M1", "limit": max(1, min(5000, minutes))}
    if before:
        params["before"] = before
    page = get("/v1/candles", token, params=params)
    if before is None and page["candles"]:
        page["candles"].pop()  # the newest bar is still forming: not history yet
    bars = page["candles"] + bars
    before = page["next_before"]
    if before is None or before <= since:  # nothing older, or far enough back
        break
    until = datetime.fromisoformat(before.replace("Z", "+00:00"))

bars = [b for b in bars if b["time"] >= since]
print(len(bars), "bars from", bars[0]["time"] if bars else None, "to", bars[-1]["time"] if bars else None)

The quickstart: from the key to the live stream, step by step

Open an account

Related guides

Symbols with the longest history