SimpleHedging/NextLevel/NextLevel.mq5

276 lines
10 KiB
MQL5

//+------------------------------------------------------------------+
//| MartingaleEA_XAUUSD.mq5 |
//| Copyright 2025, Your Name |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Your Name"
#property link "https://www.mql5.com"
#property version "1.00"
#include <Trade/Trade.mqh> // Include Trade library
//--- Input parameters
input double InitialVolume = 0.01; // Initial Volume (x) for XAUUSD
input double VolumeMultiplier = 1.5; // Volume Multiplier
input double TakeProfitPips = 50; // Take Profit (pips) for XAUUSD
input double PriceStepPips = 20; // Price Step for new orders (pips)
input double MaxSpreadPips = 5; // Maximum allowable spread (pips)
//--- Global variables
double PipValue; // Value of 1 pip in points
CTrade trade; // Trade object for order operations
double initialBuyTP = 0; // Store TP of initial Buy order
double initialBuyPrice = 0; // Store price of initial Buy order
double initialSellPrice =0;
double initialSellTP = 0;
int priceDigits; // Digits for price normalization
ulong lastDealTicket = 0; // Track last processed deal ticket
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Calculate pip value based on symbol's point
PipValue = SymbolInfoDouble(_Symbol, SYMBOL_POINT) * 10; // 1 pip = 10 points for XAUUSD
priceDigits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); // Get symbol digits for normalization
trade.SetExpertMagicNumber(123456); // Set unique magic number
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Normalize volume to comply with broker's requirements |
//+------------------------------------------------------------------+
double NormalizeVolume(double volume)
{
double minVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double volumeStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
// Normalize volume to the nearest step
double normalized = MathRound(volume / volumeStep) * volumeStep;
// Ensure volume is within min/max limits
normalized = MathMax(minVolume, MathMin(maxVolume, normalized));
// Round to correct precision
int digits = (int)MathCeil(-MathLog10(volumeStep));
return NormalizeDouble(normalized, digits);
}
//+------------------------------------------------------------------+
//| Normalize price to comply with broker's tick size |
//+------------------------------------------------------------------+
double NormalizePrice(double price)
{
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
return NormalizeDouble(price, priceDigits);
}
//+------------------------------------------------------------------+
//| Check if a pending order already exists at a specific price |
//+------------------------------------------------------------------+
bool PendingOrderExists(double price, ENUM_ORDER_TYPE orderType)
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
ulong ticket = OrderGetTicket(i);
if(OrderSelect(ticket))
{
if(OrderGetString(ORDER_SYMBOL) == _Symbol && OrderGetInteger(ORDER_TYPE) == orderType)
{
if(MathAbs(OrderGetDouble(ORDER_PRICE_OPEN) - price) < PipValue)
return true;
}
}
}
return false;
}
//+------------------------------------------------------------------+
//| Cancel all pending Sell Stop orders |
//+------------------------------------------------------------------+
void CancelPendingStops()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
ulong ticket = OrderGetTicket(i);
if(OrderSelect(ticket))
{
if(OrderGetString(ORDER_SYMBOL) == _Symbol)
{
trade.OrderDelete(ticket);
}
}
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Check spread
double spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) / 10; // Convert to pips
if(spread > MaxSpreadPips)
return; // Skip if spread is too high
// Check if there are no open positions
if(PositionsTotal() == 0)
{
// Cancel any remaining Sell Stop orders
CancelPendingStops();
// Open initial Buy order if no pending orders
if(OrdersTotal() == 0)
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double tp = NormalizePrice(ask + TakeProfitPips * PipValue);
double normalizedVolume = NormalizeVolume(InitialVolume);
// Place Sell Stop order immediately
double sellStopPrice = NormalizePrice(bid - PriceStepPips * PipValue);
double sellTP = NormalizePrice(sellStopPrice - TakeProfitPips * PipValue);
double sellVolume = NormalizeVolume(InitialVolume * VolumeMultiplier);
if(trade.Buy(normalizedVolume, _Symbol, ask, sellTP, tp, "Initial Buy"))
{
initialBuyTP = tp; // Store normalized TP of initial Buy order
initialBuyPrice = ask; // Store initial Buy price
trade.SellStop(sellVolume, sellStopPrice, _Symbol, tp, sellTP, 0, 0, "Sell Stop Hedge");
initialSellPrice = sellStopPrice;
initialSellTP = sellTP;
}
}
}
else
{
// Process open positions and pending orders
ManagePositions();
}
}
//+------------------------------------------------------------------+
//| Expert trade event function |
//+------------------------------------------------------------------+
void OnTrade()
{
// Select history for the current symbol
HistorySelect(0, TimeCurrent());
// Loop through deals to find the latest one
for(int i = HistoryDealsTotal() - 1; i >= 0; i--)
{
ulong dealTicket = HistoryDealGetTicket(i);
if(dealTicket > lastDealTicket && HistoryDealSelect(dealTicket))
{
if(HistoryDealGetString(dealTicket, DEAL_SYMBOL) == _Symbol)
{
// Check if deal was closed by TP
if(HistoryDealGetInteger(dealTicket, DEAL_REASON) == DEAL_REASON_TP)
{
// Close all remaining positions
CloseAllPositions();
// Cancel all pending orders
CancelPendingStops();
// Update last processed deal ticket
lastDealTicket = dealTicket;
break;
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close all open positions |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
if(PositionGetString(POSITION_SYMBOL) == _Symbol)
{
trade.PositionClose(ticket);
}
}
}
}
//+------------------------------------------------------------------+
//| Manage open positions and pending orders |
//+------------------------------------------------------------------+
void ManagePositions()
{
double lastVolume = InitialVolume;
int buyCount = 0;
int sellCount = 0;
bool sellStopTriggered = false;
// Loop through all open positions
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
if(PositionGetString(POSITION_SYMBOL) == _Symbol)
{
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
buyCount++;
if(buyCount == 1) // First Buy order
{
initialBuyPrice = PositionGetDouble(POSITION_PRICE_OPEN);
initialBuyTP = PositionGetDouble(POSITION_TP);
}
lastVolume = MathMax(lastVolume, PositionGetDouble(POSITION_VOLUME));
}
else // Sell position
{
sellCount++;
lastVolume = MathMax(lastVolume, PositionGetDouble(POSITION_VOLUME));
}
}
}
}
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
// Place Buy Stop order if Sell Stop was triggered and no Buy Stop exists at initialBuyPrice
if(initialBuyPrice > 0 && !PendingOrderExists(initialBuyPrice, ORDER_TYPE_BUY_STOP) && buyCount == sellCount)
{
double newVolume = NormalizeVolume(lastVolume * VolumeMultiplier);
trade.BuyStop(newVolume, initialBuyPrice, _Symbol, initialSellTP, initialBuyTP, 0, 0, "Additional Buy Stop");
}
// Place new Sell Stop orders after a Buy Stop is triggered
if(buyCount > 1 && !PendingOrderExists(initialSellPrice, ORDER_TYPE_SELL_STOP) && (buyCount - sellCount) == 1)
{
double sellVolume = NormalizeVolume(lastVolume * VolumeMultiplier);
trade.SellStop(sellVolume, initialSellPrice, _Symbol, initialBuyTP, initialSellTP, 0, 0, "Sell Stop Hedge");
}
}
//+------------------------------------------------------------------+
//| Get first Buy order ticket |
//+------------------------------------------------------------------+
ulong GetFirstBuyTicket()
{
for(int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
return ticket;
}
}
}
return 0;
}
//+------------------------------------------------------------------+