对于关注美股市场的投资者来说,夜盘交易数据至关重要。北京时间白天正是美国股市的夜盘时段,之前我的“半自动套利”程序都是使用盈透来免费获取这些数据的,今天借了一个香港朋友的富途账号来测试它的API获取美股夜盘(Overnight)实时行情数据。
起因是之前群里发了这个:
OpenD是富途提供的行情数据服务程序,是使用富途API的基础。它提供可视化和命令行两种运行方式,本文介绍操作简单的可视化版本。
# Windows系统
pip install futu-api
# Linux/Mac系统
pip3 install futu-api
默认情况下,富途API只返回美股常规交易时段(美东时间9:30-16:00)的数据。要获取夜盘数据,需要在订阅时设置 session=Session.ALL。
from futu import *
import pandas as pd
# 创建行情对象
quote_ctx = OpenQuoteContext(host='127.0.0.1', port=11111)
# 订阅美股,session设为ALL以获取夜盘数据
ret, data = quote_ctx.subscribe(
code_list=['US.XOP'], # 标普油气开采指数ETF
subtype_list=[SubType.QUOTE],
session=Session.ALL # 关键:ALL=24小时含夜盘
)
if ret == 0:
print("✅ 订阅成功")
# 获取包含夜盘字段的行情数据
ret, data = quote_ctx.get_stock_quote(['US.XOP'])
if ret == 0:
quote = data.iloc[0]
print("\n📊 美股 ETF XOP 实时行情")
print(f"数据时间:{quote['data_date']} {quote['data_time']}")
print("\n【常规盘数据】")
print(f"最新价:{quote['last_price']}")
print(f"开盘价:{quote['open_price']}")
print(f"最高价:{quote['high_price']}")
print(f"最低价:{quote['low_price']}")
print("\n【夜盘数据 (Overnight)】")
print(f"夜盘现价:{quote['overnight_price']}")
print(f"夜盘最高:{quote['overnight_high_price']}")
print(f"夜盘最低:{quote['overnight_low_price']}")
print(f"夜盘成交量:{quote['overnight_volume']}")
print(f"夜盘涨跌幅:{quote['overnight_change_rate']}%")
else:
print(f"❌ 获取行情失败:{data}")
else:
print(f"❌ 订阅失败:{data}")
# 关闭连接
quote_ctx.close()
OpenQuoteContext(host='127.0.0.1', port=11111) 建立与OpenD的连接subscribe() 方法订阅股票,设置 session=Session.ALLget_stock_quote() 获取包含夜盘字段的实时数据overnight_price:夜盘现价overnight_high_price:夜盘最高价overnight_low_price:夜盘最低价overnight_volume:夜盘成交量overnight_change_rate:夜盘涨跌幅运行上述代码,看到类似以下的输出:
✅ 订阅成功
📊 美股 ETF XOP 实时行情
数据时间:2026-05-11 11:18:15
【常规盘数据】
最新价:165.16
开盘价:165.47
最高价:167.19
最低价:163.82
【夜盘数据 (Overnight)】
夜盘现价:167.77
夜盘最高:167.81
夜盘最低:164.36
夜盘成交量:12966
夜盘涨跌幅:1.58%
有了这个作为基础,看看能不能将富途夜盘数据接入到半自动交易那套程序里面呢?
之前主要依赖盈透证券(IB)提供夜盘数据,实际手动操作是也经常看看富途APP的行情,为了多一种选择,就把富途OpenD的夜盘接口也接进来看看。
富途其实提供了非常完善的 Python SDK (futu-api),如果只是写个脚本跑一次,几行代码就能搞定:
quote_ctx = OpenQuoteContext(host='127.0.0.1', port=11111)
quote_ctx.subscribe(['US.XOP'], [SubType.QUOTE], session=Session.ALL)
但真实的程序运行不是这么简单,程序的前端沙盘需要每 5 秒轮询一次价格,如果不做特殊处理,每次请求都去 OpenQuoteContext 创建连接,富途的本地网关瞬间就会被数百个 TCP 连接打爆(连接数耗尽报错)。
AI帮助在底层架构上动了点“小手术”。
1)长连接池驻留与“防爆”机制 (Connection Pool & Anti-flood) 为了应对高频轮询,摒弃了“随用随连”的业余做法,设计了一个名为 FutuReader 的全局长连接池。
在进程初始化时,只建立唯一的一个 OpenQuoteContext 上下文,将其常驻内存。前端无论多少个客户端、每秒发起多少次轮询,后端的 FutuReader 都在内存中 O(1) 极速返回已缓存的数据。
更巧妙的是防爆重连机制:
# 限制重连频率,避免富途OpenD未启动时狂刷错误日志
if self.ctx is None:
if time.time() - self.last_connect_time < 10:
return False, "富途OpenD未连接 (等待重连...)", self.prices
self.last_connect_time = time.time()
self.ctx = OpenQuoteContext(host='127.0.0.1', port=11111)
如果用户的富途客户端意外关闭,程序不会陷入死循环疯狂报错,而是优雅地进入 10 秒冷却期(Cool-down),等待服务恢复,彻底杜绝了 CPU 满载和终端刷屏。
2)克制的控制台心跳输出 (Heartbeat Logging) 我们既希望知道后台系统在正常拉取数据,又不希望海量的日志把终端淹没。在代码中加入了一个极其轻量级的心跳节流阀:
current_time = time.time()
if current_time - self.last_log_time >= 30:
if self.prices:
price_strs = [f"{k}=${v['bid']:.2f}" for k, v in self.prices.items()]
print(f"🦉 [富途OpenD] 实时夜盘: {', '.join(price_strs)}")
self.last_log_time = current_time
在保证每秒处理成百上千次数据更新的同时,只在每 30 秒向终端吐出一次汇总心跳 🦉 [富途OpenD] 实时夜盘: GLD=$210.50, USO=$75.30...。既方便了监控系统存活状态,又保持了极简的极客美学。
z现在的主面板的夜盘数据区 多了富途的数据展示,实际计算还是用的盈透数据,先观察一小段时间看看。
