策略概述
這是一個基於多重技術指標超賣/超買背離的反轉交易策略。策略整合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時執行
//+------------------------------------------------------------------+
//| 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)
{
if(多單下單方式 == 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)
{
if(空單下單方式 == 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]) ;
}
//+------------------------------------------------------------------+
//| K棒價格數據陣列變數宣告
//+------------------------------------------------------------------+
double Open[], High[], Low[], Close[],Range[],Body[],UPshadow[],DNshadow[] ; // K棒OHLC及相關計算
double OpenD[], HighD[], LowD[], CloseD[] ; // 日線OHLC
long Volume[],BigVolume[] ; // 成交量
//+------------------------------------------------------------------+
//| 設定K棒數據陣列為時間序列
//| 說明:陣列索引[0]代表最新K棒,[1]代表前一根,以此類推
//+------------------------------------------------------------------+
void Set_OHLC_Bar_Series()
{
ArraySetAsSeries(Open,true); // 開盤價陣列
ArraySetAsSeries(High,true); // 最高價陣列
ArraySetAsSeries(Low,true); // 最低價陣列
ArraySetAsSeries(Close,true); // 收盤價陣列
ArraySetAsSeries(Volume,true); // 成交量陣列
}
//+------------------------------------------------------------------+
//| 獲取K棒OHLC數據
//| 參數:argCount - 要獲取的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); // 日線收盤價陣列
}
//+------------------------------------------------------------------+
//| 獲取日線OHLC數據
//| 參數:argCount - 要獲取的天數
//+------------------------------------------------------------------+
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) ; // 獲取日線收盤價
}
//+------------------------------------------------------------------+
//| MACD指標計算
//| 說明:計算MACD的DIF、MACD和OSC(柱狀圖)值
//+------------------------------------------------------------------+
double a_DIF[], a_MACD[], a_OSC[] ; // MACD指標三條線的數值陣列
void set_MACD()
{
int MacdLen, FastLen, SlowLen ;
int h_DIF,h_MACD ;
// 根據LenA1和LenB1動態計算MACD參數
MacdLen = MathMax(LenA1,LenB1) ;
if(MacdLen > 15)
MacdLen = 15 ; // 限制MACD週期最大為15
FastLen = (int)MathRound(MacdLen*1.33) ; // 快線週期
SlowLen = (int)MathRound(MacdLen*2.66) ; // 慢線週期
// 建立MACD指標句柄(使用加權收盤價)
h_DIF = iMACD(Symbol(),時間週期,FastLen,SlowLen,MacdLen,PRICE_WEIGHTED);
ArraySetAsSeries(a_DIF, true);
h_MACD = iMACD(Symbol(),時間週期,FastLen,SlowLen,MacdLen,PRICE_WEIGHTED);
ArraySetAsSeries(a_MACD, true);
// 獲取MACD數據
get_IndexData(h_DIF,0,0,10,a_DIF) ; // DIF線(快線-慢線)
get_IndexData(h_MACD,1,0,10,a_MACD) ; // MACD線(DIF的移動平均)
// 計算OSC柱狀圖(DIF-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] ;
}
}
//+------------------------------------------------------------------+
//| RSI指標計算
//| 說明:相對強弱指標,用於判斷超買超賣
//+------------------------------------------------------------------+
double a_RSIB[] ; // RSI指標數值陣列
void set_RSI()
{
int h_RSIB ;
// 建立RSI指標句柄(週期使用LenB1)
h_RSIB = iRSI(Symbol(),時間週期,LenB1,PRICE_CLOSE) ;
ArraySetAsSeries(a_RSIB,true) ;
// 獲取RSI數據(最近5個值)
get_IndexData(h_RSIB,0,0,5,a_RSIB) ;
}
//+------------------------------------------------------------------+
//| KD隨機指標計算
//| 說明:隨機震盪指標,用於判斷超買超賣和動能
//+------------------------------------------------------------------+
int h_KA2,h_DA2,h_KB2,h_DB2 ; // KD指標句柄
double a_KA2[], a_DA2[], a_JA2[], a_KB2[], a_DB2[], a_JB2[] ; // KD指標數值陣列
void set_KD()
{
// 建立KD指標句柄
// 參數:週期LenA2, K值平滑3, D值平滑3, EMA平滑, 使用最高最低價計算
h_KA2 = iStochastic(Symbol(),時間週期,LenA2,3,3,MODE_EMA,STO_LOWHIGH) ;
ArraySetAsSeries(a_KA2,true);
h_DA2 = iStochastic(Symbol(),時間週期,LenA2,3,3,MODE_EMA,STO_LOWHIGH) ;
ArraySetAsSeries(a_DA2,true);
// 獲取K值和D值數據
get_IndexData(h_KA2,0,0,5,a_KA2) ; // K值
get_IndexData(h_DA2,1,0,5,a_DA2) ; // D值
}
//+------------------------------------------------------------------+
//| CCI指標計算
//| 說明:順勢指標,用於判斷價格偏離程度
//+------------------------------------------------------------------+
double a_CCI[] ; // CCI指標數值陣列
void set_CCI()
{
int h_CCI ;
// 建立CCI指標句柄(週期使用LenB1)
h_CCI = iCCI(Symbol(),時間週期,LenB1,PRICE_CLOSE);
ArraySetAsSeries(a_CCI, true);
// 獲取CCI數據(最近5個值)
get_IndexData(h_CCI,0,0,5,a_CCI) ;
}
//+------------------------------------------------------------------+
//| RVI指標計算
//| 說明:相對活力指標,衡量價格波動的方向和強度
//+------------------------------------------------------------------+
double a_RVI_1[], a_RVI_2[] ; // RVI指標主線和訊號線數值陣列
void set_RVI()
{
int h_RVI_1,h_RVI_2 ;
// 建立RVI指標句柄(週期使用LenB1)
h_RVI_1 = iRVI(Symbol(),時間週期,LenB1);
ArraySetAsSeries(a_RVI_1, true);
h_RVI_2 = iRVI(Symbol(),時間週期,LenB1);
ArraySetAsSeries(a_RVI_2, true);
// 獲取RVI主線和訊號線數據
get_IndexData(h_RVI_1,0,0,5,a_RVI_1) ; // RVI主線
get_IndexData(h_RVI_2,1,0,5,a_RVI_2) ; // RVI訊號線
}
//+------------------------------------------------------------------+
//| Williams %R 威廉指標計算
//| 說明:威廉指標,測量超買超賣狀態,數值範圍-100到0
//+------------------------------------------------------------------+
double a_WPR_A[] ; // Williams %R 數值陣列
void set_WILLIAMS_PR()
{
int h_WPR_A ; // Williams %R 指標句柄
// 建立 Williams %R 指標句柄(使用 LenA1 週期)
h_WPR_A = iWPR(Symbol(), 時間週期, LenA1);
ArraySetAsSeries(a_WPR_A, true); // 設定陣列為時間序列
// 獲取 Williams %R 數據(最近15個數值)
get_IndexData(h_WPR_A, 0, 0, 15, a_WPR_A);
}
//+------------------------------------------------------------------+
//| Keltner Channel 肯特納通道指標計算
//| 說明:基於EMA和ATR的通道指標,用於判斷趨勢和突破
//+------------------------------------------------------------------+
double a_KC_UPPER_B[], a_KC_LOWER_B[], a_KC_MIDDLE_B[] ; // Keltner通道:上軌、下軌、中線
double a_KC_ATR_B[] ; // 對應的ATR數值
void set_KELTNER_CHANNEL()
{
int h_EMA_B ; // EMA句柄(用作中線)
int h_ATR_B ; // ATR句柄(用於計算通道寬度)
// 建立 Keltner Channel B組指標句柄(使用 LenB1 週期)
h_EMA_B = iMA(Symbol(), 時間週期, LenB1, 0, MODE_EMA, PRICE_CLOSE);
h_ATR_B = iATR(Symbol(), 時間週期, LenB1);
// 設定所有陣列為時間序列
ArraySetAsSeries(a_KC_UPPER_B, true);
ArraySetAsSeries(a_KC_LOWER_B, true);
ArraySetAsSeries(a_KC_MIDDLE_B, true);
ArraySetAsSeries(a_KC_ATR_B, true);
// 調整陣列大小為20
ArrayResize(a_KC_UPPER_B, 20);
ArrayResize(a_KC_LOWER_B, 20);
ArrayResize(a_KC_MIDDLE_B, 20);
ArrayResize(a_KC_ATR_B, 20);
// 獲取EMA和ATR數據
get_IndexData(h_EMA_B, 0, 0, 20, a_KC_MIDDLE_B); // EMA作為中線
get_IndexData(h_ATR_B, 0, 0, 20, a_KC_ATR_B); // ATR數據
// 計算Keltner通道上下軌
for(int i = 0; i < ArraySize(a_KC_MIDDLE_B)-1; i++)
{
// Keltner Channel 計算公式:
// 上軌 = EMA + (ATR × 倍數) - 倍數設定為1.5
// 下軌 = EMA - (ATR × 倍數)
a_KC_UPPER_B[i] = a_KC_MIDDLE_B[i] + (a_KC_ATR_B[i] * 1.5);
a_KC_LOWER_B[i] = a_KC_MIDDLE_B[i] - (a_KC_ATR_B[i] * 1.5);
}
}
//+------------------------------------------------------------------+
//| RVI 死亡交叉判斷
//| 說明:判斷RVI主線是否向下穿越訊號線(看跌訊號)
//| 返回:true=死叉發生, false=無死叉
//+------------------------------------------------------------------+
bool RVI_死叉()
{
// 前一根K棒RVI主線>=訊號線,且目前K棒主線<訊號線
if(a_RVI_1[2] >= a_RVI_2[2] && a_RVI_1[1] < a_RVI_2[1])
{
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| RVI 高點背離判斷(版本01)
//| 說明:價格創新高但RVI未創新高,顯示動能減弱(看漲背離)
//| 返回:true=出現高點背離, false=無背離
//+------------------------------------------------------------------+
bool RVI_HDiv_01()
{
// 條件1:價格最高點出現在最近3根K棒內(索引0-2)
// 條件2:RVI最高點出現在更早之前(索引>2)
// 條件3:目前RVI值<0.5(回落狀態)
if((ArrayMaximum(High) !=0 && ArrayMaximum(High) <= 2) && (ArrayMaximum(a_RVI_1) > 2) && a_RVI_1[1] < 0.5)
{
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| 多重超賣鈍化綜合判斷 |
//| 說明:統計多個指標的超賣鈍化狀態,當2個以上指標鈍化時返回true |
//| 返回:true=多重鈍化, false=未達標準 |
//+------------------------------------------------------------------+
bool 多重超賣鈍化()
{
int oversold_count = 0; // 超賣鈍化計數器
// 檢查各指標是否鈍化,每個鈍化指標計數+1
if(RSI低檔鈍化())
oversold_count++;
if(KD低檔鈍化())
oversold_count++;
if(WPR低檔鈍化())
oversold_count++;
if(CCI超賣鈍化())
oversold_count++;
// 當2個以上指標同時鈍化時,判定為多重超賣鈍化
if(oversold_count >= 2)
{
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| 流動性池價格計算 |
//| 說明:計算最近20根K棒的頂部和底部價格(從第5根開始算) |
//| 用於判斷價格突破的關鍵支撐壓力位 |
//+------------------------------------------------------------------+
double 流動性池頂部價格 = Highest_OHLC(Symbol(), 時間週期, MODE_HIGH, 20, 5);
double 流動性池底部價格 = Lowest_OHLC(Symbol(), 時間週期, MODE_LOW, 20, 5);
回測結果
測試參數交易商品:NAS100(那斯達克指數)
樣本內區間:2019/1/1 ~ 2023/8/31
交易手數:固定 1 手
時間框架:M10 分鐘圖表
交易模式:波段交易
沒有留言:
張貼留言