You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python函数外无法获取closePn值问题求助

解决Binance WebSocket回调外无法获取已收盘K线收盘价的问题

核心问题本质

你的问题根源是异步回调与同步代码的执行顺序冲突,再加上变量作用域/赋值时机的问题:

  • on_message是WebSocket客户端的异步回调函数,只有当服务器推送数据时才会触发执行
  • 外部代码如果在回调触发前就读取目标变量,自然拿不到有效数值;就算回调执行过,也可能因为变量作用域(比如局部变量未正确声明为全局或类属性)导致外部无法访问

可行解决方案

方案1:全局变量+同步锁(快速实现)

用全局变量存储收盘价,同时加锁避免多线程冲突(WebSocket回调通常在单独线程执行):

import websocket
import json
from threading import Lock
import time
import threading

# 全局变量+锁,保证线程安全
latest_closed_close = None
data_lock = Lock()

def on_message(ws, message):
    global latest_closed_close
    data = json.loads(message)
    # 只处理已收盘的1小时K线(Binance用x字段标记是否收盘)
    if data['e'] == 'kline' and data['k']['x']:
        with data_lock:
            latest_closed_close = float(data['k']['c'])

def on_error(ws, error):
    print(f"错误: {error}")

def on_close(ws):
    print("WebSocket连接关闭")

def on_open(ws):
    # 订阅BTCUSDT的1小时K线推送
    ws.send('{"method": "SUBSCRIBE","params": ["btcusdt@kline_1h"],"id": 1}')

if __name__ == "__main__":
    websocket.enableTrace(False)
    ws = websocket.WebSocketApp("wss://stream.binance.com:9443/ws",
                                on_open=on_open,
                                on_message=on_message,
                                on_error=on_error,
                                on_close=on_close)
    # 启动WebSocket客户端(后台线程)
    threading.Thread(target=ws.run_forever, daemon=True).start()
    
    # 外部读取收盘价的示例(循环定期检查)
    while True:
        with data_lock:
            if latest_closed_close is not None:
                print(f"最新已收盘1小时K线收盘价: {latest_closed_close}")
        time.sleep(60)

方案2:类封装(更优雅易维护)

把WebSocket逻辑和数据存储封装到类中,用实例属性存储收盘价,避免全局变量污染:

import websocket
import json
from threading import Lock
import time
import threading

class BinanceKlineFetcher:
    def __init__(self):
        self.latest_closed_close = None
        self.data_lock = Lock()
        self.ws_client = None

    def on_message(self, ws, message):
        data = json.loads(message)
        # 过滤出已收盘的K线数据
        if data['e'] == 'kline' and data['k']['x']:
            with self.data_lock:
                self.latest_closed_close = float(data['k']['c'])

    def on_error(self, ws, error):
        print(f"连接错误: {error}")

    def on_close(self, ws):
        print("WebSocket连接已关闭")

    def on_open(self, ws):
        ws.send('{"method": "SUBSCRIBE","params": ["btcusdt@kline_1h"],"id": 1}')

    def start(self):
        self.ws_client = websocket.WebSocketApp("wss://stream.binance.com:9443/ws",
                                                on_open=self.on_open,
                                                on_message=self.on_message,
                                                on_error=self.on_error,
                                                on_close=self.on_close)
        # 后台启动WebSocket服务
        threading.Thread(target=self.ws_client.run_forever, daemon=True).start()

    def get_closed_close(self):
        with self.data_lock:
            return self.latest_closed_close

if __name__ == "__main__":
    fetcher = BinanceKlineFetcher()
    fetcher.start()
    
    # 外部循环读取已收盘收盘价
    while True:
        close_price = fetcher.get_closed_close()
        if close_price:
            print(f"已收盘1小时BTCUSDT收盘价: {close_price}")
        time.sleep(60)

关键注意事项

  • Binance的K线推送中,data['k']['x']是判断K线是否收盘的核心字段:True代表该K线已完全收盘,False代表正在运行中的K线
  • 不需要用列表或numpy数组存储单个收盘价,直接存单个数值即可,避免不必要的复杂度
  • 必须加同步锁:WebSocket回调在独立线程执行,外部读取时不加锁可能读取到未完成赋值的脏数据

内容的提问来源于stack exchange,提问作者Atila Hutter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 18:32:39