精華筆記

· @aihub.tw

AI 量化交易

綜合實戰:從想法到模擬盤完整覆盤

綜合實戰:從想法到模擬盤完整覆盤

你已經走完七堂課了。回測跑過、AI 訊號接過、風控參數設過、dry-run 也啟動過。但很多學員告訴我,學完每一堂課感覺都還行,一旦坐下來從頭做一個「自己的策略」,卻不知道從哪裡開始——或者做到一半發現前後沒有串起來,數據格式不對、訊號沒有接進策略、風控參數跟回測設定衝突。

這就是這堂課要解決的問題:走一遍完整的流程,從一個具體的交易想法出發,一步一步帶到模擬盤穩定運行。這不是一堂新技術課,這是一次「把所有零件組裝起來,確認機器真的能跑」的完整覆盤。

風險警語 本課程所有內容僅供學習與研究用途,不構成任何投資建議。量化交易涉及本金虧損風險,模擬盤績效不代表實盤結果,回測績效更不代表未來表現。本堂課全程使用模擬盤(dry_run: true)。若你在學習後決定投入實盤,風險與責任由你自行承擔。請在充分理解所有風險後,只動用你可以全額虧損的資金。
這堂課適合誰 適合:已完成前七堂課、想整合全流程跑出自己第一個完整量化系統的人。本課程屬工程師應用專區。需要基礎:Python 中階(能改 class、懂 pandas、會看 traceback)、已安裝並能操作 freqtrade、已有 Binance 或 Bybit 帳號(只用模擬盤,不需充值)。前置課:第 1–7 課皆已完成。

這堂學什麼

  • 完整 walkthrough:從想法具體化 → 資料驗證 → 策略開發 → 嚴格回測 → AI 訊號 → 風控 → dry-run 上線
  • 全流程檢查清單:啟動模擬盤前的 20 個確認點
  • 台灣法規與稅務提醒:加密貨幣所得、海外券商申報義務
  • 最常犯的 8 個坑(含 3 個心理坑)及解法
  • 持續精進:課程之後的學習資源與社群

整條流程長什麼樣

先建立一個完整的心智模型。這門課的八堂教的是下圖中的各個區塊,而這堂課要把所有箭頭接起來。

量化交易全流程架構圖

這條流程有幾個重要的方向性原則,先在這裡說清楚:

  • 想法永遠要先於資料探索。很多人先看資料,找到一個「好像有規律」的現象就開始做策略——這是資料窺探(Data Snooping)的入口。正確做法是先用語言寫下「我認為 X 發生時 Y 會跟著發生,因為 Z」,然後才去資料裡驗證。
  • 流程是單向的:回測不好看時,正確做法是回頭審視想法假設,不是一直調參數到好看為止。「不斷調參數直到曲線好看」就是第 3 課說的過擬合(Overfitting)的標準作案手法。
  • 模擬盤不是回測的替代品:模擬盤的目的是發現「回測沒辦法測到的問題」,包括 API 連線穩定性、訊號計算延遲、部位開倉失敗等。別跳過。

手把手實戰:完整走一遍

這次的範例策略:「BTC/USDT 1h,用均線趨勢過濾 + 情緒評分確認,搭配移動停損與熔斷保護」。這是一個把前七堂核心全部連到一起的組合,夠完整、又不複雜到跑不完。

Step 1:把想法寫成可測試的假設

先開一個文字檔,用一段話寫清楚你的假設:

假設:當 BTC 處於多頭 Regime(EMA20 在 EMA50 上方)時,若近期加密貨幣新聞情緒偏正面
(LLM 情緒評分 > 0.3),則在每根 1h K 線收盤後進場做多,持倉直到均線死叉或情緒轉負。

假設的市場邏輯:趨勢行情中,正面消息驅動的買入往往有延續性;逆向情緒則代表短期超賣。
此假設成立的前提:市場 Regime 辨識準確、新聞情緒有足夠的前置訊號性(lead time)。
可以被推翻的條件:如果加入情緒訊號後的 Sharpe Ratio 比不加更低,或正面情緒期間的 Win Rate
低於 50%,假設即被推翻。

這一步很多人跳過,但它是整個系統的靈魂。假設寫不清楚的策略,出了問題沒辦法判斷「是想法錯了還是實作錯了」。

Step 2:下載並驗證資料品質

取得資料,並在進策略之前先做品質檢查:

