An idiomatic Go SDK for the Webull OpenAPI. It wraps Webull's HTTP and MQTT services in typed Go, starting with the Hong Kong region. The v0.1 release covers authentication, a core signed REST client, the Market Data HTTP API, and real-time Market Data streaming over MQTT. The v0.2 release adds the Trading HTTP API: v0.2.1 introduced account listing, balances, and positions, v0.2.2 adds the stock-order lifecycle (preview, place, replace, cancel) and order queries, v0.2.3 adds market-specific order rules for US, HK, and CN, including Hong Kong BCAN party IDs, v0.2.4 adds single-leg options orders, and v0.2.5 adds US combo orders. The v0.3 release adds real-time Trading events over gRPC. The v0.4 release adds Market Data fundamentals: capital flows, industry comparisons, earnings and dividend calendars, SEC filings, and financial statements.
- Module:
github.com/shing1211/webullapi4go - Documentation: https://shing1211.github.io/webullapi4go/
- License: Apache-2.0
- Requires Go 1.26 or newer; no cgo.
| Area | Status | Details |
|---|---|---|
| Authentication | Supported | HMAC-SHA1 request signing, token create/check/ensure, automatic token injection |
| Market Data (HTTP) | Supported | Instruments, fundamentals, futures static and market data, snapshot, tick, quotes/depth, bars, footprint, NOII, screener, watchlists, options, news, event contracts, crypto data, Display Solution |
| Market Data (MQTT streaming) | Supported | QUOTE, SNAPSHOT, and TICK pushes over MQTT or MQTT-over-WebSocket, with auto-reconnect and auto-resubscribe |
| Trading (HTTP) | Supported | Accounts, balances, and positions; stock order preview, place, replace, cancel, and order queries; US/HK/CN order-type rules, Hong Kong BCAN; single-leg and multi-leg options orders; futures order validation; event contract orders; batch place orders |
| Trading events (gRPC) | Supported | Order, event-contract position, and option status-change streams over server-streaming gRPC |
| Broker API HK | Supported | Virtual accounts, instruments, assets, orders, cash activities, funding FX, instant funding, journals, master data, event contracts (broker/ module) |
| Broker FD API US | Supported | Agreements, accounts, documents, assets, activity, funding, instruments, orders, journals, master data (brokerfd/ module) |
| Broker FD events (gRPC) | Supported | Broker FD event stream over gRPC using grpc.event.EventService (brokerfd/events/ module) |
| Display Solution | Supported | Company profile, analyst data, news, streaming, screeners, quotes (entitlement-gated: the HK sandbox host returns 403) |
| Connect API (OAuth) | Supported | Authorization-code URL builder and token exchange (authorization code / refresh) |
go get github.com/shing1211/webullapi4gopackage main
import (
"context"
"log"
"github.com/shing1211/webullapi4go/client"
"github.com/shing1211/webullapi4go/data"
)
func main() {
// WithEnv reads WEBULL_APP_KEY, WEBULL_APP_SECRET, WEBULL_REGION, and
// WEBULL_ENVIRONMENT.
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)
}
market := data.New(cl)
snaps, err := market.GetSnapshot(ctx, data.SnapshotQuery{
Symbols: []string{"AAPL"},
Category: data.StockCategoryUS,
})
if err != nil {
log.Fatal(err)
}
for _, s := range snaps {
log.Printf("%s %s", s.Symbol, s.Price)
}
}package main
import (
"context"
"log"
"github.com/shing1211/webullapi4go/client"
marketdatav1 "github.com/shing1211/webullapi4go/gen/webull/marketdata/v1"
"github.com/shing1211/webullapi4go/stream"
)
func main() {
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)
}
s, err := stream.New(cl, stream.WithWebSocket(true))
if err != nil {
log.Fatal(err)
}
defer func() { _ = s.Close() }()
s.OnSnapshot(func(snap *marketdatav1.Snapshot) {
log.Printf("%s %s", snap.GetBasic().GetSymbol(), snap.GetPrice())
})
if err := s.Connect(ctx); err != nil {
log.Fatal(err)
}
if err := s.Subscribe(ctx, stream.SubscribeRequest{
Symbols: []string{"AAPL"},
Category: stream.CategoryUSStock,
SubTypes: []stream.SubType{stream.SubTypeQuote, stream.SubTypeSnapshot, stream.SubTypeTick},
}); err != nil {
log.Fatal(err)
}
select {} // block until the process is interrupted
}package main
import (
"context"
"log"
"github.com/shing1211/webullapi4go/client"
"github.com/shing1211/webullapi4go/trade"
)
func main() {
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)
}
trading := trade.New(cl)
accounts, err := trading.ListAccounts(ctx)
if err != nil {
log.Fatal(err)
}
for _, acct := range accounts {
balance, err := trading.GetBalance(ctx, acct.AccountID)
if err != nil {
log.Fatal(err)
}
log.Printf("%s cash=%s market_value=%s", acct.AccountID,
balance.TotalCashBalance, balance.TotalMarketValue)
}
}package main
import (
"context"
"log"
"github.com/shing1211/webullapi4go/client"
"github.com/shing1211/webullapi4go/events"
)
func main() {
cl, err := client.New(client.WithEnv())
if err != nil {
log.Fatal(err)
}
defer func() { _ = cl.Close() }()
ev, err := events.New(cl, events.WithSubscribeTypes(events.SubscribeOrder))
if err != nil {
log.Fatal(err)
}
defer func() { _ = ev.Close() }()
ev.OnConnect(func() { log.Println("subscribed") })
ev.OnOrder(func(o *events.OrderEvent) {
log.Printf("%s %s %s", o.OrderID, o.OrderStatus, o.SceneType)
})
if err := ev.Run(context.Background()); err != nil {
log.Fatal(err)
}
}More runnable programs live in examples/.
Credentials and environment are never hard-coded. client.WithEnv() reads the
following process environment variables:
| Variable | Purpose |
|---|---|
WEBULL_APP_KEY |
Webull OpenAPI app key (required) |
WEBULL_APP_SECRET |
Webull OpenAPI app secret, used to sign requests (required) |
WEBULL_REGION |
Deployment region: hk (default), us, jp, sg, th, au, my, uk, br, mx, za, eu |
WEBULL_ENVIRONMENT |
prod / production (default) or uat / sandbox |
WEBULL_BASE_URL |
Optional override of the REST base URL only |
WEBULL_MQTT_URL |
Optional override of the MQTT broker address only |
Explicit functional options always take precedence over WithEnv() regardless of
order. Common options:
| Option | Purpose |
|---|---|
WithAppKey, WithAppSecret, WithCredentials |
Set credentials directly |
WithRegion(client.HK) |
Select the deployment region |
WithEnvironment(client.Sandbox), WithSandbox() |
Select the environment |
WithBaseURL, WithEndpoints |
Override resolved service endpoints |
WithHTTPClient, WithTimeout, WithUserAgent |
Tune the HTTP transport |
WithRetry(RetryConfig), WithoutRetry() |
Configure transient-failure retries |
WithRateLimiter, NewRateLimiter(rate, burst) |
Throttle requests per path |
WithBreaker, NewBreaker(threshold, cooldown) |
Add a circuit breaker |
WithAPIVersion("v2"|"v3"), WithAPIVersionFor(prefix, version) |
Select the x-version header |
WithAutoToken(true) |
Obtain a token automatically (sandbox) before the first request |
WithEnv() |
Fill configuration from the environment |
Streaming is configured with stream.WithSessionID, WithMQTTURL,
WithWebSocket, WithAutoReconnect, WithAutoResubscribe,
WithResubscribeTimeout, WithKeepAlive, WithConnectTimeout,
WithWriteTimeout, WithMessageChannelDepth, WithCleanSession, and
WithTLSConfig.
Trading is configured with trade.WithMaxOrderNotional and
trade.WithMaxOrderQuantity, advisory order guardrails that the order methods
enforce before an order is built. The notional cap does not cover multi-leg
option orders, which have no single top-level notional; the quantity cap still
applies to them.
Trading events are configured with events.WithSubscribeTypes,
events.WithAccounts, events.WithGRPCEndpoint, events.WithGRPCPort,
events.WithTLS, events.WithDialTimeout, events.WithGRPCDialOption,
events.WithAutoReconnect, events.WithReconnectBaseDelay,
events.WithReconnectMaxDelay, and events.WithMaxReconnectAttempts.
Use the sandbox while developing. Point the client at the environment and it
resolves the Hong Kong sandbox host https://api.sandbox.webull.hk:
export WEBULL_ENVIRONMENT="sandbox"
export WEBULL_APP_KEY="your-sandbox-app-key"
export WEBULL_APP_SECRET="your-sandbox-app-secret"The integration tests are skipped unless explicitly enabled and require sandbox credentials. Never commit the values.
# macOS / Linux
WEBULL_SANDBOX=1 \
WEBULL_APP_KEY=your-sandbox-app-key \
WEBULL_APP_SECRET=your-sandbox-app-secret \
go test ./... -run Integration# Windows PowerShell
$env:WEBULL_SANDBOX = "1"
$env:WEBULL_APP_KEY = "your-sandbox-app-key"
$env:WEBULL_APP_SECRET = "your-sandbox-app-secret"
go test ./... -run IntegrationMQTT over WebSocket tests additionally read WEBULL_MQTT_WEBSOCKET=1. See the
sandbox documentation and
troubleshooting guide
for known sandbox limitations (a single supported symbol, entitlement-gated
footprint data, empty depth outside market hours, and network blocking of plain
MQTT on port 1883).
| Package | Purpose |
|---|---|
client |
Core SDK: configuration, options, signing, tokens, transport, and Client.Do |
data |
Market Data HTTP endpoints (typed requests and responses) |
stream |
Market Data streaming over MQTT, with reconnect and resubscribe |
trade |
Trading HTTP endpoints (accounts, balances, positions, stock, single-leg and multi-leg options, futures validation, US combo orders, and order queries) |
events |
Trading events over gRPC: order, position, and option streams with typed payloads and reconnect |
connect |
OAuth 2.0 authorization-code flow for third-party apps (US only) |
display |
Display Solution client-to-server authentication and token management |
broker |
Broker API HK (own Go module; root module uses replace) |
brokerfd |
Broker FD US HTTP endpoints (accounts, orders, funding, instruments, etc.) |
brokerfd/events |
Broker FD US events over gRPC |
gen/webull/marketdata/v1 |
Generated protobuf types for streamed messages |
gen/webull/trade/events/v1 |
Generated protobuf types for the gRPC event service |
gen/webull/brokerfd/v1 |
Generated protobuf types for Broker FD events |
pkg/types |
Shared public domain types (markets, instrument types) |
internal/* |
Implementation details: signing, token lifecycle, region endpoints, transport, resilience, MQTT |
| Version | Scope | Status |
|---|---|---|
| v0.1 | Authentication, core HTTP client, Market Data HTTP + MQTT streaming | Done |
| v0.2 | Trading (HTTP): accounts, balances, positions (v0.2.1), stock orders (v0.2.2), market-specific rules and HK BCAN (v0.2.3), single-leg options orders (v0.2.4), US combo orders (v0.2.5), then a Market Data news SSE refactor (v0.2.6) | Done |
| v0.3 | Trading events over gRPC | Done |
| v0.4 | Market Data fundamentals: capital flows, industry comparisons, earnings/dividend calendars, SEC filings, financial statements | Done |
| v0.5 | Fund data, crypto data, screener v2, corporate actions, instrument v3 migration | Done |
| v0.6 | Broker API (HK + FD US), multi-leg options, futures validation, option chain discovery | Done |
| v0.7.0 | Event contracts, Broker API HK, Broker FD US, Broker FD gRPC events | Done |
| v0.8.0 | — | — |
| v0.9.0 | GoDoc coverage on brokerfd/ and brokerfd/events/, HK options stubs, HK futures market data, new examples (brokerfd, brokerfd-events, options), graceful credential handling | Done |
| v0.9.1 | Watchlist boolean-response fix; DoBroker transport; watchlist-cmd and broker-probe examples |
Done |
| v0.9.2 | Broker HK path correction (/openapi/v1/broker/... → /broker/...); 401 ROUTE_NOT_PERMITTED instead of 404 Route Not Found |
Done |
| v1.0 | Stable public API, full documentation, semver guarantees | Done |
| v1.1 | Full Webull OpenAPI parity: every documented endpoint implemented with official paths (209 endpoints, 0 gaps); connect/ OAuth, crypto, fund extras, event-contract Display |
Done |
- Documentation: https://shing1211.github.io/webullapi4go/
- API reference: https://pkg.go.dev/github.com/shing1211/webullapi4go
datareference: https://pkg.go.dev/github.com/shing1211/webullapi4go/datastreamreference: https://pkg.go.dev/github.com/shing1211/webullapi4go/streamtradereference: https://pkg.go.dev/github.com/shing1211/webullapi4go/tradeeventsreference: https://pkg.go.dev/github.com/shing1211/webullapi4go/events- Questions and ideas: GitHub Discussions
- Architecture decisions: ADR index
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
| Target | Description |
|---|---|
make build |
compile all packages |
make test |
unit tests (sandbox tests need WEBULL_SANDBOX=1 and valid creds) |
make test-race |
tests with the race detector |
make cover |
coverage profiling |
make lint |
golangci-lint (includes gosec) |
make fuzz |
fuzz the data deserializers |
make vuln |
govulncheck |
make docs |
build the MkDocs site (mkdocs build --strict) |
Apache-2.0. See LICENSE.
This SDK is an independent, unofficial wrapper around the Webull OpenAPI and is provided for reference and educational use only. It is not affiliated with or endorsed by Webull. Nothing here is investment advice. Use it at your own risk, and always follow Webull's terms of service and your own risk controls.