PHP Průvodce: Tržní data
Revolut X poskytuje veřejné koncové body pro čtení konfigurací trhů, cenových tickerů, hloubky trhu (order book) a historických svíček (OHLCV).
1. Měnové páry a konfigurace
use RevolutX\Client;
$client = new Client();
// Získání všech aktivních párů
$pairs = $client->getPairs();
// Detail konkrétního páru
$btcEur = $client->getPair('BTC-EUR');
echo "Minimální velikost objednávky: " . $btcEur['min_order_size'] . " BTC\n";
echo "Cenový krok: " . $btcEur['quote_step'] . " EUR\n";
2. Cenové tickery
Tickery vracejí aktuální nejlepší nabídku (bid), nejlepší poptávku (ask) a cenu posledního obchodu (last_price):
// Ticker pro jeden pár
$ticker = $client->getTicker('BTC-EUR');
echo "Bid: {$ticker['bid']} EUR | Ask: {$ticker['ask']} EUR\n";
// Všechny tickery
$allTickers = $client->getTickers();
Jeden ticker na pár a region
getTickers() vrací řádek pro každou kombinaci páru a regionu, nikoli jeden
na pár — většina symbolů je kotována v EEA i UK za odlišné ceny a
objemy, takže se v seznamu objeví dvakrát. Region poznáte z $t['region']
a nespoléhejte se na pořadí seznamu: burza ho mezi voláními přehazuje.
getTicker() tuto nejednoznačnost řeší tím, že vrátí nejlikvidnější
kotaci daného symbolu (nejvyšší volume_24h). Pokud potřebujete konkrétní
region, vyfiltrujte si ho sami:
3. Kniha objednávek (Order Book)
// Stažení hloubky trhu pro BTC-EUR (top 10 úrovní)
$orderBook = $client->getOrderBook('BTC-EUR', depth: 10);
echo "Nejlepší nabídka (Bid 1): " . $orderBook['bids'][0][0] . " EUR (objem: " . $orderBook['bids'][0][1] . " BTC)\n";
echo "Nejlepší poptávka (Ask 1): " . $orderBook['asks'][0][0] . " EUR (objem: " . $orderBook['asks'][0][1] . " BTC)\n";
4. Svíčková data (OHLCV)
Podporované časové rámce jsou definovány ve třídě Interval:
| Konstanta | Hodnota (minuty) | Popis |
|---|---|---|
Interval::M1 |
1 |
1 minuta |
Interval::M5 |
5 |
5 minut |
Interval::M15 |
15 |
15 minut |
Interval::H1 |
60 |
1 hodina |
Interval::H4 |
240 |
4 hodiny |
Interval::D1 |
1440 |
1 den |
use RevolutX\Types\Interval;
$candles = $client->getCandles('BTC-EUR', interval: Interval::H1);
foreach (array_slice($candles, -5) as $candle) {
echo "Čas: {$candle['start']} | Open: {$candle['open']} | Close: {$candle['close']} | Objem: {$candle['volume']}\n";
}
Práce s časem: dvě věci, které je potřeba vědět
Dva svíčkové přehledy postavené nad stejnými daty si můžou snadno odporovat. Téměř vždy za tím stojí jeden z následujících dvou důvodů, ne chyba.
Svíčky jsou krájené podle UTC, ne podle vašeho lokálního dne. Hodinová svíčka
začíná v celou hodinu UTC a denní svíčka D1 v 00:00 UTC — což je v zóně
Europe/Prague 01:00 lokálního času. Svíčka za váš lokální kalendářní den tedy
neexistuje. Stejně tak „dnes od půlnoci" znamená něco jiného v UTC a něco jiného
v Praze; obě čtení jsou správná, jen odpovídají na jinou otázku. Zónu proto
zvolte vědomě a výstup jí označte.
Nejnovější svíčka není dokončená. Její close, high, low a volume se
hýbou až do konce intervalu. Když stejný skript pustíte dvakrát s odstupem pár
minut, poslední řádek se legitimně bude lišit, zatímco všechny řádky nad ním
zůstanou totožné.
Stabilní přehled za jeden den
Předejte oba parametry since i until. API pak vrátí jen uzavřené svíčky,
takže ta nedokončená vám nerozhodí součty:
use RevolutX\Types\Interval;
// Zónu zvolte vědomě — nepřebírejte date_default_timezone_get().
$tz = new DateTimeZone('Europe/Prague');
$candles = $client->getCandles(
'BTC-EUR',
interval: Interval::H1,
since: new DateTimeImmutable('today midnight', $tz),
until: new DateTimeImmutable('tomorrow midnight', $tz)
);
foreach ($candles as $candle) {
// 'start' se vrací v milisekundách — viz „Omezení časového okna" níže.
$time = (new DateTimeImmutable('@' . intdiv((int) $candle['start'], 1000)))
->setTimezone($tz)
->format('Y-m-d H:i');
echo "{$time} | O: {$candle['open']} | H: {$candle['high']} | L: {$candle['low']} | C: {$candle['close']}\n";
}
Chcete naopak tu živou, nedokončenou svíčku — třeba pro zobrazení typu ticker?
Předejte samotné since a přijde jako poslední prvek.
Nestahujte všechno a nefiltrujte v PHP
Bez since/until vrací endpoint posledních 1000 svíček. Pro H1 nebo
D1 to jeden den pokryje s rezervou, ale 1000 minutových svíček je jen
asi 16,7 hodiny. Když tedy stáhnete Interval::M1 bez omezení a „dnešek" si
vyfiltrujete v PHP, někdy po 16:40 lokálního času vám ráno tiše vypadne ze
začátku rozsahu — bez chyby, jen chybějící řádky. Omezte místo toho request.
Omezení časového okna
$since a $until přijímají kteroukoli z těchto hodnot:
| Hodnota | Význam |
|---|---|
1700000000000 |
Unix timestamp v milisekundách, předá se beze změny. |
new DateTimeImmutable('2024-01-01', new DateTimeZone('UTC')) |
Převede se podle vlastní časové zóny objektu. |
'2024-01-01T00:00:00Z' |
Datum jako string — naparsuje se, offset se respektuje. |
'-7 days' |
Relativní výraz, jak ho chápe DateTimeImmutable. |
'1700000000000' |
String z 12+ číslic se bere jako milisekundy. |
use RevolutX\Types\Interval;
$candles = $client->getCandles(
'BTC-EUR',
interval: Interval::H1,
since: new DateTimeImmutable('-7 days', new DateTimeZone('UTC')),
until: new DateTimeImmutable('now', new DateTimeZone('UTC')),
);
String bez explicitního offsetu se chápe jako UTC, ne podle serverového
date.timezone — stejný kód tedy vybere stejné okno na každém stroji. Prázdný
nebo nenaparsovatelný string vyhodí InvalidArgumentException.
Čísla jsou milisekundy, ne sekundy
Čísla se nikdy nepřepočítávají, takže since: time() neskončí chybou — jen
dostanete okno začínající v lednu 1970, tedy prázdný nebo nepoužitelný
rozsah. Použijte time() * 1000, nebo předejte DateTimeImmutable a nechte
převod na SDK. V odpovědích jsou hodnoty taky v milisekundách:
$candle['start'] je potřeba před date() vydělit tisícem.
Stejný převod je k dispozici i samostatně přes
RevolutX\Helpers\TimestampConverter::toMilliseconds().
Hodnoty přicházející z requestu
Vstup od uživatele si převeďte sami, místo abyste posílali dál surový string — parser v SDK je pohodlí, ne validační vrstva:
use RevolutX\Types\Interval;
$userTz = new DateTimeZone('Europe/Prague');
$raw = trim($_GET['from'] ?? ''); // např. '2024-01-01' z <input type="date">
if ($raw !== '' && preg_match('/^\d{4}-\d{2}-\d{2}$/', $raw) !== 1) {
http_response_code(400);
exit(json_encode(['error' => 'from must be YYYY-MM-DD']));
}
// Midnight v zóně *uživatele*, ne v UTC.
$since = $raw === '' ? null : new DateTimeImmutable("{$raw} 00:00:00", $userTz);
$candles = $client->getCandles('BTC-EUR', Interval::H1, since: $since);
Čtyři věci, které kousnou, když hodnota přiteče přímo z prohlížeče:
- String bez offsetu je UTC.
'2024-01-01'je UTC midnight, ale uživatel v Praze, který vybral 1. ledna, myslí 31. prosince 23:00 UTC. Hranici proto postavte v jeho zóně a předejteDateTimeImmutablejako výše. Z JavaScriptu jsou jednoznačnéd.getTime()(milisekundy) id.toISOString()(neseZ);'2024-01-01T13:30'z<input type="datetime-local">jednoznačné není — nemá offset, takže se přečte jako UTC. - Datum se lomítky je americké.
DateTimeImmutablečte'01/02/2024'jako - ledna, takže uživatel, který myslel 1. února, dostane jiný den — a bez
jakékoli chyby. Trvejte na
YYYY-MM-DD. - Nevyplněné pole je prázdný string, ne chybějící hodnota. HTML formulář
pošle
?from=i u nedotčeného inputu a''vyhodíInvalidArgumentException— proto jsou v příkladu kontroly na=== ''. - Datum bez oddělovačů se odmítne, nehádá se.
'2024'a'20240101'vyhodí výjimku místo toho, aby skončily v roce 1970, protože krátká řada číslic je mezi datem a timestampem nerozhodnutelná. Za milisekundy se berou až 12+ číslic.
Projdou i relativní výrazy jako '-7 days' nebo 'now', což je další důvod
ukotvit povolený tvar na hranici aplikace a nepouštět dovnitř libovolné stringy
z requestu.