859 lines
31 KiB
Text
859 lines
31 KiB
Text
//+------------------------------------------------------------------+
| |||
//| GoldXAU_Scalper_Full.mq5 |
| |||
//| Gold-only scalper EA with multi-timeframe bias and trailing TP |
| |||
//+------------------------------------------------------------------+
| |||
#property copyright "Assistant"
| |||
#property version "1.12"
| |||
#property strict
| |||
| |||
#include <Trade\Trade.mqh>
| |||
CTrade trade;
| |||
| |||
//---------------------- User inputs --------------------------------
| |||
input string TradeSymbol = "XAUUSD"; // symbol (change if your broker uses a different name)
| |||
input double FixedLotSize = 0.01; // fixed lot size used when UseFixedLot=true
| |||
input bool UseFixedLot = true; // always trade fixed lot (true) or dynamic sizing (false)
| |||
input double RiskPercent = 0.5; // if UseFixedLot=false -> use this % of balance as risk per trade
| |||
| |||
// timeframe and indicator params
| |||
input ENUM_TIMEFRAMES TF = PERIOD_M5; // entry TF
| |||
input int SMA_Fast = 5;
| |||
input int SMA_Slow = 10;
| |||
input int SMA_Trend = 50;
| |||
input int ATR_Period = 14;
| |||
input double ATR_Multiplier = 0.9; // SL = ATR * multiplier
| |||
input double RewardRatio = 1.2; // TP = SL * RewardRatio
| |||
| |||
// scalper vs normal
| |||
input bool ScalperMode = false; // if true use smaller TP/SL multipliers for quick scalps
| |||
input double Scalper_RR = 0.9; // R:R for scalper (tp = rr * sl)
| |||
input int Scalper_MaxTrades = 2; // allow more small trades if scalper
| |||
| |||
// Trailing & rally behavior
| |||
input bool UseTrailingTP = true;
| |||
input double TrailingStartATRMult = 1.0; // start trailing once price is this * ATR in profit
| |||
input double TrailingPercent = 1.0; // percent behind market to place trailing TP (1.0 means TP = price*(1 - 0.01) for longs)
| |||
input double TrailingStepPoints = 0.5; // minimum price change to update TP (in price units)
| |||
| |||
// multi-timeframe bias
| |||
input bool UseMultiTFBias = true;
| |||
input ENUM_TIMEFRAMES BiasTF1 = PERIOD_H1;
| |||
input ENUM_TIMEFRAMES BiasTF2 = PERIOD_H4;
| |||
input ENUM_TIMEFRAMES BiasTF3 = PERIOD_D1;
| |||
input int BiasSMA_Period = 50; // SMA for bias check (on each bias TF)
| |||
input int BiasRequiredMajority = 2; // how many TFs must agree to consider bullish/bearish
| |||
| |||
// trade direction
| |||
enum ENUM_TRADE_DIR {DIR_BOTH=0, DIR_LONG_ONLY=1, DIR_SHORT_ONLY=2};
| |||
input ENUM_TRADE_DIR AllowedDirection = DIR_BOTH;
| |||
| |||
// safety
| |||
input int MagicNumber = 20251023;
| |||
input int MaxOpenTrades = 3;
| |||
input double MinFreeMarginBufferUSD = 5.0; // require at least this free margin (USD) to open trades
| |||
| |||
// misc
| |||
input int SlippagePoints = 200; // allowed slippage in points for order send
| |||
| |||
// NEW: Enhanced Risk Management
| |||
input double SpreadBufferMultiplier = 0.8; // add this * spread to SL for buffer
| |||
input double SlippageBufferPoints = 2.0; // add this many points to SL for slippage buffer
| |||
input int MaxDailyTrades = 5; // maximum trades per day
| |||
input int MinCooldownMinutes = 30; // minimum minutes between trades
| |||
input bool UseTimeFilters = true; // skip trading during news/gaps
| |||
input int SkipStartHour = 22; // skip trading from this hour (GMT)
| |||
input int SkipEndHour = 2; // until this hour (GMT)
| |||
input bool UseBreakEven = true; // move SL to breakeven at +0.5R profit
| |||
input double BreakEvenRMultiple = 0.5; // move SL to BE at this R profit
| |||
input bool UsePartialTP = false; // close half position at smaller TP
| |||
input double PartialTPRMultiple = 0.6; // close half at this R profit
| |||
input double TrailingATRMultiple = 0.25; // trail TP at this ATR distance
| |||
| |||
//---------------------- globals ------------------------------------
| |||
double pointSz = 0.0;
| |||
int symbolDigits = 0;
| |||
| |||
// NEW: Enhanced tracking variables
| |||
datetime lastTradeTime = 0;
| |||
int dailyTradeCount = 0;
| |||
datetime lastDailyReset = 0;
| |||
| |||
//---------------------- helper declarations -------------------------
| |||
double GetATR(const string symbol, ENUM_TIMEFRAMES tf, int period, int shift);
| |||
double GetSMA(const string symbol, ENUM_TIMEFRAMES tf, int period, int shift);
| |||
int CountMyPositions(const string symbol);
| |||
void PrintSymbolInfo(const string symbol);
| |||
bool IsMarketBiasBullish();
| |||
bool IsMarketBiasBearish();
| |||
double CalcLotByRisk_USD(const string symbol, double riskUSD, double entryPrice, double slPrice);
| |||
double NormalizeLotToStep(const string symbol, double lot);
| |||
bool CanOpenMoreTrades();
| |||
void ManageTrailing();
| |||
ulong OpenBuy(double lot, double sl, double tp);
| |||
ulong OpenSell(double lot, double sl, double tp);
| |||
double GetPriceAsk(const string symbol);
| |||
double GetPriceBid(const string symbol);
| |||
| |||
// NEW: Enhanced helper functions
| |||
bool IsTimeToTrade();
| |||
bool CanTradeNow();
| |||
double CalculateSpreadBuffer();
| |||
double CalculateSlippageBuffer();
| |||
void ManageBreakEven();
| |||
void ManagePartialTP();
| |||
void ResetDailyCounter();
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Expert initialization |
| |||
//+------------------------------------------------------------------+
| |||
int OnInit()
| |||
{
| |||
// ensure symbol exists and select it
| |||
if(!SymbolSelect(TradeSymbol,true))
| |||
{
| |||
Print("ERROR: cannot select symbol ", TradeSymbol);
| |||
return(INIT_FAILED);
| |||
}
| |||
pointSz = SymbolInfoDouble(TradeSymbol,SYMBOL_POINT);
| |||
symbolDigits = (int)SymbolInfoInteger(TradeSymbol,SYMBOL_DIGITS);
| |||
if(pointSz<=0)
| |||
pointSz = _Point;
| |||
PrintFormat("EA init symbol=%s point=%g symbolDigits=%d", TradeSymbol, pointSz, symbolDigits);
| |||
// print symbol trade properties for verification
| |||
PrintSymbolInfo(TradeSymbol);
| |||
| |||
// safety: ensure AllowedDirection valid (remove modification of input parameter)
| |||
// AllowedDirection is an input parameter and cannot be modified
| |||
if(AllowedDirection<DIR_BOTH || AllowedDirection>DIR_SHORT_ONLY)
| |||
{
| |||
Print("WARNING: Invalid AllowedDirection value. Using DIR_BOTH as default.");
| |||
}
| |||
| |||
Print("XAU Scalp EA initialized. Magic=", MagicNumber);
| |||
| |||
// Initialize enhanced tracking
| |||
lastTradeTime = 0;
| |||
dailyTradeCount = 0;
| |||
lastDailyReset = TimeCurrent();
| |||
| |||
return(INIT_SUCCEEDED);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Expert deinit |
| |||
//+------------------------------------------------------------------+
| |||
void OnDeinit(const int reason)
| |||
{
| |||
Print("EA deinitialized, reason=", reason);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| OnTick |
| |||
//+------------------------------------------------------------------+
| |||
void OnTick()
| |||
{
| |||
// Reset daily counter if new day
| |||
ResetDailyCounter();
| |||
| |||
// Check if we can trade now (time filters, cooldown, daily limits)
| |||
if(!CanTradeNow())
| |||
return;
| |||
| |||
// Ensure we have enough market data
| |||
MqlRates rates[];
| |||
int copied = CopyRates(TradeSymbol,TF,0,3,rates); // need only last 2-3 bars
| |||
if(copied<3)
| |||
return;
| |||
| |||
// Calculate indicators on closed bar (shift=1)
| |||
double smaFastPrev = GetSMA(TradeSymbol,TF,SMA_Fast,1);
| |||
double smaSlowPrev = GetSMA(TradeSymbol,TF,SMA_Slow,1);
| |||
double smaTrendPrev = GetSMA(TradeSymbol,TF,SMA_Trend,1);
| |||
double atrPrev = GetATR(TradeSymbol,TF,ATR_Period,1);
| |||
| |||
// Validate indicators
| |||
if(smaFastPrev <= 0 || smaSlowPrev <= 0 || smaTrendPrev <= 0 || atrPrev <= 0)
| |||
{
| |||
Print("Invalid indicator values - skipping tick");
| |||
return;
| |||
}
| |||
| |||
// entry conditions
| |||
bool trendUp = (iClose(TradeSymbol,TF,1) > smaTrendPrev);
| |||
bool trendDown = (iClose(TradeSymbol,TF,1) < smaTrendPrev);
| |||
| |||
// detect cross on closed bar
| |||
double smaFastPrev2 = GetSMA(TradeSymbol,TF,SMA_Fast,2);
| |||
double smaSlowPrev2 = GetSMA(TradeSymbol,TF,SMA_Slow,2);
| |||
bool crossUp = (smaFastPrev > smaSlowPrev) && (smaFastPrev2 <= smaSlowPrev2);
| |||
bool crossDown = (smaFastPrev < smaSlowPrev) && (smaFastPrev2 >= smaSlowPrev2);
| |||
| |||
// multi TF bias check
| |||
bool biasBullish = true, biasBearish = true;
| |||
if(UseMultiTFBias)
| |||
{
| |||
biasBullish = IsMarketBiasBullish(); // majority H1/H4/D1 bullish?
| |||
biasBearish = IsMarketBiasBearish();
| |||
}
| |||
| |||
// Count my EA positions on symbol
| |||
int myPositions = CountMyPositions(TradeSymbol);
| |||
| |||
// trailing modify for existing positions
| |||
if(myPositions>0 && UseTrailingTP)
| |||
ManageTrailing();
| |||
| |||
// NEW: Manage break-even and partial TP
| |||
if(myPositions>0)
| |||
{
| |||
if(UseBreakEven)
| |||
ManageBreakEven();
| |||
if(UsePartialTP)
| |||
ManagePartialTP();
| |||
}
| |||
| |||
// STOP: limit trades
| |||
if(!CanOpenMoreTrades())
| |||
return;
| |||
| |||
// Decide to open long?
| |||
bool wantLong = false, wantShort = false;
| |||
| |||
if(AllowedDirection!=DIR_SHORT_ONLY)
| |||
{
| |||
// only consider long side if allowed
| |||
if(trendUp && crossUp)
| |||
{
| |||
if(!UseMultiTFBias || biasBullish)
| |||
wantLong = true;
| |||
}
| |||
}
| |||
| |||
if(AllowedDirection!=DIR_LONG_ONLY)
| |||
{
| |||
// consider short side if allowed
| |||
if(trendDown && crossDown)
| |||
{
| |||
if(!UseMultiTFBias || biasBearish)
| |||
wantShort = true;
| |||
}
| |||
}
| |||
| |||
// Prepare order params if needed
| |||
if(wantLong || wantShort)
| |||
{
| |||
double ask = GetPriceAsk(TradeSymbol);
| |||
double bid = GetPriceBid(TradeSymbol);
| |||
if(ask<=0 || bid<=0)
| |||
return;
| |||
| |||
double slPrice=0, tpPrice=0;
| |||
double lot = FixedLotSize;
| |||
if(!UseFixedLot)
| |||
{
| |||
// calculate lot by risk (risk = RiskPercent% of balance)
| |||
double balanceNow = AccountInfoDouble(ACCOUNT_BALANCE);
| |||
double riskUSD = balanceNow * (RiskPercent/100.0);
| |||
// estimate SL using ATR
| |||
double slAmount = atrPrev * ATR_Multiplier;
| |||
if(ScalperMode)
| |||
slAmount = atrPrev * (ATR_Multiplier*0.7);
| |||
if(wantLong)
| |||
slPrice = ask - slAmount;
| |||
else
| |||
slPrice = bid + slAmount;
| |||
lot = CalcLotByRisk_USD(TradeSymbol, riskUSD, (wantLong?ask:bid), slPrice);
| |||
lot = NormalizeLotToStep(TradeSymbol, lot);
| |||
}
| |||
else
| |||
{
| |||
// Use fixed lot, but ensure normalized to broker step
| |||
lot = NormalizeLotToStep(TradeSymbol, FixedLotSize);
| |||
}
| |||
| |||
// final safety lot clamp
| |||
double minLot = SymbolInfoDouble(TradeSymbol,SYMBOL_VOLUME_MIN);
| |||
double maxLot = SymbolInfoDouble(TradeSymbol,SYMBOL_VOLUME_MAX);
| |||
if(minLot==0)
| |||
minLot = 0.01;
| |||
if(maxLot==0)
| |||
maxLot = 100;
| |||
if(lot < minLot)
| |||
lot = minLot;
| |||
if(lot > maxLot)
| |||
lot = maxLot;
| |||
| |||
// compute TP & SL if not already set
| |||
if(!UseFixedLot) { /* slPrice already computed */ }
| |||
else
| |||
{
| |||
// compute using ATR for fixed-lot mode
| |||
double slAmount = atrPrev * ATR_Multiplier;
| |||
if(ScalperMode)
| |||
slAmount = atrPrev * (ATR_Multiplier*0.7);
| |||
| |||
// NEW: Add spread and slippage buffers
| |||
double spreadBuffer = CalculateSpreadBuffer();
| |||
double slippageBuffer = CalculateSlippageBuffer();
| |||
slAmount += spreadBuffer + slippageBuffer;
| |||
| |||
if(wantLong)
| |||
slPrice = ask - slAmount;
| |||
else
| |||
slPrice = bid + slAmount;
| |||
}
| |||
| |||
double rr = RewardRatio;
| |||
if(ScalperMode)
| |||
rr = Scalper_RR;
| |||
if(wantLong)
| |||
{
| |||
tpPrice = ask + (ask - slPrice) * rr;
| |||
}
| |||
else
| |||
{
| |||
tpPrice = bid - (slPrice - bid) * rr;
| |||
}
| |||
| |||
// Validate SL/TP distances
| |||
if(wantLong && (slPrice >= ask || tpPrice <= ask))
| |||
{
| |||
Print("Invalid SL/TP for long trade");
| |||
return;
| |||
}
| |||
if(wantShort && (slPrice <= bid || tpPrice >= bid))
| |||
{
| |||
Print("Invalid SL/TP for short trade");
| |||
return;
| |||
}
| |||
| |||
// final safety checks: free margin
| |||
double freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
| |||
if(freeMargin < MinFreeMarginBufferUSD)
| |||
{
| |||
Print("Not enough free margin to open trades. FreeMargin=", freeMargin);
| |||
return;
| |||
}
| |||
| |||
// Open the trade(s)
| |||
trade.SetExpertMagicNumber(MagicNumber);
| |||
trade.SetDeviationInPoints(SlippagePoints);
| |||
| |||
if(wantLong)
| |||
{
| |||
ulong ticket = OpenBuy(lot, slPrice, tpPrice);
| |||
if(ticket>0)
| |||
{
| |||
PrintFormat("Opened BUY ticket=%I64u lot=%.2f sl=%.3f tp=%.3f", ticket, lot, slPrice, tpPrice);
| |||
lastTradeTime = TimeCurrent();
| |||
dailyTradeCount++;
| |||
}
| |||
else
| |||
PrintFormat("Buy open failed, err=%d", GetLastError());
| |||
}
| |||
if(wantShort)
| |||
{
| |||
ulong ticket = OpenSell(lot, slPrice, tpPrice);
| |||
if(ticket>0)
| |||
{
| |||
PrintFormat("Opened SELL ticket=%I64u lot=%.2f sl=%.3f tp=%.3f", ticket, lot, slPrice, tpPrice);
| |||
lastTradeTime = TimeCurrent();
| |||
dailyTradeCount++;
| |||
}
| |||
else
| |||
PrintFormat("Sell open failed, err=%d", GetLastError());
| |||
}
| |||
} // end wantLong/wantShort
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Helpers: indicator wrappers |
| |||
//+------------------------------------------------------------------+
| |||
double GetATR(const string symbol, ENUM_TIMEFRAMES tf, int period, int shift)
| |||
{
| |||
int handle = iATR(symbol, tf, period);
| |||
if(handle == INVALID_HANDLE)
| |||
return(0);
| |||
| |||
double buffer[];
| |||
if(CopyBuffer(handle, 0, shift, 1, buffer) <= 0)
| |||
return(0);
| |||
return(buffer[0]);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
double GetSMA(const string symbol, ENUM_TIMEFRAMES tf, int period, int shift)
| |||
{
| |||
int handle = iMA(symbol, tf, period, 0, MODE_SMA, PRICE_CLOSE);
| |||
if(handle == INVALID_HANDLE)
| |||
return(0);
| |||
| |||
double buffer[];
| |||
if(CopyBuffer(handle, 0, shift, 1, buffer) <= 0)
| |||
return(0);
| |||
return(buffer[0]);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Count positions opened by this EA |
| |||
//+------------------------------------------------------------------+
| |||
int CountMyPositions(const string symbol)
| |||
{
| |||
int count = 0;
| |||
for(int i=0; i<PositionsTotal(); i++)
| |||
{
| |||
ulong ticket = PositionGetTicket(i);
| |||
if(PositionSelectByTicket(ticket))
| |||
{
| |||
string posSymbol = PositionGetString(POSITION_SYMBOL);
| |||
int posMagic = (int)PositionGetInteger(POSITION_MAGIC);
| |||
if(posSymbol == symbol && posMagic == MagicNumber)
| |||
count++;
| |||
}
| |||
}
| |||
return(count);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Print symbol information for debugging |
| |||
//+------------------------------------------------------------------+
| |||
void PrintSymbolInfo(const string symbol)
| |||
{
| |||
double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
| |||
double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
| |||
double stepLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
| |||
double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
| |||
double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
| |||
| |||
PrintFormat("Symbol %s: MinLot=%.2f MaxLot=%.2f Step=%.2f TickValue=%.2f TickSize=%.5f",
| |||
symbol, minLot, maxLot, stepLot, tickValue, tickSize);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Check if market bias is bullish across multiple timeframes |
| |||
//+------------------------------------------------------------------+
| |||
bool IsMarketBiasBullish()
| |||
{
| |||
int bullishCount = 0;
| |||
| |||
// Check H1 bias
| |||
double h1SMA = GetSMA(TradeSymbol, BiasTF1, BiasSMA_Period, 1);
| |||
double h1Close = iClose(TradeSymbol, BiasTF1, 1);
| |||
if(h1Close > h1SMA)
| |||
bullishCount++;
| |||
| |||
// Check H4 bias
| |||
double h4SMA = GetSMA(TradeSymbol, BiasTF2, BiasSMA_Period, 1);
| |||
double h4Close = iClose(TradeSymbol, BiasTF2, 1);
| |||
if(h4Close > h4SMA)
| |||
bullishCount++;
| |||
| |||
// Check D1 bias
| |||
double d1SMA = GetSMA(TradeSymbol, BiasTF3, BiasSMA_Period, 1);
| |||
double d1Close = iClose(TradeSymbol, BiasTF3, 1);
| |||
if(d1Close > d1SMA)
| |||
bullishCount++;
| |||
| |||
return(bullishCount >= BiasRequiredMajority);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Check if market bias is bearish across multiple timeframes |
| |||
//+------------------------------------------------------------------+
| |||
bool IsMarketBiasBearish()
| |||
{
| |||
int bearishCount = 0;
| |||
| |||
// Check H1 bias
| |||
double h1SMA = GetSMA(TradeSymbol, BiasTF1, BiasSMA_Period, 1);
| |||
double h1Close = iClose(TradeSymbol, BiasTF1, 1);
| |||
if(h1Close < h1SMA)
| |||
bearishCount++;
| |||
| |||
// Check H4 bias
| |||
double h4SMA = GetSMA(TradeSymbol, BiasTF2, BiasSMA_Period, 1);
| |||
double h4Close = iClose(TradeSymbol, BiasTF2, 1);
| |||
if(h4Close < h4SMA)
| |||
bearishCount++;
| |||
| |||
// Check D1 bias
| |||
double d1SMA = GetSMA(TradeSymbol, BiasTF3, BiasSMA_Period, 1);
| |||
double d1Close = iClose(TradeSymbol, BiasTF3, 1);
| |||
if(d1Close < d1SMA)
| |||
bearishCount++;
| |||
| |||
return(bearishCount >= BiasRequiredMajority);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Calculate lot size based on risk in USD |
| |||
//+------------------------------------------------------------------+
| |||
double CalcLotByRisk_USD(const string symbol, double riskUSD, double entryPrice, double slPrice)
| |||
{
| |||
double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
| |||
double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
| |||
| |||
if(tickValue <= 0 || tickSize <= 0)
| |||
{
| |||
Print("Invalid tick value/size for ", symbol);
| |||
return(FixedLotSize);
| |||
}
| |||
| |||
double slDistance = MathAbs(entryPrice - slPrice);
| |||
double slInTicks = slDistance / tickSize;
| |||
double lossPerLot = slInTicks * tickValue;
| |||
| |||
if(lossPerLot <= 0)
| |||
{
| |||
Print("Invalid loss per lot calculation");
| |||
return(FixedLotSize);
| |||
}
| |||
| |||
double lot = riskUSD / lossPerLot;
| |||
return(lot);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Normalize lot size to broker step |
| |||
//+------------------------------------------------------------------+
| |||
double NormalizeLotToStep(const string symbol, double lot)
| |||
{
| |||
double step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
| |||
if(step <= 0)
| |||
step = 0.01;
| |||
| |||
double normalized = MathFloor(lot / step) * step;
| |||
return(normalized);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Check if we can open more trades |
| |||
//+------------------------------------------------------------------+
| |||
bool CanOpenMoreTrades()
| |||
{
| |||
int currentTrades = CountMyPositions(TradeSymbol);
| |||
int maxTrades = ScalperMode ? Scalper_MaxTrades : MaxOpenTrades;
| |||
| |||
if(currentTrades >= maxTrades)
| |||
{
| |||
PrintFormat("Max trades reached: %d/%d", currentTrades, maxTrades);
| |||
return(false);
| |||
}
| |||
| |||
return(true);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Manage trailing take profit for open positions |
| |||
//+------------------------------------------------------------------+
| |||
void ManageTrailing()
| |||
{
| |||
for(int i=0; i<PositionsTotal(); i++)
| |||
{
| |||
ulong ticket = PositionGetTicket(i);
| |||
if(PositionSelectByTicket(ticket))
| |||
{
| |||
string posSymbol = PositionGetString(POSITION_SYMBOL);
| |||
int posMagic = (int)PositionGetInteger(POSITION_MAGIC);
| |||
| |||
if(posSymbol == TradeSymbol && posMagic == MagicNumber)
| |||
{
| |||
double posPrice = PositionGetDouble(POSITION_PRICE_OPEN);
| |||
double posTP = PositionGetDouble(POSITION_TP);
| |||
double posSL = PositionGetDouble(POSITION_SL);
| |||
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
| |||
| |||
double currentPrice = (posType == POSITION_TYPE_BUY) ?
| |||
SymbolInfoDouble(TradeSymbol, SYMBOL_BID) :
| |||
SymbolInfoDouble(TradeSymbol, SYMBOL_ASK);
| |||
| |||
double atr = GetATR(TradeSymbol, TF, ATR_Period, 1);
| |||
double trailingStart = atr * TrailingStartATRMult;
| |||
| |||
double profit = 0;
| |||
if(posType == POSITION_TYPE_BUY)
| |||
profit = currentPrice - posPrice;
| |||
else
| |||
profit = posPrice - currentPrice;
| |||
| |||
if(profit >= trailingStart)
| |||
{
| |||
double newTP = 0;
| |||
double trailingDistance = atr * TrailingATRMultiple;
| |||
| |||
if(posType == POSITION_TYPE_BUY)
| |||
{
| |||
// NEW: ATR-based trailing instead of percentage
| |||
newTP = currentPrice - trailingDistance;
| |||
if(newTP > posTP + TrailingStepPoints)
| |||
{
| |||
trade.PositionModify(ticket, posSL, NormalizeDouble(newTP, symbolDigits));
| |||
PrintFormat("Trailing TP updated for BUY ticket %I64u: %.3f -> %.3f (ATR-based)", ticket, posTP, newTP);
| |||
}
| |||
}
| |||
else
| |||
{
| |||
// NEW: ATR-based trailing instead of percentage
| |||
newTP = currentPrice + trailingDistance;
| |||
if(newTP < posTP - TrailingStepPoints)
| |||
{
| |||
trade.PositionModify(ticket, posSL, NormalizeDouble(newTP, symbolDigits));
| |||
PrintFormat("Trailing TP updated for SELL ticket %I64u: %.3f -> %.3f (ATR-based)", ticket, posTP, newTP);
| |||
}
| |||
}
| |||
}
| |||
}
| |||
}
| |||
}
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Open buy order |
| |||
//+------------------------------------------------------------------+
| |||
ulong OpenBuy(double lot, double sl, double tp)
| |||
{
| |||
double ask = SymbolInfoDouble(TradeSymbol, SYMBOL_ASK);
| |||
if(ask <= 0)
| |||
return(0);
| |||
| |||
bool result = trade.Buy(lot, TradeSymbol, ask,
| |||
NormalizeDouble(sl, symbolDigits),
| |||
NormalizeDouble(tp, symbolDigits),
| |||
"XAU Scalper Buy");
| |||
| |||
return(result ? trade.ResultOrder() : 0);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Open sell order |
| |||
//+------------------------------------------------------------------+
| |||
ulong OpenSell(double lot, double sl, double tp)
| |||
{
| |||
double bid = SymbolInfoDouble(TradeSymbol, SYMBOL_BID);
| |||
if(bid <= 0)
| |||
return(0);
| |||
| |||
bool result = trade.Sell(lot, TradeSymbol, bid,
| |||
NormalizeDouble(sl, symbolDigits),
| |||
NormalizeDouble(tp, symbolDigits),
| |||
"XAU Scalper Sell");
| |||
| |||
return(result ? trade.ResultOrder() : 0);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Get current ask price |
| |||
//+------------------------------------------------------------------+
| |||
double GetPriceAsk(const string symbol)
| |||
{
| |||
return(SymbolInfoDouble(symbol, SYMBOL_ASK));
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Get current bid price |
| |||
//+------------------------------------------------------------------+
| |||
double GetPriceBid(const string symbol)
| |||
{
| |||
return(SymbolInfoDouble(symbol, SYMBOL_BID));
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| NEW: Check if it's time to trade (time filters) |
| |||
//+------------------------------------------------------------------+
| |||
bool IsTimeToTrade()
| |||
{
| |||
if(!UseTimeFilters)
| |||
return(true);
| |||
| |||
MqlDateTime dt;
| |||
TimeToStruct(TimeCurrent(), dt);
| |||
| |||
// Skip trading during specified hours (e.g., 22:00-02:00 GMT for gaps)
| |||
if(SkipStartHour > SkipEndHour)
| |||
{
| |||
// Cross midnight (e.g., 22:00 to 02:00)
| |||
if(dt.hour >= SkipStartHour || dt.hour < SkipEndHour)
| |||
return(false);
| |||
}
| |||
else
| |||
{
| |||
// Same day (e.g., 10:00 to 15:00)
| |||
if(dt.hour >= SkipStartHour && dt.hour < SkipEndHour)
| |||
return(false);
| |||
}
| |||
| |||
return(true);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| NEW: Check if we can trade now (all conditions) |
| |||
//+------------------------------------------------------------------+
| |||
bool CanTradeNow()
| |||
{
| |||
// Check time filters
| |||
if(!IsTimeToTrade())
| |||
{
| |||
Print("Skipping trade - outside trading hours");
| |||
return(false);
| |||
}
| |||
| |||
// Check daily trade limit
| |||
if(dailyTradeCount >= MaxDailyTrades)
| |||
{
| |||
PrintFormat("Daily trade limit reached: %d/%d", dailyTradeCount, MaxDailyTrades);
| |||
return(false);
| |||
}
| |||
| |||
// Check cooldown period
| |||
if(lastTradeTime > 0)
| |||
{
| |||
int minutesSinceLastTrade = (int)((TimeCurrent() - lastTradeTime) / 60);
| |||
if(minutesSinceLastTrade < MinCooldownMinutes)
| |||
{
| |||
PrintFormat("Cooldown period active: %d/%d minutes", minutesSinceLastTrade, MinCooldownMinutes);
| |||
return(false);
| |||
}
| |||
}
| |||
| |||
return(true);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| NEW: Calculate spread buffer for SL |
| |||
//+------------------------------------------------------------------+
| |||
double CalculateSpreadBuffer()
| |||
{
| |||
double ask = SymbolInfoDouble(TradeSymbol, SYMBOL_ASK);
| |||
double bid = SymbolInfoDouble(TradeSymbol, SYMBOL_BID);
| |||
double spread = ask - bid;
| |||
| |||
return(spread * SpreadBufferMultiplier);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| NEW: Calculate slippage buffer for SL |
| |||
//+------------------------------------------------------------------+
| |||
double CalculateSlippageBuffer()
| |||
{
| |||
return(SlippageBufferPoints * pointSz);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| NEW: Manage break-even functionality |
| |||
//+------------------------------------------------------------------+
| |||
void ManageBreakEven()
| |||
{
| |||
for(int i=0; i<PositionsTotal(); i++)
| |||
{
| |||
ulong ticket = PositionGetTicket(i);
| |||
if(PositionSelectByTicket(ticket))
| |||
{
| |||
string posSymbol = PositionGetString(POSITION_SYMBOL);
| |||
int posMagic = (int)PositionGetInteger(POSITION_MAGIC);
| |||
| |||
if(posSymbol == TradeSymbol && posMagic == MagicNumber)
| |||
{
| |||
double posPrice = PositionGetDouble(POSITION_PRICE_OPEN);
| |||
double posSL = PositionGetDouble(POSITION_SL);
| |||
double posTP = PositionGetDouble(POSITION_TP);
| |||
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
| |||
| |||
double currentPrice = (posType == POSITION_TYPE_BUY) ?
| |||
SymbolInfoDouble(TradeSymbol, SYMBOL_BID) :
| |||
SymbolInfoDouble(TradeSymbol, SYMBOL_ASK);
| |||
| |||
double profit = 0;
| |||
if(posType == POSITION_TYPE_BUY)
| |||
profit = currentPrice - posPrice;
| |||
else
| |||
profit = posPrice - currentPrice;
| |||
| |||
// Calculate R multiple
| |||
double slDistance = MathAbs(posPrice - posSL);
| |||
if(slDistance > 0)
| |||
{
| |||
double rMultiple = profit / slDistance;
| |||
| |||
// Move SL to breakeven + small buffer
| |||
if(rMultiple >= BreakEvenRMultiple && posSL != posPrice)
| |||
{
| |||
double newSL = posPrice + (posType == POSITION_TYPE_BUY ? pointSz * 2 : -pointSz * 2);
| |||
trade.PositionModify(ticket, NormalizeDouble(newSL, symbolDigits), posTP);
| |||
PrintFormat("Moved SL to breakeven for ticket %I64u: %.3f -> %.3f", ticket, posSL, newSL);
| |||
}
| |||
}
| |||
}
| |||
}
| |||
}
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| NEW: Manage partial take profit |
| |||
//+------------------------------------------------------------------+
| |||
void ManagePartialTP()
| |||
{
| |||
for(int i=0; i<PositionsTotal(); i++)
| |||
{
| |||
ulong ticket = PositionGetTicket(i);
| |||
if(PositionSelectByTicket(ticket))
| |||
{
| |||
string posSymbol = PositionGetString(POSITION_SYMBOL);
| |||
int posMagic = (int)PositionGetInteger(POSITION_MAGIC);
| |||
| |||
if(posSymbol == TradeSymbol && posMagic == MagicNumber)
| |||
{
| |||
double posPrice = PositionGetDouble(POSITION_PRICE_OPEN);
| |||
double posSL = PositionGetDouble(POSITION_SL);
| |||
double posVolume = PositionGetDouble(POSITION_VOLUME);
| |||
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
| |||
| |||
double currentPrice = (posType == POSITION_TYPE_BUY) ?
| |||
SymbolInfoDouble(TradeSymbol, SYMBOL_BID) :
| |||
SymbolInfoDouble(TradeSymbol, SYMBOL_ASK);
| |||
| |||
double profit = 0;
| |||
if(posType == POSITION_TYPE_BUY)
| |||
profit = currentPrice - posPrice;
| |||
else
| |||
profit = posPrice - currentPrice;
| |||
| |||
// Calculate R multiple
| |||
double slDistance = MathAbs(posPrice - posSL);
| |||
if(slDistance > 0)
| |||
{
| |||
double rMultiple = profit / slDistance;
| |||
| |||
// Close half position at partial TP
| |||
if(rMultiple >= PartialTPRMultiple && posVolume > 0.02) // Only if volume > 0.02
| |||
{
| |||
double closeVolume = posVolume * 0.5; // Close half
| |||
if(trade.PositionClosePartial(ticket, closeVolume))
| |||
{
| |||
PrintFormat("Partial TP executed for ticket %I64u: closed %.2f lots at %.3f", ticket, closeVolume, currentPrice);
| |||
}
| |||
}
| |||
}
| |||
}
| |||
}
| |||
}
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| NEW: Reset daily trade counter |
| |||
//+------------------------------------------------------------------+
| |||
void ResetDailyCounter()
| |||
{
| |||
MqlDateTime currentDT, lastDT;
| |||
TimeToStruct(TimeCurrent(), currentDT);
| |||
TimeToStruct(lastDailyReset, lastDT);
| |||
| |||
// If new day, reset counter
| |||
if(currentDT.day != lastDT.day || currentDT.mon != lastDT.mon || currentDT.year != lastDT.year)
| |||
{
| |||
dailyTradeCount = 0;
| |||
lastDailyReset = TimeCurrent();
| |||
Print("Daily trade counter reset - new day");
| |||
}
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
|