Observed since 20 Oct, 19:45 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Client for the adona-robot market-data API: FX and metals OHLC candles from one second to one day, and the live bid and ask over WebSocket.
A thin Python client for the adona-robot market-data API. It covers 46 FX pairs and 5 metals (gold against the dollar and the euro, silver, platinum, palladium), with OHLC candles from one second to one day by REST, and the live bid, ask and closing bars on one WebSocket.
pip install adona-market-data # candles by REST
pip install "adona-market-data[pandas]" # + to_pandas()
pip install "adona-market-data[stream]" # + the live stream
pip install "adona-market-data[all]"
No data ships with this package. Everything is read from the API with your key, and every page you read is billed in slices of 1 000 bars from your plan.
from adona_market_data import Client
client = Client() # the API key from ADONA_API_KEY; keep it on a server
bars = client.candles("EURUSD", "M1", bars=1440) # the last 1 440 one-minute bars, oldest first
frame = client.to_pandas(bars) # a DataFrame indexed by time (UTC): open, high, low, close, volume
S1, M1, M5, M15, H1, H4 and D1.client.candles(..., since=datetime(...)) reads back to an instant.client.iter_pages(...) yields the pages one by one, newest first, if you want to stop early.Prices arrive as strings and become Decimal, so no digit is rounded. to_pandas()
gives floats, or pass decimals=True to keep them exact.
A candle's volume is a tick volume: the number of price updates received in the bar,
not a traded volume.
import asyncio
from adona_market_data import Bar, Client, Quote
async def main():
client = Client()
async for event in client.stream(["quote:XAUUSD", "candle:XAUUSD:M1"]):
if isinstance(event, Quote):
print(event.symbol, event.bid, event.ask)
elif isinstance(event, Bar) and not event.snapshot:
print(event.channel, event.candle.time, event.candle.close)
asyncio.run(main())
The stream reconnects through deploys and network loss with a backoff. It raises
StreamStopped on the closes that reconnecting cannot change: an ended trial, a key cut
off, a connection limit.
Each (re)subscribe sends the candle channels' recent bars again (snapshot=True), and
those bars are billed like a REST page.
Every refusal is a Refused with the API's code, for example CUSTOMER_MINUTE_CEILING
or SYMBOL_NOT_ALLOWED. It also carries the HTTP status, the fields of a validation
error and Retry-After.
The client retries only what waiting can clear:
Retry-After.A retired token is replaced once. refused.is_answer tells you when retrying the same
call is pointless. Every code is listed, with what to do, in the
API reference.
uv venv && uv pip install -e . pytest pytest-asyncio responses pandas "websockets>=13"
.venv/bin/python -m pytest
The tests run against recorded answers and a local WebSocket server. None of them calls the API.
MIT licence for this code. The data you read through it is governed by the terms of service.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.1.0 | 10 Oct 2026 | 3 |
This describes our collected data; it is not a security assessment.
Shared repository data · GitHub
Observed since 20 Oct, 19:45 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:0ecd3661db8294f4969b6f031d60a05a52beb3141e3378f5f57eb3d074a7c472