行情推送
目前不支持通过 Webull OpenAPI 请求行情数据,请保持关注。微牛提供了支持TCP连接和Websocket的实时行情推送服务,目前支持以下几种数据类型的实时推送。
数据类型 | 描述 |
---|---|
QUOTE | 实时摆盘 |
SNAPSHOT | 行情快照 |
TICK | 逐笔明细 |
接入实时行情推送需要经过4个步骤
1. 获取客户端Token
2. 连接微牛行情推送服务
3. 发送实时行情订阅请求
4. 监听数据响应
1. 获取客户端Token
客户端的Token用户连接微牛行情服务器的鉴权,以及订阅实时行情推送的鉴权。 获取客户端Token的方法,参考Get Token
2. 连接微牛推送服务,发送连接请求
微牛的行情推送服务器使用MQTT协议实现,客户端需要使用MQTTv3.1.1标准协议与服务端进行连接,接收数据
您可以参考标准的MQTTv3.1.1协议实现私有的MQTT客户端,也可以使用开源的支持各种编程语言的客户端库进行连接
MQTTv3.1.1协议参考:
http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html
MQTT开源连接库:
Python: https://github.com/eclipse/paho.mqtt.python
Javascrpit: http://github.com/eclipse/paho.mqtt.javascript
其他更多的编程语言: https://mqtt.org/software/
在准备好MQTT的客户端之后,通过如下地址进行连接:
微牛推送服务相关信息:
TCP Server Host: usquotes-api.webullfintech.com:8883
注:请使用TLS连接
在使用MQTT客户端连接微牛行情服务器时,请使用第一步中获取到的连接Token作为user_name和password
成功连接上微牛行情服务器后,会收到连接成功的数据包返回,如果使用的是开源的MQTT客户端,则连接成功的回调方法会被调用
3. 发送订阅/取消订阅请求
在连接微牛行情服务器成功之后,请使用订阅/取消订阅的HTTP 接口进行实时行情的订阅以及取消订阅,而不是MQTT客户端的订阅以及取消订阅
订阅实时行情推送请参考 Subscribe/ Unsubscribe
4. 监听数据响应
在第三步订阅请求成功之后,MQTT客户端的数据回调方法将会被执行,你会收到两部分数据: 一部分是数据topic;另一部分就是订阅标的的行情数据了。 其中第一部分数据为字符串,第二部分数据为protobuf序列化的二进制数据。
第一部分数据的字符串构成为: instrument_id-data_type_code-interval,比如913256135-1-1000
第二部分数据对应的protobuf数据根据data_type对应不同的protobuf协议。
data_type对应的protobuf协议定义如下:
数据类型 | 数据类型编码 | Proto协议 | 说明 |
---|---|---|---|
QUOTE | 0 | 实时摆盘Proto | 实时摆盘 |
SNAPSHOT | 1 | 行情快照Proto | 行情快照 |
TICK | 2 | 逐笔明细Proto | 逐笔明细 |
5. 行情数据Proto协议定义
基础Proto
message Basic {
string symbol = 1;
string instrument_id = 2;
string timestamp = 3;
}
实时摆盘Proto
message Quote {
Basic basic = 1;
repeated AskBid asks = 2;
repeated AskBid bids = 3;
}
message AskBid {
string price = 1;
string size = 2;
repeated Order order = 3;
repeated Broker broker = 4;
}
message Order {
string mpid = 1;
string size = 2;
}
message Broker {
string bid = 1;
string name = 2;
}
行情快照Proto
message Snapshot {
Basic basic = 1;
string trade_time = 2;
string price = 3;
string open = 4;
string high = 5;
string low = 6;
string pre_close = 7;
string volume = 8;
string change = 9;
string change_ratio = 10;
}
逐笔明细Proto
message Tick {
Basic basic = 1;
string time = 2;
string price = 3;
string volume = 4;
string side = 5;
}
请求示例
- 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 = "<your_app_key>"
your_app_secret = "<your_app_secret>"
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.US.value)
client.init_default_settings('AAPL', Category.US_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.Region;
import com.webull.openapi.common.dict.Category;
import com.webull.openapi.example.config.Env;
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 QuotesSubscribe {
private static final Logger logger = LoggerFactory.getLogger(QuotesSubscribe.class);
public static void main(String[] args) {
Set<String> symbols = new HashSet<>();
symbols.add("AAPL");
Set<String> subTypes = new HashSet<>();
subTypes.add(SubscribeType.SNAPSHOT.name());
try (QuotesSubsClient client = QuotesSubsClient.builder()
.appKey(Env.APP_KEY)
.appSecret(Env.APP_SECRET)
.regionId(Region.us.name())
.onMessage(QuotesSubscribe::handleMarketData)
.addSubscription(symbols, Category.US_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));
}
}