EMA 三線排列波段交易策略:Python 回測實戰

第 2 課・共 18 課

⚠️ 本站內容僅作教育用途,不構成投資建議。投資涉及風險,作出任何投資決定前請諮詢持牌專業人士。
目錄

本課由 Algo-trading with Saleh 示範一個以三條 指數移動平均線 EMA 為核心的波段交易策略:先以均線排列確認趨勢方向,再用 ATR 設定止損與分批止盈,最後以追蹤止損盡量「坐完」整段趨勢,全部在 Python 回測框架 Jesse 上實作。

學習重點

詳細筆記

策略構想:跟住趨勢坐到尾

講者開宗明義說,這是一個趨勢跟隨型的波段策略:目標是盡量持倉跟隨趨勢,只在認為趨勢完結時才離場。他也預告這個策略會成為下一條片的基礎——之後再用遺傳演算法(genetic algorithm)優化參數。

入場條件:三條 EMA 的排列

策略只用三條 EMA,週期分別為 21、50、100(圖上以紫、黃、藍三色顯示)。在 TradingView 上,直接修改指標的 length 參數即可設定。

三條 EMA 疊在 BTC-USDT 4 小時圖上

截圖出自原片(Algo-trading with Saleh):BTC-USDT 4 小時圖上疊加 EMA 21(紫)、50(黃)、100(藍),均線排列一目瞭然。

好倉(long)條件:EMA21 在 EMA50 之上,兩者又同時在 EMA100 之上,而且現價站在 EMA21 之上——均線由短到長整齊排列,價格在最頂,才是乾淨的升勢。淡倉(short)條件完全相反:EMA21 低於 EMA50、兩者低於 EMA100,且現價在 EMA21 之下。講者特別補充最後一個條件的原因:均線剛形成空頭排列時,價格往往仍在 EMA21 附近徘徊,他要求價格明確跌穿最短那條線才進場,避免在排列初成、方向未確認時倉卒開倉。

其餘所有狀態——均線互相纏繞、排列不齊——一律視為橫行市,不交易。

在 Jesse 框架上實作

講者在 Jesse 回測框架建立新策略,命名為 Trend swing Trader。第一步是定義一個 trend 屬性,計算三條 EMA 後回傳三態:1 代表升勢、-1 代表跌勢、0 代表橫行:

# 摘錄自原片教學(Jesse 框架)
e1 = ta.ema(self.candles, 21)
e2 = ta.ema(self.candles, 50)
e3 = ta.ema(self.candles, 100)
if e3 < e2 < e1 < self.price:
    return 1
elif e3 > e2 > e1 > self.price:
    return -1
else:
    return 0

should_long 只需檢查 self.trend == 1should_short 則檢查 self.trend == -1,邏輯非常乾淨。由於進場用市價單,should_cancel_entry(掛單未成交時是否取消的鉤子)回傳甚麼都無所謂,講者直接略過。

第一版的倉位計算很粗糙:用 size_to_qty 把全部可用保證金換成倉位數量,以市價單進場。講者當時已說明這只是「先把策略跑起來」的權宜之計,稍後會改。

出場設計:ATR 止損+分批止盈+追蹤止損

出場是這課的重頭戲,分三層處理:

第一層:初始止損與首個止盈。 講者用他最愛的 ATR 指標量度每根 K 線的平均波動幅度。止損設在入場價外 2 倍 ATR——他示範時單倍 ATR 約 886 美元,嫌太近,所以用兩倍。止盈設在 3 倍 ATR,但只平掉一半倉位。為何不全走?因為這是波段策略,講者想保留一半倉位繼續跟隨趨勢。

# 摘錄自原片教學:on_open_position(好倉版本)
atr = ta.atr(self.candles, 14)
qty = self.position.qty
self.stop_loss = qty, self.price - atr * 2
self.take_profit = qty / 2, self.price + atr * 3

第二層:止盈觸發後保本。 講者定義 on_reduced_position 事件方法——這是 Jesse 在倉位被「減少但未平完」時觸發的鉤子(hook),正好對應止盈走了一半的時刻。此時把餘下倉位的止損直接移到入場價(self.position.entry_price):前半已鎖定利潤,後半最壞情況只是保本離場,整筆交易立於不敗。Jesse 會自動取消舊止損單、掛上新單,無需手動處理。

