Files
DinQuant/docs/STRATEGY_DEV_GUIDE_TW.md
T
TIANHE 6ce128f576 new
Signed-off-by: TIANHE <TIANHE@GMAIL.COM>
2025-12-30 17:03:22 +08:00

7.4 KiB

QuantDinger Python 策略開發指南

本指南將詳細介紹如何在 QuantDinger 平台中使用 Python 開發交易策略。QuantDinger 提供了靈活的執行環境,支持數據訪問、指標計算和信號生成。

1. 概覽

QuantDinger 中的策略基於 信號提供者 (Signal Provider) 模式運行。系統執行你的 Python 腳本,該腳本負責處理市場數據(DataFrame)並輸出交易信號。

執行流程如下:

  1. 輸入:系統將包含 OHLCV 數據的 df (Pandas DataFrame) 注入到你的腳本環境中。
  2. 處理:你使用 Python (pandas, numpy) 計算指標並定義 buy/sell 邏輯。
  3. 輸出:你構造一個特定的 output 字典,包含繪圖數據和信號。

2. 環境與數據

你的腳本運行在一個沙盒化的 Python 環境中。

2.1 預導入庫

以下庫默認可用(無需 import):

  • pd (pandas)
  • np (numpy)

2.2 輸入數據 (df)

一個名為 df 的 Pandas DataFrame 變量會自動存在於全局作用域中。它包含所選代碼和時間週期的歷史市場數據。

列 (Columns):

  • time: 時間戳 (datetime 或 int,視上下文而定)
  • open: 開盤價 (float)
  • high: 最高價 (float)
  • low: 最低價 (float)
  • close: 收盤價 (float)
  • volume: 成交量 (float)

示例:

# 獲取收盤價序列
closes = df['close']

# 計算簡單移動平均線 (SMA)
sma_20 = df['close'].rolling(20).mean()

3. 開發策略

一個標準的策略腳本包含三個部分:

  1. 指標計算:計算技術指標。
  2. 信號生成:定義買入和賣出信號邏輯。
  3. 輸出構建:格式化結果以供圖表展示和執行引擎使用。

3.1 指標計算

你可以使用標準的 Pandas 操作來計算指標。

# 示例:MACD 計算
short_window = 12
long_window = 26
signal_window = 9

ema12 = df['close'].ewm(span=short_window, adjust=False).mean()
ema26 = df['close'].ewm(span=long_window, adjust=False).mean()
macd = ema12 - ema26
signal_line = macd.ewm(span=signal_window, adjust=False).mean()

3.2 信號生成 (關鍵)

必須df 中創建(或作為獨立變量)兩個布爾類型的 Series,分別命名為 buysell

  • True 表示觸發信號。
  • False 表示無信號。

重要:邊緣觸發 (Edge Triggering) 為了避免在連續的 K 線上重複發出信號(這可能導致重複下單,取決於後端配置),最佳實踐是使用 邊緣觸發 信號(即只在條件變真的那一刻發出信號)。

# 條件:收盤價上穿 SMA 20
condition_buy = (df['close'] > sma_20) & (df['close'].shift(1) <= sma_20.shift(1))

# 條件:收盤價下穿 SMA 20
condition_sell = (df['close'] < sma_20) & (df['close'].shift(1) >= sma_20.shift(1))

# 賦值給 df (回測必需)
df['buy'] = condition_buy.fillna(False)
df['sell'] = condition_sell.fillna(False)

關於信號類型的說明:

  • QuantDinger 會根據你的策略配置(僅做多、僅做空或雙向)來標準化信號。
  • 你的腳本只需輸出 "buy"(看漲意圖)或 "sell"(看跌意圖)。後端會處理開倉/平倉邏輯。

3.3 可視化標記

為了在圖表上展示,你通常希望將信號圖標放在 K 線的上方或下方。

# 將買入標記放在最低價下方 0.5% 處
buy_marks = [
    df['low'].iloc[i] * 0.995 if df['buy'].iloc[i] else None 
    for i in range(len(df))
]

# 將賣出標記放在最高價上方 0.5% 處
sell_marks = [
    df['high'].iloc[i] * 1.005 if df['sell'].iloc[i] else None 
    for i in range(len(df))
]

3.4 output 變量 (必須)