# 下載 BTC/USDT 兩年資料(確保有足夠的 in-sample + out-of-sample 區間)
freqtrade download-data \
  --exchange binance \
  --pairs BTC/USDT \
  --timeframe 1h \
  --days 730

下載完之後,用 Python 做一個快速的品質檢查:

import pandas as pd
import json
from pathlib import Path

def check_data_quality(pair: str = "BTC_USDT", timeframe: str = "1h",
                        data_dir: str = "user_data/data/binance") -> None:
    """
    載入 freqtrade 格式的歷史資料並做品質檢查。
    資料格式:JSON 陣列,每筆 [timestamp_ms, open, high, low, close, volume]
    """
    filepath = Path(data_dir) / f"{pair}-{timeframe}.feather"
    if not filepath.exists():
        # 嘗試 JSON 格式
        filepath = Path(data_dir) / f"{pair}-{timeframe}.json"

    df = pd.read_feather(filepath) if str(filepath).endswith('.feather') else \
         pd.DataFrame(
             pd.read_json(filepath).values,
             columns=["date", "open", "high", "low", "close", "volume"]
         )

    df["date"] = pd.to_datetime(df["date"], unit="ms", utc=True)
    df = df.set_index("date").sort_index()

    print(f"資料期間:{df.index[0]} 到 {df.index[-1]}")
    print(f"總 K 線數:{len(df)}")

    # 檢查 1:缺失時間段
    expected_freq = pd.tseries.frequencies.to_offset("1h")
    full_range = pd.date_range(df.index[0], df.index[-1], freq=expected_freq, tz="UTC")
    missing = full_range.difference(df.index)
    print(f"缺失 K 線數:{len(missing)}"
          + (f"(最大連缺:{missing.to_series().diff().max()})" if len(missing) > 0 else " ✓"))

    # 檢查 2:異常價格(high < low 或 close <= 0)
    bad_rows = df[(df["high"] < df["low"]) | (df["close"] <= 0)]
    print(f"異常 K 線:{len(bad_rows)} 筆" + (" ✓" if len(bad_rows) == 0 else " ← 需要處理"))

    # 檢查 3:成交量為零(可能是交易所維護期)
    zero_vol = df[df["volume"] == 0]
    print(f"成交量為 0:{len(zero_vol)} 筆" + (" ✓" if len(zero_vol) == 0 else " ← 注意"))

check_data_quality()

如果缺失 K 線超過 1%,考慮換一個資料來源(例如改用 Bybit 的歷史資料,或用 ccxt 補洞)。少量缺失 freqtrade 在回測時會自動跳過,影響不大。

Step 3:用 AI 輔助寫策略程式碼

這是「策略開發輔助」的正確 LLM 使用方式:你描述邏輯,AI 幫你翻成程式碼,你審查每一行。

把以下 prompt 直接貼給 Claude:

我在用 freqtrade 開發量化策略,請幫我寫一個 Python 策略類別。

條件:
- 繼承 IStrategy
- timeframe = '1h'
- 進場:EMA20 > EMA50(多頭 Regime)且有一個外部整數訊號 sentiment_score > 30
  sentiment_score 會從 dataframe 的一個欄位讀取(預設值 0)
- 出場:EMA20 < EMA50(死叉)或 sentiment_score < -30
- 停損:stoploss = -0.05,啟用 trailing_stop
- minimal_roi:{"0": 0.10, "60": 0.05, "240": 0.02}
- can_short = False
- 加上完整的 populate_indicators、populate_entry_trend、populate_exit_trend

請完整輸出策略檔案,包括所有必要的 import,並在每個重要邏輯段落加上繁體中文註解。

Claude 會輸出一個完整的策略檔案。把它存成 user_data/strategies/CapstoneStrategy.py,然後逐行讀一遍。重點確認:

  1. populate_indicators 的指標計算只用了 shift(1) 之前的資料(無前視偏差)
  2. 進出場訊號確實對應你的假設邏輯
  3. sentiment_score 欄位有預設值(避免找不到欄位時策略崩潰)

如果有不確定的行,繼續問 Claude:「這行 dataframe['ema_cross'] = qtpylib.crossed_above(...) 的邏輯是什麼,會不會有前視偏差?」

Step 4:嚴格回測——扣費、Walk-Forward 驗證

