Subscribe Position Events
Interface Description
Subscribe to position lifecycle event notifications for subscribed accounts. Each notification provides the instrument identifier and related contract details for the lifecycle event. subscribeType only supports = 4. Event settlement messages require the latest SDK version.
Position events subscribe Proto protocol definition.
Request Proto
message SubscribeRequest {
uint32 subscribeType = 4; // 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 = 4; // 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
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 webull.trade.events.types import EVENT_TYPE_POSITION, POSITION_STATUS_CHANGED
from webull.trade.trade_events_client import TradeEventsClient
your_app_key = "<your_app_key>"
your_app_secret = "<your_app_secret>"
account_id = "<your_account_id>"
region_id = "us"
# PRD env host: events-api.webull.com
# Test env host: us-openapi-alb.uat.webullbroker.com
optional_api_endpoint = "<event_api_endpoint>"
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)
if EVENT_TYPE_POSITION == event_type and POSITION_STATUS_CHANGED == subscribe_type:
print('event payload:%s' % payload)
if EVENT_TYPE_OPTION == event_type and OPTION_STATUS_CHANGED == subscribe_type:
print('option payload:%s' % payload)
if __name__ == '__main__':
# Create EventsClient instance
trade_events_client = TradeEventsClient(your_app_key, your_app_secret, region_id)
# For non production environment, you need to set the domain name of the subscription service through eventsclient. For example, the domain name of the UAT environment is set here
# trade_events_client = TradeEventsClient(your_app_key, your_app_secret, region_id, host=optional_api_endpoint)
trade_events_client.on_log = _on_log
# Set the callback function when the event data is received.
# The data of order status change is printed here
trade_events_client.on_events_message = my_on_events_message
# Set the account ID to be subscribed and initiate the subscription. This method is synchronous
trade_events_client.do_subscribe([account_id])
The handleEventMessage method is to receive order status change messages.
import com.google.gson.reflect.TypeToken;
import com.webull.openapi.core.execption.ClientException;
import com.webull.openapi.core.execption.ServerException;
import com.webull.openapi.core.logger.Logger;
import com.webull.openapi.core.logger.LoggerFactory;
import com.webull.openapi.core.serialize.JsonSerializer;
import com.webull.openapi.samples.config.Env;
import com.webull.openapi.trade.events.subscribe.ISubscription;
import com.webull.openapi.trade.events.subscribe.ITradeEventClient;
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 TradeEventsClient {
private static final Logger logger = LoggerFactory.getLogger(TradeEventsClient.class);
public static void main(String[] args) {
try (ITradeEventClient client = ITradeEventClient.builder()
.appKey(Env.APP_KEY)
.appSecret(Env.APP_SECRET)
.regionId(Env.REGION_ID)
// .host("<event_api_endpoint>")
.onMessage(TradeEventsClient::handleEventMessage)
.build()) {
SubscribeRequest request = new SubscribeRequest("<your_account_id>");
ISubscription subscription = client.subscribe(request);
subscription.blockingAwait();
} catch (ClientException ex) {
logger.error("Client error", ex);
} catch (ServerException ex) {
logger.error("Sever error", ex);
} catch (Exception ex) {
logger.error("Unknown 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.Position.getCode() == response.getEventType()) {
logger.info("{}", payload);
}
}
}
}
Response Example
Position event scene type
- OPTION EXERCISE
- OPTION EXPIRATION
{
"account_id": "1276674499001173504",
"position_id": "037SDSML6O6DT0KHK6R4000000",
"quantity": "5",
"symbol": "AAPL261120C00305000",
"instrument_type": "OPTION",
"market": "US",
"status": "exercised",
"biz_type": "OPTION_EXERCISE"
}
DEBUG response:eventType: Ping
subscribeType: 4
contentType: "text/plain"
requestId: "ab39b532-3ad4-46c4-823d-3dff12e0f1b9"
timestamp: 1768994319673
{
"account_id": "1276674499001173504",
"position_id": "037SES739C6DT0KHJT90000000",
"quantity": "5",
"symbol": "AAPL261120C00315000",
"instrument_type": "OPTION",
"market": "US",
"status": "expired",
"biz_type": "OPTION_EXPIRATION"
}
DEBUG response:eventType: Ping
subscribeType: 4
contentType: "text/plain"
requestId: "ab39b532-3ad4-46c4-823d-3dff12e0f1b9"
timestamp: 1768994319673