快速开始
要求
- 请首先在Webull香港官网生成
app key
和app secret
。 - 编程语言版本要求:
- Python
- Java
需要安装Python 3.7或以上版本。
需要安装JDK 8或以上版本。
SDK 说明
包依赖说明
- Python
- Java
无论使用哪个产品的开发工具包,必须安装的包
webull-python-sdk-core
使用行情订阅产品,必须安装的包
webull-python-sdk-quotes-core
使用交易事件订阅产品,必须安装的包
webull-python-sdk-trade-events-core
对行情sdk的完整使用,默认需要安装的包
webull-python-sdk-core
webull-python-sdk-quotes-core
webull-python-sdk-mdata
对香港交易sdk的完整使用,默认需要安装的包
webull-python-sdk-core
webull-python-sdk-trade-events-core
webull-python-sdk-trade
对行情sdk的完整使用,必须添加的库
webull-java-sdk-quotes
使用交易事件订阅产品,必须添加的库
webull-java-sdk-trade-events
对香港交易sdk的完整使用,默认需要添加的库
webull-java-sdk-trade-events
webull-java-sdk-trade
SDK 安装
- Python
- Java
通过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配置
<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
提示
Http API地址用于普通Http请求。
交易消息推送地址用于订单状态变化等实时消息推送。
行情消息推送地址用于实时行情消息推送。
测试环境
HTTP API: hk-openapi.uat.webullbroker.com
交易消息推送: hk-openapi-events-api.uat.webullbroker.com
行情消息推送: hk-openapi-quotes-api.uat.webullbroker.com
生产环境
HTTP API: api.webull.hk
交易消息推送: events-api.webull.hk
行情消息推送: quotes-api.webull.hk
调用测试API
测试环境 App Key 和 App Secret获取方式:
首先需要在测试环境的香港官网开户,开户完成后,需要申请API,并联系Webull产品经理审核。审核通过后注册应用,并生成App Key, App Secret。 详细步骤参考API申请。
联系邮箱:webull-api@webull.hk
提示
也可以使用以下示列中的App Key和App Secret来尝试使用Webull SDK。
测试环境 HTTP请求示列:
- 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));
}
}
测试环境gRPC连接:
- 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());
}
}
测试环境MQTT连接:
- 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));
}
}
其他测试账号
App Key | App Secret |
---|---|
b6bbdf3dce431f7d309b7be25d325964 | 32b6c5aec9c9f7e965a96dc4d5ec1509 |
954d4b3b802ba2cda36c6bbe62b1c33c | 716521e2aea3a256cd5382503e97bf7e |
245b4a95a5e13f0dcdc259bad99cb456 | 513fb06c4d41998b18dd50936574e16f |
8f2da6d3beb1c1bffdc89620cfa1d38a | 05805471676bc73879556ecff0e95c0f |
10b6dd1348e0e8e977442c3efcd6fc0b | 03ce640a7752eb68bc53f908caf58892 |
反馈与沟通
可通过Webull API服务邮箱联系到我们工作人员,邮箱地址是:webull-api@webull.hk
官方WhatsApp群