Quick Start
Requirements
- Please first generate the app key and app secret on the Webull Hong Kong official website.
- Requirements for Programming language version:
- Python
- Java
Requires Python 3.7 and above.
JDK 8 or above needs to be installed.
SDK Description
Package Dependency Description
- Python
- Java
Packages that must be installed regardless of which product's development kit is used.
webull-python-sdk-core
Packages that must be installed to use market subscription products.
webull-python-sdk-quotes-core
Packages that must be installed when subscribing to products using trade events.
webull-python-sdk-trade-events-core
Packages that need to be installed by default for the complete use of quotes SDK.
webull-python-sdk-core
webull-python-sdk-quotes-core
webull-python-sdk-mdata
Packages that need to be installed by default for the complete use of the trading sdk in Hong Kong.
webull-python-sdk-core
webull-python-sdk-trade-events-core
webull-python-sdk-trade
Libraries that must be added for the complete use of quotes SDK.
webull-java-sdk-quotes
Libraries that must be added when subscribing to products using trade events.
webull-java-sdk-trade-events
Libraries that need to be added by default for the complete use of the trading sdk in Hong Kong.
webull-java-sdk-trade-events
webull-java-sdk-trade
SDK Installation
- Python
- Java
Install via pip
pip3 install --upgrade webull-python-sdk-core
pip3 install --upgrade webull-python-sdk-quotes-core
pip3 install --upgrade webull-python-sdk-mdata
pip3 install --upgrade webull-python-sdk-trade-events-core
pip3 install --upgrade webull-python-sdk-trade
Maven configuration
<dependencies>
<dependency>
<groupId>com.webull.openapi</groupId>
<artifactId>webull-java-sdk-quotes</artifactId>
<version>0.2.5</version>
</dependency>
<dependency>
<groupId>com.webull.openapi</groupId>
<artifactId>webull-java-sdk-trade-events</artifactId>
<version>0.2.5</version>
</dependency>
<dependency>
<groupId>com.webull.openapi</groupId>
<artifactId>webull-java-sdk-trade</artifactId>
<version>0.2.5</version>
</dependency>
</dependencies>
API Host
tip
The Http API address is used for normal Http requests.
The trading alerts is used for real-time pushes such as order status changes.
The push address for the market news is used for receiving the pushes for real-time market news.
Test Environment
HTTP API: hk-openapi.uat.webullbroker.com
Trading news push: hk-openapi-events-api.uat.webullbroker.com
Market news push: hk-openapi-quotes-api.uat.webullbroker.com
Production Environment
HTTP API: api.webull.hk
Trading news push: events-api.webull.hk
Market news push: quotes-api.webull.hk
Requesting API for Testing
The acquisition method of App Key and App Secret in the Test Environment:
First, you need to open an account on the Hong Kong official website in the test environment. After the account opening is completed, you need to apply for the API and contact the Webull Product Manager for review. After passing the review, you can register the app, and generate App Key and App Secret. For detailed steps, please refer to API Application.
Contact Email: webull-api@webull.hk
tip
You can also try the Webull SDK using the App Key and App Secret listed below.
Test Environment HTTP Request List:
- Python
- Java
import uuid
from webullsdkcore.client import ApiClient
from webullsdktrade.api import API
from webullsdkcore.common.region import Region
optional_api_endpoint = "hk-openapi.uat.webullbroker.com"
your_app_key = "10b6dd1348e0e8e977442c3efcd6fc0b"
your_app_secret = "03ce640a7752eb68bc53f908caf58892"
api_client = ApiClient(your_app_key, your_app_secret, Region.HK.value)
api_client.add_endpoint(Region.HK.value, optional_api_endpoint)
class TestOrder(object):
def __init__(self):
self.api = API(api_client)
def order(self):
res = self.api.account.get_app_subscriptions()
account_id = None
if res.status_code == 200:
print('app subscriptions:', res.json())
result = res.json()
account_id = result[0]['account_id']
print("account id:", account_id)
if account_id is None:
print("account id is null")
return
client_order_id = uuid.uuid4().hex
print('client order id:', client_order_id)
stock_order = {
"account_id": account_id,
"stock_order": {
"client_order_id": client_order_id,
"instrument_id": "913256409",
"side": "BUY",
"tif": "DAY",
"order_type": "AT_AUCTION",
# "limit_price": "385.000",
"qty": "1",
"extended_hours_trading": False
}
}
res = self.api.order.place_order(stock_order['account_id'], **stock_order['stock_order'])
if res.status_code == 200:
print('place order res:', res.json())
if __name__ == '__main__':
openapi = TestOrder()
openapi.order()
import com.webull.openapi.common.Region;
import com.webull.openapi.common.dict.OrderSide;
import com.webull.openapi.common.dict.OrderTIF;
import com.webull.openapi.common.dict.OrderType;
import com.webull.openapi.http.HttpApiConfig;
import com.webull.openapi.trade.api.TradeApiService;
import com.webull.openapi.trade.api.http.TradeHttpApiService;
import com.webull.openapi.trade.api.request.StockOrder;
import com.webull.openapi.trade.api.response.Account;
import com.webull.openapi.trade.api.response.OrderResponse;
import com.webull.openapi.logger.Logger;
import com.webull.openapi.logger.LoggerFactory;
import com.webull.openapi.serialize.JsonSerializer;
import com.webull.openapi.utils.CollectionUtils;
import com.webull.openapi.utils.GUID;
import com.webull.openapi.utils.StringUtils;
import java.util.List;
public class HttpApi {
private static final Logger logger = LoggerFactory.getLogger(HttpApi.class);
public static void main(String[] args) {
HttpApiConfig apiConfig = HttpApiConfig.builder()
.appKey("10b6dd1348e0e8e977442c3efcd6fc0b")
.appSecret("03ce640a7752eb68bc53f908caf58892")
.regionId(Region.hk.name())
.endpoint("hk-openapi.uat.webullbroker.com")
.build();
TradeApiService apiService = new TradeHttpApiService(apiConfig);
List<Account> accounts = apiService.getAccountList("");
String accountId = null;
if (CollectionUtils.isNotEmpty(accounts)) {
accountId = accounts.get(0).getAccountId();
logger.info("Account id: {}", accountId);
}
if (StringUtils.isBlank(accountId)) {
logger.info("Account id is empty.");
return;
}
String clientOrderId = GUID.get();
StockOrder stockOrder = new StockOrder();
stockOrder.setClientOrderId(clientOrderId);
stockOrder.setInstrumentId("913256409");
stockOrder.setSide(OrderSide.BUY.name());
stockOrder.setTif(OrderTIF.DAY.name());
stockOrder.setOrderType(OrderType.AT_AUCTION.name());
stockOrder.setQty("1");
stockOrder.setExtendedHoursTrading(false);
OrderResponse response = apiService.placeOrder(accountId, stockOrder);
logger.info("Place order: {}", JsonSerializer.toJson(response));
}
}
Test Environment gRPC Connection:
- Python
- Java
import logging
from webullsdkcore.client import ApiClient
from webullsdktradeeventscore.events_client import EventsClient
from webullsdktrade.api import API
from webullsdkcore.common.region import Region
optional_api_endpoint = "hk-openapi.uat.webullbroker.com"
your_app_key = "10b6dd1348e0e8e977442c3efcd6fc0b"
your_app_secret = "03ce640a7752eb68bc53f908caf58892"
api_client = ApiClient(your_app_key, your_app_secret, Region.HK.value)
api_client.add_endpoint(Region.HK.value, optional_api_endpoint)
PRE_HOST = "hk-openapi-events-api.uat.webullbroker.com"
def _on_log(level, log_content):
print(logging.getLevelName(level), log_content)
if __name__ == '__main__':
api = API(api_client)
res = api.account.get_app_subscriptions()
account_id = None
if res.status_code == 200:
print('app subscriptions:', res.json())
result = res.json()
account_id = result[0]['account_id']
print("account id:", account_id)
if account_id:
client = EventsClient(your_app_key, your_app_secret, host=PRE_HOST)
client.on_log = _on_log
print("subscribe account", [account_id])
client.do_subscribe([account_id])
else:
print("account id is null")
import com.webull.openapi.common.Region;
import com.webull.openapi.http.HttpApiConfig;
import com.webull.openapi.trade.api.TradeApiService;
import com.webull.openapi.trade.api.http.TradeHttpApiService;
import com.webull.openapi.trade.api.response.Account;
import com.webull.openapi.logger.Logger;
import com.webull.openapi.logger.LoggerFactory;
import com.webull.openapi.trade.events.subscribe.EventClient;
import com.webull.openapi.trade.events.subscribe.Subscription;
import com.webull.openapi.trade.events.subscribe.message.SubscribeRequest;
import com.webull.openapi.trade.events.subscribe.message.SubscribeResponse;
import com.webull.openapi.utils.CollectionUtils;
import com.webull.openapi.utils.StringUtils;
import java.util.List;
public class GrpcApi {
private static final Logger logger = LoggerFactory.getLogger(GrpcApi.class);
private static final String appKey = "10b6dd1348e0e8e977442c3efcd6fc0b";
private static final String appSecret = "03ce640a7752eb68bc53f908caf58892";
private static final String apiEndpoint = "hk-openapi.uat.webullbroker.com";
private static final String eventHost = "hk-openapi-events-api.uat.webullbroker.com";
public static void main(String[] args) {
HttpApiConfig apiConfig = HttpApiConfig.builder()
.appKey(appKey)
.appSecret(appSecret)
.regionId(Region.hk.name())
.endpoint(apiEndpoint)
.build();
TradeApiService apiService = new TradeHttpApiService(apiConfig);
List<Account> accounts = apiService.getAccountList("");
String accountId = null;
if (CollectionUtils.isNotEmpty(accounts)) {
accountId = accounts.get(0).getAccountId();
logger.info("Account id: {}", accountId);
}
if (StringUtils.isBlank(accountId)) {
logger.info("Account id is empty.");
return;
}
try (EventClient client = EventClient.builder()
.appKey(appKey)
.appSecret(appSecret)
.host(eventHost)
.onMessage(GrpcApi::handleEventMessage)
.build()) {
SubscribeRequest request = new SubscribeRequest(accountId);
Subscription subscription = client.subscribe(request);
subscription.blockingAwait();
} catch (Exception ex) {
logger.error("Subscribe trade events error", ex);
}
}
private static void handleEventMessage(SubscribeResponse response) {
logger.info("Received trade event={}", response.getPayload());
}
}
Test Environment MQTT Connection:
- Python
- Java
from webullsdkmdata.common.category import Category
from webullsdkmdata.common.subscribe_type import SubscribeType
from webullsdkmdata.quotes.subscribe.default_client import DefaultQuotesClient
from webullsdkcore.common.region import Region
your_app_key = "10b6dd1348e0e8e977442c3efcd6fc0b"
your_app_secret = "03ce640a7752eb68bc53f908caf58892"
optional_quotes_endpoint = "hk-openapi-quotes-api.uat.webullbroker.com"
def pt_logs(client, userdata, level, buf):
print("userdata:%s, level:%s, buf:%s" % (userdata, level, buf))
def on_message(client, userdata, message):
print("Received message '" + str(message.payload) + "' on topic '"
+ message.topic + "' with QoS " + str(message.qos))
if __name__ == '__main__':
client = DefaultQuotesClient(your_app_key, your_app_secret, Region.HK.value, optional_quotes_endpoint)
client.init_default_settings('00700', Category.HK_STOCK.name, SubscribeType.SNAPSHOT.name)
client.on_log = pt_logs
client.on_message = on_message
client.connect_and_loop_forever()
import com.webull.openapi.common.dict.Category;
import com.webull.openapi.logger.Logger;
import com.webull.openapi.logger.LoggerFactory;
import com.webull.openapi.quotes.subsribe.QuotesSubsClient;
import com.webull.openapi.quotes.subsribe.message.MarketData;
import com.webull.openapi.common.dict.SubscribeType;
import com.webull.openapi.serialize.JsonSerializer;
import java.util.HashSet;
import java.util.Set;
public class MqttApi {
private static final Logger logger = LoggerFactory.getLogger(MqttApi.class);
public static void main(String[] args) {
Set<String> symbols = new HashSet<>();
symbols.add("00700");
Set<String> subTypes = new HashSet<>();
subTypes.add(SubscribeType.SNAPSHOT.name());
try (QuotesSubsClient client = QuotesSubsClient.builder()
.appKey("10b6dd1348e0e8e977442c3efcd6fc0b")
.appSecret("03ce640a7752eb68bc53f908caf58892")
.host("hk-openapi-quotes-api.uat.webullbroker.com")
.onMessage(MqttApi::handleMarketData)
.addSubscription(symbols, Category.HK_STOCK.name(), subTypes)
.build()) {
client.connectBlocking();
client.subscribeBlocking();
} catch (Exception ex) {
logger.error("Subscribe market data error", ex);
}
}
private static void handleMarketData(MarketData marketData) {
logger.info("Received market data: {}", JsonSerializer.toJson(marketData));
}
}
Other Test Accounts
App Key | App Secret |
---|---|
b6bbdf3dce431f7d309b7be25d325964 | 32b6c5aec9c9f7e965a96dc4d5ec1509 |
954d4b3b802ba2cda36c6bbe62b1c33c | 716521e2aea3a256cd5382503e97bf7e |
245b4a95a5e13f0dcdc259bad99cb456 | 513fb06c4d41998b18dd50936574e16f |
8f2da6d3beb1c1bffdc89620cfa1d38a | 05805471676bc73879556ecff0e95c0f |
10b6dd1348e0e8e977442c3efcd6fc0b | 03ce640a7752eb68bc53f908caf58892 |
Feedback and Communication
You can contact us through the Webull API service email address: webull-api@webull.hk
Official WhatsApp group