1
0
Çatalla 0
şundan çatallanmış ejpenn/goldandsilvertrader
goldandsilvertrader/xau

309 satır
9 KiB
Text
Ham Kalıcı Bağlantı Normal Görünüm Geçmiş

2026-01-20 07:09:24 +00:00
//+------------------------------------------------------------------+
//| XAU/XAG Risk-Based ATR EA (MT5) |
//| Trades XAUUSD & XAGUSD with EMA+RSI(+ADX) filters |
//| SL/TP and lot size based on account value and risk % |
//+------------------------------------------------------------------+
#property strict
#include <Trade/Trade.mqh>
CTrade trade;
//------------------------- Inputs ----------------------------------
// Symbols (broker naming may differ, e.g. "XAUUSD.", "GOLD", etc.)
input string InpSymbol1 = "XAUUSD";
input string InpSymbol2 = "XAGUSD";
// Timeframe and indicators
input ENUM_TIMEFRAMES InpTF = PERIOD_M15;
input int InpFastEMA = 50;
input int InpSlowEMA = 200;
input int InpRSIPeriod = 14;
input double InpRSIBuyAbove = 52.0;
input double InpRSISellBelow = 48.0;
input bool InpUseADX = true;
input int InpADXPeriod = 14;
input double InpADXMin = 18.0;
input int InpATRPeriod = 14;
input double InpSL_ATR_Mult = 2.0; // Stop distance = ATR * mult
input double InpRiskReward = 2.0; // TP distance = SL distance * RR
// Risk / execution
input double InpRiskPercent = 1.0; // % of balance to risk per trade
input int InpMaxPositionsTotal = 2; // total open positions across symbols
input double InpMaxSpreadPoints = 50; // skip if spread > this (points)
input int InpSlippagePoints = 20; // max deviation in points
input bool InpAllowNewBarOnly = true; // only evaluate on new bar
// Optional trade session control (server time)
input bool InpUseSessionFilter = false;
input int InpSessionStartHour = 6;
input int InpSessionEndHour = 20;
//------------------------- Internals -------------------------------
datetime g_lastBarTime = 0;
// Helper: check if symbol is one of ours
bool IsTargetSymbol(const string sym)
{
return (sym == InpSymbol1 || sym == InpSymbol2);
}
// Helper: count open positions total (or for a symbol)
int CountPositions(const string sym = "")
{
int count = 0;
for(int i=0; i<PositionsTotal(); i++)
{
if(PositionSelectByIndex(i))
{
string ps = PositionGetString(POSITION_SYMBOL);
if(sym == "" || ps == sym) count++;
}
}
return count;
}
// Helper: spread filter
bool SpreadOK(const string sym)
{
double ask = SymbolInfoDouble(sym, SYMBOL_ASK);
double bid = SymbolInfoDouble(sym, SYMBOL_BID);
if(ask <= 0 || bid <= 0) return false;
double pt = SymbolInfoDouble(sym, SYMBOL_POINT);
double spreadPoints = (ask - bid) / pt;
return (spreadPoints <= InpMaxSpreadPoints);
}
// Helper: session filter (server time)
bool SessionOK()
{
if(!InpUseSessionFilter) return true;
MqlDateTime t; TimeToStruct(TimeCurrent(), t);
// Handle overnight sessions if needed
if(InpSessionStartHour <= InpSessionEndHour)
return (t.hour >= InpSessionStartHour && t.hour < InpSessionEndHour);
else
return (t.hour >= InpSessionStartHour || t.hour < InpSessionEndHour);
}
// Normalize lots to symbol constraints
double NormalizeLots(const string sym, double lots)
{
double minLot = SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(sym, SYMBOL_VOLUME_MAX);
double stepLot = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);
if(lots < minLot) lots = minLot;
if(lots > maxLot) lots = maxLot;
// Round down to step
double steps = MathFloor(lots / stepLot);
double norm = steps * stepLot;
// Ensure not below min due to rounding
if(norm < minLot) norm = minLot;
return norm;
}
// Compute lot size from risk % and stop distance (price units)
double LotsFromRisk(const string sym, double stopDistancePrice)
{
// Risk amount in account currency
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double riskMoney = balance * (InpRiskPercent / 100.0);
if(riskMoney <= 0) return 0.0;
// Convert stop distance (price) to money per 1 lot using tick value/size
double tickValue = SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_SIZE);
if(tickValue <= 0 || tickSize <= 0) return 0.0;
// How many ticks in stop distance?
double ticks = stopDistancePrice / tickSize;
if(ticks <= 0) return 0.0;
// Loss per 1 lot if SL hit:
double lossPerLot = ticks * tickValue;
if(lossPerLot <= 0) return 0.0;
double lots = riskMoney / lossPerLot;
return NormalizeLots(sym, lots);
}
// Get indicator value helpers (current closed bar = shift 1)
double iEMA(const string sym, ENUM_TIMEFRAMES tf, int period, int shift)
{
int h = iMA(sym, tf, period, 0, MODE_EMA, PRICE_CLOSE);
if(h == INVALID_HANDLE) return EMPTY_VALUE;
double buf[];
if(CopyBuffer(h, 0, shift, 1, buf) != 1) return EMPTY_VALUE;
IndicatorRelease(h);
return buf[0];
}
double iRSIValue(const string sym, ENUM_TIMEFRAMES tf, int period, int shift)
{
int h = iRSI(sym, tf, period, PRICE_CLOSE);
if(h == INVALID_HANDLE) return EMPTY_VALUE;
double buf[];
if(CopyBuffer(h, 0, shift, 1, buf) != 1) return EMPTY_VALUE;
IndicatorRelease(h);
return buf[0];
}
double iADXValue(const string sym, ENUM_TIMEFRAMES tf, int period, int shift)
{
int h = iADX(sym, tf, period);
if(h == INVALID_HANDLE) return EMPTY_VALUE;
double buf[];
if(CopyBuffer(h, 0, shift, 1, buf) != 1) return EMPTY_VALUE;
IndicatorRelease(h);
return buf[0];
}
double iATRValue(const string sym, ENUM_TIMEFRAMES tf, int period, int shift)
{
int h = iATR(sym, tf, period);
if(h == INVALID_HANDLE) return EMPTY_VALUE;
double buf[];
if(CopyBuffer(h, 0, shift, 1, buf) != 1) return EMPTY_VALUE;
IndicatorRelease(h);
return buf[0];
}
// Decide trade direction: +1 buy, -1 sell, 0 none
int GetSignal(const string sym)
{
// Use closed bar values to reduce repainting
int shift = 1;
double fast = iEMA(sym, InpTF, InpFastEMA, shift);
double slow = iEMA(sym, InpTF, InpSlowEMA, shift);
double rsi = iRSIValue(sym, InpTF, InpRSIPeriod, shift);
if(fast == EMPTY_VALUE || slow == EMPTY_VALUE || rsi == EMPTY_VALUE) return 0;
if(InpUseADX)
{
double adx = iADXValue(sym, InpTF, InpADXPeriod, shift);
if(adx == EMPTY_VALUE) return 0;
if(adx < InpADXMin) return 0; // avoid weak trends
}
// Trend + momentum confirmation
if(fast > slow && rsi >= InpRSIBuyAbove) return +1;
if(fast < slow && rsi <= InpRSISellBelow) return -1;
return 0;
}
// Place trade with ATR-based SL/TP and risk-based lots
bool ExecuteTrade(const string sym, int direction)
{
if(direction == 0) return false;
// Basic constraints
if(!SymbolInfoInteger(sym, SYMBOL_SELECT))
SymbolSelect(sym, true);
if(!SpreadOK(sym)) return false;
if(!SessionOK()) return false;
if(CountPositions("") >= InpMaxPositionsTotal) return false;
if(CountPositions(sym) > 0) return false; // one trade per symbol
double atr = iATRValue(sym, InpTF, InpATRPeriod, 1);
if(atr == EMPTY_VALUE || atr <= 0) return false;
double slDist = atr * InpSL_ATR_Mult;
double tpDist = slDist * InpRiskReward;
double ask = SymbolInfoDouble(sym, SYMBOL_ASK);
double bid = SymbolInfoDouble(sym, SYMBOL_BID);
double pt = SymbolInfoDouble(sym, SYMBOL_POINT);
if(ask <= 0 || bid <= 0 || pt <= 0) return false;
// Lot size from risk
double lots = LotsFromRisk(sym, slDist);
if(lots <= 0) return false;
trade.SetDeviationInPoints(InpSlippagePoints);
double price, sl, tp;
if(direction > 0)
{
price = ask;
sl = price - slDist;
tp = price + tpDist;
sl = NormalizeDouble(sl, (int)SymbolInfoInteger(sym, SYMBOL_DIGITS));
tp = NormalizeDouble(tp, (int)SymbolInfoInteger(sym, SYMBOL_DIGITS));
return trade.Buy(lots, sym, price, sl, tp, "EMA+RSI ATR risk buy");
}
else
{
price = bid;
sl = price + slDist;
tp = price - tpDist;
sl = NormalizeDouble(sl, (int)SymbolInfoInteger(sym, SYMBOL_DIGITS));
tp = NormalizeDouble(tp, (int)SymbolInfoInteger(sym, SYMBOL_DIGITS));
return trade.Sell(lots, sym, price, sl, tp, "EMA+RSI ATR risk sell");
}
}
// New bar detection (for the configured timeframe)
bool IsNewBar()
{
if(!InpAllowNewBarOnly) return true;
datetime t = iTime(_Symbol, InpTF, 0);
if(t == 0) return false;
if(t != g_lastBarTime)
{
g_lastBarTime = t;
return true;
}
return false;
}
//------------------------- MT5 Events ------------------------------
int OnInit()
{
// Ensure symbols are in Market Watch
SymbolSelect(InpSymbol1, true);
SymbolSelect(InpSymbol2, true);
g_lastBarTime = 0;
return(INIT_SUCCEEDED);
}
void OnTick()
{
if(!IsNewBar()) return;
// Evaluate both symbols on each new bar
string syms[2] = {InpSymbol1, InpSymbol2};
for(int i=0; i<2; i++)
{
string sym = syms[i];
if(!IsTargetSymbol(sym)) continue;
int sig = GetSignal(sym);
if(sig != 0)
ExecuteTrade(sym, sig);
}
}
//+------------------------------------------------------------------+