嚴格回測分兩個步驟:先用 in-sample 資料調整策略參數,再用 out-of-sample 資料驗證。兩段資料不得重疊。

# 以兩年資料為例:前 18 個月 in-sample,後 6 個月 out-of-sample

# 步驟 A:in-sample 回測(調整參數用)
freqtrade backtesting \
  --config config.json \
  --strategy CapstoneStrategy \
  --timerange 20240101-20250630 \
  --fees 0.001 \
  --breakdown month

# 步驟 B:out-of-sample 驗證(這段資料在調參時絕對不能看)
freqtrade backtesting \
  --config config.json \
  --strategy CapstoneStrategy \
  --timerange 20250701-20251231 \
  --fees 0.001 \
  --breakdown month

評估標準(只有 out-of-sample 的結果才算數):

評估項目                  及格線        你的結果
─────────────────────────────────────────────
Sharpe Ratio             > 0.8         ____
Max Drawdown             < -15%        ____
Win Rate                 > 48%         ____
Profit Factor            > 1.2         ____
vs Buy & Hold            不遜於太多    ____
Out/In-sample 報酬差距   < 50%         ____

最後一行「out-of-sample 報酬差距 < 50%」是過擬合的關鍵指標。如果 in-sample 年化 30%、out-of-sample 年化 2%,代表嚴重過擬合,不能上。

Walk-Forward 驗證示意圖

Step 5:接入 AI 訊號層

第 5 課已經寫過情緒評分的 script。這裡重點是把它「接正確」——確保訊號格式和策略吃進來的格式一致。

首先確認情緒評分 script 輸出到正確位置:

# scripts/generate_sentiment.py — 每 1 小時跑一次(用 cron 或 systemd timer)
import anthropic
import json
import sqlite3
from datetime import datetime, timezone

NEWS_HEADLINES = [
    # 實際上這裡要從 CryptoPanic API 或 RSS 抓最近 2 小時的新聞標題
    # 示範用硬編碼
    "Bitcoin ETF sees record inflows as institutional demand surges",
    "Fed holds rates steady, risk assets rally",
]

def score_sentiment(headlines: list[str]) -> int:
    """
    呼叫 Claude 評分新聞情緒,回傳 -100 到 100 的整數。
    使用 claude-haiku-4-5(速度快、成本低,適合定期批次呼叫)。
    """
    client = anthropic.Anthropic()

    prompt = f"""以下是加密貨幣市場的近期新聞標題清單。
請評估這批標題對 BTC 短期(1-4 小時)價格的市場情緒影響。

新聞標題:
{chr(10).join(f"- {h}" for h in headlines)}

請只回傳一個整數,範圍 -100(極度負面)到 100(極度正面),0 代表中性。
只回傳數字,不要有任何其他文字。"""

    message = client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=10,
        messages=[{"role": "user", "content": prompt}]
    )

    try:
        score = int(message.content[0].text.strip())
        return max(-100, min(100, score))  # 確保在範圍內
    except ValueError:
        return 0  # 解析失敗時回傳中性