最後一步是將一個字典賦值給變量 output。這告訴前端如何繪圖,以及告訴後端信號在哪裡。

結構:

output = {
    "name": "我的策略名稱",
    "plots": [ ... ],   # 要繪製的線條/指標列表
    "signals": [ ... ]  # 信號標記列表
}

Plots Schema (繪圖配置):

  • name: 圖例名稱 (例如 "SMA 20")
  • data: 數值列表 (必須與 df 長度一致)。使用 .tolist() 轉換。
  • color: 十六進制顏色字符串 (例如 "#ff0000")。
  • overlay: True 表示繪製在主圖(價格圖)上,False 表示繪製在副圖(如 RSI/MACD)。

Signals Schema (信號配置):

  • type: 必須是 "buy" 或 "sell"。
  • text: 圖標上顯示的文本 (例如 "B", "S")。
  • data: 數值列表 (價格位置)。無信號處為 None
  • color: 圖標顏色。

4. 完整示例:雙均線交叉 (Dual SMA)

以下是一個完整的、可複製的雙均線策略示例:當 SMA(10) 上穿 SMA(30) 時買入,下穿時賣出。

# 1. 指標計算
# -----------------------
# 計算短期和長期 SMA
sma_short = df['close'].rolling(10).mean()
sma_long = df['close'].rolling(30).mean()

# 2. 信號邏輯
# -----------------------
# 買入:短期 SMA 上穿 長期 SMA
raw_buy = (sma_short > sma_long) & (sma_short.shift(1) <= sma_long.shift(1))

# 賣出:短期 SMA 下穿 長期 SMA
raw_sell = (sma_short < sma_long) & (sma_short.shift(1) >= sma_long.shift(1))

# 清理 NaN 並確保布爾類型
buy = raw_buy.fillna(False)
sell = raw_sell.fillna(False)

# 賦值給 df 列 (後端執行的關鍵)
df['buy'] = buy
df['sell'] = sell

# 3. 可視化格式化
# -----------------------
# 計算標記位置
buy_marks = [
    df['low'].iloc[i] * 0.995 if buy.iloc[i] else None 
    for i in range(len(df))
]

sell_marks = [
    df['high'].iloc[i] * 1.005 if sell.iloc[i] else None 
    for i in range(len(df))
]

# 4. 最終輸出
# -----------------------
output = {
  'name': '雙均線策略',
  'plots': [
    {
        'name': 'SMA 10',
        'data': sma_short.fillna(0).tolist(),
        'color': '#1890ff',
        'overlay': True
    },
    {
        'name': 'SMA 30',
        'data': sma_long.fillna(0).tolist(),
        'color': '#faad14',
        'overlay': True
    }
  ],
  'signals': [
    {
        'type': 'buy',
        'text': '買',
        'data': buy_marks,
        'color': '#00E676'
    },
    {
        'type': 'sell',
        'text': '賣',
        'data': sell_marks,
        'color': '#FF5252'
    }
  ]
}

5. 最佳實踐與故障排除

5.1 處理 NaN

滾動計算(如 rolling(14))會在數據開頭產生 NaN 值。

  • 規則:生成信號前必須處理 NaN
  • 修復:使用 .fillna(0).fillna(False)

5.2 未來函數 (Look-ahead Bias)

系統基於 K 線 收盤 時產生的信號執行交易。

  • 回測引擎通常在 下一根 K 線的開盤價 執行訂單。
  • 你的信號邏輯應依賴 close (當前已完成的 K 線) 或 shift(1) (前一根 K 線)。切勿使用 shift(-1)

5.3 性能

避免在計算邏輯中遍歷 DataFrame 行 (for i in range(len(df)): ...)。這非常慢。

  • 錯誤:使用循環計算 SMA。
  • 正確:使用 df['close'].rolling(...)
  • 例外:構建 buy_marks/sell_marks 列表通常需要列表推導式,這是可接受的(僅用於可視化輸出)。

5.4 調試

由於在某些執行模式下無法輕易看到 print() 輸出,如果策略加載失敗,請檢查後端日誌 (backend_api_python/logs/app.log)。

  • 常見錯誤:KeyError (列名錯誤)。
  • 常見錯誤:ValueError (數組長度不一致)。確保 plots 中的數據長度與 df 一致。