Differences
This shows you the differences between two versions of the page.
| playground:playground [2024/08/05 06:28] – created - external edit 127.0.0.1 | playground:playground [2026/06/15 17:19] (current) – juan | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ====== PlayGround ====== | ====== 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:// | ||
| + | |||
| + | 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/ | ||
| + | * A new top-level section **[[#Binary Response Format (T4Bin / T4BinAggr)]]** describing the on-the-wire envelope, framing, 7-bit/ | ||
| + | * A new top-level section **[[# | ||
| + | * Minor clarifications to the existing **Accept** header tables to cross-reference the binary sections. | ||
| + | |||
| + | See **[[# | ||
| + | </ | ||
| + | |||
| + | ===== 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 ==== | ||
| + | < | ||
| + | |||
| + | ==== Headers ==== | ||
| + | |||
| + | For proper access and response handling, the **GetBarChart** API requires certain HTTP headers to be set in the request. | ||
| + | |||
| + | ^ Header | ||
| + | | Authorization | ||
| + | | Accept | ||
| + | |||
| + | **Examples: | ||
| + | |||
| + | * To authorize the request, include the bearer token: | ||
| + | < | ||
| + | |||
| + | * To receive the response in a compact binary format, set the `Accept` header accordingly: | ||
| + | < | ||
| + | or | ||
| + | < | ||
| + | |||
| + | 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 **[[# | ||
| + | </ | ||
| + | |||
| + | ==== Parameters ==== | ||
| + | ^ Parameter | ||
| + | | **exchangeId** | ||
| + | | **contractId** | ||
| + | | **chartType** | ||
| + | | **barInterval** | ||
| + | | **barPeriod** | ||
| + | | **tradeDateStart** | ||
| + | | **tradeDateEnd** | ||
| + | | marketID | ||
| + | | continuationType | Method of continuation for the chart. Only **Volume** is currently supported. | ||
| + | | resetInterval | ||
| + | | contractMonths | ||
| + | | rolloverThreshold| Rollover threshold (not applicable when **ContinuationType.Volume** is used). | ||
| + | | forwardMonths | ||
| + | |||
| + | ==== 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 | ||
| + | | tradeDate | ||
| + | | time | Time when the bar data starts. | ||
| + | | closeTime | ||
| + | | marketID | ||
| + | | openPrice | ||
| + | | highPrice | ||
| + | | lowPrice | ||
| + | | closePrice | ||
| + | | volume | ||
| + | | volumeAtBid | ||
| + | | volumeAtOffer | ||
| + | | trades | ||
| + | | tradesAtBid | ||
| + | | tradesAtOffer | ||
| + | |||
| + | === MarketDefinitions === | ||
| + | ^ Element | ||
| + | | marketID | ||
| + | | minPriceIncrement | Minimum increment of the market' | ||
| + | | priceCode | ||
| + | | tickValue | ||
| + | | vpt | Additional market-specific information (variable). | ||
| + | |||
| + | === ModeChanges === | ||
| + | ^ Element | ||
| + | | marketID | ||
| + | | tradeDate | ||
| + | | time | Time when the mode change occurred. | ||
| + | | marketMode | ||
| + | |||
| + | === OpenInterests === | ||
| + | ^ Element | ||
| + | | marketID | ||
| + | | tradeDate | ||
| + | | time | Time of the recorded open interest. | ||
| + | | openInterest | ||
| + | |||
| + | === Settlements === | ||
| + | ^ Element | ||
| + | | marketID | ||
| + | | tradeDate | ||
| + | | time | Time when the settlement information was recorded. | ||
| + | | settlementPrice | ||
| + | | isHeld | ||
| + | |||
| + | ==== Example JSON Response ==== | ||
| + | |||
| + | < | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ], | ||
| + | " | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ], | ||
| + | " | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | // ... additional mode changes ... | ||
| + | ], | ||
| + | " | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | // ... additional open interests ... | ||
| + | ], | ||
| + | " | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | // ... 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 ==== | ||
| + | < | ||
| + | |||
| + | ==== Headers ==== | ||
| + | ^ Header | ||
| + | | Authorization | Bearer < | ||
| + | | Accept | ||
| + | |||
| + | ==== Parameters ==== | ||
| + | ^ Parameter | ||
| + | | exchangeId | ||
| + | | contractId | ||
| + | | marketID | ||
| + | | tradeDateStart | ||
| + | | tradeDateEnd | ||
| + | | 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 **[[# | ||
| + | </ | ||
| + | |||
| + | === Response === | ||
| + | ^ Element | ||
| + | | exchangeID | ||
| + | | contractID | ||
| + | | marketID | ||
| + | | requestStatusMessage| Any status messages or errors related to the request. | ||
| + | | tradeDateStart | ||
| + | | tradeDateEnd | ||
| + | | trades | ||
| + | | marketDefinitions | ||
| + | | modeChanges | ||
| + | | openInterests | ||
| + | | settlements | ||
| + | | vwaPs | An array detailing volume-weighted average prices (VWAP). | ||
| + | |||
| + | === Trades === | ||
| + | |||
| + | ^ Element | ||
| + | | marketID | ||
| + | | tradeDate | ||
| + | | time | The specific time when the trade occurred. | ||
| + | | tradePrice | ||
| + | | aggressorSide | ||
| + | |||
| + | === VWAP(s) === | ||
| + | |||
| + | ^ Element | ||
| + | | marketID | ||
| + | | tradeDate | ||
| + | | time | The specific time when the VWAP is calculated. | ||
| + | | vwapPrice | ||
| + | |||
| + | ==== Example JSON Response ==== | ||
| + | |||
| + | < | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | ... | ||
| + | ], | ||
| + | " | ||
| + | " | ||
| + | ... | ||
| + | ], | ||
| + | " | ||
| + | ... | ||
| + | ], | ||
| + | " | ||
| + | ... | ||
| + | ], | ||
| + | " | ||
| + | ... | ||
| + | ] | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | 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/ | ||
| + | |||
| + | Two closely-related dialects exist: | ||
| + | |||
| + | ^ Stream | ||
| + | | **T4BinAggr** | ``/ | ||
| + | | **T4Bin** | ||
| + | |||
| + | < | ||
| + | You do **not** need to implement the byte-level format yourself — reference decoders are provided for JavaScript and Python (see **[[# | ||
| + | </ | ||
| + | |||
| + | ==== 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 | ||
| + | | **T4BinAggr** | ``05 01 01 00 00 00`` | length=5, tag=``CTAG_SOF`` (1), version=1 (little-endian int32) | ||
| + | | **T4Bin** | ||
| + | |||
| + | 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**: | ||
| + | * **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/ | ||
| + | |||
| + | ==== Value encodings ==== | ||
| + | |||
| + | === 7-bit variable-length integers === | ||
| + | |||
| + | Integers are stored little-endian, | ||
| + | |||
| + | ^ Type ^ Positive encoding ^ Negative encoding | ||
| + | | Signed 32-bit int | 1–5 bytes | always 5 bytes (sign-extended) | ||
| + | | Signed 64-bit long | 1–9 bytes | always 10 bytes (sign-extended) | ||
| + | |||
| + | 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/ | ||
| + | * 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' | ||
| + | |||
| + | ==== 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' | ||
| + | * **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 " | ||
| + | |||
| + | ==== Aggregated tags (T4BinAggr) ==== | ||
| + | |||
| + | Record tags emitted on ``/ | ||
| + | |||
| + | ^ Tag value ^ Constant | ||
| + | | 1 | ``CTAG_SOF`` | ||
| + | | 2 | ``CTAG_MARKET_DEFINITION`` | ||
| + | | 3 | ``CTAG_MARKET_SWITCH`` | ||
| + | | 4 | ``CTAG_TRADEDATE_SWITCH`` | ||
| + | | 10 | ``CTAG_BAR_DELTA`` | ||
| + | | 11 | ``CTAG_BAR`` | ||
| + | | 20 | ``CTAG_MARKET_MODE`` | ||
| + | | 21 | ``CTAG_OPEN_INTEREST`` | ||
| + | | 22 | ``CTAG_SETTLEMENT_PRICE`` | ||
| + | |||
| + | Each decoded ``Bar`` exposes the same fields as the JSON //Bars// array (``TradeDate``, | ||
| + | |||
| + | ==== Non-aggregated tags (T4Bin) ==== | ||
| + | |||
| + | Record tags emitted on ``/ | ||
| + | |||
| + | === Framing / market === | ||
| + | ^ Tag ^ Constant | ||
| + | | 1 | ``CTAG_SOF`` | ||
| + | | 2 | ``CTAG_MARKET_DEFINITION`` | Market parameters for price conversion. | ||
| + | | 7 | ``CTAG_CONSOLIDATED`` | ||
| + | | 8 | ``CTAG_MARKET_SWITCH`` | ||
| + | | 9 | ``CTAG_MARKET_KEY`` | ||
| + | |||
| + | === Trades / ticks === | ||
| + | ^ Tag ^ Constant | ||
| + | | 11 | ``CTAG_TICKDATAPOINT_7BIT`` | ||
| + | | 12 | ``CTAG_TICKDATAPOINT_NEG_7BIT`` | ||
| + | | 17 | ``CTAG_TICKDATAPOINT_ALT_7BIT`` | ||
| + | | 18 | ``CTAG_TICKDATAPOINT_ALT_NEG_7BIT`` | Trade (-tick) with per-order volume list. | | ||
| + | | 60 | ``CTAG_TRADE_PRICE`` | ||
| + | | 61 | ``CTAG_TRADE_PRICE_DEC`` | ||
| + | | 62 | ``CTAG_TRADE_PRICE_ALT`` | ||
| + | | 63 | ``CTAG_TRADE_PRICE_DEC_ALT`` | ||
| + | |||
| + | === Tick-change (TickChange aggregation) === | ||
| + | ^ Tag ^ Constant | ||
| + | | 14 | ``CTAG_TICKCHANGEDATAPOINT_7BIT`` | ||
| + | | 15 | ``CTAG_TICKCHANGEDATAPOINT_NEG_7BIT`` | Bar close-price moves -tick. | ||
| + | | 140 | ``CTAG_PRICE_CHANGE`` | ||
| + | | 141 | ``CTAG_PRICE_CHANGE_DEC`` | ||
| + | |||
| + | === Bars === | ||
| + | ^ Tag ^ Constant | ||
| + | | 21 | ``CTAG_BARDATAPOINT_7BIT_DELTA_LOW`` | ||
| + | | 22 | ``CTAG_BARDATAPOINT_NEG_7BIT_DELTA_LOW`` | OHLCV bar; prices as -tick offsets from bar low. | | ||
| + | | 65 | ``CTAG_BAR_PRICE`` | ||
| + | | 66 | ``CTAG_BAR_PRICE_DEC`` | ||
| + | |||
| + | === Quotes (BBO) === | ||
| + | ^ Tag ^ Constant | ||
| + | | 50 | ``CTAG_QUOTE_7BIT`` | ||
| + | | 51 | ``CTAG_QUOTE_NEG_7BIT`` | ||
| + | | 52 | ``CTAG_QUOTE_VOLUME_DELTA`` | Quote volume-only change. | ||
| + | | 53 | ``CTAG_QUOTE_PRICE`` | ||
| + | | 54 | ``CTAG_QUOTE_PRICE_DEC`` | ||
| + | |||
| + | === TPO (Time Price Opportunity / Market Profile) === | ||
| + | ^ Tag ^ Constant | ||
| + | | 30 | ``CTAG_TPO_START`` | ||
| + | | 31 | ``CTAG_TPO_START_NEGBASE`` | ||
| + | | 32 | ``CTAG_TPO_DATAPOINT`` | ||
| + | | 33 | ``CTAG_TPO_DATAPOINT_OPEN`` | ||
| + | | 34 | ``CTAG_TPO_DATAPOINT_CLOSE`` | ||
| + | | 35 | ``CTAG_TPO_DATAPOINT_OPENCLOSE`` | TPO cell (opening & closing). | ||
| + | | 190 | ``CTAG_TPO_START_PRICE`` | ||
| + | | 191 | ``CTAG_TPO_START_PRICE_DEC`` | ||
| + | | 192 | ``CTAG_TPO_PRICE`` | ||
| + | | 193 | ``CTAG_TPO_OPEN_PRICE`` | ||
| + | | 194 | ``CTAG_TPO_CLOSE_PRICE`` | ||
| + | | 195 | ``CTAG_TPO_OPENCLOSE_PRICE`` | ||
| + | |||
| + | === Market state / session events === | ||
| + | ^ Tag ^ Constant | ||
| + | | 100 | ``CTAG_MARKET_MODE`` | ||
| + | | 101 | ``CTAG_MARKET_SETTLEMENT`` | ||
| + | | 102 | ``CTAG_MARKET_HELD_SETTLEMENT`` | Held settlement price (tick). | ||
| + | | 103 | ``CTAG_MARKET_CLEARED_VOLUME`` | ||
| + | | 104 | ``CTAG_MARKET_OPEN_INTEREST`` | ||
| + | | 105 | ``CTAG_MARKET_VWAP`` | ||
| + | | 106 | ``CTAG_MARKET_RFQ`` | ||
| + | | 107 | ``CTAG_SETTLEMENT_PRICE`` | ||
| + | | 108 | ``CTAG_HELD_SETTLEMENT_PRICE`` | ||
| + | | 109 | ``CTAG_VWAP_PRICE`` | ||
| + | |||
| + | ===== 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/ | ||
| + | |||
| + | [[https:// | ||
| + | |||
| + | ^ Language | ||
| + | | JavaScript | ||
| + | | Python | ||
| + | |||
| + | ==== JavaScript: @t4/ | ||
| + | |||
| + | Requires **Node 18+** (uses global ``fetch``) or any modern browser. The only runtime dependency is **decimal.js**. | ||
| + | |||
| + | === Install === | ||
| + | Clone the [[https:// | ||
| + | |||
| + | <code powershell> | ||
| + | git clone https:// | ||
| + | cd t4-api-tools/ | ||
| + | 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. | ||
| + | |||
| + | <code javascript> | ||
| + | import { ChartClient } from ' | ||
| + | |||
| + | const client = new ChartClient({ token: ' | ||
| + | |||
| + | await client.getBarchartBinary({ | ||
| + | exchangeId: ' | ||
| + | contractId: ' | ||
| + | barInterval: | ||
| + | barPeriod: | ||
| + | tradeDateStart: | ||
| + | tradeDateEnd: | ||
| + | handler: { | ||
| + | onMarketDefinition(def) { /* def.MarketID, | ||
| + | onBar(bar) | ||
| + | onModeChange(marketId, | ||
| + | onSettlement(marketId, | ||
| + | onOpenInterest(marketId, | ||
| + | }, | ||
| + | }); | ||
| + | </ | ||
| + | |||
| + | The handler interface: | ||
| + | |||
| + | ^ Callback | ||
| + | | ``onMarketDefinition(marketDefinition)`` | ||
| + | | ``onBar(bar)`` | ||
| + | | ``onModeChange(marketId, | ||
| + | | ``onSettlement(marketId, | ||
| + | | ``onOpenInterest(marketId, | ||
| + | |||
| + | === 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, | ||
| + | |||
| + | const reader = await client.getTradehistoryBinary({ | ||
| + | exchangeId: ' | ||
| + | contractId: ' | ||
| + | tradeDateStart: | ||
| + | tradeDateEnd: | ||
| + | }); | ||
| + | |||
| + | while (reader.read()) { | ||
| + | const s = reader.state; | ||
| + | switch (s.Change) { | ||
| + | case ChartDataChange.Trade: | ||
| + | console.log(s.LastTimeTicks, | ||
| + | break; | ||
| + | case ChartDataChange.Quote: | ||
| + | console.log(' | ||
| + | break; | ||
| + | case ChartDataChange.Settlement: | ||
| + | console.log(' | ||
| + | break; | ||
| + | // ... MarketMode, OpenInterest, | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | === 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, | ||
| + | extractT4BinPayload, | ||
| + | } from ' | ||
| + | |||
| + | // Aggregated: | ||
| + | ChartDataStreamReaderAggr.read(extractT4BinPayload(bytes), | ||
| + | |||
| + | // Non-aggregated: | ||
| + | const reader = new ChartDataStreamReader({ | ||
| + | data: new ByteReader(extractT4BinPayload(bytes)), | ||
| + | tradeDate: new NDateTime(0n), | ||
| + | marketId: ' | ||
| + | dataType: ChartDataType.get(0), | ||
| + | }); | ||
| + | </ | ||
| + | |||
| + | === Browser (no bundler) === | ||
| + | |||
| + | The JSDemo copy ships a ``decoder/ | ||
| + | |||
| + | <code html> | ||
| + | <script type=" | ||
| + | < | ||
| + | window.addEventListener(' | ||
| + | const { ChartDataStreamReaderAggr, | ||
| + | // ... | ||
| + | }); | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | ==== 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:// | ||
| + | |||
| + | <code powershell> | ||
| + | git clone https:// | ||
| + | cd t4-api-tools/ | ||
| + | pip install -e . # installs from pyproject.toml | ||
| + | </ | ||
| + | |||
| + | === Usage === | ||
| + | |||
| + | <code python> | ||
| + | from t4login.client.chart_client import ChartClient | ||
| + | from t4login.definitions.chartdata.chart_data_change import ChartDataChange | ||
| + | |||
| + | client = ChartClient(token=" | ||
| + | |||
| + | # Aggregated (handler model) | ||
| + | client.get_barchart_binary( | ||
| + | exchange_id=" | ||
| + | trade_date_start=" | ||
| + | handler=my_handler, | ||
| + | ) | ||
| + | |||
| + | # Non-aggregated (state model) | ||
| + | reader = client.get_tradehistory_binary( | ||
| + | exchange_id=" | ||
| + | trade_date_start=" | ||
| + | ) | ||
| + | while reader.read(): | ||
| + | s = reader.state | ||
| + | if s.Change == ChartDataChange.Trade: | ||
| + | print(s.LastTradePrice, | ||
| + | </ | ||
| + | |||
| + | ==== ChartDataState field reference (T4Bin) ==== | ||
| + | |||
| + | Populated by ``ChartDataStreamReader``. Field names are PascalCase for parity across Java/ | ||
| + | |||
| + | ^ Group ^ Fields | ||
| + | | Change | ||
| + | | Trade date | ``TradeDate``, | ||
| + | | Market def. | ``MarketDefined``, | ||
| + | | Last trade | ``LastTradePrice``, | ||
| + | | Bar | ``BarStartTime``, | ||
| + | | TPO | ``TPOStartTime``, | ||
| + | | Quote | ``BidPrice``, | ||
| + | | Session | ||
| + | | RFQ | ``RFQBuySell`` (**[[# | ||
| + | |||
| + | ==== Enumerations ==== | ||
| + | |||
| + | === ChartDataChange === | ||
| + | The ``state.Change`` discriminator after each ``read()``. | ||
| + | |||
| + | ^ Value ^ Name | ||
| + | | 0 | ``NONE`` | ||
| + | | 1 | ``Trade`` | ||
| + | | 2 | ``Quote`` | ||
| + | | 3 | ``MarketMode`` | ||
| + | | 4 | ``Settlement`` | ||
| + | | 5 | ``TradeBar`` | ||
| + | | 6 | ``TradeDate`` | ||
| + | | 7 | ``TPO`` | ||
| + | |||
| + | === MarketMode === | ||
| + | Exchange session lifecycle state (the ``marketMode`` field in JSON, and ``state.Mode`` / ``onModeChange`` in binary). | ||
| + | |||
| + | ^ Value ^ Name | ||
| + | | 0 | ``Undefined`` | ||
| + | | 1 | ``PreOpen`` | ||
| + | | 2 | ``Open`` | ||
| + | | 3 | ``RestrictedOpen`` | | 11 | ``Expired`` | ||
| + | | 4 | ``PreClosed`` | ||
| + | | 5 | ``Closed`` | ||
| + | | 6 | ``Suspended`` | ||
| + | | 7 | ``Halted`` | ||
| + | |||
| + | === 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``, | ||
| + | |||
| + | ===== 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/ | ||
| + | | New section | **Binary Response Format (T4Bin / T4BinAggr)** — envelope/ | ||
| + | | New section | Full **CTAG record-tag tables** for both the aggregated (T4BinAggr) and non-aggregated (T4Bin) dialects. | | ||
| + | | New section | **Decoder Libraries** — JavaScript (``@t4/ | ||
| + | |||
| + | **Source of truth:** the tables above are generated from the decoder source in | ||
| + | ``tools/ | ||
| + | ``tools/ | ||
| + | (``CVAL_T4BIN_VERSION`` / ``CVAL_T4BINAGGR_VERSION``) change, regenerate the tag tables from | ||
| + | ``ChartFormat`` / ``ChartFormatAggr``. | ||
| + | </ | ||
| + | </ | ||