核心策略概述 (商品 NAS100)
這是一個基於技術指標的趨勢突破與逆勢交易策略。策略整合MACD背離分析、CDP逆勢指標、ADX趨勢強度等多項技術指標來識別進場機會,並採用嚴格的風險控制與交易時段管理。
風險控制
資金風控門檻: 帳戶餘額 < 資金風控時停止所有交易
點差控制: 進場前檢查 SP < 商品平均點差 * Point()
交易限制
每日進場次數: 限制 < 1次(EntriesToday(MagicNumber,Symbol()) < 1)
平倉冷卻期: 距離上次出場至少2根K棒(`BarSinceExit > 1`)
K棒控制: 同一根K棒不重複進場(`BarNumber != OrderBarNo`)
進出場策略
多單進場條件
LE_Cond = (High[1] == Highest_OHLC(10日) && Close[1] > Close[2]);
條件分析:
1. 創新高突破: 前一根K棒最高價 = 最近10日最高價
進場執行:
方式: 市價單買入(`Buy_at_MARKET`)
前置條件:
- 空手狀態(多單部位() == 0 && 空單部位() == 0)
- 點差合理(SP < 商品平均點差*Point())
- 今日未進場(EntriesToday < 1)
- 平倉冷卻期已過(BarSinceExit > 1)
- 不同K棒(BarNumber != OrderBarNo)
空單進場條件
SE_Cond = (Close[1] < CDP && Close[1] < NL && a_ADX[1] > a_ADX[2]);
條件分析:
1. 跌破CDP中心: 收盤價 < CDP(逆勢指標的中心軸)
2. 跌破近低值: 收盤價 < NL(CDP系統的近低值)
3. *趨勢增強: ADX上升(a_ADX[1] > a_ADX[2]),確認下跌趨勢強度增加
進場執行:
方式: 市價單賣出(`Short_at_MARKET`)
前置條件:
- 空手狀態(多單部位() == 0 && 空單部位() == 0)
- 點差合理(SP < 商品平均點差*Point())
- 今日未進場(EntriesToday < 1)
- 平倉冷卻期已過(BarSinceExit > 1)
- 不同K棒(BarNumber != OrderBarNo)
//+------------------------------------------------------------------+
//| MT5 自動交易程式 (Expert Advisor)
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh> // 引入 MT5 交易函數庫
#include <MagicMT5_函數庫V2.mqh> // 引入自定義函數庫
//+------------------------------------------------------------------+
//| EA 初始化函數 - 當 EA 載入到圖表時執行一次
//+------------------------------------------------------------------+
int OnInit()
{
// 記錄 EA 載入的時間
LoadEA = TimeCurrent();
// 顯示交易品種的最小交易手數和點值資訊
return(INIT_SUCCEEDED); // 返回初始化成功
}
//+------------------------------------------------------------------+
//| OnTick 函數 - 每次價格變動時執行
//+------------------------------------------------------------------+
void OnTick()
{
//+------------------------------------------------------------------+
//| 資金風控檢查 - 如果帳戶餘額低於設定值則停止交易
//+------------------------------------------------------------------+
if(AccountInfoDouble(ACCOUNT_BALANCE) < 資金風控)
{
Alert("********** 資金不足 *************");
return; // 資金不足時直接返回,不執行任何交易邏輯
}
//+------------------------------------------------------------------+
//| K 棒計數器與新 K 棒判斷
//+------------------------------------------------------------------+
// 計算從 EA 載入到現在經過了多少根 K 棒
BarNumber = iBarShift(Symbol(),時間週期,LoadEA);
// 計算從上次平倉到現在經過了多少根 K 棒
BarSinceExit = BarNumber-CloseOrderNo ;
// 判斷是否為新的第一根 K 棒(用於開盤時的初始化交易)
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棒(); // 更新所有指標、OHLC 數據
交易時段賦值(); // 判斷當前是否在允許交易的時段
}
//+------------------------------------------------------------------+
//| 更新市場報價與帳戶資訊
//+------------------------------------------------------------------+
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. 滿足多單進場條件(LE_Cond)
// 2. 點差小於設定的平均點差
// 3. 最近 6 筆交易內有空單平倉(表示市場可能反轉)
if(LE_Cond == true && SP < NormalizeDouble(商品平均點差*Point(),Digits()) && 最近幾筆內有空單平倉(Symbol(),6) == true)
{
// 確保當前為空手狀態且不在同一根 K 棒重複進場
if(多單部位() == 0 && 空單部位() == 0 && BarNumber != OrderBarNo)
{
// 確保距離上次出場至少 2 根 K 棒,且當日進場次數少於 1 次
if(BarSinceExit > 1 && EntriesToday(MagicNumber,Symbol()) < 1)
{
// 執行市價多單進場
多單進場單號 = Buy_at_MARKET(Symbol(),Lots,TP,SL,"BUY MARKET",MagicNumber) ;
// 記錄進場的 K 棒編號,避免同一根 K 棒重複進場
OrderBarNo = iBarShift(Symbol(),時間週期,LoadEA);
}
}
}
//+------------------------------------------------------------------+
//| 空單進場邏輯
//+------------------------------------------------------------------+
set_ShortCondition() ; // 設定空單進場條件
// 空單進場條件:
// 1. 滿足空單進場條件(SE_Cond)
// 2. 點差小於設定的平均點差
if(SE_Cond == true && SP < NormalizeDouble(商品平均點差*Point(),Digits()))
{
// 確保當前為空手狀態且不在同一根 K 棒重複進場
if(多單部位() == 0 && 空單部位() == 0 && BarNumber != OrderBarNo)
{
// 確保距離上次出場至少 2 根 K 棒,且當日進場次數少於 1 次
if(BarSinceExit > 1 && EntriesToday(MagicNumber,Symbol()) < 1)
{
// 執行市價空單進場
空單進場單號 = Short_at_MARKET(Symbol(),Lots,TP,SL,"Short Market",MagicNumber) ;
// 記錄進場的 K 棒編號
OrderBarNo = iBarShift(Symbol(),時間週期,LoadEA);
}
}
}
} // end of 允許交易時段 == true
//+------------------------------------------------------------------+
//| 出場邏輯 - 不受交易時段限制,任何時候都可以停損停利
//+------------------------------------------------------------------+
交易時段外也可停損停利();
// 更新判斷用的 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 棒形成時,更新所有指標、刪除掛單、計算技術指標
//+------------------------------------------------------------------+
void 換K棒()
{
// 設定 K 棒數據陣列為序列模式(索引 0 為最新 K 棒)
Set_OHLC_Bar_Series();
// 設定日線數據陣列為序列模式
Set_OHLC_Day_Series();
// 取得最近 30 根 K 棒的 OHLC 數據
Get_OHLC_Bar(30) ;
// 取得最近 15 根日線的 OHLC 數據
Get_OHLC_Day(15) ;
// 計算 MACD 指標
set_MACD();
// 計算 CDP 指標(逆勢操作指標)
set_CDP();
// 計算固定週期的高低點
FixBarHL();
// 計算 ADX 指標(趨勢強度指標)
set_ADX();
// 計算最近 5 日的平均波動範圍
Day5Range = ((HighD[1] - LowD[1])+(HighD[2] - LowD[2])+(HighD[3] - LowD[3])+(HighD[4] - LowD[4])+(HighD[5] - LowD[5]))/5;
}
//+------------------------------------------------------------------+
//| 函數: 交易時段賦值 |
//| 功能: 根據當前時間判斷是否在允許交易的時段內 |
//+------------------------------------------------------------------+
void 交易時段賦值()
{
// 交易時段編號 11: 允許在 14:00 到次日 06:00 之間交易
允許交易時段 = (getTM_hour(TimeCurrent()) >= 14 || getTM_hour(TimeCurrent()) < 6) ;
}
//+------------------------------------------------------------------+
//| 函數: 交易時段外也可停損停利 |
//| 功能: 不論是否在交易時段,都執行停損停利邏輯 |
//+------------------------------------------------------------------+
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()) ;
// 1. 達到最小停利且空單進場條件成立(反向訊號)
// 2. 或價格跌破停損價(前一根收盤在停損價之上,現在跌破)
LX_Cond = ((LX_MinPF == true && SE_Cond) || (Close[1] >= 多單停損價格 && Bid < 多單停損價格)) ;
// 執行多單平倉
// 條件: 出場條件成立 && 不在同一根 K 棒重複平倉 && 持倉至少 1 根 K 棒
if(LX_Cond == true && BarNumber != CloseOrderNo && LE_BarsSinceEntry(MagicNumber,多單進場單號,時間週期) > 0)
{
// 平倉指定單號的多單
LX_CloseByTicket(多單進場單號,Lots) ;
// 如果全部多單已平倉,記錄平倉的 K 棒編號
if(多單部位() == 0)
{
CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ;
}
}
} // end of 多單部位() > 0
//+------------------------------------------------------------------+
//| 空單出場邏輯 |
//+------------------------------------------------------------------+
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()) ;
// 1. 達到最小停利且 MACD DIF 由負轉正(反向訊號)
// 2. 或價格突破停損價(前一根收盤在停損價之下,現在突破)
SX_Cond = ((SX_MinPF == true && CrossOver(a_DIF[2],0,a_DIF[1],0)) || (Close[1] <= 空單停損價格 && Ask > 空單停損價格)) ;
// 執行空單平倉
// 條件: 出場條件成立 && 不在同一根 K 棒重複平倉 && 持倉至少 1 根 K 棒
if(SX_Cond == true && BarNumber != CloseOrderNo && SE_BarsSinceEntry(MagicNumber,空單進場單號,時間週期) > 0)
{
// 平倉指定單號的空單
SX_CloseByTicket(空單進場單號,Lots) ;
// 如果全部空單已平倉,記錄平倉的 K 棒編號
if(空單部位() == 0)
{
CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ;
}
}
} // end of 空單部位() > 0
} // end of 交易時段外也可停損停利()
//+------------------------------------------------------------------+
//| 函數: set_BuyCondition |
//| 功能: 設定多單進場條件(根據不同的模組編號使用不同策略) |
//+------------------------------------------------------------------+
void set_BuyCondition()
{
// 條件: 前一根 K 棒創 10 日新高 && 前一根收盤價高於前二根收盤價
LE_Cond = (High[1] == Highest_OHLC(Symbol(),時間週期,MODE_HIGH,10,1) && Close[1] > Close[2]) ;
}
//+------------------------------------------------------------------+
//| 函數: set_ShortCondition |
//| 功能: 設定空單進場條件(根據不同的模組編號使用不同策略) |
//+------------------------------------------------------------------+
void set_ShortCondition()
{
// 條件:
// 1. 收盤價跌破 CDP(逆勢指標的中心點)
// 2. 收盤價跌破 NL(近低點)
// 3. ADX 指標上升(趨勢增強)
SE_Cond = (Close[1] < CDP && Close[1] < NL && a_ADX[1] > a_ADX[2]) ;
}
//+------------------------------------------------------------------+
//| CDP 指標相關變數
//+------------------------------------------------------------------+
double CDP,AH,NH,NL,AL,CDPrange ; // CDP 各關鍵價位
bool CrossAH,CrossAL; // 是否突破最高值/最低值區間
//+------------------------------------------------------------------+
//| 函數: set_CDP
//| 功能: 計算 CDP 逆勢操作指標
//| 說明: CDP 是根據前一日的高低收計算出的 5 個關鍵價位
//+------------------------------------------------------------------+
void set_CDP()
{
double Highest2,Lowest2 ;
// CDP = (前日高 + 前日低 + 2*前日收) / 4
CDP = (HighD[1]+LowD[1]+2*CloseD[1])/4;
// AH(最高值) = CDP + 前日波動
AH = CDP + (HighD[1] - LowD[1]);
// NH(近高值) = CDP*2 - 前日低
NH = CDP*2 - LowD[1];
// NL(近低值) = CDP*2 - 前日高
NL = CDP*2 - HighD[1];
// AL(最低值) = CDP - 前日波動
AL = CDP - (HighD[1] - LowD[1]);
// CDP 波動範圍
CDPrange = HighD[1] - LowD[1] ;
// 計算最近 2 根 K 棒的高低點
Highest2 = Highest_OHLC(Symbol(),時間週期,MODE_HIGH,2,1) ;
Lowest2 = Lowest_OHLC(Symbol(),時間週期,MODE_LOW,2,1) ;
// 判斷是否在最高值區間震盪(突破 AH 但回落到 NH 以下)
CrossAH = Highest2 > AH && Lowest2 < NH ;
回測結果
測試參數交易商品:NAS100(那斯達克指數)樣本內區間:2019/1/1 ~ 2023/8/31
交易手數:固定 1 手
時間框架:M6 分鐘圖表
交易模式:波段交易
// 判斷是否在最低值區間震盪(跌破 AL 但反彈到 NL 以上)
CrossAL = Highest2 > NL && Lowest2 < AL ;
}
現在就加入《外匯實戰 MT5 EA基礎班》,用量化思維,開啟你的交易新紀元!
報名連結 =>> 外匯實戰 MT5 EA基礎班
★ ~~~ 早鳥優惠 ( 2025/11/13 前報名) ~~~ ★
🎁限量加碼 贈送 實戰EA *2
(XAUUSD *1 + NAS100 * 1)
(XAUUSD *1 + NAS100 * 1)
可攜伴2位參加文創手作聖誕樹 DIY才藝班

沒有留言:
張貼留言