【行情获取】通过WebSocket使用ws协议获取黄金、外汇实时行情(行情自动推送,方便实现数据驱动下的自动交易)


前言

一、WebSocket是什么?

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 消息操作码定义为协议的一部分。使即使服务器和客户端之间没有传输数据,也可以保持长期连接处于活动状态。

二、使用准备

1. 引入websocket-client库

websocket-client 库是一个简单好用的同步的 websocket 的客户端的库,基于回调的方式使用,开箱即用,非常的方便,其 WebSocketApp 适合于建立长期连接。在python环境下通过如下语句进行安装。

pip install websocket-client

2. 获取websocket行情数据

这里以第一黄金网为例,具体如下:
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是美元指数,AUTD是国内黄金TD,AGTD是国内白银TD。

{“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函数里写一个根据接收到的数据进行交易的策略,就可以实现数据驱动下的交易逻辑。是不是很简单呢?

此文章抛砖引玉,供大家参考。(交易有风险,入市需谨慎)

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT里的交易员

分享是一种快乐,打赏是一种肯定

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值