WebSocket

Sub/Unsub Market Data

Subscribe and unsubscribe to market data via FastConnect WebSocket.

Overview

The DATA channel returns 8 groups of market information:

TopicDescription
tradeMatched trade information
trade.indexRealtime index value
indexsummaryIndex summary information
quoteBid/ask information
roomForeign room information
putPut-through (negotiated) trades
oddlotOdd-lot trades
marketStart-of-day and session-flag information

Topic pattern

trade.[index/exchange/symbol-symbol/*]@[tick/1m/5m]
trade.index.[index_code]@[tick/1m/5m]
indexsummary.[index_code/*]
quote.[index/exchange/symbol-symbol/*]@[tick/1m/5m]
room.[index/exchange/symbol-symbol/*]@[tick/1m/5m]
put.[index/exchange/symbol-symbol/*]@[tick/1m/5m]
oddlot.[index/exchange/symbol-symbol/*]@[tick/1m/5m]
market.[index/exchange/symbol-symbol/*]
  • Multiple symbols are joined with - (e.g. ACB-SSI-GVR-KDH); * covers all symbols within scope.
  • Omitting @interval defaults to tick. The market and indexsummary topics have no interval.
  • trade.index and indexsummary only accept an index code (e.g. VN30, VNINDEX, HNXINDEX, UPCOMINDEX).

Note: valid intervals are currently tick, 1m, 5m (there is no 3m).

Subscribe market data

{
  "method": "SUBSCRIBE",
  "channel": "DATA",
  "topics": [
    "trade.SSI",
    "trade.ACB-SSI-GVR-KDH",
    "trade.vn30",
    "trade.hose"
  ]
}
  • trade.SSI — subscribe to matched-trade messages for symbol SSI
  • trade.ACB-SSI-GVR-KDH — subscribe to matched-trade messages for symbols ACB, SSI, GVR, KDH
  • trade.vn30 — subscribe to matched-trade messages for all symbols in the VN30 basket
  • trade.hose — subscribe to matched-trade messages for all symbols on the HOSE exchange

The same syntax applies to quote, room, put, oddlot, market — just change the topic prefix (e.g. quote.SSI, room.vn30, market.hose).

Unsubscribe market data

{
  "method": "UNSUBSCRIBE",
  "channel": "DATA",
  "topics": ["trade.SSI", "quote.SSI"]
}

I. Trade — matched trade information

FieldNameTypeDescription
ssymbolStringSecurities symbol
ttradingTimeStringYYYY/MM/DD HH:mi:ss
ppriceStringMatched price (unit: VND)
qquantityStringMatched quantity
aavgPriceStringAverage matched price for the day (unit: VND) = total matched value / total matched volume. "0" when there are no matches yet
sisideStringB: Buy Up / S: Sell Down
oopenPriceStringOpening price (unit: VND)
hhighPriceStringHighest price (unit: VND)
llowPriceStringLowest price (unit: VND)
vtotalVolStringTotal matched volume for the day

Sample output:

{
  "s": "SSI",
  "t": "2026/07/29 09:15:32",
  "p": "45500",
  "q": "1000",
  "a": "45350",
  "si": "B",
  "o": "45000",
  "h": "45800",
  "l": "44900",
  "v": "1250000"
}

I.1. Trade.index — realtime index value

Some symbols on the trade topic (e.g. s: "VN30") are not stocks but the realtime value of the index itself. Subscribing to trade.vn30 as above only returns the stocks belonging to the VN30 basket, not the index's own value. To receive the index's own realtime tick, use the dedicated trade.index topic.

Subscribe syntax: trade.index.[index_code]@[tick/1m/5m]

{
  "method": "SUBSCRIBE",
  "channel": "DATA",
  "topics": [
    "trade.index.VN30",
    "trade.index.VNINDEX",
    "trade.index.HNXINDEX",
    "trade.index.UPCOMINDEX"
  ]
}
  • trade.index.VN30 — subscribe to the realtime VN30 index value
  • trade.index.UPCOMINDEX — subscribe to the realtime UPCOM index value. The HNX source publishes the raw message as s: "HNXUPCOMINDEX"; the server renames it to UPCOMINDEX before forwarding to clients, so subscribe using this new name.
  • trade.index.VN30@1m, trade.index.VN30@5m — subscribe to the 1-minute/5-minute candles of the index. A candle message's data contains s (index code), st (candle start time), t (last tick time), o, h, l, c (open/high/low/close) and v (volume).

The tick data structure (no interval) is the same as the trade topic above (s, t, p, q, v, ...), where p is the index's current point value.

Sample output:

{
  "s": "VN30",
  "t": "2026/09/14 13:39:10",
  "p": "1928.81",
  "q": "75412",
  "a": "0",
  "si": "",
  "o": "0",
  "h": "0",
  "l": "0",
  "v": "129161843"
}

I.2. Indexsummary — index summary information

Returns realtime summary information of an index: index value and change, number of advancing/declining/unchanged/ceiling/floor stocks, and total matched and put-through volume and value. Unlike trade.index (which only carries the index value tick), indexsummary also carries market breadth and liquidity information for the index.

Subscribe syntax: indexsummary.[index_code/*]

This topic requires the stream:DATA:indexsummary scope.

{
  "method": "SUBSCRIBE",
  "channel": "DATA",
  "topics": [
    "indexsummary.VN30",
    "indexsummary.VNINDEX",
    "indexsummary.HNXINDEX",
    "indexsummary.UPCOMINDEX"
  ]
}
  • indexsummary.VN30 — subscribe to the VN30 index summary
  • indexsummary.UPCOMINDEX — subscribe to the UPCOM index summary. The HNX source publishes the raw message as s: "HNXUPCOMINDEX"; clients subscribe using UPCOMINDEX and the server maps it to the source code automatically.
  • indexsummary.* — subscribe to the summary of all indices

Note: indexsummary only accepts an index code. Do not subscribe by exchange code (hose, hnx, upcom) or by stock symbol as with the trade topic.

FieldNameTypeDescription
sindexNameStringIndex code
bexchangeStringExchange the index belongs to
sstradingSessionStringCurrent trading session (e.g. ATC)
ttradingTimeStringTrading time of the message, format YYYY/MM/DD HH:mi:ss
vindexValueStringCurrent index value (points)
cindexChangeStringIndex change versus the previous session (points). Negative: down, positive: up
crindexRatioChangeStringIndex change percentage versus the previous session (%). Negative: down, positive: up
advadvancesStringTotal number of advancing stocks
decdeclinesStringTotal number of declining stocks
ncnoChangeStringTotal number of unchanged stocks
ceceilingsStringTotal number of stocks at ceiling price
flfloorsStringTotal number of stocks at floor price
tmvtotalMatchedValueStringTotal matched trading value (unit: VND)
tmqtotalMatchedQtyStringTotal matched trading quantity (unit: shares)
tvptotalValuePtStringTotal put-through trading value (unit: VND)
tqptotalQtyPtStringTotal put-through trading quantity (unit: shares)
tqtotalQtyStringTotal matched and put-through trading quantity (unit: shares) = tmq + tqp
tvtotalValueStringTotal matched and put-through trading value (unit: VND) = tmv + tvp

Sample output:

{
  "s": "VNIND",
  "b": "HOSE",
  "ss": "ATC",
  "t": "2026/10/13 14:30:55",
  "v": "793.02",
  "c": "-20.44",
  "cr": "-2.51",
  "adv": "15",
  "dec": "47",
  "nc": "11",
  "ce": "1",
  "fl": "0",
  "tmv": "792414028510",
  "tmq": "37448788",
  "tvp": "22700831600",
  "tqp": "1344858",
  "tq": "38793646",
  "tv": "815114860110"
}

II. Room — foreign room information

FieldNameTypeDescription
ssymbolStringSecurities symbol
ttradingtimeStringYYYY/MM/DD HH:mi:ss
trtotalRoomStringTotal foreign room
crcurrentRoomStringRemaining foreign room
bqbuyQuantityStringForeign buy quantity
bvbuyValueStringForeign buy value
sqsellQuantityStringForeign sell quantity
svsellValueStringForeign sell value

Sample output:

{
  "s": "SSI",
  "t": "2026/07/29 09:15:32",
  "tr": "1500000",
  "cr": "980000",
  "bq": "5000",
  "bv": "227500000",
  "sq": "3000",
  "sv": "136500000"
}

III. Quote — bid/ask information

FieldTypeDescription
sStringSecurities symbol
tStringtradingtime, YYYY/MM/DD HH:mi:ss
bidsList<String[2]>List of bid levels [price, quantity]. A future upgrade will only return changed values.
asksList<String[2]>List of ask levels [price, quantity]. A future upgrade will only return changed values.

Sample output:

{
  "s": "SSI",
  "t": "2026/07/29 09:15:32",
  "bids": [
    ["45.45", "3200"],
    ["45.40", "1500"],
    ["45.35", "4200"],
    ["45.30", "2100"],
    ["45.25", "3300"]
  ],
  "asks": [
    ["45.50", "2800"],
    ["45.55", "1900"],
    ["45.60", "3600"],
    ["45.65", "2200"],
    ["45.70", "4100"]
  ]
}

IV. Put — put-through (negotiated) trades

FieldNameTypeDescription
ssymbolStringSecurities symbol
ttradingtimeStringYYYY/MM/DD HH:mi:ss
ppriceStringPut-through matched price
qquantityStringPut-through matched quantity
tqTotalQuantityStringTotal put-through quantity for the day
tvTotalValueStringTotal put-through value for the day

Sample output:

{
  "s": "SSI",
  "t": "2026/07/29 10:05:12",
  "p": "45.00",
  "q": "50000",
  "tq": "350000",
  "tv": "15750000000"
}

V. Oddlot — odd-lot trades

FieldNameTypeDescription
ssymbolStringSecurities symbol
ttradingtimeStringYYYY/MM/DD HH:mi:ss
ppriceStringOdd-lot matched price
qquantityStringOdd-lot matched quantity
bidsList<String[2]>List of odd-lot bid levels [price, quantity]
asksList<String[2]>List of odd-lot ask levels [price, quantity]

Sample output:

{
  "s": "SSI",
  "t": "2026/07/29 09:16:05",
  "p": "45.50",
  "q": "80",
  "bids": [
    ["45.45", "50"],
    ["45.40", "30"]
  ],
  "asks": [
    ["45.55", "40"],
    ["45.60", "20"]
  ]
}

VI. Market — start-of-day and session information

Subscribe syntax has no interval: market.[index/exchange/symbol-symbol/*].

Market streaming data:

FieldNameTypeDescription
ssymbolStringSecurities symbol
bboardStringHOSE, HNX, UPCOM
ttradingDateStringYYYY/MM/DD
ceceilingPriceStringCeiling price
flfloorPriceStringFloor price
refrefPriceStringReference price

Sample output:

{
  "s": "SSI",
  "b": "HOSE",
  "t": "2026/07/29",
  "ce": "48.50",
  "fl": "42.10",
  "ref": "45.30"
}

Market flag (session-flag message):

FieldNameTypeDescription
bboardStringHOSE, HNX, UPCOM, DERIVATIVES
ttradingTimeStringYYYY/MM/DD HH:mm:ss
fflagStringSession flag: ATO, LO, ATC, etc.

Sample output:

{
  "b": "HOSE",
  "t": "2026/07/29 09:00:00",
  "f": "ATO"
}

See also

Sub/Unsub Trading DataWS

Subscribe and unsubscribe to trading data via FastConnect WebSocket — including regular orders, order matches, portfolio updates, and conditional orders (FCO).

Connect WebSocket APIWS

Establish a WebSocket connection via an HTTP Upgrade request to `/ws/v3/trading`. The server returns `HTTP 101 Switching Protocols` when the connection succeeds. **Authentication:** pass the JWT access token one of two ways (checked in this order): - Query string: `wss://.../ws/v3/trading?token=<jwt>` - Header: `Authorization: Bearer <jwt>` The token must be valid (not expired, not revoked) and the API Key must be granted the `tradingws:*:*` scope — the `trading:*:*` scope used by the REST Trading API **does not work** for this WS connection; it must be granted separately. **Connection limits:** at most 10 concurrent connections per API Key; exceeding the limit is rejected with reason `Connection limit exceeded`. **⚠️ Client implementation note:** except when the request is not a valid WebSocket upgrade (a real HTTP `400` returned before connecting), every other rejection reason (401/403/429) happens AFTER the connection has already succeeded (HTTP 101) — the server accepts the connection first, sends a message describing the reason, then closes it. Reason: most WebSocket client libraries cannot reliably surface the HTTP status code of the connection step. Clients **should read the first message** after connecting to know whether the connection is actually ready to send commands. **Sample rejection message:** ```json { "code": 401, "msg": "Invalid or expired token" } ``` Possible rejection reasons: `401` missing/invalid/expired/revoked token, `403` missing `tradingws:*:*` scope, `429` concurrent-connection limit exceeded, `500` system error.

On this page