Patterns¶
Shared patterns and conventions used across the SDK.
Prerequisites
- A Webull account (sandbox or production)
- Go 1.26+
- Basic familiarity with Go's functional options pattern
Client construction¶
Every API package follows the same construction pattern:
cl, err := client.New(client.WithEnv())
if err != nil {
log.Fatal(err)
}
defer func() { _ = cl.Close() }()
ctx := context.Background()
if _, err := cl.EnsureToken(ctx); err != nil {
log.Fatal(err)
}
WithEnv() reads credentials from the environment. Alternative constructors:
| Option | Purpose |
|---|---|
client.WithCredentials(key, secret) |
Explicit credentials |
client.WithSandbox() |
Point at the HK sandbox host |
client.WithRegion(client.HK) / client.WithRegion(client.US) |
Select region |
client.WithBaseURL(url) |
Override the base URL |
client.WithTimeout(d) |
Set HTTP timeout |
client.WithAutoToken(true) |
Auto-obtain token on first sandbox request |
Options are applied in order. WithSandbox() is equivalent to
WithEnvironment(client.Sandbox).
Option pattern¶
All packages use the functional options pattern:
Each WithX constructor returns a func(*Config) that is applied during
construction. Options are validated immediately; invalid options fail the
constructor.
Pagination¶
List endpoints use cursor-based pagination with three tiers:
| Method | Behavior |
|---|---|
GetXxx(ctx, q) |
Returns the first page only |
GetXxxPage(ctx, q) |
Returns one page with PaginationKey for the next page |
GetAllXxx(ctx, q) |
Follows the cursor to exhaustion, returning all results |
// First page
open, err := trading.GetOpenOrders(ctx, accountID)
// Manual pagination
page, err := trading.GetOpenOrdersPage(ctx, accountID, "")
for _, group := range page.Orders {
// process group
}
if page.PaginationKey != "" {
next, err := trading.GetOpenOrdersPage(ctx, accountID, page.PaginationKey)
// ...
}
// Auto-pagination (all pages)
all, err := trading.GetAllOpenOrders(ctx, accountID)
GetAllXxx is bounded by MaxOrderQueryPages (100) to prevent infinite loops.
Numeric strings¶
Prices, quantities, and other numeric fields are strings on the wire and
remain strings in Go types. This preserves decimal precision that float64
would lose:
When constructing requests, pass numeric values as strings:
Error handling¶
All SDK errors are typed and support errors.Is/errors.As:
result, err := trading.PlaceOrder(ctx, req)
if err != nil {
if errors.Is(err, client.ErrAccessTokenRequired) {
// Token expired; refresh and retry
if _, err := cl.EnsureToken(ctx); err != nil {
log.Fatal(err)
}
// retry...
} else if errors.Is(err, client.ErrCircuitOpen) {
// Circuit breaker open; back off
time.Sleep(backoff)
} else {
log.Printf("order failed: %v", err)
}
}
See Errors for the full code table and handling guidance.
Display Service¶
Display Solution endpoints use a separate signing mechanism. Access them
through data.Client.DisplayService():
market := data.New(cl)
// The display service uses client-token auth, not the regular access token
profile, err := market.GetDSCompanyProfile(ctx, "AAPL")
The display service manages its own client token automatically. No separate authentication setup is required.
Streaming¶
MQTT streaming and gRPC events follow a callback + run pattern:
// MQTT (Market Data)
s, err := stream.New(cl, stream.WithWebSocket(true))
s.Connect(ctx)
s.Subscribe(ctx, stream.SubscribeRequest{...})
s.OnQuote(func(q *marketdatav1.Quote) { /* handle */ })
// gRPC (Trading Events)
ev, err := events.New(cl)
ev.OnOrder(func(o *events.OrderEvent) { /* handle */ })
ev.Run(ctx) // blocks
Register handlers before calling Connect/Run. Handlers run on the stream
pump and must not block.
HK BCAN party IDs¶
Hong Kong equity orders require BCAN party IDs. Use the helper:
NoPartyIDs: []trade.PartyID{{
PartyID: os.Getenv("WEBULL_TRADE_PARTY_ID"),
PartyIDSource: trade.HKDerivativesPartyIDSource, // "D"
PartyRole: trade.HKDerivativesPartyRole, // "3"
}},
Or use the builder:
Related¶
- Getting Started — install and first call.
- Authentication — signing and tokens.
- Errors — typed errors and classification.
- Sandbox — environments and test credentials.