WebSocket是一种基于TCP协议的全双工通信协议,它通过在客户端和服务器之间建立一个持久性的连接,实现了实时数据传输的功能。在WebSocket协议中,客户端和服务器通过HTTP协议进行握手,然后建立一个长连接,之后双方可以通过这个连接进行实时的数据传输。
WebSocket的URL格式和HTTP协议类似,只是将http或https协议改为了ws或wss协议。其中,ws协议是基于明文传输的,而wss协议是基于SSL/TLS加密传输的。
WS和WSS有什么区别呢?
WS(WebSocket )任何人只要知道你的IP和端口都可以去连接通讯。
WSS(Web Socket Secure)是WebSocket的加密版本。
使用Python中的socket库可以实现WebSocket的通信。在使用Python实现WebSocket时,需要先建立一个TCP连接,然后进行WebSocket握手,最后通过这个连接进行数据传输。
ping 和 pong
WebSocket 规范将 ping 和 pong 消息操作码定义为协议的一部分。使即使服务器和客户端之间没有传输数据,也可以保持长期连接处于活动状态。
websocket-client 库是一个简单好用的同步的 websocket 的客户端的库,基于回调的方式使用,开箱即用,非常的方便,其 WebSocketApp 适合于建立长期连接。在python环境下通过如下语句进行安装。
pip install websocket-client
这里以第一黄金网为例,具体如下:
2.1 获取ws或wss地址
使用浏览器打开http://www.dyhjw.com/quotes/choicelists,然后按F12进入开发者调试工具,再按F5刷新页面,切换Headers页面,复制Request URL备用。
2.2 查看订阅过程
切换到Messages页面,再按F5刷新可以看到如下页面
{“cmd”:“sub”,“codes”:[“XAU”,“XAG”,“USD”,“CONC”,“AUTD”,“AGTD”,“GLNC”,“SLNC”]}
{“C”:“XAU”,“EXC”:“WGJS”,“T”:1678684466,“TS”:“2023-03-13
13:14:26”,“P”:1881.12,“L”:1872.06,“H”:1894.11,“O”:1874.2,“BUY”:1881.12,“LC”:1866.67,“Sell”:1881.46,“V”:0,“ZD”:14.45,“ZDF”:0.77}
切换到其它行情页面,相同的方法可以获得订阅内容,比如USDCNY等外汇行情。
在这个示例代码中,我们首先定义了四个回调函数:on_message、on_error、on_close和on_open。当WebSocket接收到消息时,会调用on_message函数,我们在这个函数中解析消息数据,并打印出行情数据;当WebSocket出现错误时,会调用on_error函数,我们在这个函数中打印出错误信息;当WebSocket关闭时,会调用on_close函数,我们在这个函数中打印出关闭信息,并通过再次执行main()实现再次循环;当WebSocket建立连接时,会调用on_open函数,我们在这个函数中发送一个订阅请求,订阅XAU/USD的行情数据。
接着,我们使用websocket.WebSocketApp函数创建了一个WebSocket应用,指定了WebSocket服务器的URL、回调函数等参数,然后调用run_forever函数启动WebSocket连接。当WebSocket连接成功后,我们会不断地收到第一黄金网的行情数据,并在控制台上打印出来。具体代码如下:
# -*- coding:UTF-8 -*-
"""
pip install websocket-client
抓取第一黄金网的行情数据:
http://www.dyhjw.com/quotes/choicelists
{"cmd":"sub","codes":["XAU","XAG","USD","CONC","AUTD","AGTD","GLNC","SLNC"]}
{"cmd":"sub","codes":["XAU","XAG","USD","CONC","AUTD","AGTD","AU9999","MAUTD","GT","TWGD"]}
{"cmd":"sub","codes":["XAU","XAG","USD","CONC","AUTD","GLNC","SLNC","XPD","HGCC"]}
{"cmd":"sub","codes":["XAU","XAG","USD","CONC","AUTD","HONC","NGNC","RBNC"]}
{"cmd":"sub","codes":["XAU","XAG","USD","CONC","AUTD","USDCNY","USDCNH","USDJPY","EURUSD","GBPUSD","AUDUSD","USDCAD","USDCHF","USDDKK","USDHUF","USDMXN","USDNOK","USDSEK","USDSGD","USDZAR","NZDUSD"]}
{"C":"XAU","EXC":"WGJS","T":1678684466,"TS":"2023-03-13 13:14:26","P":1881.12,"L":1872.06,"H":1894.11,"O":1874.2,"BUY":1881.12,"LC":1866.67,"Sell":1881.46,"V":0,"ZD":14.45,"ZDF":0.77}
"""
import websocket,json
# socket访问地址:
socket_add='wss://ws.dyhjw.com/?token='
# 初始化价格
old_ask = 0
def on_message(ws, message):
# 服务器有数据更新时,主动推送过来的数据
# print(message)
data = json.loads(message)
# 数据那么多,我只取一瓢饮。只要XAU的时间和价格,当然也可以只订阅一个代码。
if type(data) is dict:
name = data['C']
if name == "XAU":
ts = data['TS']
ask = data['P']
#print('C:', name,'TS:', ts,'P:', ask)
global old_ask
old_ask = wait_update(old_ask,ask,ts)
def on_error(ws, error):
# 程序报错时,就会触发on_error事件
print(error)
def on_close(ws):
# 链接断开了就再运行main函数,相当于自动重启。
print("Connection closed ……")
print("reConnecting ……")
main()
def on_open(ws):
# 连接到服务器之后就会触发on_open事件,这里用于send数据
req = '{"cmd":"sub", "codes":["AUTD","XAU"]}'
# req = '{"cmd":"sub","codes":["XAU","XAG","USD","CONC","AUTD","AGTD","AU9999","MAUTD","GT","TWGD"]}'
print(req)
ws.send(req)
def wait_update(old_ask,new_ask,ts):
if old_ask != new_ask:
print(f"Quote is updated\n前值:{old_ask},最新值:{new_ask},时间:{ts}")
old_ask = new_ask
return old_ask
else:
return old_ask
def main(address=socket_add):
websocket.enableTrace(True)
ws = websocket.WebSocketApp(address,
on_message=on_message,
on_error=on_error,
on_close=on_close)
ws.on_open = on_open
ws.run_forever(ping_interval=60,ping_timeout=30)
if __name__ == "__main__":
main()
一般我们使用爬虫爬取行情数据,爬取过程中会需要解析页面,解析过程慢不说还不能直接获取信息,就算是调用js可直接获取行情数据,也无法实现数据驱动(多为时间驱动,通过while循环获取数据),获取行情又慢有难使用。
如果网站有提供websocket接口,我们就可以使用如上方法,快速获取行情,高效且稳定。如果要实现数据驱动的交易策略,我们在on_message函数里写一个根据接收到的数据进行交易的策略,就可以实现数据驱动下的交易逻辑。是不是很简单呢?
此文章抛砖引玉,供大家参考。(交易有风险,入市需谨慎)