行情推送
微牛提供了支持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: quotes-api.webull.hk: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.HK.value)
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.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("00700");
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.hk.name())
.onMessage(QuotesSubscribe::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));
}
}