美股盘前盘后行情接入:Python 算涨跌幅的三个基准(含完整代码)

美股盘前盘后行情里,同一时刻苹果的涨跌幅可以是 +0.50%、+0.68%,也可以是 +1.18%。三个数都没算错,它们回答的是三个不同的问题。财报季,价格在盘前盘后就走完了,这道题被放大。这篇讲清每个数在回答什么,最后给行情 App 一套显示规矩和一段 Python 完整代码。

10 月 15 日傍晚,美股还在盘前。你打开两个行情 App 看苹果,一个写着 +1.18%,另一个写着 +0.68%;点进详情页,又是一行“昨日 +0.50%”。

同一个时刻,同一只股票,三个数。苹果到底涨了多少?

先给答案:三个数都没算错,它们回答的是三个不同的问题。

我当时也以为三个数里总有一个是错的,后来发现三个都没算错。

所以,哪个涨跌幅是对的,其实是个假问题。真正的问题是:你的界面想回答用户哪个问题,又有没有告诉他。

这件事接下来两周会特别要紧。奈飞 10 月 20 日盘后发财报,特斯拉和 Meta 10 月 21 日盘后,谷歌和微软 10 月 28 日,苹果 11 月 2 日盘后。财报一出,价格在盘前盘后大幅移动,三个数的差距会被拉得很开。

这篇适合谁:

  • 做美股行情 App、看板的产品经理和开发者:价格卡片、涨幅榜、价格提醒、K 线图,都会碰到这个问题;
  • 券商和资讯 App 的运营:盘后推送和涨幅榜,用的是哪个涨跌幅;
  • 晚上看美股的投资者:看懂手机上的数字到底在说什么。

不写代码的读者,读完前四部分就够了,第五部分可以直接转给技术同事。

目录

  • 一、美股盘前涨跌幅怎么算:三个数回答三个问题
  • 二、财报季为什么放大涨跌幅差异:三个证据
  • 三、国内用户对美股延长交易时段的常见误读
  • 四、行情 App 三条显示规矩
  • 五、Python 获取美股盘前盘后行情:完整可运行代码
  • 六、常见问题:涨跌幅按谁算、K 线为什么不动
  • 七、术语表
  • 参考资料

一、美股盘前涨跌幅怎么算:三个数回答三个问题

三个数都没算错,差别在现价时段和基准日。

涨跌幅是一道题:现价相对某个基准价涨了多少。选哪个价格做基准,就是在回答哪个问题。

我们平时默认,涨跌幅就是“今天涨了多少”,只有一个标准答案。A 股基本是这样,因为价格只在白天的交易时段里产生。美股不一样,一天分成盘前、常规、盘后,还有夜盘,每一段都有自己的最新价,基准也就有了不止一个选法。

拿 10 月 15 日美东 06:24(北京时间 18:24)我实测的苹果来说:

涨跌幅现价基准价回答的问题
+0.50%10 月 14 日常规收盘 342.9610 月 13 日收盘 341.27昨天一整天涨了多少
+0.68%盘前 345.28最近一次常规收盘 342.96盘前这一段又涨了多少
+1.18%盘前 345.2810 月 13 日收盘 341.27前天收盘买入拿到现在一共涨了多少

后两个数用的是同一个现价,差别全在基准:一个用昨天的收盘,一个用前天的收盘。

那 +1.18% 这个数,是怎么跑到“今日涨跌”的位置上的?

问题出在前收(前一个交易日的收盘价)的切换时点。我一开始也没注意到这个细节,后来在 10 月 15 日开盘前后各取了一次:开盘前,主报价里的前收还是前天的 341.27;开盘后,它才切成 342.96。盘前盘后的报价,一直按 342.96 算。

也就是说,在美股常规时段开盘前这几个小时里,主报价的前收还停在前天。如果代码在盘前直接拿它去算盘前价的涨跌,就会得到 +1.18%,等于把昨天已经涨过的 0.50%,又算进了“今天”。