第三層:逐 K 線追蹤。 保本只是起點,講者要的是追蹤止損。他在 update_position 方法中,每根新 K 線都把止損更新為「現價減 2 倍 ATR」(淡倉則為現價加 2 倍 ATR)。但有一個陷阱:若直接更新,價格回調時止損反而會被拉遠、放大虧損。所以好倉要用 max 比較新止損價與現有止損價,只准收緊、不准放寬;淡倉則用 min

另一個細節:update_position 每根 K 線都會執行,包括止盈未觸發之前。講者加了一個條件——只有當 reduced_count == 1(即已經走過一半倉位)才啟動追蹤,避免順序錯亂。

程式碼編輯器中的策略原始碼

截圖出自原片(Algo-trading with Saleh):Jesse 策略原始碼,可見 go_long 內先算 ATR 止損價,再決定倉位數量。

第一次回測與倉位管理的威力

講者以 BTC-USDT 永續合約、4 小時圖,由 2022 年初回測至 2024 年中(講者製作影片時),並開啟 fast mode 與 benchmark 選項,讓淨值曲線可以直接與買入持有的 BTC 走勢對照。選 4 小時圖是波段策略的典型選擇:K 線夠密,能在趨勢中段給出進出場訊號;又不像 5 分鐘、15 分鐘圖般充斥雜訊與交易成本。第一版(全倉進出)的結果:利潤 77%,最大回撤 -23%,勝率 47%,平均盈虧比 1.4,跑贏同期買入持有的基準。

然後他做了一件「教學上最有價值」的事:進出場規則一個字不改,只把倉位計算由全倉改為 risk_to_qty——先算止損價(入場價減 2 倍 ATR),再以「每筆交易風險本金 3%」反推倉位大小。重跑後利潤微升至 79%,最大回撤收窄至 -18% 左右。講者強調:指標、入場、出場完全一樣,單單改變倉位管理,績效已經不同——這正是 position sizing 的威力。

用 ADX 過濾橫行市

講者接著指出淨值曲線的弱點:橫行市期間曲線持續下滑。這是趨勢跟隨策略的典型毛病——橫行市中均線反覆交叉、訊號不斷失效。他的解法是加入 平均趨向指數 ADX 作過濾器:ADX 數值介乎 0 至 100,只量度趨勢強度、不分方向;數值低於閾值(他用 25)代表無趨勢、不交易,高於閾值才允許進場。

實作上只需新增一個 adx 屬性回傳布林值,再在 should_longshould_short 各加一個 and self.adx 條件。重跑回測後(同樣為講者影片中的數據):利潤大幅上升、最大回撤顯著收窄至約 -13%,勝率 52%,平均盈虧比 1.57;橫行市期間淨值曲線不再明顯下沉。

加入 ADX 過濾後的回測結果

截圖出自原片(Algo-trading with Saleh):最終版回測結果,回測期 912 日(2022-01-01 至 2024-07-01)、80 宗已平倉交易,Total Net Profit 125.05%,Max Drawdown -13.35%。

跑贏大市的爭論與槓桿取態

講者再示範一個有意思的情境:若只由 2024 年初開始回測,策略帳面不及買入持有,但最大回撤只有約 -10%,遠低於同期市場本身的跌幅。他的論點是:策略的價值在於回撤控制,若投資者的波動容忍度較高(他自稱可接受到 -30%),可以把每筆風險由 3% 加至 5%,甚至動用槓桿(他示範時交易所槓桿設為 2 倍)放大倉位去追平或超越大市的回報,而回撤仍低於市場。但他同時表明個人立場:不會為追回報而開 5 倍、10 倍槓桿,因為控制波動、晚上睡得著對他更重要——「你按自己的容忍度決定,我也按我的做」。

只回測 2024 年上半年的結果

截圖出自原片(Algo-trading with Saleh):2024 年 1 月至 7 月的回測,17 宗交易、利潤 27.59%,最大回撤僅 -10.67%,用作說明回撤控制與「跑贏大市」之間的取捨。

值得留意的是講者對「甚麼叫做好策略」的定義:不是帳面利潤最高,而是在自己睡得著的波動範圍內取得合理回報。回撤、勝率、盈虧比三個數字要一齊看,單獨追求任何一個都會誤導。

片尾講者提到,他為此策略做了一個 premium 版本上載到其平台的策略索引頁(屬其產品推廣,此處不轉載細節),並預告下條片會用 Jesse 的遺傳演算法優化模式調參——下一課再跟進。

🙏 覺得內容有用?本站所有內容免費提供,使用推薦碼開戶就是支持我們繼續營運的最大鼓勵:

