
#property copyright ""
#property link      ""
#property show_inputs

#include <stdlib.mqh>

#import "GlobalVariable.dll"
   int GV_SetNamedInt(string a0, int a1);
   double GV_SetNamedDouble(string a0, double a1);
   int GV_SetNamedString(string a0, string a1);
#import

extern string system = "slave1sys";
extern int HourShiftGMT = 0;
extern string PairPrefix = "";
extern string PairSuffix = "";
extern bool ReverseTrades = FALSE;
extern bool OffsetReverseBySpread = TRUE;
extern int OffsetPips = 2;
extern bool EquityFilter = FALSE;
extern int EquitySMA = 3;
extern bool ReverseOnNegativeEquity = FALSE;
extern int history = 10;
extern int CycleMilliseconds = 200;
double gda_136[][11];
double gda_140[1][2];
double gd_144;
double gd_152;
string gsa_160[];
int g_datetime_168;
int g_datetime_176;
int g_datetime_180;
bool g_bool_184;

int init() {
   return (0);
}

int deinit() {
   int li_12;
   int li_0 = ArraySize(gda_136) / 11;
   int li_16 = GV_SetNamedInt(system + "lines", 0);
   for (int l_count_4 = 0; l_count_4 < li_0; l_count_4++) {
      for (int l_count_8 = 0; l_count_8 < 11; l_count_8++) {
         li_12++;
         GV_SetNamedDouble(system + "_mt_" + li_12, 0);
      }
   }
   return (1);
}

int start() {
   int li_0;
   int li_8;
   string ls_12;
   while (IsStopped() == FALSE) {
      RefreshRates();
      Sleep(CycleMilliseconds);
      ls_12 = "local time is : " + TimeToStr(TimeLocal(), TIME_SECONDS);
      ls_12 = ls_12 
         + "\n" 
         + "system=" + system + ", Time[0]=" + TimeToStr(iTime(NULL, 0, 0)) + ", HourShiftGMT=" + HourShiftGMT + ", PairPrefix=" + PairPrefix + ", PairSuffix=" + PairSuffix + ", ReverseTrades=" + ReverseTrades + ", OffsetReverseBySpread=" + OffsetReverseBySpread + ", history=" + history 
         + "\n" 
      + ", EquityFilter=" + EquityFilter + ", EquitySMA=" + EquitySMA + ", ReverseOnNegativeEquity=" + ReverseOnNegativeEquity + ", CycleMilliseconds=" + CycleMilliseconds;
      if (g_datetime_180 == 0) g_datetime_180 = iTime(NULL, 0, 0);
      if (g_datetime_180 > 0 && g_datetime_180 != iTime(NULL, 0, 0)) {
         ReadEqt();
         li_8 = ArraySize(gda_140) / 2;
         ArrayResize(gda_140, li_8 + 1);
         gd_144 = AccountEquity();
         gda_140[li_8][0] = iTime(NULL, 0, 0);
         gda_140[li_8][1] = gd_144;
         SaveEqt(gda_140);
         ReadEqt();
         g_datetime_180 = iTime(NULL, 0, 0);
         li_8 = ArraySize(gda_140) / 2;
         gd_152 = 0;
         if (li_8 >= EquitySMA) {
            for (int li_4 = li_8 - 1; li_4 >= li_8 - EquitySMA; li_4--) gd_152 += gda_140[li_4][1];
            gd_152 /= EquitySMA;
         }
      }
      ls_12 = ls_12 
         + "\n" 
      + "equity=" + DoubleToStr(gd_144, 2) + ", equity SMA=" + DoubleToStr(gd_152, 2);
      Comment(ls_12);
      if (g_datetime_176 + 10 <= TimeCurrent() && !IsConnected()) {
         g_datetime_176 = TimeCurrent();
         Alert("TradeCopy :: MT4 Server Not Connected!");
         Print("MT4 Server Not Connected!");
      }
      li_0 = FindTrades();
      FindLastClosedTrades(history);
      if (TimeLocal() - g_datetime_168 > 60) {
         Print("subacc " + system + " total trades:", CountNZ(gda_136, 11));
         g_datetime_168 = TimeLocal();
      }
      if (ArraySize(gda_136) == 0) continue;
      li_0 = 0;
      li_0 = SaveArrayToGV(gda_136, gsa_160, system);
      if (li_0 <= 0) Print("Error saving trades!");
   }
   return (0);
}

int FindTrades() {
   int l_ord_total_4 = OrdersTotal();
   ArrayResize(gda_136, 0);
   for (int l_pos_0 = l_ord_total_4 - 1; l_pos_0 >= 0; l_pos_0--)
      if (OrderSelect(l_pos_0, SELECT_BY_POS, MODE_TRADES)) AddTrade(OrderTicket(), 0, MODE_TRADES);
   return (1);
}

