//+------------------------------------------------------------------+ //| CribMarketEA.mq5 | //| Copyright 2025, MQL Development | //| https://www.mqldevelopment.com/ | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MQL Development" #property link "https://www.mqldevelopment.com/" #property version "1.00" #include CTrade trade; #define MaxOrders 10000 struct new_trade_store { ulong buyTicket; // Buy Ticket ulong sellTicket; // Sell Ticket string buySymbol; // Buy Symbol Name string sellSymbol; // Sell Symbol Name new_trade_store() { buyTicket = -1; sellTicket = -1; } }; new_trade_store newTradeStore[MaxOrders]; input string Settings = " ------------- General Settings ------------- "; //_ input int magicNo = 333; // Magic no input double lotSize = 0.01; // Lot Size input bool enableBasketTP = true; // Enable Basket TP input double basketTakeProfit = 1.0; // Basket Take Profit input int maxOpenPositions = 3; // Maximum number of Combinations input int miniHoldTimeSec = 120; // Mini time in (seconds) to hold trades closing before checking TP string goldPairs[]; int totalGoldPairs = 0; int timer = 0; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- trade.SetExpertMagicNumber(magicNo); trade.SetDeviationInPoints(10); trade.SetTypeFilling(ORDER_FILLING_IOC); trade.LogLevel(LOG_LEVEL_ALL); trade.SetAsyncMode(false); getSymbolsFromMarketWatch(); // addToStructure(153718680, 153718681, "EURUSD", "XAUUSD."); //--- create timer EventSetMillisecondTimer(1000); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- EventKillTimer(); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnTimer() { //--- timer++; Print("<><><><><><><> Timer Start: ",timer," <><><><><><><>"); removeFromStruct(); if(enableBasketTP == true) { checkBasketTakeProfit(); } string symbolToBuy = getSymbolWithLowestAsk(); string symbolToSell = getSymbolWithHighestBid(); int buyTickett = -1, sellTickett = -1; //Print(" Symbol to Buy is: ", symbolToBuy, " Symbol to Sell: ", symbolToSell); if(noOfActiveCombinations() < maxOpenPositions) { if(canTradeSymbol(symbolToBuy, symbolToSell, POSITION_TYPE_BUY, POSITION_TYPE_SELL)) { if(symbolToBuy != symbolToSell) { if(symbolToBuy != NULL && symbolToBuy != "") { buyTickett = placeBuyTrade(symbolToBuy); } if(symbolToSell != NULL && symbolToSell != "") { sellTickett = placeSellTrade(symbolToSell); } } } } if(buyTickett != -1 && sellTickett != -1) { addToStructure(buyTickett, sellTickett, symbolToBuy, symbolToSell); } Print("<><><><><><><> Timer End: ",timer," <><><><><><><>"); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool newBar() { static datetime lastbar; datetime curbar = iTime(Symbol(), PERIOD_CURRENT, 0); if(lastbar != curbar) { lastbar = curbar; Print(" ---------------------- New Bar :: ---------------------- ",lastbar); return (true); } else { return (false); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int placeBuyTrade(string symbol) { double ask = SymbolInfoDouble(symbol, SYMBOL_ASK); double buySL = 0, buyTP = 0; int count=noOfActiveCombinations()+1; if(trade.PositionOpen(symbol, ORDER_TYPE_BUY, lotSize, ask, buySL, buyTP, "Buy Trade Placed # "+(string)timer)) { Print("Buy Trade Placed on ", symbol, ": ", trade.ResultOrder()); return (int)trade.ResultOrder(); } else { Print("Error in placing Buy on ", symbol, ": ", GetLastError()); } return 0; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int placeSellTrade(string symbol) { double bid = SymbolInfoDouble(symbol, SYMBOL_BID); double sellSL = 0, sellTP = 0; int count=noOfActiveCombinations()+1; if(trade.PositionOpen(symbol, ORDER_TYPE_SELL, lotSize, bid, sellSL, sellTP, "Sell Trade Placed # "+(string)timer)) { Print("Sell Trade Placed on ", symbol, ": ", trade.ResultOrder()); return (int)trade.ResultOrder(); } else { Print("Error in placing Sell on ", symbol, ": ", GetLastError()); } return 0; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void getSymbolsFromMarketWatch() { int totalSymbols = SymbolsTotal(true); ArrayResize(goldPairs, 0); totalGoldPairs = 0; for(int i = 0; i < totalSymbols; i++) { string symbolName = SymbolName(i, true); //if(StringFind(symbolName, "GOLD") != -1 || StringFind(symbolName, "XAU") != -1) if(symbolName!="XAUUSD#") { ArrayResize(goldPairs, totalGoldPairs + 1); if(totalGoldPairs < ArraySize(goldPairs)) { goldPairs[totalGoldPairs] = symbolName; totalGoldPairs++; } else { Print("Error: Array resize failed for symbol ", symbolName); } } } Print("Found ", totalGoldPairs, " Symbol pairs in Market Watch"); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string getSymbolWithLowestAsk() { if(totalGoldPairs == 0) return NULL; string lowestSymbol = ""; //double lowestAsk = INT_MAX; // SymbolInfoDouble(lowestSymbol, SYMBOL_ASK); double lowestAsk = DBL_MAX; for(int i = 0; i < totalGoldPairs; i++) { double currentAsk = SymbolInfoDouble(goldPairs[i], SYMBOL_ASK); Print(" Ask Price: ",currentAsk," || on Pair: ",goldPairs[i]); if(currentAsk < lowestAsk) { lowestAsk = currentAsk; lowestSymbol = goldPairs[i]; } } Print("Lowest Ask Pair: ", lowestSymbol, " || Lowest Ask: ", lowestAsk); return lowestSymbol; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string getSymbolWithHighestBid() { if(totalGoldPairs == 0) return NULL; string highestSymbol = ""; //double highestBid = INT_MIN; // SymbolInfoDouble(highestSymbol, SYMBOL_BID); double highestBid = 0; for(int i = 0; i < totalGoldPairs; i++) { double currentBid = SymbolInfoDouble(goldPairs[i], SYMBOL_BID); Print(" Bid Price: ",currentBid," || on Pair: ",goldPairs[i]); if(currentBid > highestBid) { highestBid = currentBid; highestSymbol = goldPairs[i]; } } Print("Highest Bid Pair: ", highestSymbol, " || Highest Bid: ", highestBid); return highestSymbol; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int noOfActiveCombinations() { int count = 0; for(int i = 0; i < MaxOrders; i++) { if(newTradeStore[i].buyTicket != -1 && newTradeStore[i].sellTicket != -1) { count++; } } return count; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void checkBasketTakeProfit() { for(int i = 0; i < MaxOrders; i++) { if(newTradeStore[i].buyTicket != -1 && newTradeStore[i].sellTicket != -1) { if(miniTimeBeforeClosing(newTradeStore[i].buyTicket, newTradeStore[i].sellTicket)) { double combinationProfit = 0; if(PositionSelectByTicket(newTradeStore[i].buyTicket)) { Print("Ticket:",newTradeStore[i].buyTicket); Print("Profit:",PositionGetDouble(POSITION_PROFIT), " Swap:",PositionGetDouble(POSITION_SWAP)); combinationProfit += PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP) ; } if(PositionSelectByTicket(newTradeStore[i].sellTicket)) { Print("Ticket:",newTradeStore[i].sellTicket); Print("Profit:",PositionGetDouble(POSITION_PROFIT), " Swap:",PositionGetDouble(POSITION_SWAP)); combinationProfit += PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP); } if(combinationProfit >= basketTakeProfit) { Print("Combination TP hit: Closing trades. Profit = ", combinationProfit); if(!trade.PositionClose(newTradeStore[i].buyTicket)) { Print(" Error Closing Buy Trade : ", newTradeStore[i].buyTicket," ",GetLastError()); } else Print("Buy Trade Closed: ", newTradeStore[i].buyTicket); if(!trade.PositionClose(newTradeStore[i].sellTicket)) { Print(" Error Closing Sell Trade : ", newTradeStore[i].sellTicket," ",GetLastError()); } else Print("Sell Trade Closed: ", newTradeStore[i].sellTicket); } } } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool isGoldPair(string symbol) { for(int i = 0; i < totalGoldPairs; i++) { //Print("Total Gold pairs: ", totalGoldPairs, " Array: ", goldPairs[i], " Symbol: ", symbol); if(goldPairs[i] == symbol) return true; } return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void addToStructure(ulong r_buyTicket,ulong r_sellTicket, string r_buySymbol, string r_sellSymbol) { for(int i=0; i=0; j--) { ulong ticket = PositionGetTicket(j); if(PositionSelectByTicket(ticket)) { if(ticket == newTradeStore[i].buyTicket) { buyPresent = true; } if(ticket == newTradeStore[i].sellTicket) { sellPresent = true; } } } if(!buyPresent && !sellPresent) { Print("Buy ticket closed so removed from struct: ", newTradeStore[i].buyTicket); newTradeStore[i].buyTicket = -1; newTradeStore[i].buySymbol = ""; Print("Sell ticket closed so removed from struct: ", newTradeStore[i].sellTicket); newTradeStore[i].sellTicket = -1; newTradeStore[i].sellSymbol = ""; } } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool canTradeSymbol(string symbol1, string symbol2, ENUM_POSITION_TYPE type1, ENUM_POSITION_TYPE type2) { for(int i = 0; i < MaxOrders; i++) { if(newTradeStore[i].buyTicket != -1 && newTradeStore[i].sellTicket != -1) { if(newTradeStore[i].buySymbol == symbol1 && newTradeStore[i].sellSymbol == symbol2) { if(type1 == POSITION_TYPE_BUY && type2 == POSITION_TYPE_SELL) { Print("Already Have Buy and Sell on this Pair"); Print("----------- Symbol Buy: ", symbol1, " Symbol Sell: ", symbol2, " Buy Ticket: ", newTradeStore[i].buyTicket, " Sell Ticket: ", newTradeStore[i].sellTicket," ---------------"); return false; } } } } return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool miniTimeBeforeClosing(ulong buyTicket, ulong sellTicket) { datetime currentTime = TimeCurrent(); datetime buyTime = 0; datetime sellTime = 0; if(PositionSelectByTicket(buyTicket)) { buyTime = (datetime)PositionGetInteger(POSITION_TIME); } if(PositionSelectByTicket(sellTicket)) { sellTime = (datetime)PositionGetInteger(POSITION_TIME); } datetime comboOpenTime = (buyTime > sellTime) ? buyTime : sellTime; int secondsHeld = (int)(currentTime - comboOpenTime); if(secondsHeld >= miniHoldTimeSec) { Print("Minimum time REACHED (", secondsHeld, "s) "); return true; } else { int secondsRemaining = miniHoldTimeSec - secondsHeld; Print("Minimum time NOT reached (", secondsHeld, "/", miniHoldTimeSec, "s) ", secondsRemaining, "s remaining"); return false; } } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+