交易事件订阅
接口说明
交易事件订阅是基于gRPC实现的Server Streaming长连接,适用于通过OpenApi开发平台对接Webull客户。交易事件订阅完全遵循gRPC开源协议,您在使用时可以参考gRPC开源库。
目前接口支持订单状态变化消息推送,支持的场景类型如下:
| 场景类型 | 描述 | 
|---|---|
| PLACE_FAILED | 下单失败 | 
| MODIFY_SUCCESS | 改单成功 | 
| MODIFY_FAILED | 改单失败 | 
| CANCEL_SUCCESS | 撤单成功 | 
| CANCEL_FAILED | 撤单失败 | 
| FILLED | 部分成交 | 
| FINAL_FILLED | 全部成交 | 
交易事件订阅Proto协议定义
请求Proto
message SubscribeRequest {
    uint32 subscribeType = 1; // 订阅类型
    int64 timestamp = 2; // 时间戳
    string contentType = 3; // 内容类型
    string payload = 4; // 内容
    repeated string accounts = 5; // 账户ID
}
响应Proto
message SubscribeResponse {
    EventType eventType = 1; // 事件类型
    uint32 subscribeType = 2; // 订阅类型
    string contentType = 3; // 内容类型
    string payload = 4; // 内容
    string requestId = 5; // 请求ID
    int64 timestamp = 6; // 时间戳
}
EventType 枚举
enum EventType {
    SubscribeSuccess = 0; // 订阅成功
    Ping = 1; // 心跳信息
    AuthError = 2; // 认证错误
    NumOfConnExceed = 3; // 连接次数超出限制
    SubscribeExpired = 4; // 订阅过期
}
请求示例
- Python
 - Java
 
使用sdk请求时,subscribeType、timestamp、contentType、payload可以不用关注。只需要传入accounts即可。subscribeType目前仅支持=1。 以下案例中,_on_log方法是输出日志使用。my_on_events_message方法是接受订单状态变化消息。
import logging
from webullsdktrade.events.types import ORDER_STATUS_CHANGED, EVENT_TYPE_ORDER
from webullsdktradeeventscore.events_client import EventsClient
from webullsdkcore.common.region import Region
your_app_key = "<your_app_key>"
your_app_secret = "<your_app_secret>"
account_id = "<your_account_id>"
def _on_log(level, log_content):
    print(logging.getLevelName(level), log_content)
def my_on_events_message(event_type, subscribe_type, payload, raw_message):
    if EVENT_TYPE_ORDER == event_type and ORDER_STATUS_CHANGED == subscribe_type:
        print('----request_id:%s----' % payload['request_id'])
        print(payload['account_id'])
        print(payload['client_order_id'])
        print(payload['order_status'])
if __name__ == '__main__':
    client = EventsClient(your_app_key, your_app_secret, Region.HK.value)
    client.on_log = _on_log
    client.on_events_message = my_on_events_message
    print("subscribe account", [account_id])
    client.do_subscribe([account_id])
handleEventMessage方法接受订单状态变化消息。
import com.google.common.reflect.TypeToken;
import com.webull.openapi.common.Region;
import com.webull.openapi.example.config.Env;
import com.webull.openapi.logger.Logger;
import com.webull.openapi.logger.LoggerFactory;
import com.webull.openapi.serialize.JsonSerializer;
import com.webull.openapi.trade.events.subscribe.EventClient;
import com.webull.openapi.trade.events.subscribe.Subscription;
import com.webull.openapi.trade.events.subscribe.message.EventType;
import com.webull.openapi.trade.events.subscribe.message.SubscribeRequest;
import com.webull.openapi.trade.events.subscribe.message.SubscribeResponse;
import java.util.Map;
public class TradeEvents {
    private static final Logger logger = LoggerFactory.getLogger(TradeEvents.class);
    public static void main(String[] args) {
        try (EventClient client = EventClient.builder()
                .appKey(Env.APP_KEY)
                .appSecret(Env.APP_SECRET)
                .regionId(Region.hk.name())
                .onMessage(TradeEvents::handleEventMessage)
                .build()) {
            SubscribeRequest request = new SubscribeRequest("<your_account_id>");
            Subscription subscription = client.subscribe(request);
            subscription.blockingAwait();
        } catch (Exception ex) {
            logger.error("Subscribe trade events error", ex);
        }
    }
    private static void handleEventMessage(SubscribeResponse response) {
        if (SubscribeResponse.CONTENT_TYPE_JSON.equals(response.getContentType())) {
            Map<String, String> payload = JsonSerializer.fromJson(response.getPayload(),
                    new TypeToken<Map<String, String>>(){}.getType());
            if (EventType.Order.getCode() == response.getEventType() || EventType.Position.getCode() == response.getEventType()) {
                logger.info("----request_id:{}----", payload.get("request_id"));
                logger.info(payload.get("account_id"));
                logger.info(payload.get("client_order_id"));
                logger.info(payload.get("order_status"));
            }
        }
    }
}
订阅成功响应示列
# 连接成功
subscribeType: 1
contentType: "text/plain"
payload: "344992976"
requestId: "c1d2e05d-6984-45d8-b69f-f5b674c19a01"
timestamp: 1663667365268
# eventType:Ping消息为心调信息,无需处理。
eventType: Ping
subscribeType: 1
contentType: "text/plain"
requestId: "c1d2e05d-6984-45d8-b69f-f5b674c19a01"
timestamp: 1663667385269
# 接收订单变更消息
eventType: 1024
subscribeType: 1
contentType: "application/json"
payload: "{\"secAccountId\":18955861,\"requestId\":\"H2GIPOP8I0TPBREPCPDFDENO5B\",\"account_id\":\"MDJQ432JHNK60LFN3TO1JA83N9\",\"request_id\":\"47987108\",\"client_order_id\":\"6bf6bcfa365745a3bed44df29e00fb15\",\"instrument_id\":\"913256409\",\"order_status\":\"Cancelled\",\"symbol\":\"00700\",\"short_name\":\"TENCENT\",\"qty\":\"100.0\",\"filled_qty\":\"0.0\",\"side\":\"BUY\",\"scene_type\":\"CANCEL_SUCCESS\",\"category\":\"HK_STOCK\",\"order_type\":\"ENHANCED_LIMIT\"}"
requestId: "H2GIPOP8I0TPBREPCPDFDENO5B"
timestamp: 1663729830258
# my_on_events_message方法打印出来接收到订单变更消息
----request_id:47987108----
MDJQ432JHNK60LFN3TO1JA83N9
6bf6bcfa365745a3bed44df29e00fb15
Cancelled