This commit is contained in:
2025-12-30 04:31:39 +03:30
parent e62e1a13dd
commit 5850164aab
8 changed files with 2792 additions and 1 deletions
+547
View File
@@ -0,0 +1,547 @@
//+------------------------------------------------------------------+
//| XKI_MTF_EA.mq5
//| SaherElm IT Center - Strategy using XKI
//| Author: Hadi Khazaee Asl
//+------------------------------------------------------------------+
#property strict
//
// Imports ...
#include "../Libraries/x-saherelm.common.lib.mq5"
// Inputs
input string InpSymbol = "XAUUSDb";
input ENUM_TIMEFRAMES InpSignalTF = PERIOD_H1; // Signal timeframe (H1)
input int InpKiLength = 26; // KI length (XKI input)
input bool InpShowKI = true; // (XKI input)
input int InpCalcLastBars = 1500; // (XKI input)
input bool InpUseRSI = true; // Use RSI confirmation
input int InpRSIPeriod = 14;
input int InpRSIPrice = PRICE_CLOSE;
input bool InpUseH4Filter = true; // Confirm with H4
input bool InpUseD1Filter = false; // Confirm with D1
input bool InpRequireBothFilters = false; // If true, require BOTH H4 and D1 agreement; else either
input double InpFixedLot = 0.10; // Fixed lot size
input double InpRiskATRMult = 0.0; // Add ATR padding to stop (0=disabled)
input int InpATRPeriod = 14;
input double InpRR = 2.0; // Reward:Risk target
input bool InpTrailByKI = true; // Trail stop to KI
input int InpSlippagePoints = 20; // Max slippage in points
input int InpMaxSpreadPoints = 200; // Max allowed spread in points
input bool InpAvoidAsianSession = true; // Avoid 22:00–06:00 server time
input int InpAsianStartHour = 22;
input int InpAsianEndHour = 6;
input bool InpAvoidNewsWindow = false; // Placeholder flag
input int InpNewsWindowMinutes = 60; // Skip trades within +/- minutes
input int InpBarsLookbackSignal = 2; // Lookback bars for signal (e.g., last closed bar)
// Magic number and comments
input int InpMagic = 260126;
input string InpOrderComment = "XKI_MTF_EA";
// iCustom indicator path (relative to Indicators folder if compiled there)
string g_xkiIndicatorPath = "x-saherelm.x121.xki"; // the compiled name; adjust if different
// Buffers indices as per the indicator
#define KI_BUFFER_INDEX 0
#define KI_COLOR_IDX_BUFFER_INDEX 1
#define KI_STATE_BUFFER_INDEX 2
// States from indicator
#define BULLISH_STATE 1
#define NEUTURAL_STATE 0
#define BEARISH_STATE -1
// Globals
int g_digits;
double g_point;
MqlTick g_tick;
int g_atrHandleH1 = INVALID_HANDLE;
int g_atrHandleH4 = INVALID_HANDLE;
int g_atrHandleD1 = INVALID_HANDLE;
int g_rsiHandleH1 = INVALID_HANDLE;
int g_rsiHandleH4 = INVALID_HANDLE;
int g_rsiHandleD1 = INVALID_HANDLE;
//+------------------------------------------------------------------+
// OnInit
//+------------------------------------------------------------------+
int OnInit()
{
//
g_digits = (int)SymbolInfoInteger(InpSymbol, SYMBOL_DIGITS);
g_point = SymbolInfoDouble(InpSymbol, SYMBOL_POINT);
if (!SymbolInfoTick(InpSymbol, g_tick))
{
Print("Failed to get tick for symbol: ", InpSymbol);
return INIT_FAILED;
}
// Quick validation
if (InpKiLength < 5)
{
Print("Invalid KI length: ", InpKiLength);
return INIT_PARAMETERS_INCORRECT;
}
//
GetOrCreateATRHandle(InpSymbol, InpSignalTF, InpATRPeriod);
if (InpUseH4Filter)
GetOrCreateATRHandle(InpSymbol, PERIOD_H4, InpATRPeriod);
if (InpUseD1Filter)
GetOrCreateATRHandle(InpSymbol, PERIOD_D1, InpATRPeriod);
//
GetOrCreateRSIHandle(InpSymbol, InpSignalTF, InpRSIPeriod, InpRSIPrice);
if (InpUseH4Filter)
GetOrCreateRSIHandle(InpSymbol, PERIOD_H4, InpRSIPeriod, InpRSIPrice);
if (InpUseD1Filter)
GetOrCreateRSIHandle(InpSymbol, PERIOD_D1, InpRSIPeriod, InpRSIPrice);
//
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
// OnDeinit
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//
if (g_atrHandleH1 != INVALID_HANDLE)
{
IndicatorRelease(g_atrHandleH1);
g_atrHandleH1 = INVALID_HANDLE;
}
if (g_atrHandleH4 != INVALID_HANDLE)
{
IndicatorRelease(g_atrHandleH4);
g_atrHandleH4 = INVALID_HANDLE;
}
if (g_atrHandleD1 != INVALID_HANDLE)
{
IndicatorRelease(g_atrHandleD1);
g_atrHandleD1 = INVALID_HANDLE;
}
//
if (g_rsiHandleH1 != INVALID_HANDLE)
{
IndicatorRelease(g_rsiHandleH1);
g_rsiHandleH1 = INVALID_HANDLE;
}
if (g_rsiHandleH4 != INVALID_HANDLE)
{
IndicatorRelease(g_rsiHandleH4);
g_rsiHandleH4 = INVALID_HANDLE;
}
if (g_rsiHandleD1 != INVALID_HANDLE)
{
IndicatorRelease(g_rsiHandleD1);
g_rsiHandleD1 = INVALID_HANDLE;
}
}
//+------------------------------------------------------------------+
// OnTick
//+------------------------------------------------------------------+
void OnTick()
{
if (_Symbol != InpSymbol)
return;
// Basic trading safety
if (!SymbolInfoTick(InpSymbol, g_tick))
return;
double spreadPoints = GetSpread(InpSymbol);
if (spreadPoints > InpMaxSpreadPoints)
return;
if (InpAvoidAsianSession)
{
//
MqlDateTime now = GetCurrentTime();
int hr = now.hour;
if (IsHourInRange(hr, InpAsianStartHour, InpAsianEndHour))
return;
}
if (InpAvoidNewsWindow)
{
// Placeholder: implement your own calendar integration
// Skip trading in a window near news. Here we simply return.
return;
}
// Only process on new bar of signal timeframe
static datetime lastSignalBarTime = 0;
datetime currentSignalBarTime = GetLastClosedBarTime(InpSymbol, InpSignalTF);
if (currentSignalBarTime == 0 || currentSignalBarTime == lastSignalBarTime)
return;
lastSignalBarTime = currentSignalBarTime;
// Get signal state and KI on signal TF (last closed bar)
int signalBarShift = InpBarsLookbackSignal; // 1=last closed, 2=previous
int stateSignal;
double kiSignal, closeSignal;
if (!GetXKIStateAndKI(InpSymbol, InpSignalTF, signalBarShift, stateSignal, kiSignal))
return;
closeSignal = iClose(InpSymbol, InpSignalTF, signalBarShift);
// RSI confirmation
if (InpUseRSI)
{
double rsi = GetRSIValue(InpSymbol, InpSignalTF, InpRSIPeriod, InpRSIPrice, signalBarShift);
if (rsi == EMPTY_VALUE)
return;
if (stateSignal == BULLISH_STATE && rsi <= 50.0)
return;
if (stateSignal == BEARISH_STATE && rsi >= 50.0)
return;
}
// Higher timeframe agreement
bool agreesH4 = true, agreesD1 = true;
if (InpUseH4Filter)
agreesH4 = HigherTFAgrees(InpSymbol, PERIOD_H4, signalBarShift, stateSignal);
if (InpUseD1Filter)
agreesD1 = HigherTFAgrees(InpSymbol, PERIOD_D1, signalBarShift, stateSignal);
bool filterOK = true;
if (InpUseH4Filter || InpUseD1Filter)
{
if (InpRequireBothFilters)
filterOK = (agreesH4 && agreesD1);
else
filterOK = ((InpUseH4Filter && agreesH4) || (InpUseD1Filter && agreesD1));
}
if (!filterOK)
return;
// Neutral or invalid skip
if (stateSignal == NEUTURAL_STATE)
return;
// Ensure no open positions for this symbol/magic
if (HasOpenPosition(InpSymbol, InpMagic))
return;
// Prepare trade params
double atrPad = 0.0;
if (InpRiskATRMult > 0.0)
{
double atr = GetATRValue(InpSymbol, InpSignalTF, InpATRPeriod, signalBarShift);
if (atr != EMPTY_VALUE && atr > 0)
atrPad = atr * InpRiskATRMult;
}
double sl, tp;
bool isBuy = (stateSignal == BULLISH_STATE);
if (isBuy)
{
sl = kiSignal - atrPad;
tp = closeSignal + (closeSignal - sl) * InpRR;
PlaceOrder(InpSymbol, ORDER_TYPE_BUY, InpFixedLot, sl, tp);
}
else if (stateSignal == BEARISH_STATE)
{
sl = kiSignal + atrPad;
tp = closeSignal - (sl - closeSignal) * InpRR;
PlaceOrder(InpSymbol, ORDER_TYPE_SELL, InpFixedLot, sl, tp);
}
// After placement, trailing handled in OnTimer or OnTick below
if (InpTrailByKI)
TrailStopsByKI();
}
//+------------------------------------------------------------------+
// Utilities
//+------------------------------------------------------------------+
//
// Create or reuse an ATR handle for the given TF ...
int GetOrCreateATRHandle(
string symbol,
ENUM_TIMEFRAMES tf,
int period //
)
{
int h = g_atrHandleH1;
if (tf == PERIOD_H4)
h = g_atrHandleH4;
else if (tf == PERIOD_D1)
h = g_atrHandleD1;
if (h == INVALID_HANDLE)
{
h = iATR(symbol, tf, period);
if (h == INVALID_HANDLE)
Print("Failed to create ATR handle: ", symbol, " ", EnumToString(tf), " period=", period);
}
return h;
}
//
// Read ATR value for a specific bar shift (1=last closed bar) ...
double GetATRValue(
string symbol,
ENUM_TIMEFRAMES tf,
int period,
int shift //
)
{
int h = GetOrCreateATRHandle(symbol, tf, period);
if (h == INVALID_HANDLE)
return EMPTY_VALUE;
//
double buff[];
//
// Copy exactly one value at 'shift' ...
int copied = CopyBuffer(h, 0, shift, 1, buff);
if (copied != 1 || !MathIsValidNumber(buff[0]))
return EMPTY_VALUE;
//
return buff[0];
}
//
// Create or reuse an RSI handle for the given TF ...
int GetOrCreateRSIHandle(
string symbol,
ENUM_TIMEFRAMES tf,
int period,
int appliedPrice //
)
{
//
int h = g_rsiHandleH1;
if (tf == PERIOD_H4)
h = g_rsiHandleH4;
else if (tf == PERIOD_D1)
h = g_rsiHandleD1;
if (h == INVALID_HANDLE)
{
h = iRSI(symbol, tf, period, appliedPrice);
if (h == INVALID_HANDLE)
Print("Failed to create RSI handle: ", symbol, " ", EnumToString(tf), " period=", period, " price=", appliedPrice);
}
return h;
}
//
// Read RSI value for a specific bar shift (1=last closed bar) ..
double GetRSIValue(
string symbol,
ENUM_TIMEFRAMES tf,
int period,
int appliedPrice,
int shift //
)
{
int h = GetOrCreateRSIHandle(symbol, tf, period, appliedPrice);
if (h == INVALID_HANDLE)
return EMPTY_VALUE;
double buff[];
int copied = CopyBuffer(h, 0, shift, 1, buff);
if (copied != 1 || !MathIsValidNumber(buff[0]))
return EMPTY_VALUE;
return buff[0];
}
datetime GetLastClosedBarTime(string symbol, ENUM_TIMEFRAMES tf)
{
datetime times[];
if (CopyTime(symbol, tf, 0, 3, times) <= 1)
return 0;
// times[0] is current open bar time; last closed is times[1]
return times[1];
}
bool IsHourInRange(int hr, int startHr, int endHr)
{
// Handles wrap-around (e.g., 22 -> 6)
if (startHr <= endHr)
return (hr >= startHr && hr < endHr);
else
return (hr >= startHr || hr < endHr);
}
bool GetXKIStateAndKI(string symbol, ENUM_TIMEFRAMES tf, int shift, int &stateOut, double &kiOut)
{
// Prepare indicator handle for this TF
static int handleH1 = INVALID_HANDLE;
static int handleH4 = INVALID_HANDLE;
static int handleD1 = INVALID_HANDLE;
int handleRef = handleH1;
if (tf == PERIOD_H4)
handleRef = handleH4;
else if (tf == PERIOD_D1)
handleRef = handleD1;
if (handleRef == INVALID_HANDLE)
{
handleRef = iCustom(symbol, tf, g_xkiIndicatorPath,
InpKiLength, InpShowKI, InpCalcLastBars);
if (handleRef == INVALID_HANDLE)
{
Print("Failed to create XKI handle for TF: ", EnumToString(tf));
return false;
}
}
double kiBuff[];
double stateBuff[];
if (CopyBuffer(handleRef, KI_BUFFER_INDEX, shift, 1, kiBuff) != 1)
return false;
if (CopyBuffer(handleRef, KI_STATE_BUFFER_INDEX, shift, 1, stateBuff) != 1)
return false;
kiOut = kiBuff[0];
stateOut = (int)stateBuff[0];
if (!MathIsValidNumber(kiOut))
return false;
return true;
}
bool HigherTFAgrees(string symbol, ENUM_TIMEFRAMES tf, int shift, int signalState)
{
int stateHTF;
double kiHTF;
if (!GetXKIStateAndKI(symbol, tf, shift, stateHTF, kiHTF))
return false;
if (signalState == BULLISH_STATE)
return (stateHTF == BULLISH_STATE);
if (signalState == BEARISH_STATE)
return (stateHTF == BEARISH_STATE);
return false;
}
bool HasOpenPosition(string symbol, int magic)
{
for (int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if (ticket == 0)
continue;
if (PositionSelectByTicket(ticket))
{
string sym = PositionGetString(POSITION_SYMBOL);
long mg = (long)PositionGetInteger(POSITION_MAGIC);
if (sym == symbol && mg == magic)
return true;
}
}
return false;
}
void PlaceOrder(string symbol, ENUM_ORDER_TYPE type, double lots, double sl, double tp)
{
MqlTradeRequest req;
MqlTradeResult res;
ZeroMemory(req);
ZeroMemory(res);
double price = 0.0;
if (!SymbolInfoTick(symbol, g_tick))
return;
if (type == ORDER_TYPE_BUY)
price = g_tick.ask;
else if (type == ORDER_TYPE_SELL)
price = g_tick.bid;
// Normalize SL/TP
sl = NormalizeDouble(sl, g_digits);
tp = NormalizeDouble(tp, g_digits);
price = NormalizeDouble(price, g_digits);
req.action = TRADE_ACTION_DEAL;
req.symbol = symbol;
req.volume = lots;
req.type = type;
req.price = price;
req.sl = sl;
req.tp = tp;
req.deviation = InpSlippagePoints;
req.magic = InpMagic;
req.comment = InpOrderComment;
if (!OrderSend(req, res))
Print("OrderSend failed: ", res.retcode);
}
void TrailStopsByKI()
{
// Trail per position using current signal TF KI
for (int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if (ticket == 0)
continue;
if (!PositionSelectByTicket(ticket))
continue;
string sym = PositionGetString(POSITION_SYMBOL);
long mg = (long)PositionGetInteger(POSITION_MAGIC);
if (sym != InpSymbol || mg != InpMagic)
continue;
ENUM_POSITION_TYPE ptype = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
double sl = PositionGetDouble(POSITION_SL);
double priceOpen = PositionGetDouble(POSITION_PRICE_OPEN);
// Use last closed bar KI for stability
int shift = 1;
int state;
double ki;
if (!GetXKIStateAndKI(sym, InpSignalTF, shift, state, ki))
continue;
MqlTradeRequest req;
MqlTradeResult res;
ZeroMemory(req);
ZeroMemory(res);
double newSL = sl;
if (ptype == POSITION_TYPE_BUY)
{
double proposedSL = NormalizeDouble(ki, g_digits);
if (proposedSL > sl)
newSL = proposedSL; // only move up
}
else if (ptype == POSITION_TYPE_SELL)
{
double proposedSL = NormalizeDouble(ki, g_digits);
if (proposedSL < sl || sl == 0.0)
newSL = proposedSL; // only move down (or set if none)
}
if (newSL != sl && newSL != 0.0)
{
req.action = TRADE_ACTION_SLTP;
req.symbol = sym;
req.sl = newSL;
req.tp = PositionGetDouble(POSITION_TP);
req.magic = InpMagic;
if (!OrderSend(req, res))
Print("Trail SLTP failed: ", res.retcode);
}
}
}
//+------------------------------------------------------------------+
+33
View File
@@ -0,0 +1,33 @@
///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Expert Advisor
// -------------------------------------------------
// Name: X121XKIEA
// Description: Base Expert Advisor as Template ...
//
// Maintainer:
// ------------
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
//
//////////////////////////////////////////////////////
//
// Global Properties ...
#property copyright "Copyright 2023, SaherElm IT Center"
#property link "https://saherelm.ir"
#property version "1.00"
#property icon "../Images/SaherElm_Logo_Color.ico"
#property description "SaherElm XFIMA Expert Advisor"
#property strict
//
#define ShortName "X121XKIEA"
//
// Importts ...
#include "../X121XKIEA/Classes/x-saherelm.x121xki.expert.class.mq5"
//
// Inputs ...
//#region Inputs ...
//#endregion
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -8,7 +8,8 @@
"C_Cpp.default.includePath": [
"c:\\Users\\SaherElm\\AppData\\Roaming\\MetaQuotes\\Terminal\\D0E8209F77C8CF37AD8BF550E51FF075\\MQL5\\Include\\Include",
"c:\\Users\\SaherElm\\AppData\\Roaming\\MetaQuotes\\Terminal\\D0E8209F77C8CF37AD8BF550E51FF075\\MQL5\\Include",
"c:\\Users\\SaherElm\\AppData\\Roaming\\MetaQuotes\\Terminal\\572C4A1F743028C65C8BA0B780030F0D\\MQL5\\Include"
"c:\\Users\\SaherElm\\AppData\\Roaming\\MetaQuotes\\Terminal\\572C4A1F743028C65C8BA0B780030F0D\\MQL5\\Include",
"c:\\Users\\saherelm\\AppData\\Roaming\\MetaQuotes\\Terminal\\D0E8209F77C8CF37AD8BF550E51FF075\\MQL5\\Include"
],
"C_Cpp.clang_format_style": "{ BasedOnStyle: Microsoft, UseTab: Never, IndentWidth: 4, TabWidth: 4, ColumnLimit: 0}",
"files.associations": {