int FindLastClosedTrades(int ai_0) {
   int l_hist_total_8 = OrdersHistoryTotal();
   for (int l_pos_4 = l_hist_total_8 - 1; l_pos_4 >= l_hist_total_8 - ai_0; l_pos_4--)
      if (OrderSelect(l_pos_4, SELECT_BY_POS, MODE_HISTORY)) AddTrade(OrderTicket(), 1, MODE_HISTORY);
   return (1);
}

int AddTrade(int a_ticket_0, int ai_4, int ai_8) {
   string ls_12;
   string l_symbol_20;
   int li_28;
   int l_str2int_32;
   int l_str_len_44;
   int l_str_len_48;
   double ld_60;
   double ld_68;
   double ld_76;
   double ld_84;
   double ld_92;
   double ld_100;
   int li_36 = ArraySize(gda_136) / 11 + 1;
   int l_cmd_56 = -1;
   if (OrderSelect(a_ticket_0, SELECT_BY_TICKET, ai_8)) {
      ls_12 = OrderComment();
      l_str2int_32 = 0;
      if (StringFind(ls_12, "to #", 0) >= 0) {
         li_28 = StringFind(ls_12, "#", 0);
         l_str2int_32 = StrToInteger(StringSubstr(ls_12, li_28 + 1, StringLen(ls_12) - li_28 - 1));
      }
      if (StringFind(ls_12, "from #", 0) >= 0) {
         li_28 = StringFind(ls_12, "#", 0);
         l_str2int_32 = StrToInteger(StringSubstr(ls_12, li_28 + 1, StringLen(ls_12) - li_28 - 1));
      }
      l_cmd_56 = OrderType();
      ld_60 = OrderStopLoss();
      ld_68 = OrderTakeProfit();
      ld_84 = MarketInfo(OrderSymbol(), MODE_SPREAD) * MarketInfo(OrderSymbol(), MODE_POINT);
      ld_92 = OrderOpenPrice();
      ld_100 = OrderClosePrice();
      g_bool_184 = ReverseTrades;
      if (EquityFilter) {
         if (gd_144 < 0.01 || gd_152 < 0.01) return;
         if (!ReverseOnNegativeEquity && gd_144 <= gd_152) return;
         if (ReverseOnNegativeEquity && gd_144 <= gd_152) g_bool_184 = TRUE;
      }
      if (g_bool_184) {
         if (OffsetReverseBySpread) {
            if (l_cmd_56 == OP_BUY || l_cmd_56 == OP_BUYSTOP || l_cmd_56 == OP_BUYLIMIT) ld_92 += OffsetPips * MarketInfo(OrderSymbol(), MODE_POINT);
            else ld_92 -= OffsetPips * MarketInfo(OrderSymbol(), MODE_POINT);
         }
         if (l_cmd_56 == OP_BUY) {
            l_cmd_56 = 1;
            if (ld_60 > 0.0) ld_76 = ld_60 + ld_84;
            else ld_76 = 0;
            if (ld_68 > 0.0) ld_60 = ld_68 + ld_84;
            else ld_60 = 0;
            ld_68 = ld_76;
            ld_92 -= ld_84;
         } else {
            if (l_cmd_56 == OP_SELL) {
               l_cmd_56 = 0;
               if (ld_60 > 0.0) ld_76 = ld_60 - ld_84;
               else ld_76 = 0;
               if (ld_68 > 0.0) ld_60 = ld_68 - ld_84;
               else ld_60 = 0;
               ld_68 = ld_76;
               ld_92 += ld_84;
            } else {
               if (l_cmd_56 == OP_BUYSTOP) {
                  l_cmd_56 = 3;
                  if (ld_60 > 0.0) ld_76 = ld_60 + ld_84;
                  else ld_76 = 0;
                  if (ld_68 > 0.0) ld_60 = ld_68 + ld_84;
                  else ld_60 = 0;
                  ld_68 = ld_76;
                  ld_92 -= ld_84;
               } else {
                  if (l_cmd_56 == OP_SELLSTOP) {
                     l_cmd_56 = 2;
                     if (ld_60 > 0.0) ld_76 = ld_60 - ld_84;
                     else ld_76 = 0;
                     if (ld_68 > 0.0) ld_60 = ld_68 - ld_84;
                     else ld_60 = 0;
                     ld_68 = ld_76;
                     ld_92 += ld_84;
                  } else {
                     if (l_cmd_56 == OP_BUYLIMIT) {
                        l_cmd_56 = 5;
                        if (ld_60 > 0.0) ld_76 = ld_60 + ld_84;
                        else ld_76 = 0;
                        if (ld_68 > 0.0) ld_60 = ld_68 + ld_84;
                        else ld_60 = 0;
                        ld_68 = ld_76;
                        ld_92 -= ld_84;
                     } else {
                        if (l_cmd_56 == OP_SELLLIMIT) {
                           l_cmd_56 = 4;
                           if (ld_60 > 0.0) ld_76 = ld_60 - ld_84;
                           else ld_76 = 0;
                           if (ld_68 > 0.0) ld_60 = ld_68 - ld_84;
                           else ld_60 = 0;
                           ld_68 = ld_76;
                           ld_92 += ld_84;
                        }
                     }
                  }
               }
            }
         }
      }
      ArrayResize(gda_136, li_36);
      ArrayResize(gsa_160, li_36);
      gda_136[li_36 - 1][0] = a_ticket_0;
      gda_136[li_36 - 1][1] = l_cmd_56;
      gda_136[li_36 - 1][2] = ld_92;
      gda_136[li_36 - 1][3] = ld_60;
      gda_136[li_36 - 1][4] = ld_68;
      gda_136[li_36 - 1][5] = OrderOpenTime() + 60 * (60 * HourShiftGMT);
      gda_136[li_36 - 1][7] = OrderLots();
      gda_136[li_36 - 1][8] = ai_4;
      gda_136[li_36 - 1][9] = ld_100;
      gda_136[li_36 - 1][10] = l_str2int_32;
      l_symbol_20 = OrderSymbol();
      l_str_len_44 = StringLen(PairPrefix);
      l_str_len_48 = StringLen(PairSuffix);
      if (l_str_len_44 > 0) l_symbol_20 = StringSubstr(l_symbol_20, l_str_len_44);
      if (l_str_len_48 > 0) l_symbol_20 = StringSubstr(l_symbol_20, 0, StringLen(l_symbol_20) - l_str_len_48);
      gsa_160[li_36 - 1] = l_symbol_20;
   }
   return (0);
}

