//+------------------------------------------------------------------+
//|                                                           mm.mqh |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property strict
//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+
// #define MacrosHello   "Hello, world!"
// #define MacrosYear    2010
//+------------------------------------------------------------------+
//| DLL imports                                                      |
//+------------------------------------------------------------------+
// #import "user32.dll"
//   int      SendMessageA(int hWnd,int Msg,int wParam,int lParam);
// #import "my_expert.dll"
//   int      ExpertRecalculate(int wParam,int lParam);
// #import
//+------------------------------------------------------------------+
//| EX5 imports                                                      |
//+------------------------------------------------------------------+
// #import "stdlib.ex5"
//   string ErrorDescription(int error_code);
// #import
//+------------------------------------------------------------------+
/*
#import "../Libraries/extarray.dll"
int		__getPtr(double &pArray);
double	__getValue(int iPointer, int iOffset);
void		__setValue(int iPointer, int iOffset, double dValue);
#import
*/
double getDinamicLot(double _dRisk, double _dStopLoss) {
   double dFreeMargin = AccountFreeMargin();
   double dTickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
   double dMinLot = MarketInfo(Symbol(), MODE_MINLOT);
   double dMaxLot = MarketInfo(Symbol(), MODE_MAXLOT);
   double dLotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
   double dLot = MathFloor(dFreeMargin*_dRisk/100/_dStopLoss/dTickValue/dLotStep)*dLotStep;
   if(dLot < dMinLot) dLot = dMinLot;
   if(dLot > dMaxLot) dLot = dMaxLot;
   return dLot;
}

double getAverege(double _dStartLot, double _dMul, double _dSL, double _dTP, int _iMagic) {
   double dLot = _dStartLot;
   double dLotMultiplier = _dMul ? _dMul : 2 + (_dSL - _dTP) / _dTP;
   int iTotal = OrdersHistoryTotal();
   for (int i = 0; i < iTotal; i++) {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) {
         Print("OrderSelect error in getAverege");
         return 0;
      }
      if(OrderSymbol() == Symbol() && OrderMagicNumber() == _iMagic) {
         if (OrderProfit() > 0) {
            dLot = _dStartLot;
         }
         else {
            dLot *= dLotMultiplier;
         }
      }
   }

   return dLot;
}

bool isOpen(int _iMagic) {
   for(int i = 0; i < OrdersTotal(); i++) {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
         Print("OrderSelect error in isOpen");
      }
         
      if(OrderMagicNumber() == _iMagic) {
         return true;
      }
   }   
   return false;
}

bool isOpenLong(int _iMagic) {
   for(int i = 0; i < OrdersTotal(); i++) {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
         Print("OrderSelect error in isOpenLong");
      }
      
      if(OrderMagicNumber() != _iMagic) {
         continue;
      }
      
      if(OrderType() == OP_BUY) {
         return true;
      }
   }   
   return false;
}

bool isOpenShort(int _iMagic) {
   for(int i = 0; i < OrdersTotal(); i++) {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
         Print("OrderSelect error in isOpenShort");
      }
      
      if(OrderMagicNumber() != _iMagic) {
         continue;
      }
      
      if(OrderType() == OP_SELL) {
         return true;
      }
   }   
   return false;
}

double getOrderProfit(int _iMagic) {
   for(int i = 0; i < OrdersTotal(); i++) {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
         Print("OrderSelect error in isOpenShort");
      }
      
      if(OrderMagicNumber() != _iMagic) {
         continue;
      }
      
      return OrderProfit();
   }
   return 0;
}

double getOrderProfitPips(int _iMagic) {
   for(int i = 0; i < OrdersTotal(); i++) {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
         Print("OrderSelect error in isOpenShort");
      }
      
      if(OrderMagicNumber() != _iMagic) {
         continue;
      }
      
      if(OrderType() == OP_BUY) {
         return MathFloor((Bid-OrderOpenPrice())/Point);
      }
      if(OrderType() == OP_SELL) {
         return MathFloor((OrderOpenPrice()-Ask)/Point);
      }
   }
   return 0;
}

void open(int _iType, double _dLotSize, double _dSL, double _dTP, int _iSlippage, int _iMagic, string _sComment) {
   if(_iType == OP_BUY)
      openLong(_dLotSize, _dSL, _dTP, _iSlippage, _iMagic, _sComment);
   if(_iType == OP_SELL)
      openShort(_dLotSize, _dSL, _dTP, _iSlippage, _iMagic, _sComment);
}

