const res = await fetch('https://app.trdrs.co/api/market/stream?instrument=ESU6&tf=5m', {
headers: { Authorization: `Bearer ${process.env.TRDRS_API_KEY}` },
})
const decoder = new TextDecoder()
for await (const chunk of res.body!) {
// Each SSE frame: "event: <name>\ndata: <json>\n\n". Snapshot first, then live events.
process.stdout.write(decoder.decode(chunk as Uint8Array))
}curl -N 'https://app.trdrs.co/api/market/stream?instrument=ESU6&tf=5m' \
-H "Authorization: Bearer $TRDRS_API_KEY"import requests
url = "https://app.trdrs.co/api/market/stream"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.trdrs.co/api/market/stream",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://app.trdrs.co/api/market/stream"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://app.trdrs.co/api/market/stream")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.trdrs.co/api/market/stream")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body<string>{
"error": "invalid_instrument"
}{
"error": "invalid_instrument"
}{
"error": "invalid_instrument"
}{
"error": "invalid_instrument"
}Stream live bars
Streams live bars for one symbol and timeframe as server-sent events (text/event-stream). Every time you connect or reconnect, the stream sends the full current window as a snapshot before any live bar, so an EventSource that reconnects on its own needs no bookkeeping from you. A quote states the whole top of the book by itself, so quotes start as soon as the stream opens and never wait for the window to be read. A spread expression streams like any symbol. A continuous futures symbol, ES1! or ES2!, streams the contract its position names when you connect, so reconnect after its roll to follow the next contract.
Required key: Trading API key. A Connect app’s backend can also send it with the app’s API key, and a venue’s backend with its Venue key, which carries trader:read or trader:trade, each naming one of its own traders in x-trdrs-trader: it then runs on that trader’s own accounts.
const res = await fetch('https://app.trdrs.co/api/market/stream?instrument=ESU6&tf=5m', {
headers: { Authorization: `Bearer ${process.env.TRDRS_API_KEY}` },
})
const decoder = new TextDecoder()
for await (const chunk of res.body!) {
// Each SSE frame: "event: <name>\ndata: <json>\n\n". Snapshot first, then live events.
process.stdout.write(decoder.decode(chunk as Uint8Array))
}curl -N 'https://app.trdrs.co/api/market/stream?instrument=ESU6&tf=5m' \
-H "Authorization: Bearer $TRDRS_API_KEY"import requests
url = "https://app.trdrs.co/api/market/stream"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.trdrs.co/api/market/stream",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://app.trdrs.co/api/market/stream"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://app.trdrs.co/api/market/stream")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.trdrs.co/api/market/stream")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body<string>{
"error": "invalid_instrument"
}{
"error": "invalid_instrument"
}{
"error": "invalid_instrument"
}{
"error": "invalid_instrument"
}Authorizations
The Trading API key (trdrs_sk_…), for market data, orders and account state on the accounts its owner holds. Use it server-to-server, and keep it on your server. Its scope is named trading in the API.
Query Parameters
The symbol, or a spread expression as /api/market/history accepts. If any symbol in a spread is refused, the spread is refused.
The timeframe, such as 1m.
Response
An open event stream. The events are:
snapshot{ bars: WireBar[] }: the whole current window.bar{ bar: WireBar }: a bar that is forming or finished. The sametupdates the forming bar, and a newtopens the next one.quote{ bid: { price, size }, ask: { price, size } }: the real top of the book, only where the feed has one.mark{ instrument, price }: the exchange's own mark price as it moves, only where the exchange publishes one. A perpetual's open position, its P&L and its account's rules are measured at its mark, which can carry a decimal its trades can't.session{ instrument, last, open, high, low, prevClose, volume, change, changePct, spark }: the session valuesGET /api/market/quoteswould answer for the instrument, sent after the snapshot, again whenever a bar moves them (at most once a second), and read again each minute. A board with the instrument charted needs no poll for it.error{ code }: the stream is ending. The codes areunknown_instrument,not_entitled,feed_down,session_displaced(another application signed in on the login that serves the data and took its market data session) andsession_expired(your own session ended: while you are signed in, the stream can't outlive your session). Sign in again before you reconnect, rather than retrying blind.
A dropped connection carries no event, and the browser reconnects on its own.
The stream may end with a reconnect event, { code, afterMs }: the engine serving it is restarting for a release, or the trader it serves moved to another engine, and the stream closes right after the event. code is engine_draining. Open the stream again after afterMs milliseconds, which is never more than 1,000: another engine serves it, and it opens as any connection does. It is not an error, so keep what you show until the new stream's first events arrive. The event sets the stream's retry: to afterMs too, so an EventSource that reconnects on its own follows it.
The response is of type string.