diff --git a/TradeCopyMaster.ex4 b/TradeCopyMaster.ex4 new file mode 100644 index 0000000..569e3bd Binary files /dev/null and b/TradeCopyMaster.ex4 differ diff --git a/TradeCopyMaster.mq4 b/TradeCopyMaster.mq4 index d086eeb..456b104 100644 --- a/TradeCopyMaster.mq4 +++ b/TradeCopyMaster.mq4 @@ -23,144 +23,168 @@ #property copyright "Copyright © 2011-2022, Syslog.eu, rel. 2022-06-22" #property link "http://syslog.eu" -int delay=1000; -int start,TickCount; -int Size=0,PrevSize=0; -int cnt,TotalCounter; +int delay = 1000; +int start, TickCount; +int Size = 0, PrevSize = 0; +int cnt, TotalCounter; string cmt; -string nl="\n"; +string nl = "\n"; -int OrdId[],PrevOrdId[]; -string OrdSym[],PrevOrdSym[]; -int OrdTyp[],PrevOrdTyp[]; -double OrdLot[],PrevOrdLot[]; -double OrdPrice[],PrevOrdPrice[]; -double OrdSL[],PrevOrdSL[]; -double OrdTP[],PrevOrdTP[]; +int OrdId[], PrevOrdId[]; +string OrdSym[], PrevOrdSym[]; +int OrdTyp[], PrevOrdTyp[]; +double OrdLot[], PrevOrdLot[]; +double OrdPrice[], PrevOrdPrice[]; +double OrdSL[], PrevOrdSL[]; +double OrdTP[], PrevOrdTP[]; //+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ -int init() { - - int handle=FileOpen("TradeCopy.csv",FILE_CSV|FILE_WRITE|FILE_COMMON,","); - if(handle>0) { - FileClose(handle); - }else Print("File open has failed, error: ",GetLastError()); - - return(0); -} +int OnInit() + { + int handle = FileOpen("TradeCopy.csv", FILE_CSV | FILE_WRITE | FILE_COMMON, ","); + if(handle > 0) + { + FileClose(handle); + } + else + Print("File open has failed, error: ", GetLastError()); + return(0); + } //+------------------------------------------------------------------+ //| expert deinitialization function | //+------------------------------------------------------------------+ -int deinit() +void OnDeinit(const int reason) { //---- - -//---- - return(0); } //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ -int start() { - - while(!IsStopped()) { - start=GetTickCount(); - cmt=start+nl+"Counter: "+TotalCounter; - get_positions(); - if(compare_positions()) save_positions(); - Comment(cmt); - TickCount=GetTickCount()-start; - if(delay>TickCount)Sleep(delay-TickCount-2); - } - Alert("end, TradeCopy EA stopped"); - Comment(""); - return(0); - - +void OnStart() + { + while(!IsStopped()) + { + start = GetTickCount(); + cmt = start + nl + "Counter: " + TotalCounter; + get_positions(); + if(compare_positions()) + save_positions(); + Comment(cmt); + TickCount = GetTickCount() - start; + if(delay > TickCount) + Sleep(delay - TickCount - 2); + } + Alert("end, TradeCopy EA stopped"); + Comment(""); //---- - -} - - -void get_positions() { - Size=OrdersTotal(); - if (Size!= PrevSize) { - ArrayResize(OrdId,Size); - ArrayResize(OrdSym,Size); - ArrayResize(OrdTyp,Size); - ArrayResize(OrdLot,Size); - ArrayResize(OrdPrice,Size); - ArrayResize(OrdSL,Size); - ArrayResize(OrdTP,Size); } - for(int cnt=0;cnt 0) + { + FileWrite(handle, TotalCounter); + TotalCounter++; + for(i = 0; i < Size; i++) + { + FileWrite(handle, OrdId[i], OrdSym[i], OrdTyp[i], OrdLot[i], OrdPrice[i], OrdSL[i], OrdTP[i]); + } + FileClose(handle); + } + else + Print("File open has failed, error: ", GetLastError()); + } - int handle=FileOpen("TradeCopy.csv",FILE_CSV|FILE_WRITE|FILE_COMMON,","); - if(handle>0) { - FileWrite(handle,TotalCounter); - TotalCounter++; - for(i=0;iTickCount)Sleep(delay-TickCount-2); - } + Print("Got a tick..."); + while(!IsStopped()) + { + if(!IsExpertEnabled()) + break; + start = GetTickCount(); + cmt = "TickCount: " + start + nl + "Counter: " + TotalCounter; + load_positions(); + for(int i = 0; i < Size; i++) + { + cmt = cmt + nl + " [ " + OrdId[i] + " ] [ " + OrdSym[i] + " ] [ " + VerbType(OrdTyp[i]) + " ] [ " + OrdLot[i] + " ] [ " + OrdPrice[i] + " ] [ " + OrdSL[i] + " ] [ " + OrdTP[i] + " ]"; + } + // Make sense to make changes only when the market is open and trading allowed + if(IsTradeAllowed() && IsConnected()) + { + compare_positions(); + } + Comment(cmt); + TickCount = GetTickCount() - start; + if(delay > TickCount) + Sleep(delay - TickCount - 2); + } // Alert("end, TradeCopy EA stopped"); - Comment(""); - return(0); - -} - -void load_positions() { - - int handle=FileOpen(filename+".csv",FILE_CSV|FILE_READ|FILE_COMMON,";"); - if(handle>0) { + Comment(""); + } - string line=FileReadString(handle); - if (TotalCounter == StrToInteger(line)) { +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void load_positions() + { + int handle = FileOpen(filename + ".csv", FILE_CSV | FILE_READ | FILE_COMMON, ";"); + if(handle > 0) + { + string line = FileReadString(handle); + if(TotalCounter == StrToInteger(line)) + { + FileClose(handle); + return; + } + else + { + TotalCounter = StrToInteger(line); + } + cnt = 0; + while(FileIsEnding(handle) == false) + { + cmt = cmt + nl + "DEBUG: reading file"; + if(ArraySize(s) < cnt + 1) + ArrayResize(s, cnt + 1); + s[cnt] = FileReadString(handle); + cnt++; + } FileClose(handle); - return; - }else{ - TotalCounter=StrToInteger(line); - } - int cnt=0; - while(FileIsEnding(handle)==false) { - cmt=cmt+nl+"DEBUG: reading file"; - if (ArraySize(s) 0) + { + lot = ForceLot; + } + else + { + lot = lot * LotCoeff; + } + if(Balance < AccountBalance()) + Balance = AccountBalance(); + if(MicroLotBalance > 0) + { + if(MathFloor(Balance / MicroLotBalance) / 100 > lot) + { + lot = MathFloor(Balance / MicroLotBalance) / 100; + } + } +// Print("Calculated lot size: ",lot); + return(NormalizeDouble(lot, DigitsMinLot(symbol))); } -} - -double LotVol(double lot,string symbol) { - if (ForceLot > 0) { - lot=ForceLot; - }else{ - lot=lot*LotCoeff; - } - if (Balance 0) { - if (MathFloor(Balance/MicroLotBalance)/100 > lot) { - lot=MathFloor(Balance/MicroLotBalance)/100; - } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string VerbType(int type) + { + return (0); + switch(type) + { + case 0: + return ("BUY"); + break; + case 1: + return ("SELL"); + break; + case 2: + return ("BUY LIMIT"); + break; + case 3: + return ("SELL LIMIT"); + break; + case 4: + return ("BUY STOP"); + break; + case 5: + return ("SELL STOP"); + break; + } } -// Print("Calculated lot size: ",lot); - return(NormalizeDouble(lot,DigitsMinLot(symbol))); -} - - -string VerbType (int type) { - switch(type) { - case 0: - return ("BUY"); - break; - case 1: - return ("SELL"); - break; - case 2: - return ("BUY LIMIT"); - break; - case 3: - return ("SELL LIMIT"); - break; - case 4: - return ("BUY STOP"); - break; - case 5: - return ("SELL STOP"); - break; - } -} - - - -int DigitsMinLot(string symbol) { - double ml=MarketInfo(symbol,MODE_MINLOT); +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int DigitsMinLot(string symbol) + { + double ml = MarketInfo(symbol, MODE_MINLOT); //--- 1/x of lot step - double Dig=0; - if(ml!=0)Dig=1.0/ml; + double Dig = 0; + if(ml != 0) + Dig = 1.0 / ml; //--- conversion of 1/x to digits - double res=0; - if(Dig>1)res=1; - if(Dig>10)res=2; - if(Dig>100)res=3; - if(Dig>1000)res=4; + double res = 0; + if(Dig > 1) + res = 1; + if(Dig > 10) + res = 2; + if(Dig > 100) + res = 3; + if(Dig > 1000) + res = 4; return(res); -} + } -void compare_positions() { +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void compare_positions() + { // load real positions and compare them with master ones - real_positions(); - int x[]; - ArrayResize(x,RealSize); - if (RealSize>0)ArrayInitialize(x,0); + real_positions(); + int x[]; + ArrayResize(x, RealSize); + if(RealSize > 0) + ArrayInitialize(x, 0); // cmt=cmt+nl+"RealSize: "+RealSize; - //Master to Real comparations - for (int i=0;i1 && OrdPrice[i] != RealOrdPrice[j]) { - OrderSelect(RealOrdId[j],SELECT_BY_TICKET); - OrderModify(OrderTicket(),OrdPrice[i],OrderStopLoss(),OrderTakeProfit(),0); + for(int i = 0; i < Size; i++) // for all master orders + { + bool found = false; + for(int j = 0; j < RealSize; j++) // find the right real order + { + if(DoubleToStr(OrdId[i], 0) == RealOrdOrig[j]) + { + //compare values + found = true; + x[j] = 1; + // if not market order, compare open prices - later + //compare volumes - TODO later + //compare open price when delayed order + if(OrdTyp[i] > 1 && OrdPrice[i] != RealOrdPrice[j]) + { + if(OrderSelect(RealOrdId[j], SELECT_BY_TICKET)) + { + bool a = OrderModify(OrderTicket(), OrdPrice[i], OrderStopLoss(), OrderTakeProfit(), 0); + } + } + //compare SL,TP + if(IgnoreSLTP == false && (OrdTP[i] != RealOrdTP[j] || OrdSL[i] != RealOrdSL[j])) + { + if(OrderSelect(RealOrdId[j], SELECT_BY_TICKET)) + { + bool b = OrderModify(OrderTicket(), OrderOpenPrice(), OrdSL[i], OrdTP[i], 0); + } + } + } } - //compare SL,TP - if (IgnoreSLTP==false && (OrdTP[i]!=RealOrdTP[j] || OrdSL[i]!=RealOrdSL[j])) { - OrderSelect(RealOrdId[j],SELECT_BY_TICKET); - OrderModify(OrderTicket(),OrderOpenPrice(),OrdSL[i],OrdTP[i],0); + if(!found) + { + //no position open with this ID, need to open now + int result; + if(OrdTyp[i] < 2) + { + // ------ market order (check Price and OpenPrice) + double Price = MarketPrice(i); + // PipsTolerance for Price: + if((OrdTyp[i] == OP_BUY && Price < OrdPrice[i] + PipsTolerance * mp * Point) || + (OrdTyp[i] == OP_SELL && Price > OrdPrice[i] - PipsTolerance * mp * Point)) + { + result = OrderSend(OrdSym[i], OrdTyp[i], OrdLot[i], Price, 5, 0, 0, DoubleToStr(OrdId[i], 0), magic, 0); + if(result > 0) + { + if(IgnoreSLTP == false) + { bool c = OrderModify(result, OrderOpenPrice(), OrdSL[i], OrdTP[i], 0);} + } + else + Print("Open ", OrdSym[i], " failed: ", GetLastError()); + } + else + Print("Price out of tolerance ", DoubleToStr(OrdId[i], 0), ": ", OrdPrice[i], "/", Price); + } + else + { + // ------ waiting order: + if(CopyDelayedTrades) + result = OrderSend(OrdSym[i], OrdTyp[i], OrdLot[i], OrdPrice[i], 0, OrdSL[i], OrdTP[i], DoubleToStr(OrdId[i], 0), magic, 0); + } } - } - } - if (!found) { - //no position open with this ID, need to open now - int result; - if (OrdTyp[i]<2) { -// ------ market order (check Price and OpenPrice) - double Price=MarketPrice(i); - -// PipsTolerance for Price: - if ((OrdTyp[i]==OP_BUY && PriceOrdPrice[i]-PipsTolerance*mp*Point )) { - - result=OrderSend(OrdSym[i],OrdTyp[i],OrdLot[i],Price,5,0,0,DoubleToStr(OrdId[i],0),magic,0); - if (result>0) { - if (IgnoreSLTP==false) OrderModify(result,OrderOpenPrice(),OrdSL[i],OrdTP[i],0); - }else Print ("Open ",OrdSym[i]," failed: ",GetLastError()); - }else Print ("Price out of tolerance ",DoubleToStr(OrdId[i],0),": ",OrdPrice[i],"/",Price); - }else{ -// ------ waiting order: - if (CopyDelayedTrades) result=OrderSend(OrdSym[i],OrdTyp[i],OrdLot[i],OrdPrice[i],0,OrdSL[i],OrdTP[i],DoubleToStr(OrdId[i],0),magic,0); - } - } - } - for (j=0;j "+x[j]; - if (x[j]!=1) { //no master order, close the ticket -// Price=MarketPrice(RealOrdSym[j],"close"); -// OrderClose(RealOrdId[j],RealOrdLot[j],Price,5,CLR_NONE); - if (RealOrdTyp[j]<2) { - Price=MarketPrice(j,"close"); - result=OrderClose(RealOrdId[j],RealOrdLot[j],Price,5,CLR_NONE); - if (result<1) Print ("Close ",RealOrdId[j]," / ",RealOrdLot[j]," / ",Price," failed: ",GetLastError()); - if (Balance "+x[j]; + if(x[j] != 1) //no master order, close the ticket + { + // Price=MarketPrice(RealOrdSym[j],"close"); + // OrderClose(RealOrdId[j],RealOrdLot[j],Price,5,CLR_NONE); + if(RealOrdTyp[j] < 2) + { + Price = MarketPrice(j, "close"); + result = OrderClose(RealOrdId[j], RealOrdLot[j], Price, 5, CLR_NONE); + if(result < 1) + Print("Close ", RealOrdId[j], " / ", RealOrdLot[j], " / ", Price, " failed: ", GetLastError()); + if(Balance < AccountBalance()) + Balance = AccountBalance(); + } + else + { + bool d = OrderDelete(RealOrdId[j], CLR_NONE); + } + } + } } -} -double MarketPrice(int i ,string typ="open") { - RefreshRates(); - if (typ=="open") { - if (OrdTyp[i]==0) { - Print("Getting Ask open price for buy position..."); - return(NormalizeDouble(MarketInfo(OrdSym[i],MODE_ASK),digits(OrdSym[i]))); - }else{ - Print("Getting Bid open price for sell position..."); - return(NormalizeDouble(MarketInfo(OrdSym[i],MODE_BID),digits(OrdSym[i]))); - } - }else { -//close: - if (RealOrdTyp[i]==0) { - Print("Getting Bid close price for buy position..."); - return(NormalizeDouble(MarketInfo(RealOrdSym[i],MODE_BID),digits(RealOrdSym[i]))); - }else{ - Print("Getting Ask close price for sell position..."); - return(NormalizeDouble(MarketInfo(RealOrdSym[i],MODE_ASK),digits(RealOrdSym[i]))); - } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +double MarketPrice(int i, string typ = "open") + { + RefreshRates(); + if(typ == "open") + { + if(OrdTyp[i] == 0) + { + Print("Getting Ask open price for buy position..."); + return(NormalizeDouble(MarketInfo(OrdSym[i], MODE_ASK), digits(OrdSym[i]))); + } + else + { + Print("Getting Bid open price for sell position..."); + return(NormalizeDouble(MarketInfo(OrdSym[i], MODE_BID), digits(OrdSym[i]))); + } + } + else + { + //close: + if(RealOrdTyp[i] == 0) + { + Print("Getting Bid close price for buy position..."); + return(NormalizeDouble(MarketInfo(RealOrdSym[i], MODE_BID), digits(RealOrdSym[i]))); + } + else + { + Print("Getting Ask close price for sell position..."); + return(NormalizeDouble(MarketInfo(RealOrdSym[i], MODE_ASK), digits(RealOrdSym[i]))); + } + } } -} -void real_positions() { - - int i=0; - for(int cnt=0;cnt