def save_score(score: int, db_path: str = "user_data/sentiment.db") -> None:
    conn = sqlite3.connect(db_path)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS sentiment
        (timestamp TEXT PRIMARY KEY, score INTEGER)
    """)
    ts = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:00")
    conn.execute("INSERT OR REPLACE INTO sentiment VALUES (?, ?)", (ts, score))
    conn.commit()
    conn.close()
    print(f"[{ts}] Sentiment score: {score}")

if __name__ == "__main__":
    score = score_sentiment(NEWS_HEADLINES)
    save_score(score)

然後在策略的 populate_indicators 裡讀取這個分數:

def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
    # ── 技術指標 ──
    dataframe['ema20'] = ta.EMA(dataframe, timeperiod=20)
    dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)

    # ── 讀取情緒分數(從 SQLite) ──
    import sqlite3
    import pandas as _pd
    try:
        conn = sqlite3.connect("user_data/sentiment.db")
        sentiment_df = _pd.read_sql(
            "SELECT timestamp, score FROM sentiment ORDER BY timestamp",
            conn, parse_dates=["timestamp"]
        )
        conn.close()
        sentiment_df = sentiment_df.set_index("timestamp")
        # 對齊到策略 dataframe 的時間軸,用前一個已知分數填補
        dataframe = dataframe.join(
            sentiment_df.rename(columns={"score": "sentiment_score"}),
            how="left"
        )
        dataframe["sentiment_score"] = dataframe["sentiment_score"].ffill().fillna(0)
    except Exception:
        dataframe["sentiment_score"] = 0  # 資料庫不存在時用中性值

    return dataframe

重要:回測時 sentiment.db 不會有歷史資料,所以回測中情緒欄位會全部是 0——這意味著你的 in-sample/out-of-sample 回測是「無 AI 訊號版本」的基準線。加入情緒訊號的效果要等模擬盤階段才能觀察。這是正確的——你不應該用「事後重建的情緒分數」來美化回測。

Step 6:套入風控,確認參數一致

這一步最常犯的錯:回測的 config.json 和 dry-run 的 config.json 參數不一致,導致模擬盤行為和你預期的不同。

建立一份「生產用」的 config,確保以下參數全部對齊:

{
    "dry_run": true,
    "dry_run_wallet": 1000,

    "stake_currency": "USDT",
    "stake_amount": "unlimited",
    "tradable_balance_ratio": 0.3,
    "max_open_trades": 3,
    "amend_last_stake_amount": true,

    "stoploss": -0.05,
    "trailing_stop": true,
    "trailing_stop_positive": 0.02,
    "trailing_stop_positive_offset": 0.04,
    "trailing_only_offset_is_reached": true,

    "protections": [
        {
            "method": "MaxDrawdown",
            "lookback_period_candles": 48,
            "trade_limit": 2,
            "stop_duration_candles": 24,
            "max_allowed_drawdown": 0.10
        },
        {
            "method": "StoplossGuard",
            "lookback_period_candles": 24,
            "trade_limit": 3,
            "stop_duration_candles": 12,
            "only_per_pair": false
        }
    ],

    "exchange": {
        "name": "binance",
        "key": "",
        "secret": ""
    },

    "telegram": {
        "enabled": true,
        "token": "YOUR_TELEGRAM_BOT_TOKEN",
        "chat_id": "YOUR_CHAT_ID"
    },

    "api_server": {
        "enabled": true,
        "listen_ip_address": "127.0.0.1",
        "listen_port": 8080,
        "verbosity": "error",
        "enable_openapi": false,
        "jwt_secret_key": "YOUR_RANDOM_SECRET",
        "username": "your_username",
        "password": "your_password"
    }
}

注意:keysecret 欄位是空字串——dry-run 模式下不需要 API 金鑰。等第 7 課的內容確認完觀察期後,再決定要不要填入只讀金鑰測試 WebSocket 連線。

Step 7:啟動 dry-run,設定觀察框架

啟動前,先做一次「起跑前檢查」(下一節的完整清單):

# 確認策略語法沒問題
freqtrade check-exchange --config config.json --strategy CapstoneStrategy

# 跑一次最近 7 天的快速回測,確認策略在最新的市場環境還能運作
freqtrade backtesting \
  --config config.json \
  --strategy CapstoneStrategy \
  --timerange 20260621-20260704 \
  --fees 0.001

# 確認沒問題,啟動 dry-run
freqtrade trade \
  --config config.json \
  --strategy CapstoneStrategy \
  --logfile user_data/logs/capstone.log

模擬盤跑起來之後,建立你的觀察框架。推薦用一個簡單的 Notion 或 Google Sheets,每週紀錄:

週次    | 模擬盤報酬 | 進場次數 | 勝率 | 最大回撤 | 情緒訊號有效次數 | 備註
────────────────────────────────────────────────────────────────────────────
Week 1  |            |          |      |          |                  |
Week 2  |            |          |      |          |                  |
...

觀察期建議至少 4–8 週,涵蓋不同的市場狀態(最好能看到一次明顯的行情回調)。不要在第一週就下結論——無論是「模擬盤賺了就上實盤」,還是「模擬盤虧了就改策略」,都太倉促了。

模擬盤觀察期架構圖

全流程檢查清單

在正式啟動模擬盤之前,把以下 20 個項目逐一打勾。沒打完不能跑。

【資料層】
□ 1. 資料下載期間足夠(至少 1.5 年,最好 2 年以上)
□ 2. 資料品質檢查通過(缺失 K 線 < 1%,無異常價格)
□ 3. 資料時區確認為 UTC

【策略層】
□ 4. 策略假設已用文字清楚描述(假設 + 推翻條件)
□ 5. 指標計算無前視偏差(全部使用 shift(1) 前的資料)
□ 6. `freqtrade check-exchange` 無錯誤
□ 7. 策略 Python 語法無 warning

【回測層】
□ 8. 回測有扣手續費(--fees 0.001 以上)
□ 9. in-sample 和 out-of-sample 回測都跑過
□ 10. out-of-sample Sharpe Ratio > 0.8(否則不上)
□ 11. out-of-sample Max Drawdown < -15%(否則不上)
□ 12. 策略績效已與同期 Buy & Hold 比較

【風控層】
□ 13. stoploss 設定基於 ATR 分析,不是拍腦袋
□ 14. max_open_trades 和 tradable_balance_ratio 對應倉位不超過帳戶 15%
□ 15. protections 區塊已設定(MaxDrawdown + StoplossGuard 至少各一)
□ 16. dry_run: true 確認無誤(不是 false!)

【AI 訊號層】
□ 17. 情緒評分 script 可獨立跑,輸出格式正確
□ 18. 策略在 sentiment_score = 0 時仍能正常運作(fallback 處理)
□ 19. LLM API 金鑰存在 .env,已加入 .gitignore

【監控層】
□ 20. Telegram bot 設定完成,能收到進出場通知

全流程檢查清單分層視覺化

台灣法規與稅務提醒

這段是很多量化教學課程不會講、但你遲早會碰到的現實。本課程不提供稅務建議,以下資訊以 2026 年 7 月現況為準,請以財政部最新公告及專業會計師建議為準。

加密貨幣所得

台灣財政部自 2024 年起明確對虛擬資產交易所得課稅。以下是基本架構:

  • 境內平台:若你使用台灣註冊的虛擬資產服務業者(VASP),平台依法可能有申報義務
  • 境外平台所得:Binance、Bybit、OKX 等境外交易所的交易所得屬「海外所得」,每年海外所得超過新台幣 100 萬元,需計入「基本所得額」申報最低稅負制(AMT,稅率 20%),扣除 670 萬元基本所得免稅額後課徵
  • 資本利得計算:加密貨幣的成本基礎如何計算(FIFO 或加權平均法)目前仍有討論空間,強烈建議保存完整的交易紀錄(交易所匯出的 CSV 至少保留 5 年)
  • DeFi 與質押收益:性質較複雜,需個案判斷,請諮詢熟悉虛擬資產的會計師

海外券商(台股以外)

若你的量化系統操作台灣以外的海外股票或期貨(例如透過 Interactive Brokers、Alpaca 等):

  • 海外所得超過門檻同樣適用 AMT 申報
  • 海外期貨盈虧計算方式與現貨不同,期貨損失是否可以扣抵所得,需確認你的申報方式
  • 部分海外券商會對台灣用戶做 FATCA(美國外國帳戶稅收合規法)申報,資產和所得資訊可能被交換

本課程的立場

本課程全程使用模擬盤,不涉及真實資金操作。一旦你考慮從模擬盤走向實盤,建議在投入任何資金之前:

  1. 確認你使用的交易所在台灣的合法性(金管會 VASP 登記狀態)
  2. 諮詢具有虛擬資產稅務經驗的會計師(不是一般的財務顧問)
  3. 建立完整的交易紀錄系統(所有進出場、日期、金額、幣種)

最常犯的 8 個坑

坑 1:回測沒有 out-of-sample 驗證就上模擬盤

症狀:在 in-sample 期間把參數調到「Sharpe 2.0、最大回撤 5%」,興奮地啟動模擬盤,第一週就開始虧損。

問題:你看到的好看數字只是策略「記住了過去」的結果。out-of-sample 是唯一能稍微測試策略是否有真實預測力的方式。

# 檢查你有沒有做 out-of-sample:看回測的 timerange 範圍
# 如果你只跑了一段時間,全都用來「調參數」,那就是問題所在
freqtrade backtesting --config config.json --strategy YourStrategy \
  --timerange 20250101-20250630 --fees 0.001
# ← 如果這段時間你根本沒看過(完全保留給驗證),才算 out-of-sample

坑 2:sentiment_score 欄位格式錯誤導致策略無法進場

症狀:啟動 dry-run 後,策略一直沒有進場訊號,日誌顯示:

WARNING - CapstoneStrategy: Column 'sentiment_score' is of type object, expected numeric.
  Skipping entry signal generation.

原因:從 SQLite 讀取的分數被解析為字串而不是整數。

解法:在 populate_indicators 裡加明確的型別轉換:

dataframe["sentiment_score"] = pd.to_numeric(
    dataframe["sentiment_score"], errors="coerce"
).fillna(0).astype(int)

坑 3:dry_run 誤設為 false,不小心動到真實帳戶

症狀:你以為在跑模擬,結果看到交易所帳戶出現不認識的訂單。

這個坑第 1 課就提過,這裡再說一次:啟動前每次都要:

grep "dry_run" config.json
# 預期輸出:
#   "dry_run": true,

看到 false 就停手,改回 true,確認無誤再啟動。沒有例外。

坑 4:Telegram 通知設定錯誤,無法接到警報

症狀:策略跑了三天,完全沒收到任何 Telegram 訊息,後來發現帳戶已經觸發熔斷、停了很久。

解法:啟動後立即測試通知:

# 用 freqtrade 的 Telegram 測試功能
freqtrade trade --config config.json --strategy CapstoneStrategy &
# 然後在 Telegram 對 bot 發送 /status
# 若 bot 有回應,代表通知鏈路正常

如果 bot 沒有回應,檢查:Token 有無拼錯、chat_id 是個人 ID 還是群組 ID(群組 ID 有負號)、bot 有沒有被加進你的聊天。

坑 5:只看總報酬,忽略 Profit Factor 和盈虧比

症狀:回測顯示總報酬 +15%,感覺不錯。但實盤發現幾次大虧把所有小贏全部抹掉。

診斷:把 freqtrade 的回測結果裡找 Profit Factor 這個數字:

freqtrade backtesting --config config.json --strategy CapstoneStrategy \
  --timerange 20250101-20250630 --fees 0.001 --export trades \
  --export-filename user_data/backtest_results/capstone.json

# 然後用這個指令看詳細統計
freqtrade backtesting-show --export-filename user_data/backtest_results/capstone.json

Profit Factor = 總獲利 / 總虧損。低於 1.2 代表盈虧比太差,策略靠「多次小贏」撐起績效,遇到幾次大虧就撐不住。

坑 6:Cron 排程跑到一半掛掉,情緒評分停止更新

症狀:模擬盤跑了一週後,發現 sentiment_score 欄位全部是 0——情緒評分 script 的 Cron 任務在某個時間點靜悄悄地失敗了。

解法:讓情緒評分 script 寫入執行狀態,並在 freqtrade 策略裡加過時檢查:

def is_sentiment_fresh(db_path: str = "user_data/sentiment.db",
                        max_age_hours: int = 3) -> bool:
    """回傳情緒分數是否在 max_age_hours 小時內更新過。"""
    import sqlite3
    from datetime import datetime, timezone, timedelta
    try:
        conn = sqlite3.connect(db_path)
        row = conn.execute(
            "SELECT timestamp FROM sentiment ORDER BY timestamp DESC LIMIT 1"
        ).fetchone()
        conn.close()
        if not row:
            return False
        last_ts = datetime.fromisoformat(row[0]).replace(tzinfo=timezone.utc)
        return datetime.now(timezone.utc) - last_ts < timedelta(hours=max_age_hours)
    except Exception:
        return False

# 在策略 populate_indicators 中:
if not is_sentiment_fresh():
    # 情緒資料過時,用中性值,同時記入日誌
    self.dp.send_msg("⚠ 情緒評分資料過時超過 3 小時,已切換為中性訊號")
    dataframe["sentiment_score"] = 0

坑 7(心理坑):模擬盤剛賺就以為策略成熟了

症狀:模擬盤第一週賺了 3%,馬上把 dry_run: false,投入幾萬元。結果第二、三週連跌,因為第一週剛好碰上有利市場 Regime。

根本問題:4 週以內的模擬盤樣本量太小,無論盈虧都不代表統計意義。一個好策略也可能連輸好幾週;一個爛策略也可能碰上順風局賺一波。

正確做法:設定一個你在啟動模擬盤之前就寫下來的「上實盤條件」(例如「連續 8 週正報酬且最大回撤未超過 12%」),然後嚴格執行。決策規則必須在觀察之前就寫好,不是觀察之後才定。

坑 8(心理坑):策略虧損時不斷手動干預,破壞系統紀律

症狀:模擬盤連跌兩週,開始「幫策略做決定」——手動取消幾筆進場訂單、手動提早平倉、修改 config 的 stoploss。結果變成「人工+程式混合決策」,既沒有程式的紀律,也沒有人工的判斷力。

量化交易系統的核心價值就是「消除情緒干預」。一旦你在市場不利時手動介入,你就失去了這個系統的最大優勢。

正確做法:如果你覺得策略「需要調整」,先停機(不要在跑的時候改設定),做一次重新回測確認想法,然後從頭部署。永遠不要「邊跑邊改」。

三個心理坑的決策樹

作業

  1. 完整走一遍這堂課的 Step 1–7:從寫下你的交易假設開始,到模擬盤跑起來、Telegram 收到第一條通知為止。不需要策略完美,重點是完整跑過一遍整條流程,找出你在哪個環節卡住。
  2. 打完全流程清單的 20 個勾:把本堂的檢查清單列印或抄到你的筆記,逐條確認。有任何一項還沒搞定的,就是下一步的功課清單。
  3. 寫下你的「上實盤條件」:不管你現在有沒有打算上實盤,先把條件寫下來。格式:「當模擬盤連續 ___ 週,報酬 ___,Max Drawdown < ___,我才考慮最小部位實盤。」把這張紙放在顯眼的地方。
  4. 選做:壓力測試你的策略:把 timerange 設成 2022 年全年(歷史上的主要熊市),跑一次回測,看看你的風控有沒有辦法撐過那段環境。這是最能讓你了解自己策略下行風險的方式。

持續精進的資源

這門課教到這裡,你有了一個完整的出發點。但量化交易是一個需要持續學習的領域,以下是有實際價值的方向:

社群與討論:

  • freqtrade Discord 官方伺服器(搜尋「freqtrade discord」)——遇到技術問題,這裡比 Stack Overflow 快得多
  • QuantConnect 論壇——雖然平台不同,但策略設計的討論品質很高
  • Twitter/X 上的 #freqtrade 標籤——可以看到其他人在做什麼

書籍(比課程更深):

  • Ernest Chan《Algorithmic Trading》:策略設計和統計驗證的標準讀物,偏學術但扎實
  • Marcos López de Prado《Advances in Financial Machine Learning》:如果你想在 ML 方向深入,這是業界公認的參考書

免費資源:

  • freqtrade 官方文件(freqtrade.io)——所有設定參數的最終權威,每次升版都要看 changelog
  • Quantopian 留下的免費教學(已在 Zipline 遷移後繼續運作)

重要的心理準備:量化交易沒有「學完就能賺錢」的終點。市場在變、策略會失效、新工具會出現。把這當成一個長期的研究項目,而不是一個你學完就能自動產出報酬的機器——這個心態調整,比任何技術更重要。

寫在最後

你在這八堂課裡學了量化交易的全流程,從第 1 課的「先潑冷水」,到這堂的「把所有零件接起來」。這不是一門讓你複製貼上一個策略、放著跑就能賺錢的課——如果你期待那種課,可以去找,但它大機率會讓你在不理解風險的情況下虧損。

這門課的目標是讓你理解你在做什麼:資料從哪裡來、策略的假設是什麼、回測數字代表什麼意思、AI 在哪裡有用、風控在保護你什麼。理解了這些,你才能在出問題的時候知道問題在哪,在策略失效的時候知道該怎麼辦。

量化交易能做到的,是把你的交易邏輯系統化、紀律化、可量測化——這已經比大多數散戶多了很大的優勢。但市場永遠比任何一個模型複雜。保持謙遜,保持學習,把資金管理當成比策略本身更重要的事。

最終風險聲明 本課程八堂所有內容僅供學習與研究用途,不構成任何投資建議,不保證任何策略在實盤中獲利。金融市場存在本金全損風險,量化系統可能因策略失效、程式錯誤、API 異常、交易所風險或不可預見的市場事件而造成損失,且損失速度可能遠快於人工交易。回測績效、模擬盤績效均不代表未來實盤結果。若你決定投入實盤,請只動用你可以接受全額虧損的資金,並在投入前諮詢具備金融執照的專業人士及熟悉虛擬資產的稅務會計師。本課程作者不對任何因使用課程內容而產生的財務損失負責。

#AI 量化交易#綜合實戰#freqtrade#全流程#風控#模擬盤#台灣稅務

← 回所有文章