- Cleaned up whitespace and formatting in various files including http.py, language.py, logger.py, safe_exec.py, and SQL migration scripts. - Consolidated import statements and removed unnecessary blank lines. - Updated logging configuration for better clarity. - Enhanced the safe execution code with improved error handling and logging. - Removed commented-out code and unnecessary variables in backfill_zero_trades.py and other scripts. - Added a pyproject.toml for Ruff and Vulture configuration. - Introduced requirements-dev.txt for development dependencies. - Removed commented-out stock entries in init.sql for cleaner migration scripts.
7.4 KiB
QuantDinger Python 策略開發指南
本指南將詳細介紹如何在 QuantDinger 平台中使用 Python 開發交易策略。QuantDinger 提供了靈活的執行環境,支持數據訪問、指標計算和信號生成。
1. 概覽
QuantDinger 中的策略基於 信號提供者 (Signal Provider) 模式運行。系統執行你的 Python 腳本,該腳本負責處理市場數據(DataFrame)並輸出交易信號。
執行流程如下:
- 輸入:系統將包含 OHLCV 數據的
df(Pandas DataFrame) 注入到你的腳本環境中。 - 處理:你使用 Python (
pandas,numpy) 計算指標並定義buy/sell邏輯。 - 輸出:你構造一個特定的
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. 開發策略
一個標準的策略腳本包含三個部分:
- 指標計算:計算技術指標。
- 信號生成:定義買入和賣出信號邏輯。
- 輸出構建:格式化結果以供圖表展示和執行引擎使用。
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,分別命名為 buy 和 sell。
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一致。