====== PlayGround ======
====== T4 Chart API ======
Our chart API provides data in aggregated or non-aggregated (raw trade) formats.
All times are in CST.
The complete API documentation is available via Swagger UI at:
[[https://api-sim.t4login.com/chart/swagger/index.html|T4 Chart API Documentation]]
The Swagger documentation provides:
* Complete list of available endpoints
* Request parameters and response formats
* Interactive testing capability
* Authentication requirements
**What changed in this revision** \\
This page has been extended to document the **compact binary response format** (``application/octet-stream`` / ``application/t4``) and the **open-source decoder libraries** that consume it. The original JSON documentation below is unchanged; the new material is additive:
* A new top-level section **[[#Binary Response Format (T4Bin / T4BinAggr)]]** describing the on-the-wire envelope, framing, 7-bit/decimal value encodings, price & time conventions, and the full record-tag (CTAG) tables.
* A new top-level section **[[#Decoder Libraries]]** documenting the JavaScript (``@t4/chart-decoder``) and Python (``t4login``) reference decoders, including the streaming handler interface, the ``ChartDataState`` field reference, and the ``ChartDataChange`` / ``MarketMode`` / ``BidOffer`` enumerations.
* Minor clarifications to the existing **Accept** header tables to cross-reference the binary sections.
See **[[#Revision Notes / Changelog]]** at the bottom for the detailed list.
===== Aggregated Chart Data =====
==== Overview ====
The **GetBarChart** API retrieves bar chart data for a specified trading instrument over a given date range. This API supports various chart types and bar intervals, tailored for detailed data analysis in financial contexts.
==== API Endpoint ====
GET https://api-sim.t4login.com/chart/barchart
==== Headers ====
For proper access and response handling, the **GetBarChart** API requires certain HTTP headers to be set in the request.
^ Header ^ Value ^ Description ^
| Authorization | Bearer | **Required**. A valid bearer token to authenticate the request. |
| Accept | application/json, text/csv, application/octet-stream, application/t4 | **Optional**. Specifies the response format the client can handle. If omitted, the API returns JSON. Use text/csv to request CSV, or application/octet-stream / application/t4 to request the compact binary format (see **[[#Binary Response Format (T4Bin / T4BinAggr)]]**). |
**Examples:**
* To authorize the request, include the bearer token:
Authorization: Bearer YOUR_ACCESS_TOKEN
* To receive the response in a compact binary format, set the `Accept` header accordingly:
Accept: application/octet-stream
or
Accept: application/t4
Setting the `Accept` header is optional, and if it is not included, the API will return the response in a JSON format.
The aggregated binary stream is referred to as **T4BinAggr**. Its envelope, framing, and record tags are documented under **[[#Aggregated tags (T4BinAggr)]]**, and a ready-made decoder is described under **[[#Decoder Libraries]]**.
==== Parameters ====
^ Parameter ^ Description ^
| **exchangeId** | **Required**. Identifier for the exchange. |
| **contractId** | **Required**. Identifier for the contract. |
| **chartType** | **Required**. Type of chart to compute. Currently, only **Bar** type is supported. |
| **barInterval** | **Required**. Interval at which bars are aggregated. Possible values:\\ • **Tick**: Bars aggregated based on trade count.\\ • **TickRange**: Bars aggregated based on price range.\\ • **Volume**: Bars aggregated based on number of contracts traded.\\ • **Second**: Bars aggregated into multiples of seconds.\\ • **Minute**: Bars aggregated into multiples of minutes.\\ • **Hour**: Bars aggregated into multiples of hours.\\ • **Day**: Bars aggregated into multiples of days.\\ • **Week**: Bars aggregated into multiples of weeks. |
| **barPeriod** | **Required**. Period for the bars. |
| **tradeDateStart** | **Required**. Start date for the trade data. |
| **tradeDateEnd** | **Required**. End date for the trade data. |
| marketID | Market ID (optional). Can be omitted when using ContinuationType. |
| continuationType | Method of continuation for the chart. Only **Volume** is currently supported. |
| resetInterval | Interval at which bar computations reset (not applicable when ContinuationType.Volume is used). \\ Defaults to **TradingDay**. Other possible values:\\ • **None**: No reset interval.\\ • **TradingWeek**: Reset on the trading week boundary.\\ • **ExpiryChange**: Reset on an expiry change. |
| contractMonths | Contract months to include (not applicable when **ContinuationType.Volume** is used). |
| rolloverThreshold| Rollover threshold (not applicable when **ContinuationType.Volume** is used). |
| forwardMonths | Forward months (not applicable when **ContinuationType.Volume** is used). |
==== Response ====
The response from the **GetBarChart** API is a JSON object containing detailed information about the bar chart data. Below is the structure of the response along with a description of each element:
=== Bars ===
^ Element ^ Description ^
| tradeDate | Date of the trade. |
| time | Time when the bar data starts. |
| closeTime | Time when the bar data ends. |
| marketID | Identifier for the market. |
| openPrice | Opening price for this bar. |
| highPrice | Highest price in this bar. |
| lowPrice | Lowest price in this bar. |
| closePrice | Closing price for this bar. |
| volume | Total volume of trades in this bar. |
| volumeAtBid | Volume of trades at the bid price. |
| volumeAtOffer | Volume of trades at the offer price. |
| trades | Total number of trades in this bar. |
| tradesAtBid | Number of trades at the bid price. |
| tradesAtOffer | Number of trades at the offer price. |
=== MarketDefinitions ===
^ Element ^ Description ^
| marketID | Identifier for the market. |
| minPriceIncrement | Minimum increment of the market's price. |
| priceCode | Code related to the pricing of the market. |
| tickValue | Value of each tick in the market's pricing. |
| vpt | Additional market-specific information (variable). |
=== ModeChanges ===
^ Element ^ Description ^
| marketID | Identifier for the market. |
| tradeDate | Date of the trade. |
| time | Time when the mode change occurred. |
| marketMode | The mode of the market at the given time. |
=== OpenInterests ===
^ Element ^ Description ^
| marketID | Identifier for the market. |
| tradeDate | Date of the trade. |
| time | Time of the recorded open interest. |
| openInterest | The amount of open interest. |
=== Settlements ===
^ Element ^ Description ^
| marketID | Identifier for the market. |
| tradeDate | Date of the trade. |
| time | Time when the settlement information was recorded. |
| settlementPrice | Price at which the trade was settled. |
| isHeld | Indicates if the settlement was held (boolean). |
==== Example JSON Response ====
{
"tradeDateStart": "2024-01-08T00:00:00",
"tradeDateEnd": "2024-01-08T00:00:00",
"activeMarket": "XCME_Eq ES (H24)",
"bars": [
{
"tradeDate": "2024-01-08T00:00:00",
"time": "2024-01-08T00:00:00",
"closeTime": "2024-01-08T15:59:59.5853624",
"marketID": "XCME_Eq ES (H24)",
"openPrice": "473575",
"highPrice": "480325",
"lowPrice": "471525",
"closePrice": "479800",
"volume": 1339989,
"volumeAtBid": 665050,
"volumeAtOffer": 674939,
"trades": 320624,
"tradesAtBid": 152333,
"tradesAtOffer": 168291
}
],
"marketDefinitions": [
{
"marketID": "XCME_Eq ES (H24)",
"minPriceIncrement": "25",
"priceCode": "",
"tickValue": 12.5,
"vpt": ""
}
],
"modeChanges": [
{
"marketID": "XCME_Eq ES (H24)",
"tradeDate": "2024-01-08T00:00:00",
"time": "2024-01-07T08:04:27.7736882",
"marketMode": 5
},
// ... additional mode changes ...
],
"openInterests": [
{
"marketID": "XCME_Eq ES (H24)",
"tradeDate": "2024-01-08T00:00:00",
"time": "2024-01-07T12:43:16.8256856",
"openInterest": 2211632
},
// ... additional open interests ...
],
"settlements": [
{
"marketID": "XCME_Eq ES (H24)",
"tradeDate": "2024-01-08T00:00:00",
"time": "2024-01-05T16:38:39.9345143",
"settlementPrice": "473475"
},
{
"marketID": "XCME_Eq ES (H24)",
"tradeDate": "2024-01-08T00:00:00",
"time": "2024-01-08T15:01:01.4810068",
"isHeld": true
}
// ... additional settlements ...
]
}
===== Non-Aggregated Chart Data (Trade History) =====
==== Overview ====
The **GetTradeHistory** API retrieves historical trade data for a specified trading instrument within a given date and time range. This API allows for querying trade data based on the trade date or specific start and end timestamps.
==== API Endpoint ====
GET https://api-sim.t4login.com/chart/tradehistory
==== Headers ====
^ Header ^ Value ^ Description ^
| Authorization | Bearer | **Required**. A valid bearer token to authenticate the request. |
| Accept | application/octet-stream, application/t4 | **Optional**. Specifies the content type that the client can handle. Use this header to request a compact binary format response (see **[[#Binary Response Format (T4Bin / T4BinAggr)]]**). If omitted, the default response format is JSON. |
==== Parameters ====
^ Parameter ^ Description ^
| exchangeId | **Required**. Identifier for the exchange. |
| contractId | **Required**. Identifier for the contract. |
| marketID | Market ID (optional). |
| tradeDateStart | The start date for the trade history based on trade dates (optional). |
| tradeDateEnd | The end date for the trade history based on trade dates (optional). |
| start | The calendar start date and time for the request in CST (optional). |
| end | The calendar end date and time for the request in CST (optional). |
| since | Filters data to only include trades after the specified date and time (optional). |
**Note:** Pass either **tradeDateStart** and **tradeDateEnd** OR **start** and **end**. Including both will result in an error. Use **since** to further filter data to only include trades after the specified date and time.
The non-aggregated binary stream is referred to as **T4Bin**. Unlike the JSON response (which materialises the entire payload into arrays), the binary stream is a **delta-encoded event log**: each record carries only the change from the previous one, so it must be decoded sequentially. See **[[#Non-aggregated tags (T4Bin)]]** and **[[#Decoder Libraries]]**.
=== Response ===
^ Element ^ Description ^
| exchangeID | Identifier for the exchange. |
| contractID | Identifier for the contract. |
| marketID | Identifier for the market. |
| requestStatusMessage| Any status messages or errors related to the request. |
| tradeDateStart | The starting date of the trade data. |
| tradeDateEnd | The ending date of the trade data. |
| trades | An array of trade objects, each detailing individual trades. |
| marketDefinitions | An array of market definition objects, detailing market-specific information. |
| modeChanges | An array of mode change objects, each showing changes in the market mode. |
| openInterests | An array containing information about open interests. |
| settlements | An array detailing settlement information, including prices. |
| vwaPs | An array detailing volume-weighted average prices (VWAP). |
=== Trades ===
^ Element ^ Description ^
| marketID | Identifier for the market. |
| tradeDate | The date of the trade as per trade date convention. |
| time | The specific time when the trade occurred. |
| tradePrice | The price at which the trade was executed. |
| aggressorSide | Indicates the side of the aggressor of the trade. 1 for buyer, -1 for seller. |
=== VWAP(s) ===
^ Element ^ Description ^
| marketID | Identifier for the market. |
| tradeDate | The date of the trade as per trade date convention. |
| time | The specific time when the VWAP is calculated. |
| vwapPrice | The volume-weighted average price for the trades up to the specified time. |
==== Example JSON Response ====
{
"exchangeID": "CME_E",
"contractID": "YM",
"marketID": "XCME_E YM (H24)",
"requestStatusMessage": "",
"tradeDateStart": "2024-01-08T00:00:00",
"tradeDateEnd": "2024-01-08T00:00:00",
"trades": [
{
"marketID": "XCME_E YM (H24)",
"tradeDate": "2024-01-08T00:00:00",
"time": "2024-01-07T17:00:00",
"tradePrice": "37674",
"aggressorSide": 1
},
...
],
"marketDefinitions": [],
"modeChanges": [
...
],
"openInterests": [
...
],
"settlements": [
...
],
"vwaPs": [
...
]
}
The response is structured as a JSON object with various elements containing detailed trade data and related information for the specified contract and exchange within the requested time frame.
===== Binary Response Format (T4Bin / T4BinAggr) =====
When the **Accept** header requests ``application/octet-stream`` or ``application/t4``, the chart endpoints return a **compact binary stream** instead of JSON. The binary format is typically an order of magnitude smaller than the equivalent JSON and is the recommended transport for large date ranges or high-resolution (tick / quote) history.
Two closely-related dialects exist:
^ Stream ^ Endpoint ^ Aggregation ^ Decoder entry point ^
| **T4BinAggr** | ``/chart/barchart`` | Pre-aggregated OHLCV bars | ``ChartDataStreamReaderAggr`` |
| **T4Bin** | ``/chart/tradehistory`` | Raw, delta-encoded events | ``ChartDataStreamReader`` |
You do **not** need to implement the byte-level format yourself — reference decoders are provided for JavaScript and Python (see **[[#Decoder Libraries]]**). This section documents the wire format for completeness and for anyone porting the decoder to another language.
==== Envelope & payload extraction ====
The HTTP body may contain a small amount of framing before the actual T4Bin payload. The payload begins at a **Start-Of-Format (SOF)** record whose first bytes form a recognisable signature. A decoder should scan for the first matching signature and treat everything from that offset onward as the stream.
^ Stream ^ SOF signature (hex) ^ Meaning ^
| **T4BinAggr** | ``05 01 01 00 00 00`` | length=5, tag=``CTAG_SOF`` (1), version=1 (little-endian int32) |
| **T4Bin** | ``0D 01 01 00 00 00`` | length=13, tag=``CTAG_SOF`` (1), version=1 (little-endian int32) |
If a non-empty response contains neither signature, the body is almost certainly an error message or an unexpected format and should be treated as a hard error rather than decoded.
==== Record framing ====
Both dialects are a flat sequence of **length-prefixed records**:
[ length : 7-bit int ] [ tag : 7-bit int ] [ tag-specific payload ... ]
* **length** — the number of bytes in the record //after// the length prefix itself (i.e. tag + payload). A decoder reads ``length``, resets a byte counter, reads the tag and payload, then skips any unconsumed trailing bytes so that exactly ``length`` bytes are consumed. This makes the format **forward-compatible**: unknown tags and extra trailing fields in known tags are skipped safely.
* **tag** — one of the ``CTAG_*`` constants in the tables below. The tag namespaces are **separate** for the two dialects (e.g. tag ``11`` means ``CTAG_BAR`` in T4BinAggr but ``CTAG_TICKDATAPOINT_7BIT`` in T4Bin).
* A record with ``length == 0`` is a no-op padding/keepalive and is ignored.
==== Value encodings ====
=== 7-bit variable-length integers ===
Integers are stored little-endian, 7 bits per byte, with the high bit (``0x80``) used as a continuation flag.
^ Type ^ Positive encoding ^ Negative encoding ^ Decoder result type ^
| Signed 32-bit int | 1–5 bytes | always 5 bytes (sign-extended) | JS ``number`` / Py ``int`` |
| Signed 64-bit long | 1–9 bytes | always 10 bytes (sign-extended) | JS ``BigInt`` / Py ``int`` |
64-bit values (notably **tick timestamps**) must be decoded with a wide integer type. The JavaScript decoder uses ``BigInt`` throughout to avoid loss of precision above ``2^53``.
=== Decimal encoding (96-bit unscaled) ===
Prices and tick values use a .NET ``decimal``-compatible layout: a single **header byte** (2 bits per chunk, 4 chunks) followed by up to four 7-bit-encoded magnitudes.
* Chunks (MSB→LSB in the header): ``lo``, ``mid``, ``hi`` (the 96-bit unscaled integer split into three 32-bit words) and a ``sign/scale`` chunk.
* Per-chunk 2-bit tag: ``0x00`` = zero (no magnitude bytes follow), ``0x01`` = positive, ``0x02`` = negative, ``0x03`` = the ``Int32.MinValue`` sentinel (no magnitude bytes follow).
* In the sign/scale chunk: **bit 31** set ⇒ value is negative; **bits 16–23** hold the decimal **scale** (number of fractional digits).
* Final value = ``(±) unscaled / 10^scale``.
The reference decoders represent decimals with arbitrary-precision libraries (**decimal.js** at scale 18 in JavaScript, ``decimal.Decimal`` in Python) so that round-tripping matches Java ``BigDecimal`` exactly.
=== Nullable price (decodePriceN) ===
Some fields (e.g. a market's minimum cabinet price) are nullable: a single header byte is read first; if bit 0 is **clear** the value is ``null`` and no further bytes follow, otherwise a decimal (above) follows.
==== Price & time conventions ====
* **Prices** are exposed as a ``Price`` type — a decimal quantized to **scale 18** with **HALF_EVEN** rounding. Many tick records encode a price as a //tick increment// relative to a running value; the decoder converts these to absolute prices via the market's denominator / minimum-price-increment / VPT. The JSON ``openPrice`` etc. fields (which are integer-tick strings such as ``"473575"``) correspond to the decoded ``Price`` after conversion.
* **Timestamps** are .NET-style **ticks**: 1 tick = 100 ns since ``0001-01-01 00:00:00``. The decoder wraps these in an ``NDateTime`` type. As with the JSON API, **all times are CST**.
* Many time fields are **delta-encoded** against the previous record. A decoded "delta" larger than a threshold (~ year 1900 in ticks, ``599266080000000000``) is interpreted as an **absolute** tick value rather than a delta — a decoder must apply this rule to reconstruct timestamps correctly.
==== Aggregated tags (T4BinAggr) ====
Record tags emitted on ``/chart/barchart`` with a binary ``Accept`` header. Format version constant ``CVAL_T4BINAGGR_VERSION = 1``.
^ Tag value ^ Constant ^ Purpose ^
| 1 | ``CTAG_SOF`` | Start of format; carries the little-endian int32 version. Resets state. |
| 2 | ``CTAG_MARKET_DEFINITION`` | Market parameters: id, numerator, denominator, price code, tick value, VPT, min-cabinet price. |
| 3 | ``CTAG_MARKET_SWITCH`` | Switch the active market id for subsequent records. |
| 4 | ``CTAG_TRADEDATE_SWITCH`` | Switch the active trade date (7-bit datetime). |
| 10 | ``CTAG_BAR_DELTA`` | An OHLCV bar with prices encoded as tick increments relative to the bar low. |
| 11 | ``CTAG_BAR`` | An OHLCV bar with absolute decimal-encoded prices. |
| 20 | ``CTAG_MARKET_MODE`` | Market mode change (see **[[#MarketMode]]**). |
| 21 | ``CTAG_OPEN_INTEREST`` | Open-interest sample. |
| 22 | ``CTAG_SETTLEMENT_PRICE`` | Settlement price + ``held`` boolean. |
Each decoded ``Bar`` exposes the same fields as the JSON //Bars// array (``TradeDate``, ``Time``, ``CloseTime``, ``MarketID``, ``OpenPrice``, ``HighPrice``, ``LowPrice``, ``ClosePrice``, ``Volume``, ``VolumeAtBid``, ``VolumeAtOffer``, ``Trades``, ``TradesAtBid``, ``TradesAtOffer``), with PascalCase names for parity with the Java/Python sources.
==== Non-aggregated tags (T4Bin) ====
Record tags emitted on ``/chart/tradehistory`` with a binary ``Accept`` header. Format version constant ``CVAL_T4BIN_VERSION = 1``. Each record updates the decoder's ``ChartDataState`` and sets ``state.Change`` to the corresponding **[[#ChartDataChange]]** value.
=== Framing / market ===
^ Tag ^ Constant ^ Purpose ^
| 1 | ``CTAG_SOF`` | Start of format (+ optional version and trade date). Resets state. |
| 2 | ``CTAG_MARKET_DEFINITION`` | Market parameters for price conversion. |
| 7 | ``CTAG_CONSOLIDATED`` | Marks the stream as a consolidated (multi-market) feed. |
| 8 | ``CTAG_MARKET_SWITCH`` | Switch active market by previously-registered key. |
| 9 | ``CTAG_MARKET_KEY`` | Register a market key → market id mapping. |
=== Trades / ticks ===
^ Tag ^ Constant ^ Purpose ^
| 11 | ``CTAG_TICKDATAPOINT_7BIT`` | Trade; price as +tick increment. |
| 12 | ``CTAG_TICKDATAPOINT_NEG_7BIT`` | Trade; price as -tick increment. |
| 17 | ``CTAG_TICKDATAPOINT_ALT_7BIT`` | Trade (+tick) with per-order volume list. |
| 18 | ``CTAG_TICKDATAPOINT_ALT_NEG_7BIT`` | Trade (-tick) with per-order volume list. |
| 60 | ``CTAG_TRADE_PRICE`` | Trade; price as decimal increment (cumulative). |
| 61 | ``CTAG_TRADE_PRICE_DEC`` | Trade; price as absolute decimal increment. |
| 62 | ``CTAG_TRADE_PRICE_ALT`` | As 60, with per-order volume list. |
| 63 | ``CTAG_TRADE_PRICE_DEC_ALT`` | As 61, with per-order volume list. |
=== Tick-change (TickChange aggregation) ===
^ Tag ^ Constant ^ Purpose ^
| 14 | ``CTAG_TICKCHANGEDATAPOINT_7BIT`` | Bar close-price moves +tick. |
| 15 | ``CTAG_TICKCHANGEDATAPOINT_NEG_7BIT`` | Bar close-price moves -tick. |
| 140 | ``CTAG_PRICE_CHANGE`` | Bar close-price moves by decimal increment. |
| 141 | ``CTAG_PRICE_CHANGE_DEC`` | Bar close-price set to absolute decimal. |
=== Bars ===
^ Tag ^ Constant ^ Purpose ^
| 21 | ``CTAG_BARDATAPOINT_7BIT_DELTA_LOW`` | OHLCV bar; prices as +tick offsets from bar low. |
| 22 | ``CTAG_BARDATAPOINT_NEG_7BIT_DELTA_LOW`` | OHLCV bar; prices as -tick offsets from bar low. |
| 65 | ``CTAG_BAR_PRICE`` | OHLCV bar; decimal increments from running low. |
| 66 | ``CTAG_BAR_PRICE_DEC`` | OHLCV bar; absolute decimal prices. |
=== Quotes (BBO) ===
^ Tag ^ Constant ^ Purpose ^
| 50 | ``CTAG_QUOTE_7BIT`` | Bid/offer quote; bid as +tick increment. |
| 51 | ``CTAG_QUOTE_NEG_7BIT`` | Bid/offer quote; bid as -tick increment. |
| 52 | ``CTAG_QUOTE_VOLUME_DELTA`` | Quote volume-only change. |
| 53 | ``CTAG_QUOTE_PRICE`` | Quote; bid as cumulative decimal increment. |
| 54 | ``CTAG_QUOTE_PRICE_DEC`` | Quote; bid as absolute decimal. |
=== TPO (Time Price Opportunity / Market Profile) ===
^ Tag ^ Constant ^ Purpose ^
| 30 | ``CTAG_TPO_START`` | TPO row start; base price +tick. |
| 31 | ``CTAG_TPO_START_NEGBASE`` | TPO row start; base price -tick. |
| 32 | ``CTAG_TPO_DATAPOINT`` | TPO cell. |
| 33 | ``CTAG_TPO_DATAPOINT_OPEN`` | TPO cell (opening). |
| 34 | ``CTAG_TPO_DATAPOINT_CLOSE`` | TPO cell (closing). |
| 35 | ``CTAG_TPO_DATAPOINT_OPENCLOSE`` | TPO cell (opening & closing). |
| 190 | ``CTAG_TPO_START_PRICE`` | TPO row start; cumulative decimal base. |
| 191 | ``CTAG_TPO_START_PRICE_DEC`` | TPO row start; absolute decimal base. |
| 192 | ``CTAG_TPO_PRICE`` | TPO cell; decimal price. |
| 193 | ``CTAG_TPO_OPEN_PRICE`` | TPO cell (opening); decimal price. |
| 194 | ``CTAG_TPO_CLOSE_PRICE`` | TPO cell (closing); decimal price. |
| 195 | ``CTAG_TPO_OPENCLOSE_PRICE`` | TPO cell (open & close); decimal price. |
=== Market state / session events ===
^ Tag ^ Constant ^ Purpose ^
| 100 | ``CTAG_MARKET_MODE`` | Market mode change (see **[[#MarketMode]]**). |
| 101 | ``CTAG_MARKET_SETTLEMENT`` | Settlement price (tick). |
| 102 | ``CTAG_MARKET_HELD_SETTLEMENT`` | Held settlement price (tick). |
| 103 | ``CTAG_MARKET_CLEARED_VOLUME`` | Cleared volume. |
| 104 | ``CTAG_MARKET_OPEN_INTEREST`` | Open interest. |
| 105 | ``CTAG_MARKET_VWAP`` | VWAP (tick). |
| 106 | ``CTAG_MARKET_RFQ`` | Request-for-quote (side + volume). |
| 107 | ``CTAG_SETTLEMENT_PRICE`` | Settlement price (decimal increment). |
| 108 | ``CTAG_HELD_SETTLEMENT_PRICE`` | Held settlement price (decimal increment). |
| 109 | ``CTAG_VWAP_PRICE`` | VWAP (decimal increment). |
===== Decoder Libraries =====
Open-source reference decoders are maintained alongside this API so you do not have to implement the binary format by hand. Both libraries are line-for-line ports of the original Java ``com.t4login`` chart-data reader and are validated against each other and against the CSV/JSON output.
All of the tools below live in the public **CTS-Futures/t4-api-tools** repository:
[[https://github.com/CTS-Futures/t4-api-tools/tree/main/tools|https://github.com/CTS-Futures/t4-api-tools/tree/main/tools]]
^ Language ^ Package / module ^ Location in the repo ^
| JavaScript | ``@t4/chart-decoder`` (ES modules) | ``tools/JavaScript/t4-javascript-api/`` (and a browser copy under ``tools/JavaScript/JSDemo/decoder/``) |
| Python | ``t4login`` | ``tools/Python/t4-pythonConversion-api/src/t4login/`` |
==== JavaScript: @t4/chart-decoder ====
Requires **Node 18+** (uses global ``fetch``) or any modern browser. The only runtime dependency is **decimal.js**.
=== Install ===
Clone the [[https://github.com/CTS-Futures/t4-api-tools/tree/main/tools|t4-api-tools]] repository, then install dependencies:
git clone https://github.com/CTS-Futures/t4-api-tools.git
cd t4-api-tools/tools/JavaScript/t4-javascript-api
npm install
=== Aggregated barchart (push / handler model) ===
``ChartDataStreamReaderAggr`` decodes the whole stream and dispatches each record to a handler. Any subset of callbacks may be supplied; missing callbacks are skipped.
import { ChartClient } from '@t4/chart-decoder';
const client = new ChartClient({ token: 'YOUR_ACCESS_TOKEN' });
await client.getBarchartBinary({
exchangeId: 'CME_Eq',
contractId: 'ESM6',
barInterval: 'Minute',
barPeriod: 1,
tradeDateStart: '2026-05-01',
tradeDateEnd: '2026-05-02',
handler: {
onMarketDefinition(def) { /* def.MarketID, def.TickValue, ... */ },
onBar(bar) { console.log(bar.Time.toString(), bar.ClosePrice.toString()); },
onModeChange(marketId, tradeDate, time, mode) { /* ... */ },
onSettlement(marketId, tradeDate, time, price, held) { /* ... */ },
onOpenInterest(marketId, tradeDate, time, oi) { /* ... */ },
},
});
The handler interface:
^ Callback ^ Emitted for tag(s) ^
| ``onMarketDefinition(marketDefinition)`` | ``CTAG_MARKET_DEFINITION`` |
| ``onBar(bar)`` | ``CTAG_BAR``, ``CTAG_BAR_DELTA`` |
| ``onModeChange(marketId, tradeDate, time, mode)`` | ``CTAG_MARKET_MODE`` |
| ``onSettlement(marketId, tradeDate, time, settlementPrice, held)`` | ``CTAG_SETTLEMENT_PRICE`` |
| ``onOpenInterest(marketId, tradeDate, time, openInterest)`` | ``CTAG_OPEN_INTEREST`` |
=== Non-aggregated trade history (pull / state model) ===
``ChartDataStreamReader`` is a sequential cursor. Each ``read()`` consumes one record and mutates the public ``reader.state`` object; ``read()`` returns ``false`` at end-of-stream. Branch on ``state.Change``:
import { ChartClient, ChartDataChange } from '@t4/chart-decoder';
const reader = await client.getTradehistoryBinary({
exchangeId: 'CME_E',
contractId: 'YM',
tradeDateStart: '2024-01-08',
tradeDateEnd: '2024-01-08',
});
while (reader.read()) {
const s = reader.state;
switch (s.Change) {
case ChartDataChange.Trade:
console.log(s.LastTimeTicks, s.LastTradePrice.toString(), s.TradeVolume, s.AtBidOrOffer);
break;
case ChartDataChange.Quote:
console.log('BBO', s.BidPrice.toString(), s.OfferPrice.toString());
break;
case ChartDataChange.Settlement:
console.log('settle', s.SettlementPrice?.toString());
break;
// ... MarketMode, OpenInterest, VWAP, TPO, TradeBar, TickChange, RFQ ...
}
}
=== Lower-level / advanced usage ===
You can also decode bytes you already have (e.g. from a saved file) without the HTTP client:
import {
ByteReader, NDateTime, ChartDataType,
ChartDataStreamReader, ChartDataStreamReaderAggr,
extractT4BinPayload,
} from '@t4/chart-decoder';
// Aggregated:
ChartDataStreamReaderAggr.read(extractT4BinPayload(bytes), handler);
// Non-aggregated:
const reader = new ChartDataStreamReader({
data: new ByteReader(extractT4BinPayload(bytes)),
tradeDate: new NDateTime(0n),
marketId: 'XCME_E YM (H24)',
dataType: ChartDataType.get(0), // Tick
});
=== Browser (no bundler) ===
The JSDemo copy ships a ``decoder/loader.js`` ES-module entry point that publishes the decoder on ``window.T4ChartDecoder`` and fires a ``t4-decoder-ready`` event, so classic ``
==== Python: t4login ====
The Python package mirrors the JavaScript API one-to-one (same class names, same field names). It is the original conversion the JavaScript port was derived from.
=== Install ===
Clone the [[https://github.com/CTS-Futures/t4-api-tools/tree/main/tools|t4-api-tools]] repository, then install dependencies:
git clone https://github.com/CTS-Futures/t4-api-tools.git
cd t4-api-tools/tools/Python/t4-pythonConversion-api
pip install -e . # installs from pyproject.toml
=== Usage ===
from t4login.client.chart_client import ChartClient
from t4login.definitions.chartdata.chart_data_change import ChartDataChange
client = ChartClient(token="YOUR_ACCESS_TOKEN")
# Aggregated (handler model)
client.get_barchart_binary(
exchange_id="CME_Eq", contract_id="ESM6",
trade_date_start="2026-05-01", trade_date_end="2026-05-02",
handler=my_handler,
)
# Non-aggregated (state model)
reader = client.get_tradehistory_binary(
exchange_id="CME_E", contract_id="YM",
trade_date_start="2024-01-08", trade_date_end="2024-01-08",
)
while reader.read():
s = reader.state
if s.Change == ChartDataChange.Trade:
print(s.LastTradePrice, s.TradeVolume)
==== ChartDataState field reference (T4Bin) ====
Populated by ``ChartDataStreamReader``. Field names are PascalCase for parity across Java/Python/JS. Prices are ``Price`` objects (call ``.toString()`` / Python ``str()``); 64-bit tick times are ``BigInt`` in JS.
^ Group ^ Fields ^
| Change | ``Change`` (a **[[#ChartDataChange]]** value) |
| Trade date | ``TradeDate``, ``TradeDateTicks`` |
| Market def. | ``MarketDefined``, ``MarketID``, ``Numerator``, ``Denominator``, ``PriceCode``, ``TickValue``, ``VPT``, ``MinCabPrice``, ``MinPriceIncrement``, ``PointValue`` |
| Last trade | ``LastTradePrice``, ``TradeVolume``, ``LastTTV``, ``LastTimeTicks``, ``AtBidOrOffer`` (**[[#BidOffer]]**), ``DueToSpread``, ``OrderVolumes`` |
| Bar | ``BarStartTime``, ``BarCloseTime``, ``BarOpenPrice``, ``BarHighPrice``, ``BarLowPrice``, ``BarClosePrice``, ``BarVolume``, ``BarBidVolume``, ``BarOfferVolume``, ``BarTrades``, ``BarTradesAtBid``, ``BarTradesAtOffer`` |
| TPO | ``TPOStartTime``, ``TPOBasePrice``, ``TPOPrice``, ``TPOVolume``, ``TPOVolumeAtBid``, ``TPOVolumeAtOffer``, ``TPOIsOpening``, ``TPOIsClosing`` |
| Quote | ``BidPrice``, ``BidRealVolume``, ``BidImpliedVolume``, ``OfferPrice``, ``OfferRealVolume``, ``OfferImpliedVolume`` |
| Session | ``Mode`` (**[[#MarketMode]]**), ``SettlementPrice``, ``SettlementHeldPrice``, ``ClearedVolume``, ``OpenInterest``, ``VWAP_Price`` |
| RFQ | ``RFQBuySell`` (**[[#BidOffer]]**), ``RFQVolume`` |
==== Enumerations ====
=== ChartDataChange ===
The ``state.Change`` discriminator after each ``read()``.
^ Value ^ Name ^ ^ Value ^ Name ^
| 0 | ``NONE`` | | 8 | ``TickChange`` |
| 1 | ``Trade`` | | 9 | ``RFQ`` |
| 2 | ``Quote`` | | 10 | ``HeldSettlement``|
| 3 | ``MarketMode`` | | 11 | ``ClearedVolume`` |
| 4 | ``Settlement`` | | 12 | ``OpenInterest`` |
| 5 | ``TradeBar`` | | 13 | ``VWAP`` |
| 6 | ``TradeDate`` | | 14 | ``MarketSwitch`` |
| 7 | ``TPO`` | | 15 | ``MarketDefinition`` |
=== MarketMode ===
Exchange session lifecycle state (the ``marketMode`` field in JSON, and ``state.Mode`` / ``onModeChange`` in binary).
^ Value ^ Name ^ ^ Value ^ Name ^
| 0 | ``Undefined`` | | 8 | ``Failed`` |
| 1 | ``PreOpen`` | | 9 | ``PreCross`` |
| 2 | ``Open`` | | 10 | ``Cross`` |
| 3 | ``RestrictedOpen`` | | 11 | ``Expired`` |
| 4 | ``PreClosed`` | | 12 | ``Rejected`` |
| 5 | ``Closed`` | | 13 | ``Unavailable`` |
| 6 | ``Suspended`` | | 14 | ``NoPermission`` |
| 7 | ``Halted`` | | 15 | ``TrialExpired`` |
=== BidOffer ===
Which side of the market a trade/RFQ executed against (mirrors the JSON ``aggressorSide``).
^ Value ^ Name ^
| 1 | ``Bid`` |
| 0 | ``Undefined`` |
| -1 | ``Offer`` |
==== Numeric correctness ====
* 64-bit ticks / 7-bit-long values use **BigInt** (JS) / native ``int`` (Python).
* 96-bit unscaled decimals use **decimal.js** at scale 18 with ``ROUND_HALF_EVEN`` (JS) / ``decimal.Decimal`` (Python), matching Java ``BigDecimal``.
* Field naming preserves Java/Python PascalCase on ``ChartDataState``, ``Bar``, and ``MarketDefinition`` for 1:1 parity across all three implementations.
===== Revision Notes / Changelog =====
This revision adds documentation for the binary transport and the reference decoders. Nothing in the original JSON documentation was removed or semantically altered.
^ Area ^ Change ^
| Accept headers (both endpoints) | Clarified that ``application/octet-stream`` / ``application/t4`` return the compact binary format and cross-linked to the new sections. |
| New section | **Binary Response Format (T4Bin / T4BinAggr)** — envelope/SOF extraction, length-prefixed record framing, 7-bit int/long and 96-bit decimal encodings, nullable price, and price/time (CST tick) conventions. |
| New section | Full **CTAG record-tag tables** for both the aggregated (T4BinAggr) and non-aggregated (T4Bin) dialects. |
| New section | **Decoder Libraries** — JavaScript (``@t4/chart-decoder``) and Python (``t4login``) usage, the aggregated handler interface, the non-aggregated state-cursor model, browser loader, the ``ChartDataState`` field reference, and the ``ChartDataChange`` / ``MarketMode`` / ``BidOffer`` enumerations. |
**Source of truth:** the tables above are generated from the decoder source in
``tools/JavaScript/t4-javascript-api/src`` (mirror under ``tools/JavaScript/JSDemo/decoder``) and
``tools/Python/t4-pythonConversion-api/src/t4login``. If the format version constants
(``CVAL_T4BIN_VERSION`` / ``CVAL_T4BINAGGR_VERSION``) change, regenerate the tag tables from
``ChartFormat`` / ``ChartFormatAggr``.