Show pageOld revisionsBacklinksBack to top This page is read only. You can view the source, but not change it. Ask your administrator if you think this is wrong. ====== PlayGround ====== ====== T4 Chart API ====== Our chart API provides data in aggregated or non-aggregated (raw trade) formats. <bootnote> All times are in CST. </bootnote> 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 <bootnote info> **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. </bootnote> ===== 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 ==== <code>GET https://api-sim.t4login.com/chart/barchart</code> ==== 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 <token> | **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: <code>Authorization: Bearer YOUR_ACCESS_TOKEN</code> * To receive the response in a compact binary format, set the `Accept` header accordingly: <code>Accept: application/octet-stream</code> or <code>Accept: application/t4</code> Setting the `Accept` header is optional, and if it is not included, the API will return the response in a JSON format. <bootnote> 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]]**. </bootnote> ==== 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 ==== <code> { "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 ... ] } </code> ===== 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 ==== <code>GET https://api-sim.t4login.com/chart/tradehistory</code> ==== Headers ==== ^ Header ^ Value ^ Description ^ | Authorization | Bearer <token> | **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. <bootnote> 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]]**. </bootnote> === 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 ==== <code> { "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": [ ... ] } </code> 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`` | <bootnote tip> 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. </bootnote> ==== 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**: <code> [ length : 7-bit int ] [ tag : 7-bit int ] [ tag-specific payload ... ] </code> * **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: <code powershell> git clone https://github.com/CTS-Futures/t4-api-tools.git cd t4-api-tools/tools/JavaScript/t4-javascript-api npm install </code> === 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. <code javascript> 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) { /* ... */ }, }, }); </code> 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``: <code javascript> 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 ... } } </code> === Lower-level / advanced usage === You can also decode bytes you already have (e.g. from a saved file) without the HTTP client: <code javascript> 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 }); </code> === 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 ``<script>`` code can use it without an ``import`` statement: <code html> <script type="module" src="decoder/loader.js"></script> <script> window.addEventListener('t4-decoder-ready', (e) => { const { ChartDataStreamReaderAggr, extractT4BinPayload } = e.detail; // ... }); </script> </code> ==== 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: <code powershell> 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 </code> === Usage === <code python> 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) </code> ==== 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``. </content> </invoke> playground/playground.txt Last modified: 2026/06/15 17:19by juan