核心策略概述 (交易商品 NAS100 )
這是一個基於多重技術指標超賣/超買背離的反轉交易策略。策略整合RVI背離、多重指標鈍化(RSI、KD、Williams %R、CCI)、Keltner通道突破等多項指標來識別進場機會,並使用固定時段交易模式(14:00-22:00)。
交易限制:
資金風控門檻: 低於門檻時停止交易
商品平均點差限制: 進場前檢查點差 < 商品平均點差 * Point()
每日限制1次進場
距離上次平倉需間隔 > 1根K棒
交易時段: 14:00 至 22:00
進出場策略
多單進場條件
LE_Cond = (RVI_HDiv_01() && Close[1] > 流動性池底部價格 && Close[1] > a_KC_UPPER_B[1]);
條件分析:
RVI高點背離 (RVI_HDiv_01())
價格最高點在最近3根K棒內(索引0-2)發生
RVI最高點出現在更早之前(索引>2),顯示動能減弱 目前RVI值 < 0.5(回落狀態)
突破流動性池底部價格
收盤價突破最近20根K棒的最低價(從第5根開始計算)
突破Keltner通道上軌B 確認突破強度
進場方式: 市價單買入,僅在無部位、點差小、最近6筆內有空單平倉、今日未進場、BarSinceExit > 1時執行
空單進場條件
SE_Cond = (多重超賣鈍化() && Close[1] > Close[3] && Close[1] < Open[1]);
條件分析:
多重超賣鈍化 (多重超賣鈍化())
需要至少2個以上指標同時出現低檔鈍化:
RSI低檔鈍化: RSI < 30 且出現 ≥ 4次
KD低檔鈍化: K值 < 30 且出現 ≥ 4次
Williams %R低檔鈍化: WPR < -80 且出現 ≥ 4次
CCI超賣鈍化: CCI < -100 且出現 ≥ 4次
價格回升確認
Close[1] > Close[3] (收盤價高於2根K棒前) 確認超賣後的反彈動作
黑K確認 Close[1] < Open[1] (收盤價低於開盤價) 形成看跌K線型態
進場方式: 市價單賣出,僅在無部位、點差小、今日未進場、BarSinceExit > 1時執行
//+------------------------------------------------------------------+
//| MT5 自動交易程式 (Expert Advisor)
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh> // 引入 MT5 交易函數庫
#include <MagicMT5_函數庫V2.mqh> // 引入自定義函數庫
//+------------------------------------------------------------------+
//| EA 初始化函數
//| 說明:程式啟動時執行一次,用於初始化變數和顯示商品資訊
//+------------------------------------------------------------------+
int OnInit()
{
// 記錄EA載入時間
LoadEA = TimeCurrent();
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| EA 主要執行函數
//| 說明:每個Tick(價格變動)都會執行,包含所有交易邏輯
//+------------------------------------------------------------------+
void OnTick()
{
// 檢查帳戶餘額是否低於風控設定值
if(AccountInfoDouble(ACCOUNT_BALANCE) < 資金風控)
{
Alert("********** 資金不足 *************");
return; // 資金不足時停止執行
}
// 計算目前K棒編號(從EA載入時間開始算起)
BarNumber = iBarShift(Symbol(),時間週期,LoadEA);
// 計算距離上次平倉後經過的K棒數量
BarSinceExit = BarNumber-CloseOrderNo ;
// 當出現新K棒時(BarNumber=1)且未重複判斷時,執行測試交易
if((BarNumber == 1 && BarNumber != JudgeNo))
{
// 執行多單市價進場並立即平倉(用於測試)
多單進場單號 = Buy_at_MARKET(Symbol(),Lots,0,0,"1st_K",MagicNumber) ;
LX_CloseByTicket(多單進場單號,Lots) ;
// 執行空單市價進場並立即平倉(用於測試)
空單進場單號 = Short_at_MARKET(Symbol(),Lots,0,0,"1st_K",MagicNumber) ;
SX_CloseByTicket(空單進場單號,Lots) ;
// 記錄平倉時的K棒編號
CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA);
// 計算快慢均線週期(取較小值和較大值)
FastSma = MathMin(LenA1, LenB1);
SlowSma = MathMax(LenA1, LenB1);
}
// 當K棒編號改變時,更新指標和交易時段設定
if(BarNumber != JudgeNo)
{
換K棒(); // 更新所有技術指標和K棒數據
交易時段賦值(); // 判斷是否在允許交易時段內
}
// 取得目前市場價格資訊
Ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK); // 買入價(賣方報價)
Bid=SymbolInfoDouble(Symbol(),SYMBOL_BID); // 賣出價(買方報價)
AccountBalance=AccountInfoDouble(ACCOUNT_BALANCE); // 帳戶餘額
Tickvalue=SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_VALUE); // 每跳點價值
SP = NormalizeDouble(MathAbs(Ask-Bid),Digits()) ; // 計算買賣價差(點差)
//+------------------------------------------------------------------+
//| 動態計算交易手數
//| 說明:根據風險百分比和停損點數自動計算合適的交易手數
//+------------------------------------------------------------------+
if(動態計算手數 == true)
{
// 根據帳戶餘額、風險百分比和停損點數計算手數
Lots = get_dynamic_lot_size(是否偶數單,Symbol(),風險百分比,AccountBalance,SL) ;
// 限制手數範圍在0.01到0.3之間
Lots = MathMin(0.3,MathMax(0.01,Lots)) ;
}
// 只有在允許交易時段內才執行進場邏輯
if(允許交易時段 == true)
{
//+------------------------------------------------------------------+
//| 多單進場邏輯
//+------------------------------------------------------------------+
set_BuyCondition(); // 計算多單進場條件
// 多單進場判斷:
// 1. 多單進場條件成立
// 2. 點差小於商品平均點差
// 3. 最近6筆內有空單平倉記錄
if(LE_Cond == true && SP < NormalizeDouble(商品平均點差*Point(),Digits()) && 最近幾筆內有空單平倉(Symbol(),6) == true)
{
// 確認目前空手且非同一根K棒重複下單
if(多單部位() == 0 && 空單部位() == 0 && BarNumber != OrderBarNo)
{
// 確認距離上次平倉超過1根K棒,且當日交易次數未超過1次
if(BarSinceExit > 1 && EntriesToday(MagicNumber,Symbol()) < 1)
{
// 執行市價多單進場
多單進場單號 = Buy_at_MARKET(Symbol(),Lots,TP,SL,"BUY MARKET",MagicNumber) ;
// 記錄下單時的K棒編號(避免重複下單)
OrderBarNo = iBarShift(Symbol(),時間週期,LoadEA);
}
}
}
//+------------------------------------------------------------------+
//| 空單進場邏輯
//+------------------------------------------------------------------+
set_ShortCondition() ; // 計算空單進場條件
// 空單進場判斷:
// 1. 空單進場條件成立
// 2. 點差小於商品平均點差
if(SE_Cond == true && SP < NormalizeDouble(商品平均點差*Point(),Digits()))
{
// 確認目前空手且非同一根K棒重複下單
if(多單部位() == 0 && 空單部位() == 0 && BarNumber != OrderBarNo)
{
// 確認距離上次平倉超過1根K棒,且當日交易次數未超過1次
if(BarSinceExit > 1 && EntriesToday(MagicNumber,Symbol()) < 1)
{
// 執行市價空單進場
空單進場單號 = Short_at_MARKET(Symbol(),Lots,TP,SL,"Short Market",MagicNumber) ;
// 記錄下單時的K棒編號(避免重複下單)
OrderBarNo = iBarShift(Symbol(),時間週期,LoadEA);
}
}
}
}
// 執行停損停利邏輯(即使不在交易時段也可執行)
交易時段外也可停損停利();
// 更新判斷編號,避免同一K棒重複判斷
JudgeNo = iBarShift(Symbol(),時間週期,LoadEA);
} //end of onTick
//+------------------------------------------------------------------+
//| 自訂函數庫區塊
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| 多單部位數量
//| 返回:目前持有的多單數量
//+------------------------------------------------------------------+
int 多單部位()
{
int count;
count = get_TradeCounts(Symbol(), MagicNumber,POSITION_TYPE_BUY) ;
return count ;
}
//+------------------------------------------------------------------+
//| 空單部位數量
//| 返回:目前持有的空單數量
//+------------------------------------------------------------------+
int 空單部位()
{
int count;
count = get_TradeCounts(Symbol(), MagicNumber,POSITION_TYPE_SELL) ;
return count ;
}
//+------------------------------------------------------------------+
//| 換K棒時執行的更新函數
//| 說明:每當新K棒產生時,更新所有技術指標和K棒數據
//+------------------------------------------------------------------+
void 換K棒()
{
// 新K棒產生時刪除所有未成交的掛單
if(total_pending_order_count(Symbol(), MagicNumber,-1) != 0)
{
delete_pending_orders_all(Symbol(), MagicNumber, -1, 0x0000ff);
}
// 設定K棒和日線數據的陣列序列(必要步驟)
Set_OHLC_Bar_Series();
Set_OHLC_Day_Series();
// 獲取最近30根K棒和15天的OHLC數據
Get_OHLC_Bar(30) ;
Get_OHLC_Day(15) ;
// 更新所有技術指標
set_MACD(); // 更新MACD指標
set_RSI(); // 更新RSI指標
set_KD() ; // 更新KD隨機指標
set_CCI(); // 更新CCI指標
set_RVI(); // 更新RVI指標
set_WILLIAMS_PR() ; // 更新威廉指標
set_KELTNER_CHANNEL() ; // 更新肯特納通道
// 計算最近5日的平均波動範圍
Day5Range = ((HighD[1] - LowD[1])+(HighD[2] - LowD[2])+(HighD[3] - LowD[3])+(HighD[4] - LowD[4])+(HighD[5] - LowD[5]))/5;
}
//+------------------------------------------------------------------+
//| 交易時段判斷
//| 說明:根據時間設定允許交易的時段
//+------------------------------------------------------------------+
void 交易時段賦值()
{
// 允許交易時間為14:00到22:00
允許交易時段 = (getTM_hour(TimeCurrent()) >= 14 && getTM_hour(TimeCurrent()) < 22);
}
//+------------------------------------------------------------------+
//| 停損停利執行函數 |
//| 說明:即使不在交易時段也執行停損停利,保護帳戶資金 |
//+------------------------------------------------------------------+
void 交易時段外也可停損停利()
{
// 處理多單部位的停損停利
if(多單部位() > 0)
{
//+------------------------------------------------------------------+
//| 多單出場方法設定 |
//+------------------------------------------------------------------+
double 多單最小停利 = 0.0;
bool LX_MinPF = false ;
// 取得多單進場價格
多單進場價格 = LE_EntryPrice(MagicNumber,多單進場單號);
// 計算最小停利價格(進場價格+3倍點差)
多單最小停利 = NormalizeDouble(多單進場價格 + SP*3,Digits()) ;
LX_MinPF = Bid > 多單最小停利 ; // 判斷是否達到最小停利
// 計算多單停利價格(進場價格+停利點數)
多單停利價格 = NormalizeDouble(多單進場價格 + TP * Point(),Digits()) ;
// 計算多單停損價格(進場價格-停損點數)
多單停損價格 = NormalizeDouble(多單進場價格 - SL * Point(),Digits()) ;
// 多單出場方式13:動態停利(加上5日平均波動)
// 停利價格加上5日平均波動範圍
多單停利價格 = NormalizeDouble(多單進場價格 + (TP+Day5Range) * Point(),Digits()) ;
// 多單出場條件:價格突破停利或停損價格
LX_Cond = ((Close[1] <= 多單停利價格 && Bid > 多單停利價格) || (Close[1] >= 多單停損價格 && Bid < 多單停損價格)) ;
// 執行多單平倉
// 條件:1.出場條件成立 2.非同一K棒重複平倉 3.持倉超過0根K棒
if(LX_Cond == true && BarNumber != CloseOrderNo && LE_BarsSinceEntry(MagicNumber,多單進場單號,時間週期) > 0)
{
// 執行平倉
LX_CloseByTicket(多單進場單號,Lots) ;
// 如果多單已全部平倉,記錄平倉K棒編號
if(多單部位() == 0)
{
CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ;
}
}
}
// 處理空單部位的停損停利
if(空單部位() > 0)
{
//+------------------------------------------------------------------+
//| 空單出場方法設定 |
//+------------------------------------------------------------------+
double 空單最小停利 = 0.0;
bool SX_MinPF = false ;
// 取得空單進場價格
空單進場價格 = SE_EntryPrice(MagicNumber,空單進場單號);
// 計算最小停利價格(進場價格-3倍點差)
空單最小停利 = NormalizeDouble(空單進場價格 - SP*3,Digits()) ;
SX_MinPF = Ask < 空單最小停利 ; // 判斷是否達到最小停利
// 計算空單停利價格(進場價格-停利點數)
空單停利價格 = NormalizeDouble(空單進場價格 - TP * Point(),Digits()) ;
// 計算空單停損價格(進場價格+停損點數)
空單停損價格 = NormalizeDouble(空單進場價格 + SL * Point(),Digits()) ;
// 空單出場方式11:MACD黃金交叉或觸及停損
// 空單出場條件:1.達到最小停利且MACD向上交叉0軸 2.價格突破停損
SX_Cond = ((SX_MinPF == true && CrossOver(a_MACD[2],0,a_MACD[1],0)) || (Close[1] <= 空單停損價格 && Ask > 空單停損價格)) ;
}
// 執行空單平倉
// 條件:1.出場條件成立 2.非同一K棒重複平倉 3.持倉超過0根K棒
if(SX_Cond == true && BarNumber != CloseOrderNo && SE_BarsSinceEntry(MagicNumber,空單進場單號,時間週期) > 0)
// 執行平倉
SX_CloseByTicket(空單進場單號,Lots) ;
// 如果空單已全部平倉,記錄平倉K棒編號
if(空單部位() == 0)
{
CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ;
}
}
}
}
//+------------------------------------------------------------------+
//| 多單進場條件設定
//| 說明:根據多單模組編號設定不同的進場條件
//+------------------------------------------------------------------+
void set_BuyCondition()
{
// 條件1:RVI高點背離(價格創新高但RVI未創新高)
// 條件2:收盤價突破流動性池底部價格
// 條件3:收盤價突破Keltner通道上軌B
LE_Cond = (RVI_HDiv_01() && Close[1] > 流動性池底部價格 && Close[1] > a_KC_UPPER_B[1]) ;
}
//+------------------------------------------------------------------+
//| 空單進場條件設定
//| 說明:根據空單模組編號設定不同的進場條件
//+------------------------------------------------------------------+
void set_ShortCondition()
{
// 條件1:多重超賣鈍化(多個指標同時顯示超賣且持續)
// 條件2:價格回升(收盤價高於2根K棒前)
// 條件3:形成黑K(收盤價低於開盤價)
SE_Cond = (多重超賣鈍化() && Close[1] > Close[3] && Close[1] < Open[1]) ;
}
回測結果
測試參數交易商品:NAS100(那斯達克指數)樣本內區間:2019/1/1 ~ 2023/8/31
交易手數:固定 1 手
時間框架:M10 分鐘圖表
交易模式:波段交易
現在就加入《外匯實戰 MT5 EA基礎班》,用量化思維,開啟你的交易新紀元!
報名連結 =>> 外匯實戰 MT5 EA基礎班
★ ~~~ 早鳥優惠 ( 2025/11/13 前報名) ~~~ ★
🎁限量加碼 贈送 實戰EA *2
(XAUUSD *1 + NAS100 * 1)
(XAUUSD *1 + NAS100 * 1)
可攜伴2位參加文創手作聖誕樹 DIY才藝班

沒有留言:
張貼留言