int SaveArrayToGV(double ada_0[][11], string asa_4[], string as_8) {
   int li_36;
   int li_40;
   int li_16 = ArraySize(ada_0) / 11;
   if (li_16 <= 0) return (1);
   int li_20 = GV_SetNamedInt(as_8 + "lines", li_16);
   for (int l_index_28 = 0; l_index_28 < li_16; l_index_28++) {
      for (int l_count_32 = 0; l_count_32 < 11; l_count_32++) {
         li_36++;
         GV_SetNamedDouble(as_8 + "_mt_" + li_36, ada_0[l_index_28][l_count_32]);
      }
      li_40 = GV_SetNamedString(as_8 + "_mts_" + l_index_28, asa_4[l_index_28]);
      if (li_40 < 0) Print("err set gv str ", as_8 + "_mts_" + l_index_28, " ", asa_4[l_index_28]);
   }
   return (1);
}

int CountNZ(double ada_0[][11], int ai_4) {
   int li_ret_20;
   int li_16 = ArraySize(ada_0) / ai_4;
   for (int l_index_8 = 0; l_index_8 < li_16; l_index_8++)
      if (ada_0[l_index_8][0] > 0.0) li_ret_20++;
   return (li_ret_20);
}

int SaveEqt(double ada_0[1][2]) {
   int li_8;
   string l_name_16 = "TCEQv" + system;
   int l_file_4 = FileOpen(l_name_16, FILE_CSV|FILE_WRITE);
   if (l_file_4 < 1) {
      Print("File " + l_name_16 + " not found, the last error is ", ErrorDescription(GetLastError()));
      return (0);
   }
   int li_12 = ArraySize(ada_0) / 2;
   for (int li_24 = li_12 - 1; li_24 >= 0; li_24--) {
      li_8 = FileWrite(l_file_4, ada_0[li_24][0], ada_0[li_24][1]);
      if (li_24 < li_12 - EquitySMA - 1) break;
   }
   if (li_8 < 0) {
      Print("writing file error : ", ErrorDescription(GetLastError()));
      return (0);
   }
   FileClose(l_file_4);
   return (1);
}

int ReadEqt() {
   int li_8;
   int li_12;
   int li_16;
   double ld_20;
   double ld_28;
   double lda_36[][2];
   string l_name_40 = "TCEQv" + system;
   int l_file_0 = FileOpen(l_name_40, FILE_CSV|FILE_READ);
   if (l_file_0 < 1) return (0);
   ArrayResize(lda_36, 0);
   ArrayResize(gda_140, 0);
   while (!FileIsEnding(l_file_0)) {
      li_8++;
      ArrayResize(lda_36, li_8);
      ld_20 = FileReadNumber(l_file_0);
      ld_28 = FileReadNumber(l_file_0);
      lda_36[li_8 - 1][0] = ld_20;
      lda_36[li_8 - 1][1] = ld_28;
      if (li_8 > 1) {
         li_12 = lda_36[li_8 - 1][0];
         li_16 = lda_36[li_8 - 2][0];
         if (li_16 - li_12 > 60 * Period() + 1) {
            li_8--;
            break;
         }
      }
   }
   ArrayResize(lda_36, li_8);
   ArrayResize(gda_140, li_8);
   for (int li_48 = li_8 - 1; li_48 >= 0; li_48--) {
      gda_140[li_48][0] = lda_36[li_8 - 1 - li_48][0];
      gda_140[li_48][1] = lda_36[li_8 - 1 - li_48][1];
   }
   FileClose(l_file_0);
   return (1);
}