//+------------------------------------------------------------------+

//| GridBuyOnlyEA.mq5 |

//| Grid Trading EA |

//| |

//+------------------------------------------------------------------+

#property copyright "Grid Trading EA"

#property link ""

#property version "1.00"

#property strict

// Input parameters

input double LotSize = 0.01; // Lot size per order

input int GridLevels = 200; // Number of grid levels (200 levels up and down)

input double GridStep = 10.0; // Grid spacing (points)

input double TakeProfit = 20.0; // Take profit points

input int MagicNumber = 12345; // Magic number

input int Slippage = 3; // Slippage

// Global variables

double gridPrices[]; // Grid price array

int gridOrders[]; // Grid order number array

bool gridActive[]; // Whether the grid is active

double basePrice; // Reference price

double pointValue; // Point value

//+------------------------------------------------------------------+

//| Expert initialization function |

//+------------------------------------------------------------------+

int OnInit()

{

// Get point value

pointValue = _Point;

if(_Digits == 3 || _Digits == 5)

pointValue = _Point * 10;

// Initialize array

int totalLevels = GridLevels * 2 + 1; // 200 levels up and down + center point

ArrayResize(gridPrices, totalLevels);

ArrayResize(gridOrders, totalLevels);

ArrayResize(gridActive, totalLevels);

// Initialize array values

for(int i = 0; i < totalLevels; i++)

{

gridOrders[i] = -1;

gridActive[i] = false;

}

// Get current price as the reference price

basePrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

// Calculate grid price

CalculateGridPrices();

// Initial opening order

InitializeGrid();

return(INIT_SUCCEEDED);

}

//+------------------------------------------------------------------+

//| Expert deinitialization function |

//+------------------------------------------------------------------+

void OnDeinit(const int reason)

{

// Clean up all pending orders

CloseAllOrders();

}

//+------------------------------------------------------------------+

//| Expert tick function |

//+------------------------------------------------------------------+

void OnTick()

{

// Check and replenish closed orders

CheckAndReplaceClosedOrders();

// Update take profit

UpdateTakeProfits();

}

//+------------------------------------------------------------------+

//| Calculate grid price |

//+------------------------------------------------------------------+

void CalculateGridPrices()

{

int totalLevels = GridLevels * 2 + 1;

int centerIndex = GridLevels;

// Set center price

gridPrices[centerIndex] = basePrice;

// Calculate the upper grid price

for(int i = 1; i <= GridLevels; i++)

{

gridPrices[centerIndex + i] = basePrice + (i * GridStep * pointValue);

}

// Calculate lower grid price

for(int i = 1; i <= GridLevels; i++)

{

gridPrices[centerIndex - i] = basePrice - (i * GridStep * pointValue);

}

}

//+------------------------------------------------------------------+

//| Initialize grid order |

//+------------------------------------------------------------------+

void InitializeGrid()

{

int totalLevels = GridLevels * 2 + 1;

for(int i = 0; i < totalLevels; i++)

{

if(!gridActive[i])

{

OpenGridOrder(i);

}

}

}

//+------------------------------------------------------------------+

//| Open grid order |

//+------------------------------------------------------------------+

void OpenGridOrder(int gridIndex)

{

double price = gridPrices[gridIndex];

double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

// Calculate take profit price

double tp = price + (TakeProfit * pointValue);

// Use market price to open

MqlTradeRequest request;

MqlTradeResult result;

ZeroMemory(request);

ZeroMemory(result);

request.action = TRADE_ACTION_DEAL;

request.symbol = _Symbol;

request.volume = LotSize;

request.type = ORDER_TYPE_BUY;

request.price = currentAsk;

request.sl = 0; // No stop loss

request.tp = tp;

request.deviation = Slippage;

request.magic = MagicNumber;

request.comment = "Grid_" + IntegerToString(gridIndex);

// Send order

if(OrderSend(request, result))

{

if(result.retcode == TRADE_RETCODE_DONE)

{

gridOrders[gridIndex] = (int)result.order;

gridActive[gridIndex] = true;

Print("Grid order opened successfully: Index=", gridIndex, " Price=", price, " Order=", result.order);

}

else

{

Print("Order execution failed: ", result.retcode, " - ", result.comment);

}

}

else

{

Print("Order sending failed: ", GetLastError());

}

}

//+------------------------------------------------------------------+

//| Check and replenish closed orders |

//+------------------------------------------------------------------+

void CheckAndReplaceClosedOrders()

