核心策略概述 (商品 NAS100)
這是一個基於CDP指標和技術分析的日內交易策略,結合多空條件判斷、動態風險管理和嚴格的出場機制。
基礎概念
動態手數計算(基於風險百分比、帳戶餘額與SL),手數限制在0.01~0.3
商品平均點差限制: 進場前檢查點差 < 商品平均點差 * Point()
動態手數計算(基於風險百分比、帳戶餘額與SL),手數限制在0.01~0.3
商品平均點差限制: 進場前檢查點差 < 商品平均點差 * Point()
資金風控門檻: 低於門檻時停止交易並退出EA
交易限制:
每日限制1次進場
點差控制: 進場前檢查點差 < 商品平均點差 × Point()
交易時段限制(交易時段編號33): 00:00-04:00 或 08:00-12:00
BarSinceExit > 1 (平倉後至少間隔1根K棒才能再進場)
進場策略
多單進場條件
LE_Cond = (ArrayMaximum(High) + 1 <= 8)
條件分析:
近期最高價位置條件(具體邏輯需搭配ArrayMaximum函數定義)
必須同時滿足: 空手狀態、點差符合、近期有空單平倉記錄(最近6筆)
空單進場條件
SE_Cond = (CDPrange > 0 && Close[1] < (CDP - CDPrange×0.3) && Close[1] < Open[1])
條件分析:
CDP區間有效(CDPrange > 0)
收盤價跌破CDP下方30%位置
前一根為黑K棒(Close[1] < Open[1])
進場方式: 市價單賣出
出場策略
多單出場
停損停利設定:
停利: H6時間框架3根K棒內的最高價(向前取2根)
停損: 進場價 - SL × Point()
移動停損(啟用時):
當進場後最高價 > 進場價 + TP×0.3 時啟動
停損調整為: 最高價 - SL × Point()
保本機制(啟用時):
觸發條件: 最高價 > 進場價 + TP×0.5
保本價格: 進場價 + TP×0.168
出場條件: 前收在保本價之上,當前價跌破保本價
主要出場條件:
價格突破H6最高價(上穿)
或價格跌破停損價(下穿)
空單出場
停損停利設定:
停利: 進場價 - TP × Point()
停損: 進場價 + SL × Point()
最小停利: 進場價 - 點差×3
移動停損(啟用時):
當進場後最低價 < 進場價 - TP×0.3 時啟動
停損調整為: 最低價 + SL × Point()
保本機制(啟用時):
觸發條件: 最低價 < 進場價 - TP×0.5
保本價格: 進場價 - TP×0.168
出場條件: 前收在保本價之下,當前價突破保本價
主要出場條件:
達到最小停利且RSI低點背離(RSI_LDiv_02)
或價格突破停損價(上穿)
//+------------------------------------------------------------------+
//| MT5 自動交易程式 (Expert Advisor)
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh> // 引入 MT5 交易函數庫
#include <MagicMT5_函數庫V2.mqh> // 引入自定義函數庫
ENUM_TIMEFRAMES 時間週期 = PERIOD_H2; // EA 主要運行的時間週期。
ENUM_TIMEFRAMES 時間框架 = PERIOD_D1; // 相對大週期,可能用於趨勢判斷或過濾
//+------------------------------------------------------------------+
//| EA 初始化函數,當 EA 載入圖表時執行一次 |
//+------------------------------------------------------------------+
int OnInit()
{
LoadEA = TimeCurrent(); // 記錄 EA 啟動時的當前伺服器時間
return(INIT_SUCCEEDED); // 初始化成功,返回成功代碼
}
//+------------------------------------------------------------------+
//| EA 核心循環函數,每一跳報價 (Tick) 進來時都會執行一次 |
//+------------------------------------------------------------------+
void OnTick()
{
// --- 資金風險控制 ---
// 如果當前帳戶餘額低於設定的「資金風控」值,則停止交易
if(AccountInfoDouble(ACCOUNT_BALANCE) < 資金風控)
{
Alert("********** 資金不足 *************");
// 以下註解掉的部分為強制平倉與退出 EA 的邏輯(如有需要可取消註解)
/*
if(total_pending_order_count(Symbol(), MagicNumber,-1) != 0)
{
delete_pending_orders_all(Symbol(), MagicNumber, -1, 0x0000ff); // 刪除所有掛單
}
if(多單部位() > 0 && BarNumber != CloseOrderNo)
LX_CloseByTicket(多單進場單號,Lots) ; // 多單平倉
if(空單部位() > 0 && BarNumber != CloseOrderNo)
SX_CloseByTicket(空單進場單號,Lots) ; // 空單平倉
ExpertRemove(); // 將 EA 從圖表中移除
*/
return; // 結束本次 OnTick
}
// --- 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) ; // 立即平倉
CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA); // 記錄平倉 K 棒位置
FastSma = MathMin(LenA1, LenB1); // 設定快線參數
SlowSma = MathMax(LenA1, LenB1); // 設定慢線參數
}
// 如果進入了新的 K 棒(當前 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); // Tick 價值
SP = NormalizeDouble(MathAbs(Ask-Bid),Digits()) ; // 計算當前點差 (Spread)
// --- 手數計算邏輯 ---
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(); // 呼叫多單條件判斷模組
// 如果符合多單條件、點差小於平均值且最近 6 根 K 棒內有空單平倉紀錄
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) ;
OrderBarNo = iBarShift(Symbol(),時間週期,LoadEA); // 記錄下單時的 K 棒編號
}
}
}
// --- 空單進場 ---
set_ShortCondition() ; // 呼叫空單條件判斷模組
// 如果符合空單條件且點差符合要求
if(SE_Cond == true && SP < NormalizeDouble(商品平均點差*Point(),Digits()))
{
if(多單部位() == 0 && 空單部位() == 0 && BarNumber != OrderBarNo)
{
if(BarSinceExit > 1 && EntriesToday(MagicNumber,Symbol()) < 1)
{
空單進場單號 = Short_at_MARKET(Symbol(),Lots,TP,SL,"Short Market",MagicNumber) ;
OrderBarNo = iBarShift(Symbol(),時間週期,LoadEA); // 記錄下單時的 K 棒編號
}
}
}
} // 結束允許交易時段
// 無論是否在交易時段內,都要處理持倉單的停損停利監控
交易時段外也可停損停利();
JudgeNo = iBarShift(Symbol(),時間週期,LoadEA); // 更新 JudgeNo 為當前 K 棒編號
} // 結束 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 棒更換時的數據更新與清理 |
//+------------------------------------------------------------------+
void 換K棒()
{
// 當新 K 棒產生時,刪除所有未成交的掛單
if(total_pending_order_count(Symbol(), MagicNumber,-1) != 0)
{
delete_pending_orders_all(Symbol(), MagicNumber, -1, 0x0000ff);
}
// 更新歷史數據系列與常用的技術數據
Set_OHLC_Bar_Series(); // 保留:設定 K 棒數據序列
Set_OHLC_Day_Series(); // 保留:設定日線數據序列
Get_OHLC_Bar(30) ; // 保留:獲取前 30 根 K 棒數據
Get_OHLC_Day(15) ; // 保留:獲取前 15 日數據
set_CDP(); // 計算 CDP 指標(逆勢操作指標)
FixBarHL(); // 修正 K 棒高低價數據
// 計算過去 5 天的平均震盪區間 (Average Range)
Day5Range = ((HighD[1] - LowD[1])+(HighD[2] - LowD[2])+(HighD[3] - LowD[3])+(HighD[4] - LowD[4])+(HighD[5] - LowD[5]))/5;
}
//+------------------------------------------------------------------+
//| 定義允許交易的時間段 |
//+------------------------------------------------------------------+
void 交易時段賦值()
{
// 僅允許 00:00-03:59 與 08:00-11:59 進行交易
允許交易時段 = (getTM_hour(TimeCurrent()) >= 0 && getTM_hour(TimeCurrent()) < 4) || (getTM_hour(TimeCurrent()) >= 8 && getTM_hour(TimeCurrent()) < 12);
}
//+------------------------------------------------------------------+
//| 管理持倉部位的停損、停利、移動停損及保本邏輯 |
//+------------------------------------------------------------------+
void 交易時段外也可停損停利()
{
// --- 多單管理 ---
if(多單部位() > 0)
{
double 多單最小停利 = 0.0, 多單保本價格 = 0.0 ;
bool LX_MinPF = false, LongPull = false ;
多單進場價格 = LE_EntryPrice(MagicNumber,多單進場單號); // 獲取多單實際成交價
多單最小停利 = NormalizeDouble(多單進場價格 + SP*3,Digits()) ; // 設定最小利潤點(3倍點差)
LX_MinPF = Bid > 多單最小停利 ; // 檢查是否已達到最小利潤
多單停利價格 = NormalizeDouble(多單進場價格 + TP * Point(),Digits()) ;
多單停損價格 = NormalizeDouble(多單進場價格 - SL * Point(),Digits()) ;
// 多單移動停損:若價格創高且利潤超過 TP 的 30%,則將停損上移
if(移動停損利 == true)
{
多單最高價 = iHigh(Symbol(),時間週期, iHighest(Symbol(),時間週期,MODE_HIGH,LE_BarsSinceEntry(MagicNumber,多單進場單號,時間週期),1));
多單最高價 = NormalizeDouble(多單最高價,Digits()) ;
if(多單最高價 > (多單進場價格+TP * Point()*0.3))
多單停損價格 = NormalizeDouble(多單最高價 - SL * Point(),Digits()) ;
}
// 多單保本 (保藍):若利潤超過 TP 的 50%,設定保本價為利潤的 16.8%,破位平倉
if(保藍設定 == true)
{
if(多單最高價 > 多單進場價格+TP * Point()*0.5)
{
LongPull = true ;
多單保本價格 = NormalizeDouble(多單進場價格+TP * Point()*0.168,Digits()) ;
LX_Cond = (LongPull == true && Close[1] >= 多單保本價格 && Bid < 多單保本價格);
}
else
LX_Cond = false ;
// 如果觸發保本條件,則平倉
if(LX_Cond == true && BarNumber != CloseOrderNo && LE_BarsSinceEntry(MagicNumber,多單進場單號,時間週期) > 0)
{
LX_CloseByTicket(多單進場單號,Lots) ;
if(多單部位() == 0) CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ;
}
}
// 使用 6 小時高點作為停利參考
bool LXcond291 ;
多單停利價格 = NormalizeDouble(get_HRangeOHLC(Symbol(),PERIOD_H6,MODE_HIGH,3,2),Digits()) ;
LXcond291 = (多單進場價格 < 多單停利價格 && Close[1] <= 多單停利價格 && Bid > 多單停利價格) ;
LX_Cond = (LXcond291 == true || (Close[1] >= 多單停損價格 && Bid < 多單停損價格)) ;
// 最終多單平倉執行
if(LX_Cond == true && BarNumber != CloseOrderNo && LE_BarsSinceEntry(MagicNumber,多單進場單號,時間週期) > 0)
{
LX_CloseByTicket(多單進場單號,Lots) ;
if(多單部位() == 0) CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ;
}
} // 結束多單部位管理
// --- 空單管理 ---
if(空單部位() > 0)
{
double 空單最小停利 = 0.0, 空單保本價格 = 0.0 ;
bool SX_MinPF = false, ShortPull = false ;
空單進場價格 = SE_EntryPrice(MagicNumber,空單進場單號);
空單最小停利 = NormalizeDouble(空單進場價格 - SP*3,Digits()) ;
SX_MinPF = Ask < 空單最小停利 ;
空單停利價格 = NormalizeDouble(空單進場價格 - TP * Point(),Digits()) ;
空單停損價格 = NormalizeDouble(空單進場價格 + SL * Point(),Digits()) ;
// 空單移動停損:若價格創低且利潤超過 TP 的 30%,則將停損下移
if(移動停損利 == true)
{
空單最低價 = iLow(Symbol(),時間週期, iLowest(Symbol(),時間週期,MODE_LOW,SE_BarsSinceEntry(MagicNumber,空單進場單號,時間週期),1));
空單最低價 = NormalizeDouble(空單最低價,Digits()) ;
if(空單最低價 < (空單進場價格-TP * Point()*0.3))
空單停損價格 = NormalizeDouble(空單最低價 + SL * Point(),Digits()) ;
}
// 空單保本 (保藍):邏輯同多單,保護已獲得的利潤
if(保藍設定 == true)
{
if(空單最低價 < 空單進場價格-TP * Point()*0.5)
{
ShortPull = true ;
空單保本價格 = NormalizeDouble(空單進場價格-TP * Point()*0.168,Digits()) ;
SX_Cond = (ShortPull == true && Close[1] <= 空單保本價格 && Ask > 空單保本價格);
}
else
SX_Cond = false ;
if(SX_Cond == true && BarNumber != CloseOrderNo && SE_BarsSinceEntry(MagicNumber,空單進場單號,時間週期) > 0)
{
SX_CloseByTicket(空單進場單號,Lots) ;
if(空單部位() == 0) CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ;
}
}
// 結合 RSI 背離進行平倉
SX_Cond = ((SX_MinPF == true && (RSI_LDiv_02() == true)) || (Close[1] <= 空單停損價格 && Ask > 空單停損價格)) ;
// 最終空單平倉執行
if(SX_Cond == true && BarNumber != CloseOrderNo && SE_BarsSinceEntry(MagicNumber,空單進場單號,時間週期) > 0)
{
SX_CloseByTicket(空單進場單號,Lots) ;
if(空單部位() == 0) CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ;
}
} // 結束空單部位管理
} // 結束 交易時段外也可停損停利()
//+------------------------------------------------------------------+
//| 多單進場條件模組:定義不同編號的進場策略 |
//+------------------------------------------------------------------+
void set_BuyCondition()
{
// 判斷最高價陣列的索引位置,屬於特定的技術形態過濾
LE_Cond = (ArrayMaximum(High) + 1 <= 8) ;
}
//+------------------------------------------------------------------+
//| 空單進場條件模組:定義不同編號的進場策略 |
//+------------------------------------------------------------------+
void set_ShortCondition()
{
// 跌破 CDP 指標下方區間 30% 且前一根為黑 K,視為跌勢確認
SE_Cond = (CDPrange > 0 && Close[1] < (CDP - CDPrange*0.3) && Close[1] < Open[1]) ;
}
回測結果
測試參數交易商品:NAS100(那斯達克指數)樣本內區間:2019/1/1 ~ 2023/10/30
交易手數:固定 1 手
時間框架: H2 圖表
交易模式:波段交易

沒有留言:
張貼留言