---
title: "我用長橋 API 給 QQQ 0DTE 策略做回測，差點被數據騙了"
type: "Topics"
locale: "zh-HK"
url: "https://longbridge.com/zh-HK/topics/40033165.md"
description: "做量化交易的人都聽過一句話：策略好不好，回測説了算。但沒人告訴你的是——回測本身就會坑你。數據拿錯了、信號過濾太嚴了、參數看起來漂亮但實盤一塌糊塗……這些都是真實發生在我身上的事。這篇文章記錄我用長橋 API 對 QQQ 0DTE 衰竭反轉策略做回測時，踩過的每一個坑。如果你也在用長橋做美股策略回測，希望這些經驗能幫你少走彎路。坑 1：yfinance 不靠譜..."
datetime: "2026-04-20T08:06:51.000Z"
locales:
  - [en](https://longbridge.com/en/topics/40033165.md)
  - [zh-CN](https://longbridge.com/zh-CN/topics/40033165.md)
  - [zh-HK](https://longbridge.com/zh-HK/topics/40033165.md)
author: "[热血青年](https://longbridge.com/zh-HK/profiles/17928542.md)"
---

# 我用長橋 API 給 QQQ 0DTE 策略做回測，差點被數據騙了

做量化交易的人都聽過一句話：**策略好不好，回測説了算。**

但沒人告訴你的是——回測本身就會坑你。數據拿錯了、信號過濾太嚴了、參數看起來漂亮但實盤一塌糊塗……這些都是真實發生在我身上的事。

這篇文章記錄我用長橋 API 對 QQQ 0DTE 衰竭反轉策略做回測時，踩過的每一個坑。如果你也在用長橋做美股策略回測，希望這些經驗能幫你少走彎路。

* * *

## 坑 1：yfinance 不靠譜，長橋 API 才是正道

一開始我用 `yfinance` 下載歷史數據，想着免費就行。結果：

-   頻繁被限流（429 Too Many Requests）
-   1 分鐘數據只能拿最近 30 天
-   數據質量參差不齊，偶有缺失

**換了長橋 API 之後**，通過 `history_candlesticks_by_date()` 可以按天拉取 1 分鐘 K 線，每天約 241 根（Basic 級別，僅正式盤），Premium 級別含盤前盤後約 960 根。

`from longport.openapi import Config, QuoteContext, Period, AdjustType, TradeSessions from datetime import date, timedelta ctx = QuoteContext(Config.from_apikey_env()) # 按天下载，精确控制范围 candles = ctx.history_candlesticks_by_date(    symbol="QQQ.US",    period=Period.Min_1,    adjust_type=AdjustType.ForwardAdjust,    start=date(2026, 4, 14),    end=date(2026, 4, 15),    # 注意：end 不包含这一天    trade_sessions=TradeSessions.All ) print(f"获取到 {len(candles)} 根 K 线")`

### ⚡ 踩坑要點

**1\.** `**start**` **和** `**end**` **必須是** `**date**` **對象，不能是字符串**

`# ❌ 报错：'str' object cannot be cast as 'date' candles = ctx.history_candlesticks_by_date(..., start='2026-04-14', end='2026-04-15') # ✅ 正确 from datetime import date candles = ctx.history_candlesticks_by_date(..., start=date(2026,4,14), end=date(2026,4,15))`

**2\. 單次最多返回 1000 根 K 線**

一天的 1 分鐘 K 線（含盤前盤後）剛好接近 1000 根的限制。所以**按天循環下載**是正確姿勢，別想一口氣拉一個月的數據：

`import time from datetime import date, timedelta all_candles = [] current = date(2025, 7, 1) end_date = date(2026, 4, 18) while current <= end_date:    try:        candles = ctx.history_candlesticks_by_date(            symbol="QQQ.US",            period=Period.Min_1,            adjust_type=AdjustType.ForwardAdjust,            start=current,            end=current + timedelta(days=1),            trade_sessions=TradeSessions.All        )        all_candles.extend(candles)        print(f"  {current}: {len(candles)}根")    except Exception as e:        print(f"  {current}: {e}")    current += timedelta(days=1)    time.sleep(0.2)  # 别太快，防限流`

**3\.** `**timestamp**` **可能是** `**datetime**` **對象**

長橋返回的 `Candlestick.timestamp` 在不同 SDK 版本下可能是 `datetime` 或 Unix timestamp。直接用 `fromtimestamp()` 可能炸：

`# ✅ 防御性写法 ts = candle.timestamp if isinstance(ts, (int, float)):    ts = datetime.fromtimestamp(ts) # 如果已经是 datetime，直接用`

* * *

## 坑 2:5 分鐘數據在開盤 1 小時窗口內直接啞火——0 筆交易

第一輪迴測，我用 5 分鐘 K 線跑了 60 天的數據結果 0 筆交易。

但我當時沒當回事，覺得是數據量不夠。直到後來用**完整的 v6 全過濾策略**（雙向突破 +ITM 期權 +Black-Scholes 定價）在 5 分鐘和 1 分鐘數據上做了一次正式對比，結果讓我徹底服了：

 

5 分鐘 K 線

1 分鐘 K 線

K 線總數

40,583 根

202,866 根

交易日數

536 天

536 天

策略窗口

09:35-10:50（開盤 1 小時）

09:35-10:50（開盤 1 小時）

**總交易筆數**

**0 筆**

**451 筆**

勝率

—

78.5%

總得分

—

+2139.92%

每年

0 筆

198 筆

最大回撤

—

25.19%

**5 分鐘數據在開盤 1 小時內，一筆交易都沒觸發。**

為什麼？因為我的策略窗口只有開盤 1 小時（09:35-10:50），5 分鐘 K 線在這個窗口裏只有約 15 根。再加上全過濾（SMA20 趨勢 + 量能 + 動量 +K 線實體），15 根 5 分鐘 K 線根本不夠過濾條件判斷的——指標還沒算出來，窗口就關了。

而 1 分鐘 K 線在同一窗口內有約 75 根，信號充足，經過 6 層過濾後仍保留 451 筆。

**教訓：策略的時間尺度和數據的顆粒度必須匹配。** 開盤 1 小時的快速行情，5 分鐘顆粒度完全跟不上。這不是參數問題，是數據粒度的物理限制。

* * *

## 坑 3:24746 次突破信號只剩 454 筆——6 層過濾漏斗每一層都在"殺人"

切換到 1 分鐘數據後，信心滿滿跑回測。這次不是 0 筆了，但我想搞清楚：**過濾條件到底砍掉了多少信號？**

寫了個診斷腳本，逐層統計每一層過濾通過的次數：

`突破信号触发      → 24746 次  ✅ 信号源充足 ↓ 时间窗口过滤（只做 09:35-10:50） 时间窗口通过      →  3535 次  (14.3%)  ⚠️ 85% 被砍 ↓ 跳空过滤（gap < 0.20%） 跳空过滤通过      →  3464 次  (98.0%)  ✅ 跳空不是问题 ↓ SMA20 趋势过滤（做多价格>SMA20，做空<SMA20） SMA20 通过        →  3450 次  (99.6%)  ✅ 趋势几乎不影响 ↓ 量能过滤（成交量 ≥ 20 均量 × 1.2） 量能通过          →  1205 次  (34.9%)  ⚠️ 65% 被砍！ ↓ 动量确认（最近 2 根 K 线同向） 动量通过          →   616 次  (51.1%)  ⚠️ 又砍一半 ↓ K 线实体确认（实体 ≥ 0.03%） K 线实体通过       →   454 次  (73.7%) ↓ 最终入场 最终信号          →   454 次  (100%)  ✅ 全部入场`

**漏斗分析揭示了三個關鍵真相：**

**1\. 時間窗口是第一大瓶頸（保留 14.3%）。** 開盤 1 小時雖然信號質量高，但直接砍掉了 85% 的突破信號。這是有意為之——全天的突破信號太多噪音，開盤時段的信號最有效。

**2\. 量能過濾是第二大瓶頸（保留 34.9%）。** 要求成交量達到 20 日均量的 1.2 倍，直接砍掉了 65% 的信號。這意味着大部分突破發生在縮量狀態下，放量突破才是真突破。

**3\. SMA20 趨勢過濾幾乎沒用（保留 99.6%）。** 原以為"做多必須價格在 SMA20 之上"會砍掉很多假信號，實際上 99.6% 的突破信號本身就已經滿足這個條件。趨勢是結果不是原因——突破本身就隱含了趨勢。

### 診斷代碼

如果你也遇到類似問題，可以用這個方法定位瓶頸：

`# 逐层统计过滤漏斗 —— 直接告诉你哪里卡住了 stages = {    '突破信号': 0, '时间窗口': 0, '跳空过滤': 0,    'SMA20': 0, '量能': 0, '动量': 0, 'K 线实体': 0, '最终入场': 0, } for i in range(n):    # 第一层：突破信号    if not (prev_close > upper or prev_close < lower):        continue    stages['突破信号'] += 1    # 第二层：时间窗口    if not (9*60+35 <= hour_min <= 10*60+50):        continue    stages['时间窗口'] += 1    # 第三层：跳空    if gap > 0.0020:        continue    stages['跳空过滤'] += 1    # 第四层：SMA20    if sig == 'call' and close < sma20:        continue    if sig == 'put' and close > sma20:        continue    stages['SMA20'] += 1    # 第五层：量能    if volume < sma_vol * 1.2:        continue    stages['量能'] += 1    # 第六层：动量（2 根同向）    if not (连续 2 根同向 K 线):        continue    stages['动量'] += 1    # 第七层：K 线实体    if prev_body < 0.0003:        continue    stages['K 线实体'] += 1    stages['最终入场'] += 1 for stage, count in stages.items():    print(f"  {stage:10s} → {count:5d} 次")`

**這個漏斗圖比任何優化算法都管用。** 它直接告訴你哪層過濾太鬆（浪費計算）、哪層太緊（漏掉機會）、哪層純屬擺設。

* * *

* * *

## 坑 4：調參數治標不治本

發現問題後，我嘗試調整參數：

big\_mult

fail\_thresh

交易筆數

結果

2.5

2

0

原始參數，全滅

2.0

2

0

放寬了，還是沒用

1.5

2

1

終於有 1 筆了

1.5

1

1

降低衰竭閾值，還是一筆

1.2

2

1

極端放寬，依然只有 1 筆

**結論：參數調整在當前市場環境下效果有限。**

這不是參數的問題，是**市場狀態**的問題。最近 QQQ 處於低波動的趨勢行情，衰竭反轉信號本身就少。策略需要的是高波動、頻繁反轉的市場環境才能發揮。

這給我的啓發是：**回測不能只看數字好看不好看，還要看回測數據覆蓋了什麼樣的市場狀態。**

-   只回測牛市？策略可能只會做多
-   只回測低波動？策略可能一單都不觸發
-   必須覆蓋**牛、熊、震盪**至少三種行情

* * *

## 坑 5：時區差點讓我多做了一筆假交易

長橋返回的 K 線時間戳是 **HKT（UTC+8）**，不是 UTC，也不是美股東部時間（ET）。

我一開始沒注意，直接拿 HKT 時間去判斷"美東 9:30 開盤"，結果時間全部偏移了 13 個小時（夏令時 12 小時）。這意味着：

-   美東 9:30 開盤 = 北京時間 21:30
-   如果代碼裏寫 `if hour == 9`，實際對應的是北京時間 9 點——**根本不在交易時段內**

正確的處理方式：

`from datetime import datetime import pytz # 长桥返回的是 UTC 时间 utc_time = candle.timestamp  # datetime with tzinfo=UTC # 转换为美东时间 et = pytz.timezone('America/New_York') et_time = utc_time.astimezone(et) # 判断是否在交易时段 if et_time.hour == 9 and et_time.minute >= 30:    # 正式开盘    pass`

**WSL 環境的額外坑**：`pip3` 可能指向系統 Python，而你在虛擬環境裏。安裝 `pytz` 要用：

`# ❌ pip3 install pytz → 可能装到系统 python 去了 # ✅ /usr/bin/python3 -m pip install pytz --break-system-packages`

* * *

## 坑 6：舊數據和新數據合併時格式不統一

我的回測數據來自兩個時期：

-   **舊數據**：CSV 格式，時間列無時區信息
-   **新數據**：從長橋 API 獲取，帶 UTC 時區

直接 `pd.concat()` 會報錯或者時間對不上。正確做法：

`import pandas as pd # 强制统一为 UTC old['Datetime'] = pd.to_datetime(old['Datetime'], utc=True) new['Datetime'] = pd.to_datetime(new['Datetime'], utc=True) # 可选：统一转为美东时间（去掉时区信息，方便按小时筛选）old['Datetime'] = old['Datetime'].dt.tz_convert('America/New_York').dt.tz_localize(None) new['Datetime'] = new['Datetime'].dt.tz_convert('America/New_York').dt.tz_localize(None) # 合并去重 all_data = pd.concat([old, new]).drop_duplicates(subset='Datetime').sort_values('Datetime')`

* * *

## 總結：回測中我學到的 6 件事

**數據源要可靠**。yfinance 免費但不穩定，長橋 API 按天下載 1 分鐘 K 線是更好的選擇，注意 `start/end` 必須是 `date` 對象，單次最多 1000 根。

**數據粒度要匹配策略**。0DTE 做分鐘級交易，必須用 1 分鐘數據，5 分鐘會漏掉大部分信號。

**回測時一定要做信號漏斗分析**。逐層統計每個過濾條件通過的次數，快速定位瓶頸在哪。

**參數調優有上限**。如果市場狀態不支持策略邏輯，調什麼參數都沒用。要看回測數據是否覆蓋了不同市場環境。

**時區處理是重災區**。長橋返回 UTC 時間，做美股策略需要轉成 ET。WSL 下 pip 版本可能串，注意用對 Python。

**數據合併前先統一格式**。舊 CSV 無時區 + API 數據有時區，直接拼會出 bug。先統一為同一時區再去重合並。

* * *

_以上是我在 QQQ 0DTE 策略回測過程中的真實踩坑經歷。如果你也在用長橋做量化交易，歡迎交流。_

_本文僅供技術交流，不構成投資建議。_

@LongbridgeAI  $納指 100 ETF - Invesco(QQQ.US)

### 相關股票

- [SQQQ.US](https://longbridge.com/zh-HK/quote/SQQQ.US.md)
- [PSQ.US](https://longbridge.com/zh-HK/quote/PSQ.US.md)
- [QQQ.US](https://longbridge.com/zh-HK/quote/QQQ.US.md)

## 評論 (6)

- **OceanLou · 2026-04-21T06:00:38.000Z**: 發給我的 agent 看看，改進下回測數據
- **比奇堡交易员-章鱼哥 · 2026-04-20T13:06:56.000Z**: 長橋 api 要錢嗎 怎麼收費的
  - **热血青年** (2026-04-23T02:55:58.000Z): 免費
- **社会主义核心价值观er · 2026-04-20T12:24:40.000Z**: 量化框架用的啥？
- **牙签 · 2026-04-20T08:24:25.000Z**: 算了，太麻煩了😪
- **LongbridgeAI · 2026-04-20T08:07:43.000Z**: 這篇用户分享的技術文章非常詳盡，總結了作者在使用長橋 API對QQQ 0DTE 衰竭反轉策略進行回測時的踩坑經歷，極具實際操作性與啓發性。以下是內容要點的梳理與總結：關鍵踩坑點及經驗分享：1. 數據源可靠性與使用技巧yfinance 的侷限性：數據穩定性差、限流頻繁、數據質量參差不齊（例如：1 分鐘數據僅支持最近 30 天）。長橋 API 的優勢：支持按天拉取歷史數據，準確性更高。Basic 級別每天僅包含正式交易時段約 241 條 K 線，Premium 級別含盤前盤後約 960 條 K 線。使用時需注意：start 和 end 參數必須是datetime.date對象，不能直接傳字符串。單
