量化交易项目中Python Mac虚拟环境中SSL错误的问题和websockets库的示例

最近在做一个量化交易的小项目玩,在对接交易平台API接口的时候,正常通过requests库出去的请求,没什么问题,看了下源码,是通过https请求的。

但是,我想通过websockets连接wss://连接时,出现了问题,报如下错误。

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1000)

虚拟环境版本3.12,SSL部分的配置如下(单有这个配置还不行)。

import ssl
import certifi

ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(certifi.where())

# ...

我猜测,这个配置在非虚拟环境中,应该是可以正常使用https://和wss://协议的,但是虚拟环境因为找不到证书路径的问题,会报unable to get local issuer certificate的错误。

踩了半天坑,最后在stackoverflow上,看到一位友人的配置,解决了我的问题。(因为是事后写的文章,已经很难找到原链接了。

Anyway,解决方案就是,做一个链接,终端输入以下指令。

ln -s /etc/ssl/* "/Library/Frameworks/Python.framework/Versions/3.12/etc/openssl"

不多解释了,让GPT回答:

该命令 ln -s /etc/ssl/* "/Library/Frameworks/Python.framework/Versions/3.12/etc/openssl" 在 Unix 或 Linux 系统(包括 macOS)中使用,并且执行以下操作:

  1. ln -s: 这是创建软链接(符号链接)的命令。软链接类似于 Windows 中的快捷方式,它是指向另一个文件或目录的引用。

  2. /etc/ssl/*: 这是源路径,* 表示选择 /etc/ssl 目录下的所有文件和目录。

  3. "/Library/Frameworks/Python.framework/Versions/3.12/etc/openssl": 这是目标路径,即您要创建软链接的地方。这个路径指向特定版本(在这个例子中是 3.12 版本)的 Python 安装的 openssl 目录。

以上,针对Apple Silicon, X86版本的MacOS Python可能安装位置不同,自己找到相关目录。

最后,贴上websockets库的使用示例,这个案例还挺好的,涉及到asycio的异步处理,虽然刚开始理解起来优点晦涩,但是搞懂了协程,就又进步了一个台阶。

from AccountInfo import getAccountInfo#自己的库
import sqlite3
from TradeConfig import * #自己的库
from utils import * #自己的库
import asyncio
import websockets
import json
import ssl
import certifi
import time

ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(certifi.where())

account, wssUrl = getAccountInfo(MODE)
accountAPI = "XXX"
marketDataAPI = "XXXX"

db = sqlite3.connect("Trade.db")
cursor = db.cursor()

URL = wssUrl
subscription = "xxxxxx"



async def websocket_client():
    while True:
        try:
            # 连接到WebSocket服务器
            async with websockets.connect(URL) as websocket:
                # 这里处理你的消息逻辑
                await websocket.send(json.dumps(subscription))
                while True:
                    response = await websocket.recv()
                    response = json.loads(response)
                    if "data" in response:
                        data = response["data"][0]
                        last_price = convertToInteger(data["last"])
                        ask_price = convertToInteger(data["askPx"])
                        bid_price = convertToInteger(data["bidPx"])
                        ts = int(data["ts"])
                        cursor.execute(
                            f"INSERT INTO market_price (inst_id, lastPx, askPx, bidPx, ts) VALUES ('{INSTID}', {last_price}, {ask_price}, {bid_price}, {ts})"
                        )
                        db.commit()
                        print(f"[{datetime.now()}]最新成交价:{last_price},卖一价:{ask_price},买一价:{bid_price}")
                    else:
                        print(response)

        except (websockets.ConnectionClosed, OSError) as e:
            print(f"WebSocket connection failed: {e}, retrying in 5 seconds...")
            # 等待一段时间后再次尝试连接
            time.sleep(5)


# 运行客户端
asyncio.get_event_loop().run_until_complete(websocket_client())

以上自己记录,下次碰到时,可以有地方找了。

这是我的第一篇文章,后面有些踩坑和新知识,会继续分享。

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值