ZA Bank 邀請碼 P20923 —— 你享 HKD 2,000 迎新獎賞,本站獲得營運支持。 立即開戶 → (聯盟連結|投資涉及風險,受條款及細則約束,此資料僅可於香港境內分發)

MT5 可行性速評

項目評估
邏輯可移植性高。三條 EMA 用 iMAMODE_EMA)開三個句柄即可,ATR(iATR)、ADX(iADX)全屬內建指標;均線排列比較、ATR 止損、「風險 3% 反推倉位」、分批平倉與追蹤止損都是標準 EA 寫法。
平台限制Jesse 的 on_reduced_position 事件在 MQL5 沒有直接對應,須在 OnTradeTransaction 偵測部分平倉後手動改掛保本止損;追蹤邏輯則放 OnTick 並記錄「只收緊」的上次止損價。另外原片標的為 BTC 永續合約,一般 MT5 券商未必提供,移植後參數須重新驗證。
評級✅ 全部指標皆為內建基本款,入場條件是單純的數值比較,出場雖有三層(初始止損/保本/追蹤)但狀態簡單,是本系列中移植難度最低的一類策略。
MQL5 寫法提示見下
int e21 = iMA(_Symbol, PERIOD_CURRENT, 21, 0, MODE_EMA, PRICE_CLOSE);
int e50 = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE);
int e100 = iMA(_Symbol, PERIOD_CURRENT, 100, 0, MODE_EMA, PRICE_CLOSE);
int atr_h = iATR(_Symbol, PERIOD_CURRENT, 14);
int adx_h = iADX(_Symbol, PERIOD_CURRENT, 14);
// 好倉:e21 > e50 > e100 && Close < ... 實際為 Close > e21 && ADX > 25
// 止損 = entry - 2*ATR;3*ATR 平一半;其後止損只准上移(好倉取 max)

注意:即使成功移植,MT5 策略測試器跑出的回測同樣會過度擬合——21/50/100、2 倍與 3 倍 ATR、ADX 25、風險 3% 全是對著歷史數據選出來的參數,換平台並不能解決方法論問題。

欣利克的看法

名詞解釋

常見問題 FAQ

為甚麼用 EMA 而不用 SMA?

EMA 對近期價格加權較高,對趨勢轉變的反應比 SMA 快。在波段策略中,進出場時機差幾根 K 線已可影響整筆交易的盈虧,所以講者及多數趨勢策略都傾向用 EMA。不過兩者本質都是滯後指標,選哪一種對策略成敗的影響,遠小於倉位管理與出場設計。

ADX 閾值一定要用 25 嗎?

不一定。25 是講者採用的經驗值,常見參考範圍是 20 至 30:閾值越低,過濾越少、交易次數越多;閾值越高,訊號越精但會錯過趨勢初段。閾值本身也是可被過度擬合的參數,應用樣本外數據驗證,而不是在回測中試到最亮麗為止。

分批止盈加保本止損,豈不是穩賺?

不是。保本止損只保證該筆交易「最壞情況」不虧,但代價是許多本可繼續發展的倉位被提前掃走,拉低整體平均盈利。而且保本止損未觸發前,倉位仍承受 2 倍 ATR 的初始風險,連續幾宗止損出場一樣會造成可觀回撤。

這個策略可以直接用在股票或外匯上嗎?

邏輯上可以——均線排列、ATR 止損、ADX 過濾都是跨市場通用的概念。但原片的所有參數(21/50/100、2 倍與 3 倍 ATR、4 小時圖)都是對著 BTC 永續合約的波動特性調出來的,換標的、換時間框架後必須重新回測驗證,並留意股票有隔晚跳空、外匯有點差與隔夜利息等影片未有處理的成本。

原影片

本文整理自以下影片,版權屬原創作者所有,建議配合原片觀看:

來源:https://www.youtube.com/watch?v=H54VqsCb04M

🏦 ZA Bank 開戶優惠

本站所有內容免費提供。多使用網站的推薦碼,就是對我們繼續製作優質內容的最大鼓勵和支持 🙏

去 ZA Bank 開戶,享價值 HKD 2,000 迎新獎賞,仲有機會享 USD 30 指定美股兌換券!

  • 💛 全線上開戶,無需前往分行
  • 💛 無最低存款要求,零賬戶管理費
  • 💛 24x7 銀行服務

專屬邀請碼:P20923

立即開戶 → (聯盟連結)