推到这里,结论就清楚了:一个涨跌幅能不能用,要看它旁边说不说得出两件事——现价是哪一段的,基准是哪天的收盘。说不出来,用户就会拿一个回答“前天买到现在”的数,去判断“今天盘前涨了多少”。

平时盘前盘后波动小,三个数差不多,没人在意。财报季就不一样了。

美股一天时段时间线(美东时间)

04:00 ── 09:30  盘前(延长交易时段)
09:30 ── 16:00  常规时段
16:00 ── 20:00  盘后(延长交易时段)
20:00 ── 次日 04:00  夜盘(延长交易时段)

关键:K 线通常只覆盖 09:30–16:00 的常规时段。


二、财报季为什么放大涨跌幅差异:三个证据

价格在盘前盘后走完,K 线却看不到,选错基准的代价被放大。

财报季里,价格在盘后和盘前就大幅移动,三个数的差距被拉开,选错基准的代价也跟着变大。

为什么偏偏是盘外?因为美股公司习惯在常规时段之外发布财报。交易所长期以来给上市公司的建议是:收盘后发布重大消息,至少等到 16:01 之后,最好是 16:05(纳斯达克),或者 16:15(纽交所)。奈飞、特斯拉、苹果都选了盘后,摩根大通选了盘前。财报的第一轮反应,几乎都落在盘外。

证据一:跌幅在开盘前就走完了

台积电 10 月 15 日开财报会。当天美股开盘 415.10,比前一天收盘 430 低了 3.5%。但这 3.5% 不是开盘那一刻跌出来的:前一晚盘后 422.55,夜盘 422.05,开盘前的最后一笔盘前价是 415.12,几乎就是开盘价。

可 K 线只含常规时段。我同一时刻查苹果也是这样:盘前已经在交易,1 分钟 K 线的最后一根还停在前一天 15:59。所以日 K 上只剩一个缺口,盘后到盘前这段下跌,在 K 线里看不到。用户盯着价格卡片看它一直在动,再看 K 线一动不动,第一反应是 App 卡了。

证据二:盘外的最新价,是几笔成交定出来的

以苹果 10 月 14 日为例:

时段成交量
盘后382.8 万股
夜盘9.8 万股
常规时段5,006 万股

盘后和夜盘加起来,还不到常规时段的一成。成交少,几笔单子就能把价格带走。

美国证监会在给投资者的公告里,把这一点列为延长时段的主要风险:交易兴趣少、价差更宽、波动更大,延长时段的价格“可能和常规时段的价格不一致”,包括第二天的开盘价。

证据三:开盘时的方向,不一定撑到收盘

摩根大通 10 月 13 日盘前发财报,开盘 339.97,比前收 334.30 高 1.7%;收盘却是 331.43,跌了 0.86%。

如果 App 在开盘时推送“摩根大通高开 1.7%”,到了收盘,用户看到的是另一回事。一家券商的投资者教育页面说得很直接:盘前盘后“价格对新闻的反应可能被夸大,往往在常规市场开盘后出现反转”。

三个证据放在一起看:财报季的盘前盘后涨跌,是少数人在稀薄成交里给出的临时答案。界面要把“这是哪一段、成交有多少”一起告诉用户,而不是只甩出一个百分比。

对国内用户来说,还有一层麻烦:他们心里的“盘后”,和美股的“盘后”不是一回事。


三、国内用户对美股延长交易时段的常见误读

A 股收盘后价格定死,美股盘前盘后价格还在变。

国内用户熟悉的“盘后”,价格是定死的;美股的盘后,价格一直在变。

A 股收盘后的固定价格交易在 15:05–15:30,按当天收盘价成交。今年 7 月 6 日起,这种方式从科创板、创业板扩大到全部 A 股和沪深 ETF。港股的收市竞价在 16:01–16:10,系统在 16:08 到 16:10 之间随机收市,竞价定出收盘价。这两个市场的“盘后”,说到底都是在收盘价这个点上成交,价格不会再跑。