void openLong(double _dLotSize, double _dSL, double _dTP, int _iSlippage, int _iMagic, string _sComment) {
   if(!OrderSend(
         Symbol(),
         OP_BUY,
         _dLotSize,
         Ask,
         _iSlippage,
         _dSL ? Bid - _dSL : 0,
         _dTP ? Ask + _dTP : 0,
         _sComment,
         _iMagic,
         0,
         clrBlue
   )) {
      Print("OrderSend error in openLong");
   }
}

void openShort(double _dLotSize, double _dSL, double _dTP, int _iSlippage, int _iMagic, string _sComment) {
   if(!OrderSend(
         Symbol(),
         OP_SELL,
         _dLotSize,
         Bid,
         _iSlippage,
         _dSL ? Ask + _dSL : 0,
         _dTP ? Bid - _dTP : 0,
         _sComment,
         _iMagic,
         0,
         clrRed
   )) {
      Print("OrderSend error in openShort");
   }
}

void trailingStop(double _dTP, double _dTS, int _iMagic) {
   double dNewSL = 0;
   double dMinSL = MarketInfo(NULL, MODE_STOPLEVEL);
   
   for(int i = 0; i < OrdersTotal(); i++) {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
         Print("OrderSelect error in trailingStop");
      }
      
      if(OrderMagicNumber() != _iMagic) {
         continue;
      }
      
      if(OrderType() == OP_BUY) {
         if(Bid - OrderOpenPrice() <= (_dTP + _dTS) ) {
            continue;
         }
         
         dNewSL = NormalizeDouble(Bid - _dTS, Digits);
         if(OrderStopLoss() >= dNewSL) {
            continue;
         }
         if(dNewSL - OrderStopLoss() <= dMinSL) {
            continue;
         }
         if(!OrderModify(OrderTicket(), OrderOpenPrice(), dNewSL, 0, 0, clrBlue)) {
            Print("OrderModify error in trailingStop");
         }
      }

      if(OrderType() == OP_SELL) {
         if(OrderOpenPrice() - Ask <= (_dTP + _dTS) ) {
            continue;
         }
         
         dNewSL = NormalizeDouble(Ask + _dTS, Digits);
         if(OrderStopLoss() <= dNewSL) {
            continue;
         }
         if(OrderStopLoss() - dNewSL <= dMinSL) {
            continue;
         }
         if(!OrderModify(OrderTicket(), OrderOpenPrice(), dNewSL, 0, 0, clrBlue)) {
            Print("OrderModify error in trailingStop");
         }
      }
   }
}

void closeAll(int _iMagic, int _iSlippage) {
   for(int i = 0; i < OrdersTotal(); i++) {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
         Print("OrderSelect error in trailingStop");
      }
      
      if(OrderMagicNumber() != _iMagic) {
         continue;
      }

      if(OrderType() == OP_BUY) {
         if(!OrderClose(OrderTicket(), OrderLots(), Bid, _iSlippage, clrBlue)) {
            Print("OrderClose error in closeAll");
         }
      }
      if(OrderType() == OP_SELL) {
         if(!OrderClose(OrderTicket(), OrderLots(), Ask, _iSlippage, clrRed)) {
            Print("OrderClose error in closeAll");
         }
      }
   }
}

ENUM_TIMEFRAMES periodCurrent() {
   switch(Period()) {
      case 1:     return PERIOD_M1;    break;
      case 5:     return PERIOD_M5;    break;
      case 15:    return PERIOD_M15;   break;
      case 30:    return PERIOD_M30;   break;
      case 60:    return PERIOD_H1;    break;
      case 240:   return PERIOD_H4;    break;
      case 1440:  return PERIOD_D1;    break;
      case 10080: return PERIOD_W1;    break;
      case 43200: return PERIOD_MN1;   break;
   }
   
   return 0;
}
/*
string globalName(string _sName) {
   return Symbol()+"_"+EnumToString(periodCurrent())+"_"+_sName;
}

void registerBuffer(string _sName, double &_dBuffer[]) {
   int iAddr = __getPtr(_dBuffer[0]);
   GlobalVariableSet(globalName(_sName), iAddr);
}

int getBufferAddr(string _sName) {
   return (int)GlobalVariableGet(globalName(_sName));
}
*/