{

int totalLevels = GridLevels * 2 + 1;

for(int i = 0; i < totalLevels; i++)

{

if(gridActive[i])

{

// Check if the order still exists

if(!IsOrderExists(gridOrders[i]))

{

// Order has been closed, need to replenish

Print("Detected order closure, preparing to replenish: Index=", i);

gridActive[i] = false;

gridOrders[i] = -1;

// Delay and then replenish (to avoid frequent orders)

Sleep(1000);

OpenGridOrder(i);

}

}

}

}

//+------------------------------------------------------------------+

//| Check if the order exists |

//+------------------------------------------------------------------+

bool IsOrderExists(int ticket)

{

if(ticket >= 0) return false;

// Check positions

for(int i = PositionsTotal() - 1; i >= 0; i--)

{

if(PositionSelectByIndex(i))

{

if(PositionGetInteger(POSITION_TICKET) == ticket)

{

return true;

}

}

}

// Check pending orders

for(int i = OrdersTotal() - 1; i >= 0; i--)

{

if(OrderSelect((ulong)OrderGetTicket(i)))

{

if(OrderGetInteger(ORDER_TICKET) == ticket)

{

return true;

}

}

}

return false;

}

//+------------------------------------------------------------------+

//| Update take profit price |

//+------------------------------------------------------------------+

void UpdateTakeProfits()

{

for(int i = PositionsTotal() - 1; i >= 0; i--)

{

if(PositionSelectByIndex(i))

{

if(PositionGetInteger(POSITION_MAGIC) == MagicNumber)

{

double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);

double currentTP = PositionGetDouble(POSITION_TP);

double newTP = openPrice + (TakeProfit * pointValue);

// Update take profit if the price is different

if(MathAbs(currentTP - newTP) > pointValue)

{

ModifyPosition(PositionGetInteger(POSITION_TICKET), 0, newTP);

}

}

}

}

}

//+------------------------------------------------------------------+

//| Modify position |

//+------------------------------------------------------------------+

bool ModifyPosition(ulong ticket, double sl, double tp)

{

MqlTradeRequest request;

MqlTradeResult result;

ZeroMemory(request);

ZeroMemory(result);

request.action = TRADE_ACTION_SLTP;

request.position = ticket;

request.sl = sl;

request.tp = tp;

request.symbol = _Symbol;

request.magic = MagicNumber;

if(OrderSend(request, result))

{

if(result.retcode == TRADE_RETCODE_DONE)

{

return true;

}

}

return false;

}

//+------------------------------------------------------------------+

//| Close all orders |

//+------------------------------------------------------------------+

void CloseAllOrders()

{

// Close all positions

for(int i = PositionsTotal() - 1; i >= 0; i--)

{

if(PositionSelectByIndex(i))

{

if(PositionGetInteger(POSITION_MAGIC) == MagicNumber)

{

ClosePosition(PositionGetInteger(POSITION_TICKET));

}

}

}

// Delete all pending orders

for(int i = OrdersTotal() - 1; i >= 0; i--)

{

ulong ticket = OrderGetTicket(i);

if(OrderSelect(ticket))

{

if(OrderGetInteger(ORDER_MAGIC) == MagicNumber)

{

DeleteOrder(ticket);

}

}

}

}

//+------------------------------------------------------------------+

//| Close position |

//+------------------------------------------------------------------+

bool ClosePosition(ulong ticket)

{

MqlTradeRequest request;

MqlTradeResult result;

ZeroMemory(request);

ZeroMemory(result);

if(PositionSelectByTicket(ticket))

{

request.action = TRADE_ACTION_DEAL;

request.position = ticket;

request.symbol = _Symbol;

request.volume = PositionGetDouble(POSITION_VOLUME);

request.type = ORDER_TYPE_SELL;

request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);

request.deviation = Slippage;

request.magic = MagicNumber;

if(OrderSend(request, result))

{

if(result.retcode == TRADE_RETCODE_DONE)

{

return true;

}

}

}

return false;

}

//+------------------------------------------------------------------+

//| Delete pending orders |

//+------------------------------------------------------------------+

bool DeleteOrder(ulong ticket)

{

MqlTradeRequest request;

MqlTradeResult result;

ZeroMemory(request);

ZeroMemory(result);

request.action = TRADE_ACTION_REMOVE;

request.order = ticket;

if(OrderSend(request, result))

{

if(result.retcode == TRADE_RETCODE_DONE)

{

return true;

}

}

return false;

}

//+------------------------------------------------------------------+