Streaming¶
The stream package delivers real-time Market Data over MQTT. Subscribe and
unsubscribe are HTTP calls made through the core client; the MQTT connection
only carries pushes. Requires a valid token (see Authentication).
Prerequisites
- A Webull account (sandbox or production)
- Go 1.26+
- An authenticated client — see Authentication
Error handling
All SDK functions return error. See Errors for the typed error model, transient vs permanent classification, and retry patterns.
Build a streaming client from a configured
*client.Client:
cl, err := client.New(client.WithEnv())
if err != nil {
return err
}
defer func() { _ = cl.Close() }()
if _, err := cl.EnsureToken(ctx); err != nil {
return err
}
s, err := stream.New(cl, stream.WithWebSocket(true))
if err != nil {
return err
}
defer func() { _ = s.Close() }()
The broker address comes from the client's resolved endpoints. WithWebSocket(true)
selects the MQTT-over-WebSocket endpoint (wss://...:8883/mqtt); otherwise the
plain TCP endpoint (...:1883) is used. WithMQTTURL overrides both.
Connect and subscribe¶
if err := s.Connect(ctx); err != nil {
return err
}
if err := s.Subscribe(ctx, stream.SubscribeRequest{
Symbols: []string{"AAPL"},
Category: stream.CategoryUSStock,
SubTypes: []stream.SubType{stream.SubTypeQuote, stream.SubTypeSnapshot, stream.SubTypeTick},
Grab: true,
}); err != nil {
return err
}
SubscribeRequest fields:
| Field | Purpose |
|---|---|
SessionID |
Overrides the client session id for this call; rarely needed |
Symbols |
Symbols to subscribe to; at most 100 per request |
Category |
Security type: CategoryUSStock, CategoryUSETF, CategoryHKStock, CategoryCNStock (validated with Category.Valid()) |
SubTypes |
Data types: SubTypeQuote, SubTypeSnapshot, SubTypeTick (validated with SubType.Valid()) |
Grab |
Request an immediate snapshot push on subscription |
Depth |
Level-2 order-book depth as a string (optional; defaults to "10", US stocks up to "50") |
OvernightRequired |
Include the overnight session for US stocks |
Unsubscribe mirrors it and accepts UnsubscribeAll: true to cancel every
subscription for the session.
Handlers¶
Register handlers before or after Connect; each may be called more than once.
| Handler | Payload | Fires on |
|---|---|---|
OnQuote |
*marketdatav1.Quote |
Order-book pushes |
OnSnapshot |
*marketdatav1.Snapshot |
Market snapshots |
OnTick |
*marketdatav1.Tick |
Tick-by-tick trades |
OnNotice |
[]byte (JSON) |
Server notifications |
OnError |
error |
Async errors (decode failures, unknown topics, resubscribe failures) |
OnConnect |
none | Initial connect and every reconnect |
OnDisconnect |
error |
A live connection was lost |
s.OnSnapshot(func(snap *marketdatav1.Snapshot) {
log.Printf("%s %s", snap.GetBasic().GetSymbol(), snap.GetPrice())
})
The marketdatav1 package is
github.com/shing1211/webullapi4go/gen/webull/marketdata/v1.
Options¶
| Option | Purpose |
|---|---|
WithSessionID, WithClientID |
Set the MQTT client id / session id (a unique id is generated by default) |
WithMQTTURL |
Override the broker address (tcp://, wss://, or bare host:port) |
WithWebSocket(bool) |
Select the WebSocket endpoint |
WithAutoReconnect(bool) |
Enable the background reconnect loop |
WithAutoResubscribe(bool) |
Re-issue active subscriptions after a reconnect (default true) |
WithResubscribeTimeout(d) |
Bound the whole re-subscription sequence |
WithKeepAlive(d) |
MQTT keep-alive interval |
WithConnectTimeout(d) |
Bound a single connection attempt |
WithWriteTimeout(d) |
Bound writing a control packet |
WithMessageChannelDepth(n) |
Inbound message buffer size |
WithCleanSession(bool) |
Request a clean MQTT session (default true) |
WithTLSConfig(*tls.Config) |
Override the TLS configuration |
SessionID() returns the MQTT client id used by the client. It is stable for
the lifetime of the Client.
Reconnection and limits¶
Webull does not restore subscriptions after a connection is lost. With
WithAutoReconnect, the client detects the drop, reconnects, and re-issues the
HTTP subscribe calls for every active subscription before OnConnect fires, so
handlers observe a restored session. Re-subscription is idempotent. Reconnecting
reports an in-progress reconnect attempt and IsConnected reports the live
state.
Webull applies the following rules:
- An App Key supports at most 5 concurrent MQTT connections. Exceeding the
limit fails with Webull error code 105;
Connectreturns an error explaining the limit. After a disconnect the server retains state for about one minute, so wait roughly a minute before reconnecting. - A new connection that reuses an existing session id disconnects the previous
one.
Newgenerates a unique session id by default; only setWithSessionIDwhen exclusivity is guaranteed. - The server pushes at most three messages per second per connection.
Topics¶
| Topic constant | Value | Encoding |
|---|---|---|
TopicQuote |
quote |
protobuf (Quote) |
TopicSnapshot |
snapshot |
protobuf (Snapshot) |
TopicTick |
tick |
protobuf (Tick) |
TopicNotice |
notice |
JSON |
TopicEcho |
echo |
heartbeat, ignored |
Full example¶
The runnable example in
examples/streaming
connects over WebSocket, subscribes to AAPL quote/snapshot/tick pushes, prints
messages, and handles Ctrl+C.
Related¶
- Market Data — HTTP queries.
- Troubleshooting — connection and entitlement issues.