美股完全不同。盘后 16:00–20:00 是连续交易,之后还有 20:00 到次日 04:00 的夜盘,价格随着每一笔成交刷新。

于是就有了一个很常见的误读:国内用户看到美股“盘后涨 1%”,按 A 股的经验理解成“今天已经定了,明天开盘就是这个价”。可这 1% 只是盘后稀薄成交给出的临时价,第二天开盘完全可能变样,摩根大通就是例子。

海外券商是怎么处理的?Robinhood 的帮助中心写明,盘后显示的涨跌,是当前价和常规时段收盘价之差。也就是第一部分里 +0.68% 的算法:先说清是“盘后这一段”,再说相对哪个收盘。

所以,跨市场 App 不能用一个“盘后”标签管三个市场。A 股的盘后、港股的收市竞价、美股的盘后和夜盘,要按市场分开标,否则用户会拿一个还在变的价格,去做一个以为已经定死的判断。

把前面三部分落到界面上,就是下面三条规矩。


四、行情 App 三条显示规矩

标时段、标基准、量和提醒单独处理。

规矩一:标时段

主价按当前时段选,旁边写“盘前 06:24 美东”这样的时段和时间。用户一眼就知道这是哪一段的价格,而不是一个笼统的“最新价”。

规矩二:标基准

盘前、盘后、夜盘的涨跌,统一对比最近一次常规收盘;常规时段的涨跌单独一行,写明是哪一天的。不要在盘前直接拿主报价里的前收来算,+1.18% 就是这么来的。

规矩三:量和提醒单独处理

盘后和夜盘的成交量单独显示,不和常规时段加在一起。第二部分说过,盘后和夜盘的量加起来不到常规时段的一成。盘外触发的价格提醒,写明“盘后成交,流动性低”,或者默认只在常规时段推送。否则用户凌晨收到一条“苹果涨超 1%”,以为是确定的信号,其实只是几笔成交。

还有一处顺手要改:财报时间。按美东时间存,显示给国内用户时按时区名换算成北京时间,不要写死时差。美国 11 月 1 日结束夏令时,之后美东 16:00 从北京时间 04:00 变成 05:00,苹果 11 月 2 日盘后的财报,对国内用户是 11 月 3 日早上 5 点。

价格卡片决策流程(文字版)

取快照
  ↓
判断哪一段的时间最新
  ↓
常规时段? → 用主报价 prev_close
  ↓
盘前/盘后/夜盘? → 用该段自己的 prev_close
  ↓
显示主价 + 时段 + 美东时间
  ↓
其他时段涨跌另起一行,标清基准日

App 各模块修改清单

模块用户原来会看到什么改成什么
价格卡片一个“最新价”,不知道是哪段主价按时段选,标时段和美东时间
涨跌幅、涨幅榜盘前显示 +1.18%,和别家对不上盘外对比最近收盘;常规涨跌另起一行写日期
K 线图价格在动,K 线不动图上加一条“最新盘后价”参考线
成交量盘外的量混进全天盘后、夜盘的量单独显示
价格提醒半夜误报盘外提醒标注流动性低,或只在常规时段推送
财报日历冬令时后差一小时按时区名换算,标明盘前还是盘后

读法:前两行管“显示哪个数”,后四行管“什么时候、怎么提示”。数据来自 10 月 13 日至 15 日的实测。


五、Python 获取美股盘前盘后行情:完整可运行代码

一次快照返回四段报价,按最新时段选主价。

TickDB 为开发者和 AI 应用提供统一的全球行情数据接口,让团队通过一套接入获取多市场实时与历史数据,更快构建行情、分析和监控产品。

