策略概述
這是一個基於多重技術指標的日內交易策略,使用H1(小時)時間週期進行交易決策。策略結合唐奇安通道突破、RSI超買超賣、MACD背離等多種技術分析工具來識別進出場時機,並採用嚴格的風險控制和當沖平倉機制。
基礎概念
時間週期: H1(1小時)
風險控制: 動態手數計算,風險百分比為1%
資金風控門檻: 5000
商品平均點差限制: 50點
交易限制: 每日限制1次進場
交易時段: 06:00-22:00
當沖設定: 23:00或01:00強制平倉
停利停損: TP=3360點,SL=1000點
進出場策略
多單進場條件
LE_Cond = (High[1] >= a_DC_HIGH_A[3] && a_RSIA[1] > 70);
條件分析:
唐奇安通道突破: 前一根K棒最高價突破第3根K棒的唐奇安通道上軌
RSI超買確認: RSI指標大於70,確認強勢上漲動能
進場方式: 市價單買入
空單進場條件
條件分析:
三黑創低收: 連續3根陰線且收盤價創新低
高點下降趨勢: 確認空頭趨勢形成
跌破支撐: 跌破第四根K棒低點
進場方式: 市價單賣出
進場價格計算
多單進場價格
BuyPrice = (FVG_多頭上緣價格 + FVG_多頭下緣價格) / 2;
計算方式: FVG多頭缺口的中間價位
空單進場價格
ShortPrice = MathMin(High[1], MathMin(High[2], High[3]));
計算方式: 取前3根K棒中的最低高點
//+------------------------------------------------------------------+
//| MT5 自動交易程式 (Expert Advisor)
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh> // 引入 MT5 交易函數庫
#include <MagicMT5_函數庫V2.mqh> // 引入自定義函數庫
ENUM_TIMEFRAMES 時間週期 = PERIOD_H1; // 主交易時間框架(小時圖)
ENUM_TIMEFRAMES 時間框架 = PERIOD_D1; // 相對大週期(日線圖)
//+------------------------------------------------------------------+
//| 初始化函數
//+------------------------------------------------------------------+
int OnInit()
{
LoadEA = TimeCurrent(); // 記錄 EA 載入時間
return(INIT_SUCCEEDED); // 初始化成功
}
//+------------------------------------------------------------------+
//| 每tick執行函數
//+------------------------------------------------------------------+
void OnTick()
{
// 檢查帳戶餘額是否低於風控門檻
if(AccountBalance < 資金風控)
{
Alert("********** 資金不足 *************"); // 提示資金不足
return;
}
// 計算當前 K 棒編號及自上次平倉後的 K 棒數
BarNumber = iBarShift(Symbol(), 時間週期, LoadEA);
BarSinceExit = BarNumber - CloseOrderNo;
// 模擬測試:第一根 K 棒下單並立即平倉
if((BarNumber == 1 && BarNumber != JudgeNo))
{
多單進場單號 = Buy_at_MARKET(Symbol(), Lots, 0, 0, "1st_K", MagicNumber); // 市價買單
LX_CloseByTicket(多單進場單號, Lots); // 立即平倉
CloseOrderNo = iBarShift(Symbol(), 時間週期, LoadEA); // 更新平倉 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); // 每點價值
SP = NormalizeDouble(MathAbs(Ask - Bid), Digits()); // 計算點差
//+------------------------------------------------------------------+
//| 動態計算交易手數
//+------------------------------------------------------------------+
if(動態計算手數 == true)
{
Lots = get_dynamic_lot_size(是否偶數單, Symbol(), 風險百分比, AccountBalance, SL); // 計算動態手數
Lots = MathMin(0.3, MathMax(0.01, Lots)); // 限制手數範圍
}
// 當沖模式:限制進場時間
if(當沖 == true)
{
接近收盤 = (getTM_hour(TimeCurrent()) >= 18 || getTM_hour(TimeCurrent()) <= 1); // 18:00 至次日 1:00 為接近收盤
允許交易時段 = (允許交易時段 && !接近收盤); // 更新交易時段狀態
}
// 在允許交易時段內執行進場邏輯
if(允許交易時段 == true)
{
//+------------------------------------------------------------------+
//| 多單進場
//+------------------------------------------------------------------+
set_BuyCondition(); // 設定多單進場條件
if(LE_Cond == true && SP < NormalizeDouble(商品平均點差 * Point(), Digits()))
{
if(多單部位() == 0 && 空單部位() == 0 && BarNumber != OrderBarNo)
{
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 棒編號
}
}
}
// 當沖模式:到達指定時間自動平倉
if(當沖 == true && (getTM_hour(TimeCurrent()) == 當沖出場時間 || getTM_hour(TimeCurrent()) == 1))
{
if(多單部位() > 0 || 空單部位() > 0)
{
當沖平倉(); // 執行當沖平倉
}
}
交易時段外也可停損停利(); // 檢查停損停利條件
JudgeNo = iBarShift(Symbol(), 時間週期, LoadEA); // 更新判斷 K 棒編號
}
//+------------------------------------------------------------------+
//| 自訂函數:計算多單部位數
//+------------------------------------------------------------------+
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_BarInfo(); // 計算 K 棒資訊(範圍、實體、上影線、下影線)
set_ATR(); // 計算 ATR 指標
set_MACD(); // 計算 MACD 指標
set_RSI(); // 計算 RSI 指標
set_DONCHIAN_CHANNEL(); // 計算 Donchian Channel
計算FVG價格(); // 計算公平價值缺口(FVG)價格
Day5Range = ((HighD[1] - LowD[1]) + (HighD[2] - LowD[2]) + (HighD[3] - LowD[3]) +
(HighD[4] - LowD[4]) + (HighD[5] - LowD[5])) / 5; // 計算五日平均震幅
}
//+------------------------------------------------------------------+
//| 自訂函數:設定交易時段
//+------------------------------------------------------------------+
void 交易時段賦值()
{
允許交易時段 = (getTM_hour(TimeCurrent()) >= 6 && getTM_hour(TimeCurrent()) < 22); // 交易時段:6:00-22:00
}
//+------------------------------------------------------------------+
//| 自訂函數:當沖平倉
//+------------------------------------------------------------------+
void 當沖平倉()
{
if((getTM_hour(TimeCurrent()) == 當沖出場時間 || getTM_hour(TimeCurrent()) == 1))
{
if(多單部位() > 0 && BarNumber != CloseOrderNo)
LX_CloseByTicket(多單進場單號, Lots); // 平倉多單
if(空單部位() > 0 && BarNumber != CloseOrderNo)
SX_CloseByTicket(空單進場單號, Lots); // 平倉空單
CloseOrderNo = iBarShift(Symbol(), 時間週期, LoadEA); // 更新平倉 K 棒編號
}
}
//+------------------------------------------------------------------+
//| 自訂函數:交易時段外檢查停損停利
//+------------------------------------------------------------------+
void 交易時段外也可停損停利()
{
// 多單停損停利
if(多單部位() > 0)
{
多單進場價格 = LE_EntryPrice(MagicNumber, 多單進場單號); // 獲取多單進場價格
double 多單最小停利 = NormalizeDouble(多單進場價格 + SP * 3, Digits()); // 最小停利:進場價 + 3 倍點差
bool LX_MinPF = Bid > 多單最小停利; // 檢查是否達到最小停利
多單停利價格 = NormalizeDouble(多單進場價格 + TP * Point(), Digits()); // 止盈價格
多單停損價格 = NormalizeDouble(多單進場價格 - SL * Point(), Digits()); // 止損價格
LX_Cond = ((LX_MinPF == true && MACD_HDiv_01() == true) ||
(Close[1] >= 多單停損價格 && Bid < 多單停損價格)); // 出場條件:MACD 背離或觸及止損
if(LX_Cond == true && BarNumber != CloseOrderNo && LE_BarsSinceEntry(MagicNumber, 多單進場單號, 時間週期) > 0)
{
LX_CloseByTicket(多單進場單號, Lots); // 平倉多單
if(多單部位() == 0)
CloseOrderNo = iBarShift(Symbol(), 時間週期, LoadEA); // 更新平倉 K 棒編號
}
}
// 空單停損停利
if(空單部位() > 0)
{
空單進場價格 = SE_EntryPrice(MagicNumber, 空單進場單號); // 獲取空單進場價格
double 空單最小停利 = NormalizeDouble(空單進場價格 - SP * 3, Digits()); // 最小停利:進場價 - 3 倍點差
bool SX_MinPF = Ask < 空單最小停利; // 檢查是否達到最小停利
空單停利價格 = NormalizeDouble(空單進場價格 - TP * Point(), Digits()); // 止盈價格
空單停損價格 = NormalizeDouble(空單進場價格 + SL * Point(), Digits()); // 止損價格
SX_Cond = ((SX_MinPF == true && MACD_LDiv_01() == true) ||
(Close[1] <= 空單停損價格 && Ask > 空單停損價格)); // 出場條件:MACD 背離或觸及止損
if(SX_Cond == true && BarNumber != CloseOrderNo && SE_BarsSinceEntry(MagicNumber, 空單進場單號, 時間週期) > 0)
{
SX_CloseByTicket(空單進場單號, Lots); // 平倉空單
if(空單部位() == 0)
CloseOrderNo = iBarShift(Symbol(), 時間週期, LoadEA); // 更新平倉 K 棒編號
}
}
}
//+------------------------------------------------------------------+
//| 自訂函數:設定多單進場條件
//+------------------------------------------------------------------+
void set_BuyCondition()
{
LE_Cond = (High[1] >= a_DC_HIGH_A[3] && a_RSIA[1] > 70); // 條件:價格突破 Donchian Channel 上軌且 RSI > 70
}
//+------------------------------------------------------------------+
//| 自訂函數:設定空單進場條件
//+------------------------------------------------------------------+
void set_ShortCondition()
{
SE_Cond = (Black3Bar_LClose()); // 條件:三黑創低收形態
}
//+------------------------------------------------------------------+
//| 自訂函數:設定 K 棒開高低收序列
//+------------------------------------------------------------------+
double Open[], High[], Low[], Close[], Range[], Body[], UPshadow[], DNshadow[];
double OpenD[], HighD[], LowD[], CloseD[];
long Volume[], BigVolume[];
void Set_OHLC_Bar_Series()
{
ArraySetAsSeries(Open, true); // 設定開盤價陣列為時間序列
ArraySetAsSeries(High, true); // 設定最高價陣列為時間序列
ArraySetAsSeries(Low, true); // 設定最低價陣列為時間序列
ArraySetAsSeries(Close, true); // 設定收盤價陣列為時間序列
ArraySetAsSeries(Volume, true); // 設定成交量陣列為時間序列
}
//+------------------------------------------------------------------+
//| 自訂函數:獲取 K 棒開高低收數據
//+------------------------------------------------------------------+
void Get_OHLC_Bar(int argCount)
{
get_OpenData(Symbol(), 時間週期, argCount, Open); // 獲取開盤價
get_HighData(Symbol(), 時間週期, argCount, High); // 獲取最高價
get_LowData(Symbol(), 時間週期, argCount, Low); // 獲取最低價
get_CloseData(Symbol(), 時間週期, argCount, Close); // 獲取收盤價
get_VolumeData(Symbol(), 時間週期, argCount, Volume); // 獲取成交量
}
//+------------------------------------------------------------------+
//| 自訂函數:設定日線開高低收序列
//+------------------------------------------------------------------+
void Set_OHLC_Day_Series()
{
ArraySetAsSeries(OpenD, true); // 設定日線開盤價陣列
ArraySetAsSeries(HighD, true); // 設定日線最高價陣列
ArraySetAsSeries(LowD, true); // 設定日線最低價陣列
ArraySetAsSeries(CloseD, true); // 設定日線收盤價陣列
}
//+------------------------------------------------------------------+
//| 自訂函數:獲取日線開高低收數據
//+------------------------------------------------------------------+
void Get_OHLC_Day(int argCount)
{
get_OpenData(Symbol(), PERIOD_D1, argCount, OpenD); // 獲取日線開盤價
get_HighData(Symbol(), PERIOD_D1, argCount, HighD); // 獲取日線最高價
get_LowData(Symbol(), PERIOD_D1, argCount, LowD); // 獲取日線最低價
get_CloseData(Symbol(), PERIOD_D1, argCount, CloseD); // 獲取日線收盤價
}
//+------------------------------------------------------------------+
//| 自訂函數:計算 K 棒資訊(範圍、實體、影線)
//+------------------------------------------------------------------+
void set_BarInfo()
{
ArrayResize(Range, ArraySize(Open)); // 調整範圍陣列大小
ArraySetAsSeries(Range, true);
ArrayResize(Body, ArraySize(Open)); // 調整實體陣列大小
ArraySetAsSeries(Body, true);
ArrayResize(UPshadow, ArraySize(Open)); // 調整上影線陣列大小
ArraySetAsSeries(UPshadow, true);
ArrayResize(DNshadow, ArraySize(Open)); // 調整下影線陣列大小
ArraySetAsSeries(DNshadow, true);
for(int i = 0; i < ArraySize(Open) - 1; i++)
{
Range[i] = High[i] - Low[i]; // 計算 K 棒範圍
Body[i] = MathAbs(Close[i] - Open[i]); // 計算 K 棒實體
UPshadow[i] = High[i] - MathMax(Close[i], Open[i]); // 計算上影線
DNshadow[i] = MathMin(Close[i], Open[i]) - Low[i]; // 計算下影線
}
}
//+------------------------------------------------------------------+
//| 自訂函數:計算 ATR 指標
//+------------------------------------------------------------------+
double a_ATR[];
void set_ATR()
{
int h_ATR;
h_ATR = iATR(Symbol(), 時間週期, LenB2); // 創建 ATR 指標句柄(週期 LenB2 = 24)
ArraySetAsSeries(a_ATR, true);
get_IndexData(h_ATR, 0, 0, 5, a_ATR); // 獲取最近 5 筆 ATR 數據
}
//+------------------------------------------------------------------+
//| 自訂函數:計算 MACD 指標
//+------------------------------------------------------------------+
double a_DIF[], a_MACD[], a_OSC[];
void set_MACD()
{
int MacdLen, FastLen, SlowLen;
MacdLen = MathMax(LenA1, LenB1); // 取 LenA1 和 LenB1 的最大值
if(MacdLen > 15) MacdLen = 15; // 限制最大週期為 15
FastLen = (int)MathRound(MacdLen * 1.33); // 快速線週期
SlowLen = (int)MathRound(MacdLen * 2.66); // 慢速線週期
int h_DIF = iMACD(Symbol(), 時間週期, FastLen, SlowLen, MacdLen, PRICE_WEIGHTED); // 創建 MACD 指標句柄
ArraySetAsSeries(a_DIF, true);
int h_MACD = iMACD(Symbol(), 時間週期, FastLen, SlowLen, MacdLen, PRICE_WEIGHTED);
ArraySetAsSeries(a_MACD, true);
get_IndexData(h_DIF, 0, 0, 10, a_DIF); // 獲取 DIF 數據
get_IndexData(h_MACD, 1, 0, 10, a_MACD); // 獲取 MACD 數據
ArraySetAsSeries(a_OSC, true);
ArrayResize(a_OSC, ArraySize(a_DIF));
for(int i = 0; i < ArraySize(a_OSC); i++)
{
a_OSC[i] = a_DIF[i] - a_MACD[i]; // 計算 OSC(柱狀圖)
}
}
//+------------------------------------------------------------------+
//| 自訂函數:計算 RSI 指標
//+------------------------------------------------------------------+
double a_RSIA[], a_RSIB[];
void set_RSI()
{
int h_RSIA = iRSI(Symbol(), 時間週期, LenA1, PRICE_CLOSE); // 創建 RSI 指標句柄(週期 LenA1)
ArraySetAsSeries(a_RSIA, true);
get_IndexData(h_RSIA, 0, 0, 5, a_RSIA); // 獲取 RSI A 數據
int h_RSIB = iRSI(Symbol(), 時間週期, LenB1, PRICE_CLOSE); // 創建 RSI 指標句柄(週期 LenB1)
ArraySetAsSeries(a_RSIB, true);
get_IndexData(h_RSIB, 0, 0, 5, a_RSIB); // 獲取 RSI B 數據
}
//+------------------------------------------------------------------+
//| 自訂函數:MACD 高點背離
//+------------------------------------------------------------------+
bool MACD_HDiv_01()
{
if((ArrayMaximum(High) != 0 && ArrayMaximum(High) <= 2) &&
(ArrayMaximum(a_DIF) > 2) && (a_RSIA[1] < 70))
{
return true; // 價格新高但 MACD 未創新高,且 RSI < 70
}
return false;
}
//+------------------------------------------------------------------+
//| 自訂函數:MACD 低點背離
//+------------------------------------------------------------------+
bool MACD_LDiv_01()
{
if((ArrayMinimum(Low) != 0 && ArrayMinimum(Low) <= 2) &&
(ArrayMinimum(a_DIF) > 2) && (a_RSIA[1] > 30))
{
return true; // 價格新低但 MACD 未創新低,且 RSI > 30
}
return false;
}
//+------------------------------------------------------------------+
//| 自訂函數:三黑創低收形態
//+------------------------------------------------------------------+
bool Black3Bar_LClose()
{
int j = 0;
for(int i = 1; i <= 3; i++)
{
if(Close[i] < Open[i]) // 檢查是否為陰線
{
j++;
}
}
if((j == 3 && Close[1] <= MathMin(Close[2], Close[3]))) // 三根陰線且最新收盤價最低
{
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| 自訂函數:計算 Donchian Channel
//+------------------------------------------------------------------+
double a_DC_HIGH_A[], a_DC_LOW_A[], a_DC_MIDDLE_A[]; // Donchian Channel A 組
void set_DONCHIAN_CHANNEL()
{
// 設定陣列為時間序列並調整大小
ArraySetAsSeries(a_DC_HIGH_A, true);
ArraySetAsSeries(a_DC_LOW_A, true);
ArraySetAsSeries(a_DC_MIDDLE_A, true);
ArrayResize(a_DC_HIGH_A, 25); // 調整陣列大小
ArrayResize(a_DC_LOW_A, 25);
ArrayResize(a_DC_MIDDLE_A, 25);
int Idx_AH, Idx_BH, Idx_CH, Idx_AL, Idx_BL, Idx_CL;
for(int i = 0; i < ArraySize(a_DC_HIGH_A) - 1; i++)
{
Idx_AH = iHighest(Symbol(), 時間週期, MODE_HIGH, LenA1, i); // LenA1 週期最高價索引
Idx_AL = iLowest(Symbol(), 時間週期, MODE_LOW, LenA1, i); // LenA1 週期最低價索引
a_DC_HIGH_A[i] = iHigh(Symbol(), 時間週期, Idx_AH); // A 組上軌
a_DC_LOW_A[i] = iLow(Symbol(), 時間週期, Idx_AL); // A 組下軌
a_DC_MIDDLE_A[i] = a_DC_HIGH_A[i] - a_DC_LOW_A[i]; // A 組中線
}
}
測試參數交易商品:XAUUSD(黃金)
樣本內區間:2019/1/1 ~ 2023/7/31
交易手數:固定0.1手
時間框架:H1 小時圖表
交易模式:當沖交易
沒有留言:
張貼留言