Market Data WebSocket¶
Stream real-time market data ticks as binary Protocol Buffers, automatically decoded by the SDK.
from blitzsdk.marketdata import MarketDataWebSocketClient
def on_message(decoded):
# decoded is a protobuf MarketDataMessageBase object
# Use decoded.WhichOneof("subtype") to check which field is set
print(decoded)
client = MarketDataWebSocketClient(app_key="YOUR_KEY", user_id="YOUR_USER")
client.set_on_message(on_message)
client.set_on_connect(lambda: print("Connected"))
client.set_on_close(lambda code, reason: print("Disconnected:", code))
client.set_on_error(lambda e: print("Error:", e))
client.start()
client.subscribe([110010002000001, 110010000002885])
# To unsubscribe:
# client.unsubscribe([110010000002885])
using BlitzConnect.MarketData;
var mdWs = new MarketDataWebSocket("wss://{baseurl}/md-streaming/ws?key=YOUR_TOKEN");
mdWs.OnMessage += (msg) => Console.WriteLine(msg);
mdWs.OnMarketDepth += (d) => Console.WriteLine($"Depth: {d.InstrumentName} LTP={d.LTP}");
mdWs.OnTick += (t) => Console.WriteLine($"Tick: {t.InstrumentName} LTP={t.LTP}");
mdWs.OnConnected += () => Console.WriteLine("Connected");
mdWs.OnDisconnected += (code, reason) => Console.WriteLine($"Disconnected: {code}");
await mdWs.ConnectAsync();
await mdWs.SubscribeAsync(new List<long> { 110010002000001, 110010000002885 });
// To unsubscribe:
// await mdWs.UnsubscribeAsync(new List<long> { 110010000002885 });
Typed callbacks¶
Besides the generic on_message, the SDKs dispatch each decoded frame to a per-message-type callback:
def on_tick(t):
print("TICK", t.InstrumentName, t.LTP)
def on_depth(d):
print("DEPTH", d.InstrumentName, len(d.BestBidLevel), "bid levels")
def on_touchline(t):
print("TOUCHLINE", t.InstrumentName, t.LTP)
def on_index(i):
print("INDEX", i.InstrumentName, i.LTP)
def on_incremental(inc):
print("INCREMENTAL", inc)
client.set_on_tick(on_tick)
client.set_on_depth(on_depth)
client.set_on_touchline(on_touchline)
client.set_on_index(on_index) # receives both IndexDataMessage and IndexDataListMessage
client.set_on_incremental(on_incremental)
mdWs.OnMarketDepth += (d) => ...; // MarketDepthMessage
mdWs.OnTick += (t) => ...; // TickDataMessage
mdWs.OnTouchline += (t) => ...; // TouchLineDataMessage
mdWs.OnIndex += (i) => ...; // IndexDataMessage
mdWs.OnIndexList += (il) => ...; // IndexDataListMessage
mdWs.OnIncremental += (inc) => ...; // IncrementalUpdateMessage
// Convenience event: fires for any frame carrying an LTP > 0
// (TickDataMessage, TickData, TouchLineDataMessage, MarketDepthMessage)
mdWs.OnLtp += (instrumentId, ltp) => ...;
mdWs.OnError += (err) => ...; // string error (parse failures etc.)
Python notes: the raw decoded protobuf envelope of the last received frame is always available as
ws.last_envelope;TickData(1506) frames are folded intoset_on_tickalongsideTickDataMessage. The C# client exposes the genericOnMessageevent for every decoded envelope plus the typed events above.
Connection URL¶
wss://{baseurl}/md-streaming/ws?key=YOUR_TOKEN
Subscribe / unsubscribe¶
After connecting, send a JSON subscribe message:
{
"action": "subscribe",
"instrumentIds": [110010002000001, 110010000002885]
}
To unsubscribe:
{
"action": "unsubscribe",
"instrumentIds": [110010000002885]
}
instrumentIdsmust be numeric instrument IDs (not symbol strings).
Heartbeat¶
The server sends "ping" as a text message periodically. Both SDKs filter ping messages out automatically, so callbacks never see them. (The Python interactive WebSocket client additionally sends its own "ping" keep-alive every 30 seconds.)
Message types¶
Binary frames are base64-wrapped Protocol Buffers (MarketDataMessageBase); exactly one subtype is set per frame.
| Subtype | MessageCode | Description |
|---|---|---|
TickDataMessage |
1501 | Trade tick |
MarketDepthMessage |
1502 | Top-of-book snapshot with depth levels |
IndexDataMessage |
1503 | Single index snapshot |
IncrementalUpdateMessage |
1504 | Incremental market data entries |
IndexDataListMessage |
1505 | Batch of index snapshots (IndexDataList array) |
TickData |
1506 | Compact trade tick |
TouchLineDataMessage |
1507 | Touchline (OHLC + best prices) |
Depth is top-5 only
The feed disseminates 5 bid + 5 ask levels maximum per MarketDepthMessage — this is an exchange-side limit of the public tick feed, not an SDK or gateway restriction. BestBidLevel / BestAskLevel always contain at most 5 entries.
Response¶
Below are the JSON representations of each message type, as produced by google.protobuf.json_format.MessageToJson() on the protobuf envelope received by on_message:
MarketDepthMessage (MessageCode = 1502)¶
{
"MessageCode": 1502,
"ID": "110010000014366",
"MarketDepthMessage": {
"InstrumentID": "110010000014366",
"ExchangeSegment": "NSECM",
"ExchangeInstrumentID": 14366,
"InstrumentName": "IDEA",
"TimeStamp": "1770728960",
"LTP": 11.51,
"LTQ": 6,
"LTT": "1770728958",
"ATP": 11.55,
"VTT": "268805264",
"TBQ": "28554459",
"TSQ": "80855892",
"Open": 11.58,
"High": 11.67,
"Low": 11.48,
"Close": 11.58,
"BestBidLevel": [
{ "Qty": 833392, "Price": 11.5, "Orders": 32 },
{ "Qty": 1544228, "Price": 11.49, "Orders": 77 },
{ "Qty": 2661470, "Price": 11.48, "Orders": 376 },
{ "Qty": 979035, "Price": 11.47, "Orders": 126 },
{ "Qty": 835550, "Price": 11.46, "Orders": 126 }
],
"BestAskLevel": [
{ "Qty": 1022084, "Price": 11.51, "Orders": 66 },
{ "Qty": 812256, "Price": 11.52, "Orders": 69 },
{ "Qty": 1156649, "Price": 11.53, "Orders": 70 },
{ "Qty": 1867230, "Price": 11.54, "Orders": 120 },
{ "Qty": 1503815, "Price": 11.55, "Orders": 219 }
]
}
}
In the live JSON,
TimeStamp,LTT,VTT,TBQandTSQ(int64 values) are serialized as strings.ExchangeSegmentis returned as a string ("NSECM") rather than a numeric code. Depth levels use theQty/Price/Ordersfields.
| Field | Type | Description |
|---|---|---|
MessageCode |
int | Message type code (1502) |
ID |
string | Instrument ID |
MarketDepthMessage |
object | Market depth payload |
InstrumentID |
string | Instrument ID |
ExchangeSegment |
string | Exchange segment ("NSECM") |
ExchangeInstrumentID |
uint64 | Exchange instrument ID |
InstrumentName |
string | Instrument name |
TimeStamp |
string | Tick timestamp (epoch seconds) |
LTP |
double | Last traded price |
LTQ |
int | Last traded quantity |
LTT |
string | Last traded time (epoch seconds) |
ATP |
double | Average traded price |
VTT |
string | Volume today |
TBQ |
string | Total buy quantity |
TSQ |
string | Total sell quantity |
Open |
double | Opening price |
High |
double | High price |
Low |
double | Low price |
Close |
double | Previous close |
BestBidLevel |
repeated | Best bid depth levels |
BestAskLevel |
repeated | Best ask depth levels |
Depth level fields (BestBidLevel / BestAskLevel)¶
| Field | Type | Description |
|---|---|---|
Qty |
int | Quantity at level |
Price |
double | Bid/Ask price |
Orders |
int | Number of orders |
IndexDataMessage (MessageCode = 1503) / IndexDataListMessage (MessageCode = 1505)¶
Single index snapshots arrive as IndexDataMessage; batches arrive as IndexDataListMessage, where the payloads are wrapped in an IndexDataList array:
{
"MessageCode": 1505,
"IndexDataListMessage": {
"IndexDataList": [
{
"InstrumentID": "110010002000001",
"ExchangeSegment": "NSECM",
"ExchangeInstrumentID": 2000001,
"IndexName": "NIFTY 50",
"TimeStamp": "1770719042",
"Last": 25963.3,
"Open": 25922.65,
"High": 25971.85,
"Low": 25870.45,
"Close": 24511.2,
"YearlyHigh": 26373.2,
"YearlyLow": 21743.65
}
]
}
}
| Field | Type | Description |
|---|---|---|
InstrumentID |
string | Index instrument ID |
ExchangeSegment |
string | Exchange segment ("NSECM") |
ExchangeInstrumentID |
uint64 | Exchange instrument ID |
IndexName |
string | Index name |
TimeStamp |
string | Tick timestamp (epoch seconds) |
Last |
double | Last index value |
Open |
double | Open value |
High |
double | High value |
Low |
double | Low value |
Close |
double | Previous close value |
YearlyHigh |
double | 52-week high |
YearlyLow |
double | 52-week low |
When consuming via the Python typed callback,
set_on_indexreceives both subtypes: usepayload.IndexDataListfor batch frames andpayload.IndexDatafor single frames.
TickDataMessage (MessageCode = 1501) / TickData (MessageCode = 1506)¶
Trade-tick updates for actively traded instruments. 1501 is the full tick message; 1506 is a compact variant carrying an extra Flag.
{
"MessageCode": 1501,
"ID": "110010000002885",
"TickDataMessage": {
"InstrumentID": "110010000002885",
"ExchangeSegment": "NSECM",
"ExchangeInstrumentID": 2885,
"InstrumentName": "RELIANCE",
"TimeStamp": "1455185634",
"LTP": 1463.9,
"LTQ": 3,
"LTT": "1455185633"
}
}
{
"MessageCode": 1506,
"ID": "110010000002885",
"TickData": {
"InstrumentID": "110010000002885",
"ExchangeSegment": "NSECM",
"ExchangeInstrumentID": 2885,
"InstrumentName": "RELIANCE",
"LTP": 1463.9,
"LTQ": 3,
"LTT": "1455185633",
"Flag": 0
}
}
| Field | Type | Description |
|---|---|---|
InstrumentID |
string | Instrument ID |
ExchangeSegment |
string | Exchange segment ("NSECM") |
ExchangeInstrumentID |
uint64 | Exchange instrument ID |
InstrumentName |
string | Instrument name |
TimeStamp |
string | Tick timestamp (epoch seconds); absent in the 1506 variant |
LTP |
double | Last traded price |
LTQ |
int | Last traded quantity |
LTT |
string | Last traded time (epoch seconds) |
Flag |
int | Tick flag (1506 variant only) |
TouchLineDataMessage (MessageCode = 1507)¶
OHLC/statistics snapshot without depth levels (touchline data):
{
"MessageCode": 1507,
"ID": "110010000002885",
"TouchLineDataMessage": {
"InstrumentID": "110010000002885",
"ExchangeSegment": "NSECM",
"ExchangeInstrumentID": 2885,
"InstrumentName": "RELIANCE",
"TimeStamp": "1455185634",
"LTP": 1463.9,
"LTQ": 3,
"LTT": "1455185633",
"ATP": 1467.26,
"VTT": "916059",
"TBQ": "326915",
"TSQ": "707507",
"Open": 1471.0,
"High": 1471.0,
"Low": 1462.7,
"Close": 1461.6
}
}
| Field | Type | Description |
|---|---|---|
InstrumentID |
string | Instrument ID |
ExchangeSegment |
string | Exchange segment ("NSECM") |
ExchangeInstrumentID |
uint64 | Exchange instrument ID |
InstrumentName |
string | Instrument name |
TimeStamp |
string | Tick timestamp (epoch seconds) |
LTP |
double | Last traded price |
LTQ |
int | Last traded quantity |
LTT |
string | Last traded time (epoch seconds) |
ATP |
double | Average traded price |
VTT |
string | Volume today |
TBQ |
string | Total buy quantity |
TSQ |
string | Total sell quantity |
Open / High / Low / Close |
double | OHLC prices |
IncrementalUpdateMessage (MessageCode = 1504)¶
Depth deltas during fast markets. Each frame carries a list of MDEntries entries; MDUpdateAction says what happened to the level and MDEntryPosition where it sits in the book:
{
"MessageCode": 1504,
"IncrementalUpdateMessage": {
"MDEntriesList": [
{
"MDUpdateAction": 0,
"MDEntryType": 0,
"InstrumentID": "110010000002885",
"ExchangeSegment": "NSECM",
"ExchangeInstrumentID": 2885,
"InstrumentName": "RELIANCE",
"MDEntryPrice": 1463.8,
"MDEntrySize": 420,
"MDEntryTime": 1455185634,
"MDEntryPosition": 1,
"OI": 0
},
{
"MDUpdateAction": 0,
"MDEntryType": 1,
"InstrumentID": "110010000002885",
"ExchangeSegment": "NSECM",
"ExchangeInstrumentID": 2885,
"InstrumentName": "RELIANCE",
"MDEntryPrice": 1464.0,
"MDEntrySize": 380,
"MDEntryTime": 1455185634,
"MDEntryPosition": 1,
"OI": 0
}
]
}
}
| Field | Type | Description |
|---|---|---|
MDUpdateAction |
int | Update action for the level (0 = new/update) |
MDEntryType |
int | Entry type (0 = bid, 1 = ask; trade/OI variants per FIX conventions) |
InstrumentID |
string | Instrument ID |
ExchangeSegment |
string | Exchange segment ("NSECM") |
ExchangeInstrumentID |
uint64 | Exchange instrument ID |
InstrumentName |
string | Instrument name |
MDEntryPrice |
double | Level price |
MDEntrySize |
int | Quantity at the level |
MDEntryTime |
int | Entry time (epoch seconds) |
MDEntryPosition |
int | Position in the book (1-based) |
OI |
int64 | Open interest (derivatives) |
Which frames you actually receive
The 1502 and 1505 examples above are verbatim UAT captures. Tick (1501/1506), touchline (1507) and incremental (1504) frames flow only for high-activity instruments during market bursts; their structures above are complete per the server protobuf schema (marketdata.proto), with representative values. Proto3 omits fields equal to zero (e.g. NetChangeIndicator, OI) from the JSON.