文中的价格和时间,来自它的美股快照:一次请求同时返回常规、盘前、盘后、夜盘四段报价,每段带价格、时间、成交量和自己的前收(pre_market_quote、post_market_quote、overnight_quote)。三条规矩需要的数据,都在这一次返回里。

5.1 快照返回什么

    {
      "code": 0,
      "message": "success",
      "data": [
        {
          "symbol": "AAPL.US",
          "last_price": "342.96",
          "prev_close": "341.27",
          "timestamp": 1792008001000,
          "pre_market_quote":  {"last_done": "345.28", "prev_close": "342.96", "timestamp": 1792059840000, "volume": "126868"},
          "post_market_quote": {"last_done": "345.00", "prev_close": "342.96", "timestamp": 1792022397000, "volume": "3827539"},
          "overnight_quote":   {"last_done": "345.75", "prev_close": "342.96", "timestamp": 1792051199000, "volume": "97619"}
        }
      ]
    }

说明(节选,省略了其他字段;10 月 15 日美东 06:24 实测):

  • 判断成功看 code 是否为 0,不要只看 HTTP 200;
  • 价格和成交量都是字符串,计算前转成 Decimal,不要直接转 float;
  • timestamp 是毫秒;
  • 主报价的 prev_close(341.27)和三个延长时段对象的 prev_close(342.96)不一样,这就是 +1.18% 的来源。

下面这段代码用 TickDB 的 /v1/market/ticker 接口拉取快照,按时间最新的一段选主价,涨跌对比各段自己的前收,并标出美东时间:

# 测试环境:Python 3.11 / 2026-10-16(用 10/15 两次真实快照验证)
# 用途:美股行情卡片按“当前时段”选主价,并标清时段、时间和涨跌基准
import os
from datetime import datetime
from decimal import Decimal
from zoneinfo import ZoneInfo

import requests

ET = ZoneInfo("America/New_York")
EXTENDED = {"pre_market_quote": "盘前", "post_market_quote": "盘后", "overnight_quote": "夜盘"}

def get_quote(symbol):
    r = requests.get("https://api.tickdb.ai/v1/market/ticker", params={"symbols": symbol},
                     headers={"X-API-Key": os.environ["TICKDB_API_KEY"]}, timeout=10)  # Key 只放服务端
    body = r.json()
    if body.get("code") != 0:
        raise RuntimeError(body.get("message"))
    return body["data"][0]

def pct(last, base):
    return (Decimal(str(last)) - Decimal(str(base))) / Decimal(str(base)) * 100

def price_card(q):
    # 常规时段:对比主报价自己的前收(开盘时才切到最近一个收盘)
    rows = [("常规", q["last_price"], int(q["timestamp"]), pct(q["last_price"], q["prev_close"]))]
    # 盘前/盘后/夜盘:对比对象里的 prev_close,即最近一个常规收盘
    for key, name in EXTENDED.items():
        s = q.get(key)
        if s:
            rows.append((name, s["last_done"], int(s["timestamp"]), pct(s["last_done"], s["prev_close"])))
    main = max(rows, key=lambda r: r[2])                      # 时间最新的一段做主价
    fmt = lambda r: f"{r[0]} {r[1]}  {r[3]:+.2f}%  {datetime.fromtimestamp(r[2] / 1000, ET):%m-%d %H:%M} 美东"
    return {"main": fmt(main), "others": [fmt(r) for r in rows if r is not main]}

if __name__ == "__main__":
    print(price_card(get_quote("AAPL.US")))

设置环境变量 TICKDB_API_KEY 后运行,Key 只放在服务端。用 10 月 15 日 06:24 的快照跑,主价输出“盘前 345.28 +0.68% 10-15 06:24 美东”,正是第一部分里回答“盘前这一段涨了多少”的那个数。

