Subscribe Trade Events
Interface Description
Trade events subscription is a server streaming
persistent connection implemented based on gRPC
, which is suitable for connecting Webull customers through the OpenApi development platform. The trade events subscription fully follows the gRPC
open source protocol, and you can refer to the gRPC open source library when using it.
Currently, the interface supports order status change message push, and the supported scenarios are as follows:
Scene Type | Description |
---|---|
PLACE_FAILED | Order failed |
MODIFY_SUCCESS | Change order successfully |
MODIFY_FAILED | Change order failed |
CANCEL_SUCCESS | Cancellation succeeded |
CANCEL_FAILED | Cancellation failed |
FILLED | Partially filled |
FINAL_FILLED | All filled |
Trade events subscribe Proto protocol definition.
Request Proto
message SubscribeRequest {
uint32 subscribeType = 1; // Subscription type
int64 timestamp = 2; // Timestamp
string contentType = 3; // Content type
string payload = 4; // Content
repeated string accounts = 5; // Account ID
}
Response Proto
message SubscribeResponse {
EventType eventType = 1; // Event type
uint32 subscribeType = 2; // Subscription type
string contentType = 3; // Subscription type
string payload = 4; // Content
string requestId = 5; // Request id
int64 timestamp = 6; // Timestamp
}
EventType Enumeration
enum EventType {
SubscribeSuccess = 0; // Subscription succeeded
Ping = 1; // Heartbeat information
AuthError = 2; // Authentication error
NumOfConnExceed = 3; // Connection limit exceeded
SubscribeExpired = 4; // Subscription expired
}
Request Example
- Python
- Java
When using sdk request, subscribeType, timestamp, contentType, and payload can be ignored. Just pass in the accounts. subscribeType currently only supports =1. In the following case, the _on_log method is used to output the log. The my_on_events_message method is to receive order status change messages.
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 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'])
def _on_log(level, log_content):
print(logging.getLevelName(level), log_content)
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])
The handleEventMessage method is to receive order status change messages.
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"));
}
}
}
}
Subscription Success Response List
# Connection succeeded
subscribeType: 1
contentType: "text/plain"
payload: "344992976"
requestId: "c1d2e05d-6984-45d8-b69f-f5b674c19a01"
timestamp: 1663667365268
# eventType: Ping messages are heart-tuned messages and do not need to be processed.
eventType: Ping
subscribeType: 1
contentType: "text/plain"
requestId: "c1d2e05d-6984-45d8-b69f-f5b674c19a01"
timestamp: 1663667385269
# Receive order change messages
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
# The my_on_events_message method prints out the received message of order changes.
----request_id:47987108----
MDJQ432JHNK60LFN3TO1JA83N9
6bf6bcfa365745a3bed44df29e00fb15
Cancelled