5.2 边界情况

  • 盘后对象会保留到下一次盘后开始(约 24 小时)。第二天常规时段里仍能查到前一晚的盘后价,所以选主价要比较时间戳,不能只看“有没有这个字段”。代码里的 max(rows, key=时间戳) 就是为此。
  • 节假日和半日市:交易时段要从接口或交易所日历读,不要写死 09:30–16:00。
  • 夜盘对象的时间戳可能落在时段结束的时刻(如 03:59:59),显示“夜盘收盘价”比显示具体分钟更稳。

六、常见问题:涨跌幅按谁算、K 线为什么不动

Q2:为什么盘前显示的涨跌幅和别家 App 对不上?

A:常见原因是基准不同。有的用最近一次常规收盘,有的用主报价里尚未切换的前收。盘前直接拿主报价前收算,就会把昨天已经涨过的部分又算进“今天”。

Q3:价格在动,K 线为什么不动?

A:K 线通常只含常规时段。盘前已经在交易,但 1 分钟 K 线最后一根可能还停在前一天 15:59。界面可以加一条“最新盘后价”参考线,避免用户以为 App 卡了。

Q4:盘后和夜盘的成交量要不要并进全天?

A:建议单独显示。盘后和夜盘成交少,几笔单子就能带走价格,混进全天会误导流动性判断。

Q5:财报日历怎么处理时区?

A:按美东时间存,显示给国内用户时按时区名换算,不要写死时差。冬令时切换后,美东 16:00 对应的北京时间会变。

Q6:财报时间的时区换算怎么写?

    from datetime import datetime, timezone
    from zoneinfo import ZoneInfo

    release_utc = datetime(2026, 11, 2, 21, 0, tzinfo=timezone.utc)   # 财报日历给的 UTC 时间
    print(release_utc.astimezone(ZoneInfo("America/New_York")))  # 2026-11-02 16:00:00-05:00
    print(release_utc.astimezone(ZoneInfo("Asia/Shanghai")))     # 2026-11-03 05:00:00+08:00

按时区名换算,夏令时切换由时区库处理,不要写死 +12 或 +13。


七、术语表

术语定义
前收前一个交易日的收盘价
常规时段美股 09:30–16:00 美东时间
盘前常规时段前,04:00–09:30 美东时间
盘后常规时段后,16:00–20:00 美东时间
夜盘20:00–次日 04:00 美东时间
pre_market_quote盘前报价对象
post_market_quote盘后报价对象
overnight_quote夜盘报价对象

涨跌幅本身不会错,错的是不告诉用户它在回答什么。三个数可以同时出现在一个界面上,只要每个数旁边写清楚:现价是哪一段的,基准是哪天的收盘。

我后来发现,问题不在涨跌幅本身,而在界面有没有说清它回答的是哪个问题。

今晚美股收盘后,打开你们 App 的苹果页面看一眼:价格旁边有没有写时段,涨跌幅跟谁比。


参考资料

访问日期均为 2026 年 10 月 16 日。

  1. 美国证券交易委员会(SEC)投资者教育办公室,《Extended-Hours Trading: Investor Bulletin》,2022 年 6 月 6 日。
  2. Robinhood 帮助中心,《Robinhood 24 Hour Market》《Extended-hours trading》。
  3. moomoo(富途旗下)投资者教育,《盘前交易与盘后交易》。
  4. 央视新闻客户端,《A 股交易规则三大修订今起落地执行》(标题有删节),2026 年 7 月 6 日(扬子晚报网转载)。
  5. 中信证券(香港),《收市竞价交易时段》服务说明。
  6. Davis Polk,《Nasdaq and NYSE Reminders on Material News Announcements》,2015 年 11 月 3 日。
  7. 台积电投资者关系,季度业绩发布日程。
  8. The Old Farmer's Almanac,《Daylight Saving Time Ends》。
  9. 苹果、台积电、摩根大通的价格、成交量、K 线与财报日历:TickDB 实测,2026 年 10 月 13 日至 15 日。
0
0
0
0
评论
未登录
暂无评论