//+------------------------------------------------------------------+
//|                                                      Account.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "..\BaseObj.mqh"
#include "..\..\Services\DELib.mqh"
//+------------------------------------------------------------------+
//| Класс аккаунта                                                   |
//+------------------------------------------------------------------+
class CAccount : public CBaseObj
  {
private:
   struct SData
     {
      //--- Целочисленные свойства счёта
      long           login;                        // ACCOUNT_LOGIN (Номер счёта)
      int            trade_mode;                   // ACCOUNT_TRADE_MODE (Тип торгового счета)
      long           leverage;                     // ACCOUNT_LEVERAGE (Размер предоставленного плеча)
      int            limit_orders;                 // ACCOUNT_LIMIT_ORDERS (Максимально допустимое количество действующих отложенных ордеров)
      int            margin_so_mode;               // ACCOUNT_MARGIN_SO_MODE (Режим задания минимально допустимого уровня залоговых средств)
      bool           trade_allowed;                // ACCOUNT_TRADE_ALLOWED (Разрешенность торговли для текущего счета со стороны сервера)
      bool           trade_expert;                 // ACCOUNT_TRADE_EXPERT (Разрешенность торговли для эксперта со стороны сервера)
      int            margin_mode;                  // ACCOUNT_MARGIN_MODE (Режим расчета маржи)
      int            currency_digits;              // ACCOUNT_CURRENCY_DIGITS (Количество знаков после запятой для валюты счета)
      int            server_type;                  // Тип торгового сервера (MetaTrader5, MetaTrader4)
      bool           fifo_close;                   // Признак того, что позиции можно закрывать только по правилу FIFO
      //--- Вещественные свойства счёта
      double         balance;                      // ACCOUNT_BALANCE (Баланс счета в валюте депозита)
      double         credit;                       // ACCOUNT_CREDIT (Размер предоставленного кредита в валюте депозита)
      double         profit;                       // ACCOUNT_PROFIT (Размер текущей прибыли на счете в валюте депозита)
      double         equity;                       // ACCOUNT_EQUITY (Значение собственных средств на счете в валюте депозита)
      double         margin;                       // ACCOUNT_MARGIN (Размер зарезервированных залоговых средств на счете  в валюте депозита)
      double         margin_free;                  // ACCOUNT_MARGIN_FREE (Размер свободных средств на счете  в валюте депозита, доступных для открытия позиции)
      double         margin_level;                 // ACCOUNT_MARGIN_LEVEL (Уровень залоговых средств на счете в процентах)
      double         margin_so_call;               // ACCOUNT_MARGIN_SO_CALL (Уровень залоговых средств, при котором происходит MarginCall)
      double         margin_so_so;                 // ACCOUNT_MARGIN_SO_SO (Уровень залоговых средств, при достижении которого происходит StopOut)
      double         margin_initial;               // ACCOUNT_MARGIN_INITIAL (Размер средств, зарезервированных на счёте, для обеспечения гарантийной суммы по всем отложенным ордерам)
      double         margin_maintenance;           // ACCOUNT_MARGIN_MAINTENANCE (Размер средств, зарезервированных на счёте, для обеспечения минимальной суммы по всем открытым позициям)
      double         assets;                       // ACCOUNT_ASSETS (Текущий размер активов на счёте)
      double         liabilities;                  // ACCOUNT_LIABILITIES (Текущий размер обязательств на счёте)
      double         comission_blocked;            // ACCOUNT_COMMISSION_BLOCKED (Текущая сумма заблокированных комиссий по счёту)
      //--- Строковые свойства счёта
      uchar          name[128];                    // ACCOUNT_NAME (Имя клиента)
      uchar          server[64];                   // ACCOUNT_SERVER (Имя торгового сервера)
      uchar          currency[32];                 // ACCOUNT_CURRENCY (Валюта депозита)
      uchar          company[128];                 // ACCOUNT_COMPANY (Имя компании, обслуживающей счет)
     };
   SData             m_struct_obj;                                      // Структура объекта-аккаунта
   uchar             m_uchar_array[];                                   // uchar-массив структуры объекта-аккаунта
   
//--- Свойства объекта
   long              m_long_prop[ACCOUNT_PROP_INTEGER_TOTAL];           // Целочисленные свойства
   double            m_double_prop[ACCOUNT_PROP_DOUBLE_TOTAL];          // Вещественные свойства
   string            m_string_prop[ACCOUNT_PROP_STRING_TOTAL];          // Строковые свойства

//--- Возвращает индекс массива, по которому фактически расположено (1) double-свойство и (2) string-свойство аккаунта
   int               IndexProp(ENUM_ACCOUNT_PROP_DOUBLE property) const { return(int)property-ACCOUNT_PROP_INTEGER_TOTAL;                                   }
   int               IndexProp(ENUM_ACCOUNT_PROP_STRING property) const { return(int)property-ACCOUNT_PROP_INTEGER_TOTAL-ACCOUNT_PROP_DOUBLE_TOTAL;         }
protected:
//--- Создаёт (1) структуру объекта-аккаунта, (2) объект-аккаунт из структуры
   bool              ObjectToStruct(void);
   void              StructToObject(void);
public:
//--- Конструктор
                     CAccount(void);
//--- Устанавливает (1) целочисленное, (2) вещественное и (3) строковое свойство аккаунта
   void              SetProperty(ENUM_ACCOUNT_PROP_INTEGER property,long value)        { this.m_long_prop[property]=value;                                  }
   void              SetProperty(ENUM_ACCOUNT_PROP_DOUBLE property,double value)       { this.m_double_prop[this.IndexProp(property)]=value;                }
   void              SetProperty(ENUM_ACCOUNT_PROP_STRING property,string value)       { this.m_string_prop[this.IndexProp(property)]=value;                }
//--- Возвращает из массива свойств (1) целочисленное, (2) вещественное и (3) строковое свойство аккаунта
   long              GetProperty(ENUM_ACCOUNT_PROP_INTEGER property)             const { return this.m_long_prop[property];                                 }
   double            GetProperty(ENUM_ACCOUNT_PROP_DOUBLE property)              const { return this.m_double_prop[this.IndexProp(property)];               }
   string            GetProperty(ENUM_ACCOUNT_PROP_STRING property)              const { return this.m_string_prop[this.IndexProp(property)];               }
//--- Возвращает флаг расчёта уровне MarginCall и StopOut в процентах
   bool              IsPercentsForSOLevels(void)                                 const { return this.MarginSOMode()==ACCOUNT_STOPOUT_MODE_PERCENT;          }
//--- Возвращает флаг поддержания объектом-аккаунтом данного свойства
   virtual bool      SupportProperty(ENUM_ACCOUNT_PROP_INTEGER property)               { return true; }
   virtual bool      SupportProperty(ENUM_ACCOUNT_PROP_DOUBLE property)                { return true; }
   virtual bool      SupportProperty(ENUM_ACCOUNT_PROP_STRING property)                { return true; }

//--- Сравнивает объекты CAccount между собой по всем возможным свойствам (для сортировки списков по указанному свойству объекта-аккаунта)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Сравнивает объекты CAccount между собой по свойствам счёта (для поиска равных объектов-аккаунтов)
   bool              IsEqual(CAccount* compared_account) const;
//--- Обновляет все данные аккаунта
   virtual void      Refresh(void);
//--- (1) Сохраняет объект-аккаунт в файл, (2), загружает объект-аккаунт из файла
   virtual bool      Save(const int file_handle);
   virtual bool      Load(const int file_handle);
 
//--- Возвращает размер маржи, требуемый для открытия позиции или установки отложенного ордера
   double            MarginForAction(const ENUM_ORDER_TYPE action,const string symbol,const double volume,const double price) const;

//+------------------------------------------------------------------+
//| Методы упрощённого доступа к свойствам объекта-аккаунта          |
//+------------------------------------------------------------------+
//--- Возвращает целочисленные свойства аккаунта
   ENUM_ACCOUNT_TRADE_MODE    TradeMode(void)                        const { return (ENUM_ACCOUNT_TRADE_MODE)this.GetProperty(ACCOUNT_PROP_TRADE_MODE);           }
   ENUM_ACCOUNT_STOPOUT_MODE  MarginSOMode(void)                     const { return (ENUM_ACCOUNT_STOPOUT_MODE)this.GetProperty(ACCOUNT_PROP_MARGIN_SO_MODE);     }
   ENUM_ACCOUNT_MARGIN_MODE   MarginMode(void)                       const { return (ENUM_ACCOUNT_MARGIN_MODE)this.GetProperty(ACCOUNT_PROP_MARGIN_MODE);         }
   long              Login(void)                                     const { return this.GetProperty(ACCOUNT_PROP_LOGIN);                                         }
   long              Leverage(void)                                  const { return this.GetProperty(ACCOUNT_PROP_LEVERAGE);                                      }
   long              LimitOrders(void)                               const { return this.GetProperty(ACCOUNT_PROP_LIMIT_ORDERS);                                  }
   long              TradeAllowed(void)                              const { return this.GetProperty(ACCOUNT_PROP_TRADE_ALLOWED);                                 }
   long              TradeExpert(void)                               const { return this.GetProperty(ACCOUNT_PROP_TRADE_EXPERT);                                  }
   long              CurrencyDigits(void)                            const { return this.GetProperty(ACCOUNT_PROP_CURRENCY_DIGITS);                               }
   long              ServerType(void)                                const { return this.GetProperty(ACCOUNT_PROP_SERVER_TYPE);                                   }
   long              FIFOClose(void)                                 const { return this.GetProperty(ACCOUNT_PROP_FIFO_CLOSE);                                    }
   bool              IsHedge(void)                                   const { return this.MarginMode()==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING;                        }
//--- Возвращает вещественные свойства аккаунта
   double            Balance(void)                                   const { return this.GetProperty(ACCOUNT_PROP_BALANCE);                                       }
   double            Credit(void)                                    const { return this.GetProperty(ACCOUNT_PROP_CREDIT);                                        }
   double            Profit(void)                                    const { return this.GetProperty(ACCOUNT_PROP_PROFIT);                                        }
   double            Equity(void)                                    const { return this.GetProperty(ACCOUNT_PROP_EQUITY);                                        }
   double            Margin(void)                                    const { return this.GetProperty(ACCOUNT_PROP_MARGIN);                                        }
   double            MarginFree(void)                                const { return this.GetProperty(ACCOUNT_PROP_MARGIN_FREE);                                   }
   double            MarginLevel(void)                               const { return this.GetProperty(ACCOUNT_PROP_MARGIN_LEVEL);                                  }
   double            MarginSOCall(void)                              const { return this.GetProperty(ACCOUNT_PROP_MARGIN_SO_CALL);                                }
   double            MarginSOSO(void)                                const { return this.GetProperty(ACCOUNT_PROP_MARGIN_SO_SO);                                  }
   double            MarginInitial(void)                             const { return this.GetProperty(ACCOUNT_PROP_MARGIN_INITIAL);                                }
   double            MarginMaintenance(void)                         const { return this.GetProperty(ACCOUNT_PROP_MARGIN_MAINTENANCE);                            }
   double            Assets(void)                                    const { return this.GetProperty(ACCOUNT_PROP_ASSETS);                                        }
   double            Liabilities(void)                               const { return this.GetProperty(ACCOUNT_PROP_LIABILITIES);                                   }
   double            ComissionBlocked(void)                          const { return this.GetProperty(ACCOUNT_PROP_COMMISSION_BLOCKED);                            }
   
//--- Возвращает строковые свойства аккаунта
   string            Name(void)                                      const { return this.GetProperty(ACCOUNT_PROP_NAME);                                          }
   string            Server(void)                                    const { return this.GetProperty(ACCOUNT_PROP_SERVER);                                        }
   string            Currency(void)                                  const { return this.GetProperty(ACCOUNT_PROP_CURRENCY);                                      }
   string            Company(void)                                   const { return this.GetProperty(ACCOUNT_PROP_COMPANY);                                       }

//+------------------------------------------------------------------+
//| Получение и установка параметров отслеживаемых изменений свойств |
//+------------------------------------------------------------------+
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня плеча
   //--- получение (3) величины изменения плеча,
   //--- получение флага изменения плеча больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlLeverageInc(const long value)               { this.SetControlledValueINC(ACCOUNT_PROP_LEVERAGE,(long)::fabs(value));               }
   void              SetControlLeverageDec(const long value)               { this.SetControlledValueDEC(ACCOUNT_PROP_LEVERAGE,(long)::fabs(value));               }
   void              SetControlLeverageLevel(const long value)             { this.SetControlledValueLEVEL(ACCOUNT_PROP_LEVERAGE,(long)::fabs(value));             }
   long              GetValueChangedLeverage(void)                   const { return this.GetPropLongChangedValue(ACCOUNT_PROP_LEVERAGE);                          }
   bool              IsIncreasedLeverage(void)                       const { return (bool)this.GetPropLongFlagINC(ACCOUNT_PROP_LEVERAGE);                         }
   bool              IsDecreasedLeverage(void)                       const { return (bool)this.GetPropLongFlagDEC(ACCOUNT_PROP_LEVERAGE);                         }
   
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня количества действующих отложенных ордеров
   //--- получение (3) величины изменения количества действующих отложенных ордеров,
   //--- получение флага изменения количества действующих отложенных ордеров больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlLimitOrdersInc(const long value)            { this.SetControlledValueINC(ACCOUNT_PROP_LIMIT_ORDERS,(long)::fabs(value));           }
   void              SetControlLimitOrdersDec(const long value)            { this.SetControlledValueDEC(ACCOUNT_PROP_LIMIT_ORDERS,(long)::fabs(value));           }
   void              SetControlLimitOrdersLevel(const long value)          { this.SetControlledValueLEVEL(ACCOUNT_PROP_LIMIT_ORDERS,(long)::fabs(value));         }
   long              GetValueChangedLimitOrders(void)                const { return this.GetPropLongChangedValue(ACCOUNT_PROP_LIMIT_ORDERS);                      }
   bool              IsIncreasedLimitOrders(void)                    const { return (bool)this.GetPropLongFlagINC(ACCOUNT_PROP_LIMIT_ORDERS);                     }
   bool              IsDecreasedLimitOrders(void)                    const { return (bool)this.GetPropLongFlagDEC(ACCOUNT_PROP_LIMIT_ORDERS);                     }
   
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня разрешения торговли для текущего счета со стороны сервера
   //--- получение (3) величины изменения разрешения торговли для текущего счета со стороны сервера,
   //--- получение флага изменения разрешения торговли для текущего счета со стороны сервера больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlTradeAllowedInc(const long value)           { this.SetControlledValueINC(ACCOUNT_PROP_TRADE_ALLOWED,(long)::fabs(value));          }
   void              SetControlTradeAllowedDec(const long value)           { this.SetControlledValueDEC(ACCOUNT_PROP_TRADE_ALLOWED,(long)::fabs(value));          }
   void              SetControlTradeAllowedLevel(const long value)         { this.SetControlledValueLEVEL(ACCOUNT_PROP_TRADE_ALLOWED,(long)::fabs(value));        }
   long              GetValueChangedTradeAllowed(void)               const { return this.GetPropLongChangedValue(ACCOUNT_PROP_TRADE_ALLOWED);                     }
   bool              IsIncreasedTradeAllowed(void)                   const { return (bool)this.GetPropLongFlagINC(ACCOUNT_PROP_TRADE_ALLOWED);                    }
   bool              IsDecreasedTradeAllowed(void)                   const { return (bool)this.GetPropLongFlagDEC(ACCOUNT_PROP_TRADE_ALLOWED);                    }
   
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня разрешения торговли для эксперта со стороны сервера
   //--- получение (3) величины изменения разрешения торговли для эксперта со стороны сервера,
   //--- получение флага изменения разрешения торговли для эксперта со стороны сервера больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlTradeExpertInc(const long value)            { this.SetControlledValueINC(ACCOUNT_PROP_TRADE_EXPERT,(long)::fabs(value));           }
   void              SetControlTradeExpertDec(const long value)            { this.SetControlledValueDEC(ACCOUNT_PROP_TRADE_EXPERT,(long)::fabs(value));           }
   void              SetControlTradeExpertLevel(const long value)          { this.SetControlledValueLEVEL(ACCOUNT_PROP_TRADE_EXPERT,(long)::fabs(value));         }
   long              GetValueChangedTradeExpert(void)                const { return this.GetPropLongChangedValue(ACCOUNT_PROP_TRADE_EXPERT);                      }
   bool              IsIncreasedTradeExpert(void)                    const { return (bool)this.GetPropLongFlagINC(ACCOUNT_PROP_TRADE_EXPERT);                     }
   bool              IsDecreasedTradeExpert(void)                    const { return (bool)this.GetPropLongFlagDEC(ACCOUNT_PROP_TRADE_EXPERT);                     }
   
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня баланса
   //--- получение (3) величины изменения баланса,
   //--- получение флага изменения баланса больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlBalanceInc(const long value)                { this.SetControlledValueINC(ACCOUNT_PROP_BALANCE,(double)::fabs(value));              }
   void              SetControlBalanceDec(const long value)                { this.SetControlledValueDEC(ACCOUNT_PROP_BALANCE,(double)::fabs(value));              }
   void              SetControlBalanceLevel(const long value)              { this.SetControlledValueLEVEL(ACCOUNT_PROP_BALANCE,(double)::fabs(value));            }
   double            GetValueChangedBalance(void)                    const { return this.GetPropDoubleChangedValue(ACCOUNT_PROP_BALANCE);                         }
   bool              IsIncreasedBalance(void)                        const { return (bool)this.GetPropDoubleFlagINC(ACCOUNT_PROP_BALANCE);                        }
   bool              IsDecreasedBalance(void)                        const { return (bool)this.GetPropDoubleFlagDEC(ACCOUNT_PROP_BALANCE);                        }
   
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня кредита
   //--- получение (3) величины изменения кредита,
   //--- получение флага изменения кредита больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlCreditInc(const long value)                 { this.SetControlledValueINC(ACCOUNT_PROP_CREDIT,(double)::fabs(value));               }
   void              SetControlCreditDec(const long value)                 { this.SetControlledValueDEC(ACCOUNT_PROP_CREDIT,(double)::fabs(value));               }
   void              SetControlCreditLevel(const long value)               { this.SetControlledValueLEVEL(ACCOUNT_PROP_CREDIT,(double)::fabs(value));             }
   double            GetValueChangedCredit(void)                     const { return this.GetPropDoubleChangedValue(ACCOUNT_PROP_CREDIT);                          }
   bool              IsIncreasedCredit(void)                         const { return (bool)this.GetPropDoubleFlagINC(ACCOUNT_PROP_CREDIT);                         }
   bool              IsDecreasedCredit(void)                         const { return (bool)this.GetPropDoubleFlagDEC(ACCOUNT_PROP_CREDIT);                         }
   
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня прибыли
   //--- получение (3) величины изменения прибыли,
   //--- получение флага изменения прибыли больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlProfitInc(const long value)                 { this.SetControlledValueINC(ACCOUNT_PROP_PROFIT,(double)::fabs(value));               }
   void              SetControlProfitDec(const long value)                 { this.SetControlledValueDEC(ACCOUNT_PROP_PROFIT,(double)::fabs(value));               }
   void              SetControlProfitLevel(const long value)               { this.SetControlledValueLEVEL(ACCOUNT_PROP_PROFIT,(double)::fabs(value));             }
   double            GetValueChangedProfit(void)                     const { return this.GetPropDoubleChangedValue(ACCOUNT_PROP_PROFIT);                          }
   bool              IsIncreasedProfit(void)                         const { return (bool)this.GetPropDoubleFlagINC(ACCOUNT_PROP_PROFIT);                         }
   bool              IsDecreasedProfit(void)                         const { return (bool)this.GetPropDoubleFlagDEC(ACCOUNT_PROP_PROFIT);                         }
   
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня средств
   //--- получение (3) величины изменения средств,
   //--- получение флага изменения средств больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlEquityInc(const long value)                 { this.SetControlledValueINC(ACCOUNT_PROP_EQUITY,(double)::fabs(value));               }
   void              SetControlEquityDec(const long value)                 { this.SetControlledValueDEC(ACCOUNT_PROP_EQUITY,(double)::fabs(value));               }
   void              SetControlEquityLevel(const long value)               { this.SetControlledValueLEVEL(ACCOUNT_PROP_EQUITY,(double)::fabs(value));             }
   double            GetValueChangedEquity(void)                     const { return this.GetPropDoubleChangedValue(ACCOUNT_PROP_EQUITY);                          }
   bool              IsIncreasedEquity(void)                         const { return (bool)this.GetPropDoubleFlagINC(ACCOUNT_PROP_EQUITY);                         }
   bool              IsDecreasedEquity(void)                         const { return (bool)this.GetPropDoubleFlagDEC(ACCOUNT_PROP_EQUITY);                         }
   
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня залоговых средств
   //--- получение (3) величины изменения залоговых средств,
   //--- получение флага изменения залоговых средств больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlMarginInc(const long value)                 { this.SetControlledValueINC(ACCOUNT_PROP_MARGIN,(double)::fabs(value));               }
   void              SetControlMarginDec(const long value)                 { this.SetControlledValueDEC(ACCOUNT_PROP_MARGIN,(double)::fabs(value));               }
   void              SetControlMarginLevel(const long value)               { this.SetControlledValueLEVEL(ACCOUNT_PROP_MARGIN,(double)::fabs(value));             }
   double            GetValueChangedMargin(void)                     const { return this.GetPropDoubleChangedValue(ACCOUNT_PROP_MARGIN);                          }
   bool              IsIncreasedMargin(void)                         const { return (bool)this.GetPropDoubleFlagINC(ACCOUNT_PROP_MARGIN);                         }
   bool              IsDecreasedMargin(void)                         const { return (bool)this.GetPropDoubleFlagDEC(ACCOUNT_PROP_MARGIN);                         }
   
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня свободных средств
   //--- получение (3) величины изменения свободных средств,
   //--- получение флага изменения свободных средств больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlMarginFreeInc(const long value)             { this.SetControlledValueINC(ACCOUNT_PROP_MARGIN_FREE,(double)::fabs(value));          }
   void              SetControlMarginFreeDec(const long value)             { this.SetControlledValueDEC(ACCOUNT_PROP_MARGIN_FREE,(double)::fabs(value));          }
   void              SetControlMarginFreeLevel(const long value)           { this.SetControlledValueLEVEL(ACCOUNT_PROP_MARGIN_FREE,(double)::fabs(value));        }
   double            GetValueChangedMarginFree(void)                 const { return this.GetPropDoubleChangedValue(ACCOUNT_PROP_MARGIN_FREE);                     }
   bool              IsIncreasedMarginFree(void)                     const { return (bool)this.GetPropDoubleFlagINC(ACCOUNT_PROP_MARGIN_FREE);                    }
   bool              IsDecreasedMarginFree(void)                     const { return (bool)this.GetPropDoubleFlagDEC(ACCOUNT_PROP_MARGIN_FREE);                    }
   
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня уровня свободных средств
   //--- получение (3) величины изменения уровня свободных средств,
   //--- получение флага изменения уровня свободных средств больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlMarginLevelInc(const long value)            { this.SetControlledValueINC(ACCOUNT_PROP_MARGIN_LEVEL,(double)::fabs(value));         }
   void              SetControlMarginLevelDec(const long value)            { this.SetControlledValueDEC(ACCOUNT_PROP_MARGIN_LEVEL,(double)::fabs(value));         }
   void              SetControlMarginLevelLevel(const long value)          { this.SetControlledValueLEVEL(ACCOUNT_PROP_MARGIN_LEVEL,(double)::fabs(value));       }
   double            GetValueChangedMarginLevel(void)                const { return this.GetPropDoubleChangedValue(ACCOUNT_PROP_MARGIN_LEVEL);                    }
   bool              IsIncreasedMarginLevel(void)                    const { return (bool)this.GetPropDoubleFlagINC(ACCOUNT_PROP_MARGIN_LEVEL);                   }
   bool              IsDecreasedMarginLevel(void)                    const { return (bool)this.GetPropDoubleFlagDEC(ACCOUNT_PROP_MARGIN_LEVEL);                   }
   
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня Margin Call
   //--- получение (3) величины изменения уровня Margin Call,
   //--- получение флага изменения уровня Margin Call больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlMarginCallInc(const long value)             { this.SetControlledValueINC(ACCOUNT_PROP_MARGIN_SO_CALL,(double)::fabs(value));       }
   void              SetControlMarginCallDec(const long value)             { this.SetControlledValueDEC(ACCOUNT_PROP_MARGIN_SO_CALL,(double)::fabs(value));       }
   void              SetControlMarginCallLevel(const long value)           { this.SetControlledValueLEVEL(ACCOUNT_PROP_MARGIN_SO_CALL,(double)::fabs(value));     }
   double            GetValueChangedMarginCall(void)                 const { return this.GetPropDoubleChangedValue(ACCOUNT_PROP_MARGIN_SO_CALL);                  }
   bool              IsIncreasedMarginCall(void)                     const { return (bool)this.GetPropDoubleFlagINC(ACCOUNT_PROP_MARGIN_SO_CALL);                 }
   bool              IsDecreasedMarginCall(void)                     const { return (bool)this.GetPropDoubleFlagDEC(ACCOUNT_PROP_MARGIN_SO_CALL);                 }
   
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня Margin StopOut
   //--- получение (3) величины изменения уровня Margin StopOut,
   //--- получение флага изменения уровня Margin StopOut больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlMarginStopOutInc(const long value)          { this.SetControlledValueINC(ACCOUNT_PROP_MARGIN_SO_SO,(double)::fabs(value));         }
   void              SetControlMarginStopOutDec(const long value)          { this.SetControlledValueDEC(ACCOUNT_PROP_MARGIN_SO_SO,(double)::fabs(value));         }
   void              SetControlMarginStopOutLevel(const long value)        { this.SetControlledValueLEVEL(ACCOUNT_PROP_MARGIN_SO_SO,(double)::fabs(value));       }
   double            GetValueChangedMarginStopOut(void)              const { return this.GetPropDoubleChangedValue(ACCOUNT_PROP_MARGIN_SO_SO);                    }
   bool              IsIncreasedMarginStopOut(void)                  const { return (bool)this.GetPropDoubleFlagINC(ACCOUNT_PROP_MARGIN_SO_SO);                   }
   bool              IsDecreasedMarginStopOut(void)                  const { return (bool)this.GetPropDoubleFlagDEC(ACCOUNT_PROP_MARGIN_SO_SO);                   }
   
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня величины прироста размера зарезервированных средств для обеспечения гарантийной суммы по отложенным ордерам
   //--- получение (3) величины изменения величины прироста размера зарезервированных средств для обеспечения гарантийной суммы по отложенным ордерам,
   //--- получение флага изменения величины прироста размера зарезервированных средств для обеспечения гарантийной суммы по отложенным ордерам больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlMarginInitialInc(const long value)          { this.SetControlledValueINC(ACCOUNT_PROP_MARGIN_INITIAL,(double)::fabs(value));       }
   void              SetControlMarginInitialDec(const long value)          { this.SetControlledValueDEC(ACCOUNT_PROP_MARGIN_INITIAL,(double)::fabs(value));       }
   void              SetControlMarginInitialLevel(const long value)        { this.SetControlledValueLEVEL(ACCOUNT_PROP_MARGIN_INITIAL,(double)::fabs(value));     }
   double            GetValueChangedMarginInitial(void)              const { return this.GetPropDoubleChangedValue(ACCOUNT_PROP_MARGIN_INITIAL);                  }
   bool              IsIncreasedMarginInitial(void)                  const { return (bool)this.GetPropDoubleFlagINC(ACCOUNT_PROP_MARGIN_INITIAL);                 }
   bool              IsDecreasedMarginInitial(void)                  const { return (bool)this.GetPropDoubleFlagDEC(ACCOUNT_PROP_MARGIN_INITIAL);                 }
   
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня величины прироста зарезервированных средств для обеспечения минимальной суммы по всем открытым позициям
   //--- получение (3) величины изменения величины прироста зарезервированных средств для обеспечения минимальной суммы по всем открытым позициям,
   //--- получение флага изменения величины прироста зарезервированных средств для обеспечения минимальной суммы по всем открытым позициям больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlMarginMaintenanceInc(const long value)      { this.SetControlledValueINC(ACCOUNT_PROP_MARGIN_MAINTENANCE,(double)::fabs(value));   }
   void              SetControlMarginMaintenanceDec(const long value)      { this.SetControlledValueDEC(ACCOUNT_PROP_MARGIN_MAINTENANCE,(double)::fabs(value));   }
   void              SetControlMarginMaintenanceLevel(const long value)    { this.SetControlledValueLEVEL(ACCOUNT_PROP_MARGIN_MAINTENANCE,(double)::fabs(value)); }
   double            GetValueChangedMarginMaintenance(void)          const { return this.GetPropDoubleChangedValue(ACCOUNT_PROP_MARGIN_MAINTENANCE);              }
   bool              IsIncreasedMarginMaintenance(void)              const { return (bool)this.GetPropDoubleFlagINC(ACCOUNT_PROP_MARGIN_MAINTENANCE);             }
   bool              IsDecreasedMarginMaintenance(void)              const { return (bool)this.GetPropDoubleFlagDEC(ACCOUNT_PROP_MARGIN_MAINTENANCE);             }
   
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня активов
   //--- получение (3) величины изменения активов,
   //--- получение флага изменения активов больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlAssetsInc(const long value)                 { this.SetControlledValueINC(ACCOUNT_PROP_ASSETS,(double)::fabs(value));               }
   void              SetControlAssetsDec(const long value)                 { this.SetControlledValueDEC(ACCOUNT_PROP_ASSETS,(double)::fabs(value));               }
   void              SetControlAssetsLevel(const long value)               { this.SetControlledValueLEVEL(ACCOUNT_PROP_ASSETS,(double)::fabs(value));             }
   double            GetValueChangedAssets(void)                     const { return this.GetPropDoubleChangedValue(ACCOUNT_PROP_ASSETS);                          }
   bool              IsIncreasedAssets(void)                         const { return (bool)this.GetPropDoubleFlagINC(ACCOUNT_PROP_ASSETS);                         }
   bool              IsDecreasedAssets(void)                         const { return (bool)this.GetPropDoubleFlagDEC(ACCOUNT_PROP_ASSETS);                         }
   
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня обязательств
   //--- получение (3) величины изменения обязательств,
   //--- получение флага изменения обязательств больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlLiabilitiesInc(const long value)            { this.SetControlledValueINC(ACCOUNT_PROP_LIABILITIES,(double)::fabs(value));          }
   void              SetControlLiabilitiesDec(const long value)            { this.SetControlledValueDEC(ACCOUNT_PROP_LIABILITIES,(double)::fabs(value));          }
   void              SetControlLiabilitiesLevel(const long value)          { this.SetControlledValueLEVEL(ACCOUNT_PROP_LIABILITIES,(double)::fabs(value));        }
   double            GetValueChangedLiabilities(void)                const { return this.GetPropDoubleChangedValue(ACCOUNT_PROP_LIABILITIES);                     }
   bool              IsIncreasedLiabilities(void)                    const { return (bool)this.GetPropDoubleFlagINC(ACCOUNT_PROP_LIABILITIES);                    }
   bool              IsDecreasedLiabilities(void)                    const { return (bool)this.GetPropDoubleFlagDEC(ACCOUNT_PROP_LIABILITIES);                    }
   
   //--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня заблокированных комиссий
   //--- получение (3) величины изменения заблокированных комиссий,
   //--- получение флага изменения заблокированных комиссий больше, чем на величину (4) прироста, (5) уменьшения
   void              SetControlComissionBlockedInc(const long value)       { this.SetControlledValueINC(ACCOUNT_PROP_COMMISSION_BLOCKED,(double)::fabs(value));   }
   void              SetControlComissionBlockedDec(const long value)       { this.SetControlledValueDEC(ACCOUNT_PROP_COMMISSION_BLOCKED,(double)::fabs(value));   }
   void              SetControlComissionBlockedLevel(const long value)     { this.SetControlledValueLEVEL(ACCOUNT_PROP_COMMISSION_BLOCKED,(double)::fabs(value)); }
   double            GetValueChangedComissionBlocked(void)           const { return this.GetPropDoubleChangedValue(ACCOUNT_PROP_COMMISSION_BLOCKED);              }
   bool              IsIncreasedComissionBlocked(void)               const { return (bool)this.GetPropDoubleFlagINC(ACCOUNT_PROP_COMMISSION_BLOCKED);             }
   bool              IsDecreasedComissionBlocked(void)               const { return (bool)this.GetPropDoubleFlagDEC(ACCOUNT_PROP_COMMISSION_BLOCKED);             }

//+------------------------------------------------------------------+
//| Описания свойств объекта-аккаунта                                |
//+------------------------------------------------------------------+
//--- Возвращает описание (1) целочисленного, (2) вещественного и (3) строкового свойства аккаунта
   string            GetPropertyDescription(ENUM_ACCOUNT_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_ACCOUNT_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_ACCOUNT_PROP_STRING property);
//--- Возвращает наименование типа торгового счёта (демо, конкурс, реал)
   string            TradeModeDescription(void)    const;
//--- Возвращает наименование типа торгового сервера (MetaTrader5, MetaTrader4)
   string            ServerTypeDescription(void)    const;
//--- Возвращает описание режима задания минимально допустимого уровня залоговых средств
   string            MarginSOModeDescription(void) const;
//--- Возвращает описание режима расчета маржи
   string            MarginModeDescription(void)   const;
//--- Выводит в журнал описание свойств аккаунта (full_prop=true - все свойства, false - только поддерживаемые - реализуется в наследниках класса)
   void              Print(const bool full_prop=false);
//--- Выводит в журнал краткое описание счёта
   void              PrintShort(void);
  };
//+------------------------------------------------------------------+
//| Методы класса                                                    |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Конструктор                                                      |
//+------------------------------------------------------------------+
CAccount::CAccount(void)
  {
//--- Инициализация контролируемых данных
   this.SetControlDataArraySizeLong(ACCOUNT_PROP_INTEGER_TOTAL);
   this.SetControlDataArraySizeDouble(ACCOUNT_PROP_DOUBLE_TOTAL);
   this.ResetChangesParams();
   this.ResetControlsParams();
  
//--- Сохранение целочисленных свойств
   this.m_long_prop[ACCOUNT_PROP_LOGIN]                              = ::AccountInfoInteger(ACCOUNT_LOGIN);
   this.m_long_prop[ACCOUNT_PROP_TRADE_MODE]                         = ::AccountInfoInteger(ACCOUNT_TRADE_MODE);
   this.m_long_prop[ACCOUNT_PROP_LEVERAGE]                           = ::AccountInfoInteger(ACCOUNT_LEVERAGE);
   this.m_long_prop[ACCOUNT_PROP_LIMIT_ORDERS]                       = ::AccountInfoInteger(ACCOUNT_LIMIT_ORDERS);
   this.m_long_prop[ACCOUNT_PROP_MARGIN_SO_MODE]                     = ::AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE);
   this.m_long_prop[ACCOUNT_PROP_TRADE_ALLOWED]                      = ::AccountInfoInteger(ACCOUNT_TRADE_ALLOWED);
   this.m_long_prop[ACCOUNT_PROP_TRADE_EXPERT]                       = ::AccountInfoInteger(ACCOUNT_TRADE_EXPERT);
   this.m_long_prop[ACCOUNT_PROP_MARGIN_MODE]                        = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_MARGIN_MODE) #else ACCOUNT_MARGIN_MODE_RETAIL_HEDGING #endif ;
   this.m_long_prop[ACCOUNT_PROP_CURRENCY_DIGITS]                    = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2 #endif ;
   this.m_long_prop[ACCOUNT_PROP_SERVER_TYPE]                        = (::TerminalInfoString(TERMINAL_NAME)=="MetaTrader 5" ? 5 : 4);
   this.m_long_prop[ACCOUNT_PROP_FIFO_CLOSE]                         = (#ifdef __MQL5__::TerminalInfoInteger(TERMINAL_BUILD)<2155 ? false : ::AccountInfoInteger(ACCOUNT_FIFO_CLOSE) #else false #endif );
   
//--- Сохранение вещественных свойств
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_BALANCE)]          = ::AccountInfoDouble(ACCOUNT_BALANCE);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_CREDIT)]           = ::AccountInfoDouble(ACCOUNT_CREDIT);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_PROFIT)]           = ::AccountInfoDouble(ACCOUNT_PROFIT);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_EQUITY)]           = ::AccountInfoDouble(ACCOUNT_EQUITY);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN)]           = ::AccountInfoDouble(ACCOUNT_MARGIN);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_FREE)]      = ::AccountInfoDouble(ACCOUNT_MARGIN_FREE);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_LEVEL)]     = ::AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_CALL)]   = ::AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_SO)]     = ::AccountInfoDouble(ACCOUNT_MARGIN_SO_SO);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_INITIAL)]   = ::AccountInfoDouble(ACCOUNT_MARGIN_INITIAL);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_MAINTENANCE)]=::AccountInfoDouble(ACCOUNT_MARGIN_MAINTENANCE);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_ASSETS)]           = ::AccountInfoDouble(ACCOUNT_ASSETS);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_LIABILITIES)]      = ::AccountInfoDouble(ACCOUNT_LIABILITIES);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_COMMISSION_BLOCKED)]=::AccountInfoDouble(ACCOUNT_COMMISSION_BLOCKED);
   
//--- Сохранение строковых свойств
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_NAME)]             = ::AccountInfoString(ACCOUNT_NAME);
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_SERVER)]           = ::AccountInfoString(ACCOUNT_SERVER);
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_CURRENCY)]         = ::AccountInfoString(ACCOUNT_CURRENCY);
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_COMPANY)]          = ::AccountInfoString(ACCOUNT_COMPANY);

//--- Имя объекта-аккаунта
   this.m_name=CMessage::Text(MSG_LIB_PROP_ACCOUNT)+" "+(string)this.Login()+": "+this.Name()+" ("+this.Company()+")";
   this.m_type=COLLECTION_ACCOUNT_ID;

//--- Заполнение текущих данных аккаунта
   for(int i=0;i<ACCOUNT_PROP_INTEGER_TOTAL;i++)
      this.m_long_prop_event[i][3]=this.m_long_prop[i];
   for(int i=0;i<ACCOUNT_PROP_DOUBLE_TOTAL;i++)
      this.m_double_prop_event[i][3]=this.m_double_prop[i];

//--- Обновление данных в базовом объекте и поиск изменений
   CBaseObj::Refresh();
  }
//+-------------------------------------------------------------------+
//|Сравнивает объекты CAccount между собой по всем возможным свойствам|
//+-------------------------------------------------------------------+
int CAccount::Compare(const CObject *node,const int mode=0) const
  {
   const CAccount *account_compared=node;
//--- сравнение целочисленных свойств двух аккаунтов
   if(mode<ACCOUNT_PROP_INTEGER_TOTAL)
     {
      long value_compared=account_compared.GetProperty((ENUM_ACCOUNT_PROP_INTEGER)mode);
      long value_current=this.GetProperty((ENUM_ACCOUNT_PROP_INTEGER)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- сравнение вещественных свойств двух аккаунтов
   else if(mode<ACCOUNT_PROP_DOUBLE_TOTAL+ACCOUNT_PROP_INTEGER_TOTAL)
     {
      double value_compared=account_compared.GetProperty((ENUM_ACCOUNT_PROP_DOUBLE)mode);
      double value_current=this.GetProperty((ENUM_ACCOUNT_PROP_DOUBLE)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- сравнение строковых свойств двух аккаунтов
   else if(mode<ACCOUNT_PROP_DOUBLE_TOTAL+ACCOUNT_PROP_INTEGER_TOTAL+ACCOUNT_PROP_STRING_TOTAL)
     {
      string value_compared=account_compared.GetProperty((ENUM_ACCOUNT_PROP_STRING)mode);
      string value_current=this.GetProperty((ENUM_ACCOUNT_PROP_STRING)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
   return 0;
  }
//+------------------------------------------------------------------+
//| Сравнивает объекты CAccount между собой по свойствам счёта       |
//+------------------------------------------------------------------+
bool CAccount::IsEqual(CAccount *compared_account) const
  {
   if(this.GetProperty(ACCOUNT_PROP_COMPANY)!=compared_account.GetProperty(ACCOUNT_PROP_COMPANY) ||
      this.GetProperty(ACCOUNT_PROP_LOGIN)!=compared_account.GetProperty(ACCOUNT_PROP_LOGIN)     ||
      this.GetProperty(ACCOUNT_PROP_NAME)!=compared_account.GetProperty(ACCOUNT_PROP_NAME)
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+
//| Обновляет все данные аккаунта                                    |
//+------------------------------------------------------------------+
void CAccount::Refresh(void)
  {
//--- Инициализация событийных данных
   this.m_is_event=false;
   this.m_hash_sum=0;
//--- Обновление целочисленных свойств
   this.m_long_prop[ACCOUNT_PROP_LOGIN]                                 = ::AccountInfoInteger(ACCOUNT_LOGIN);
   this.m_long_prop[ACCOUNT_PROP_TRADE_MODE]                            = ::AccountInfoInteger(ACCOUNT_TRADE_MODE);
   this.m_long_prop[ACCOUNT_PROP_LEVERAGE]                              = ::AccountInfoInteger(ACCOUNT_LEVERAGE);
   this.m_long_prop[ACCOUNT_PROP_LIMIT_ORDERS]                          = ::AccountInfoInteger(ACCOUNT_LIMIT_ORDERS);
   this.m_long_prop[ACCOUNT_PROP_MARGIN_SO_MODE]                        = ::AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE);
   this.m_long_prop[ACCOUNT_PROP_TRADE_ALLOWED]                         = ::AccountInfoInteger(ACCOUNT_TRADE_ALLOWED);
   this.m_long_prop[ACCOUNT_PROP_TRADE_EXPERT]                          = ::AccountInfoInteger(ACCOUNT_TRADE_EXPERT);
   this.m_long_prop[ACCOUNT_PROP_MARGIN_MODE]                           = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_MARGIN_MODE) #else ACCOUNT_MARGIN_MODE_RETAIL_HEDGING #endif ;
   this.m_long_prop[ACCOUNT_PROP_CURRENCY_DIGITS]                       = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2 #endif ;
   this.m_long_prop[ACCOUNT_PROP_SERVER_TYPE]                           = (::TerminalInfoString(TERMINAL_NAME)=="MetaTrader 5" ? 5 : 4);
   this.m_long_prop[ACCOUNT_PROP_FIFO_CLOSE]                            = (#ifdef __MQL5__::TerminalInfoInteger(TERMINAL_BUILD)<2155 ? false : ::AccountInfoInteger(ACCOUNT_FIFO_CLOSE) #else false #endif );
   
//--- Обновление вещественных свойств
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_BALANCE)]             = ::AccountInfoDouble(ACCOUNT_BALANCE);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_CREDIT)]              = ::AccountInfoDouble(ACCOUNT_CREDIT);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_PROFIT)]              = ::AccountInfoDouble(ACCOUNT_PROFIT);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_EQUITY)]              = ::AccountInfoDouble(ACCOUNT_EQUITY);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN)]              = ::AccountInfoDouble(ACCOUNT_MARGIN);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_FREE)]         = ::AccountInfoDouble(ACCOUNT_MARGIN_FREE);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_LEVEL)]        = ::AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_CALL)]      = ::AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_SO)]        = ::AccountInfoDouble(ACCOUNT_MARGIN_SO_SO);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_INITIAL)]      = ::AccountInfoDouble(ACCOUNT_MARGIN_INITIAL);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_MAINTENANCE)]  = ::AccountInfoDouble(ACCOUNT_MARGIN_MAINTENANCE);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_ASSETS)]              = ::AccountInfoDouble(ACCOUNT_ASSETS);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_LIABILITIES)]         = ::AccountInfoDouble(ACCOUNT_LIABILITIES);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_COMMISSION_BLOCKED)]  = ::AccountInfoDouble(ACCOUNT_COMMISSION_BLOCKED);

//--- Заполнение текущих данных аккаунта в базовом объекте
   for(int i=0;i<ACCOUNT_PROP_INTEGER_TOTAL;i++)
      this.m_long_prop_event[i][3]=this.m_long_prop[i];
   for(int i=0;i<ACCOUNT_PROP_DOUBLE_TOTAL;i++)
      this.m_double_prop_event[i][3]=this.m_double_prop[i];
   
//--- Обновление данных в базовом объекте и поиск изменений
   CBaseObj::Refresh();
   this.CheckEvents();
  }
//+------------------------------------------------------------------+
//| Сохраняет объект-аккаунт в файл                                  |
//+------------------------------------------------------------------+
bool CAccount::Save(const int file_handle)
  {
   if(!this.ObjectToStruct())
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_OBJ_STRUCT));
      return false;
     }
   if(::FileWriteArray(file_handle,this.m_uchar_array)==0)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_WRITE_UARRAY_TO_FILE));
      return false;
     }
   return true;
  }
//+------------------------------------------------------------------+
//| Загружает объект-аккаунт из файла                                |
//+------------------------------------------------------------------+
bool CAccount::Load(const int file_handle)
  {
   if(::FileReadArray(file_handle,this.m_uchar_array)==0)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_LOAD_UARRAY_FROM_FILE));
      return false;
     }
   if(!::CharArrayToStruct(this.m_struct_obj,this.m_uchar_array))
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_OBJ_STRUCT_FROM_UARRAY));
      return false;
     }
   this.StructToObject();
   return true;
  }
//+------------------------------------------------------------------+
//| Создаёт структуру объекта-аккаунта                               |
//+------------------------------------------------------------------+
bool CAccount::ObjectToStruct(void)
  {
//--- Сохранение целочисленных свойств
   this.m_struct_obj.login=this.Login();
   this.m_struct_obj.trade_mode=this.TradeMode();
   this.m_struct_obj.leverage=this.Leverage();
   this.m_struct_obj.limit_orders=(int)this.LimitOrders();
   this.m_struct_obj.margin_so_mode=this.MarginSOMode();
   this.m_struct_obj.trade_allowed=this.TradeAllowed();
   this.m_struct_obj.trade_expert=this.TradeExpert();
   this.m_struct_obj.margin_mode=this.MarginMode();
   this.m_struct_obj.currency_digits=(int)this.CurrencyDigits();
   this.m_struct_obj.server_type=(int)this.ServerType();
//--- Сохранение вещественных свойств
   this.m_struct_obj.balance=this.Balance();
   this.m_struct_obj.credit=this.Credit();
   this.m_struct_obj.profit=this.Profit();
   this.m_struct_obj.equity=this.Equity();
   this.m_struct_obj.margin=this.Margin();
   this.m_struct_obj.margin_free=this.MarginFree();
   this.m_struct_obj.margin_level=this.MarginLevel();
   this.m_struct_obj.margin_so_call=this.MarginSOCall();
   this.m_struct_obj.margin_so_so=this.MarginSOSO();
   this.m_struct_obj.margin_initial=this.MarginInitial();
   this.m_struct_obj.margin_maintenance=this.MarginMaintenance();
   this.m_struct_obj.assets=this.Assets();
   this.m_struct_obj.liabilities=this.Liabilities();
   this.m_struct_obj.comission_blocked=this.ComissionBlocked();
//--- Сохранение строковых свойств
   ::StringToCharArray(this.Name(),this.m_struct_obj.name);
   ::StringToCharArray(this.Server(),this.m_struct_obj.server);
   ::StringToCharArray(this.Currency(),this.m_struct_obj.currency);
   ::StringToCharArray(this.Company(),this.m_struct_obj.company);
   //--- Сохранение структуры в uchar-массив
   ::ResetLastError();
   if(!::StructToCharArray(this.m_struct_obj,this.m_uchar_array))
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_SAVE_OBJ_STRUCT_TO_UARRAY),(string)::GetLastError());
      return false;
     }
   return true;
  }
//+------------------------------------------------------------------+
//| Создаёт объект-аккаунт из структуры                              |
//+------------------------------------------------------------------+
void CAccount::StructToObject(void)
  {
//--- Сохранение целочисленных свойств
   this.m_long_prop[ACCOUNT_PROP_LOGIN]                              = this.m_struct_obj.login;
   this.m_long_prop[ACCOUNT_PROP_TRADE_MODE]                         = this.m_struct_obj.trade_mode;
   this.m_long_prop[ACCOUNT_PROP_LEVERAGE]                           = this.m_struct_obj.leverage;
   this.m_long_prop[ACCOUNT_PROP_LIMIT_ORDERS]                       = this.m_struct_obj.limit_orders;
   this.m_long_prop[ACCOUNT_PROP_MARGIN_SO_MODE]                     = this.m_struct_obj.margin_so_mode;
   this.m_long_prop[ACCOUNT_PROP_TRADE_ALLOWED]                      = this.m_struct_obj.trade_allowed;
   this.m_long_prop[ACCOUNT_PROP_TRADE_EXPERT]                       = this.m_struct_obj.trade_expert;
   this.m_long_prop[ACCOUNT_PROP_MARGIN_MODE]                        = this.m_struct_obj.margin_mode;
   this.m_long_prop[ACCOUNT_PROP_CURRENCY_DIGITS]                    = this.m_struct_obj.currency_digits;
   this.m_long_prop[ACCOUNT_PROP_SERVER_TYPE]                        = this.m_struct_obj.server_type;
   this.m_long_prop[ACCOUNT_PROP_FIFO_CLOSE]                         = this.m_struct_obj.fifo_close;
//--- Сохранение вещественных свойств
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_BALANCE)]          = this.m_struct_obj.balance;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_CREDIT)]           = this.m_struct_obj.credit;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_PROFIT)]           = this.m_struct_obj.profit;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_EQUITY)]           = this.m_struct_obj.equity;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN)]           = this.m_struct_obj.margin;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_FREE)]      = this.m_struct_obj.margin_free;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_LEVEL)]     = this.m_struct_obj.margin_level;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_CALL)]   = this.m_struct_obj.margin_so_call;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_SO)]     = this.m_struct_obj.margin_so_so;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_INITIAL)]   = this.m_struct_obj.margin_initial;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_MAINTENANCE)]=this.m_struct_obj.margin_maintenance;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_ASSETS)]           = this.m_struct_obj.assets;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_LIABILITIES)]      = this.m_struct_obj.liabilities;
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_COMMISSION_BLOCKED)]=this.m_struct_obj.comission_blocked;
//--- Сохранение строковых свойств
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_NAME)]             = ::CharArrayToString(this.m_struct_obj.name);
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_SERVER)]           = ::CharArrayToString(this.m_struct_obj.server);
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_CURRENCY)]         = ::CharArrayToString(this.m_struct_obj.currency);
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_COMPANY)]          = ::CharArrayToString(this.m_struct_obj.company);
  }
//+------------------------------------------------------------------+
//| Выводит в журнал свойства аккаунта                               |
//+------------------------------------------------------------------+
void CAccount::Print(const bool full_prop=false)
  {
   ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_BEG)," ==================");
   int beg=0, end=ACCOUNT_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_ACCOUNT_PROP_INTEGER prop=(ENUM_ACCOUNT_PROP_INTEGER)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=ACCOUNT_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_ACCOUNT_PROP_DOUBLE prop=(ENUM_ACCOUNT_PROP_DOUBLE)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=ACCOUNT_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_ACCOUNT_PROP_STRING prop=(ENUM_ACCOUNT_PROP_STRING)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("================== ",CMessage::Text(MSG_LIB_PARAMS_LIST_END)," ==================\n");
  }
//+------------------------------------------------------------------+
//| Выводит в журнал краткое описание счёта                          |
//+------------------------------------------------------------------+
void CAccount::PrintShort(void)
  {
   string mode=(this.MarginMode()==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING ? ", Hedge" : this.MarginMode()==ACCOUNT_MARGIN_MODE_EXCHANGE ? ", Exhange" : "");
   string names=this.m_name+" ";
   string values=::DoubleToString(this.Balance(),(int)this.CurrencyDigits())+" "+this.Currency()+", 1:"+(string)+this.Leverage()+mode+", "+this.TradeModeDescription()+" "+this.ServerTypeDescription();
   ::Print(names,values);
  }
//+------------------------------------------------------------------+
//| Возвращает описание целочисленного свойства аккаунта             |
//+------------------------------------------------------------------+
string CAccount::GetPropertyDescription(ENUM_ACCOUNT_PROP_INTEGER property)
  {
   return
     (
      property==ACCOUNT_PROP_LOGIN           ?  CMessage::Text(MSG_ACC_PROP_LOGIN)+": "+(string)this.GetProperty(property)                            :
      property==ACCOUNT_PROP_TRADE_MODE      ?  CMessage::Text(MSG_ACC_PROP_TRADE_MODE)+": "+this.TradeModeDescription()                              :
      property==ACCOUNT_PROP_LEVERAGE        ?  CMessage::Text(MSG_ACC_PROP_LEVERAGE)+": "+(string)this.GetProperty(property)                         :
      property==ACCOUNT_PROP_LIMIT_ORDERS    ?  CMessage::Text(MSG_ACC_PROP_LIMIT_ORDERS)+": "+(string)this.GetProperty(property)                     :
      property==ACCOUNT_PROP_MARGIN_SO_MODE  ?  CMessage::Text(MSG_ACC_PROP_MARGIN_SO_MODE)+": "+this.MarginSOModeDescription()                       :
      property==ACCOUNT_PROP_TRADE_ALLOWED   ?  CMessage::Text(MSG_ACC_PROP_TRADE_ALLOWED)+": "+
                                                   (this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))  :
      property==ACCOUNT_PROP_TRADE_EXPERT    ?  CMessage::Text(MSG_ACC_PROP_TRADE_EXPERT)+": "+
                                                   (this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))  :
      property==ACCOUNT_PROP_MARGIN_MODE     ?  CMessage::Text(MSG_ACC_PROP_MARGIN_MODE)+": "+this.MarginModeDescription()                            :
      property==ACCOUNT_PROP_CURRENCY_DIGITS ?  CMessage::Text(MSG_ACC_PROP_CURRENCY_DIGITS)+": "+(string)this.GetProperty(property)                  :
      property==ACCOUNT_PROP_SERVER_TYPE     ?  CMessage::Text(MSG_ACC_PROP_SERVER_TYPE)+": "+(string)this.GetProperty(property)                      :
      property==ACCOUNT_PROP_FIFO_CLOSE      ?  CMessage::Text(MSG_ACC_PROP_FIFO_CLOSE)+": "+(string)this.GetProperty(property)                       :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание вещественного свойства аккаунта              |
//+------------------------------------------------------------------+
string CAccount::GetPropertyDescription(ENUM_ACCOUNT_PROP_DOUBLE property)
  {
   return
     (
      property==ACCOUNT_PROP_BALANCE            ?  CMessage::Text(MSG_ACC_PROP_BALANCE)+": "+
                                                   ::DoubleToString(this.GetProperty(property),(int)this.CurrencyDigits())+" "+this.Currency()  :
      property==ACCOUNT_PROP_CREDIT             ?  CMessage::Text(MSG_ACC_PROP_CREDIT)+": "+
                                                   ::DoubleToString(this.GetProperty(property),(int)this.CurrencyDigits())+" "+this.Currency()  :
      property==ACCOUNT_PROP_PROFIT             ?  CMessage::Text(MSG_ACC_PROP_PROFIT)+": "+
                                                   ::DoubleToString(this.GetProperty(property),(int)this.CurrencyDigits())+" "+this.Currency()  :
      property==ACCOUNT_PROP_EQUITY             ?  CMessage::Text(MSG_ACC_PROP_EQUITY)+": "+
                                                   ::DoubleToString(this.GetProperty(property),(int)this.CurrencyDigits())+" "+this.Currency()  :
      property==ACCOUNT_PROP_MARGIN             ?  CMessage::Text(MSG_ACC_PROP_MARGIN)+": "+
                                                   ::DoubleToString(this.GetProperty(property),(int)this.CurrencyDigits())+" "+this.Currency()  :
      property==ACCOUNT_PROP_MARGIN_FREE        ?  CMessage::Text(MSG_ACC_PROP_MARGIN_FREE)+": "+
                                                   ::DoubleToString(this.GetProperty(property),(int)this.CurrencyDigits())                      :
      property==ACCOUNT_PROP_MARGIN_LEVEL       ?  CMessage::Text(MSG_ACC_PROP_MARGIN_LEVEL)+": "+
                                                   ::DoubleToString(this.GetProperty(property),1)+"%"                                           :
      property==ACCOUNT_PROP_MARGIN_SO_CALL     ?  CMessage::Text(MSG_ACC_PROP_MARGIN_SO_CALL)+": "+
                                                   ::DoubleToString(this.GetProperty(property),(this.IsPercentsForSOLevels() ? 1 : (int)this.CurrencyDigits()))+
                                                   (this.IsPercentsForSOLevels() ? "%" : this.Currency())                                       :
      property==ACCOUNT_PROP_MARGIN_SO_SO       ?  CMessage::Text(MSG_ACC_PROP_MARGIN_SO_SO)+": "+
                                                   ::DoubleToString(this.GetProperty(property),(this.IsPercentsForSOLevels() ? 1 : (int)this.CurrencyDigits()))+
                                                   (this.IsPercentsForSOLevels() ? "%" : this.Currency())                                       :
      property==ACCOUNT_PROP_MARGIN_INITIAL     ?  CMessage::Text(MSG_ACC_PROP_MARGIN_INITIAL)+": "+
                                                   ::DoubleToString(this.GetProperty(property),(int)this.CurrencyDigits())                      :
      property==ACCOUNT_PROP_MARGIN_MAINTENANCE ? CMessage::Text(MSG_ACC_PROP_MARGIN_MAINTENANCE)+": "+
                                                   ::DoubleToString(this.GetProperty(property),(int)this.CurrencyDigits())                      :
      property==ACCOUNT_PROP_ASSETS             ?  CMessage::Text(MSG_ACC_PROP_ASSETS)+": "+
                                                   ::DoubleToString(this.GetProperty(property),(int)this.CurrencyDigits())                      :
      property==ACCOUNT_PROP_LIABILITIES        ?  CMessage::Text(MSG_ACC_PROP_LIABILITIES)+": "+
                                                   ::DoubleToString(this.GetProperty(property),(int)this.CurrencyDigits())                      :
      property==ACCOUNT_PROP_COMMISSION_BLOCKED ? CMessage::Text(MSG_ACC_PROP_COMMISSION_BLOCKED)+": "+
                                                   ::DoubleToString(this.GetProperty(property),(int)this.CurrencyDigits())                      :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание строкового свойства аккаунта                 |
//+------------------------------------------------------------------+
string CAccount::GetPropertyDescription(ENUM_ACCOUNT_PROP_STRING property)
  {
   return
     (
      property==ACCOUNT_PROP_NAME      ?  CMessage::Text(MSG_ACC_PROP_NAME)+": \""+this.GetProperty(property)+"\""      :
      property==ACCOUNT_PROP_SERVER    ?  CMessage::Text(MSG_ACC_PROP_SERVER)+": \""+this.GetProperty(property)+"\""    :
      property==ACCOUNT_PROP_CURRENCY  ?  CMessage::Text(MSG_ACC_PROP_CURRENCY)+": \""+this.GetProperty(property)+"\""  :
      property==ACCOUNT_PROP_COMPANY   ?  CMessage::Text(MSG_ACC_PROP_COMPANY)+": \""+this.GetProperty(property)+"\""   :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Возвращает наименование типа торгового счёта                     |
//+------------------------------------------------------------------+
string CAccount::TradeModeDescription(void) const
  {
   return
     (
      this.TradeMode()==ACCOUNT_TRADE_MODE_DEMO    ? CMessage::Text(MSG_ACC_TRADE_MODE_DEMO)    :
      this.TradeMode()==ACCOUNT_TRADE_MODE_CONTEST ? CMessage::Text(MSG_ACC_TRADE_MODE_CONTEST) :
      this.TradeMode()==ACCOUNT_TRADE_MODE_REAL    ? CMessage::Text(MSG_ACC_TRADE_MODE_REAL)    :
      CMessage::Text(MSG_ACC_TRADE_MODE_UNKNOWN)
     );
  }
//+------------------------------------------------------------------+
//| Возвращает наименование типа торгового сервера                   |
//+------------------------------------------------------------------+
string CAccount::ServerTypeDescription(void) const
  {
   return(this.ServerType()==5 ? "MetaTrader 5" : "MetaTrader 4");
  }
//+------------------------------------------------------------------+
//| Возвращает описание режима задания                               |
//| минимально допустимого уровня залоговых средств                  |
//+------------------------------------------------------------------+
string CAccount::MarginSOModeDescription(void) const
  {
   return
     (
      this.MarginSOMode()==ACCOUNT_STOPOUT_MODE_PERCENT  ? CMessage::Text(MSG_ACC_STOPOUT_MODE_PERCENT)  : 
      CMessage::Text(MSG_ACC_STOPOUT_MODE_MONEY)
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание режима расчета маржи                         |
//+------------------------------------------------------------------+
string CAccount::MarginModeDescription(void) const
  {
   return
     (
      this.MarginMode()==ACCOUNT_MARGIN_MODE_RETAIL_NETTING ? CMessage::Text(MSG_ACC_MARGIN_MODE_RETAIL_NETTING)  :
      this.MarginMode()==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING ? CMessage::Text(MSG_ACC_MARGIN_MODE_RETAIL_HEDGING)  :
      CMessage::Text(MSG_ACC_MARGIN_MODE_RETAIL_EXCHANGE)
     );
  }
//+------------------------------------------------------------------+
//| Возвращает размер маржи, требуемый для открытия позиции          |
//| или установки отложенного ордера                                 |
//+------------------------------------------------------------------+
double CAccount::MarginForAction(const ENUM_ORDER_TYPE action,const string symbol,const double volume,const double price) const
  {
   double margin=EMPTY_VALUE;
   #ifdef __MQL5__
      return(!::OrderCalcMargin(ENUM_ORDER_TYPE(action%2),symbol,volume,price,margin) ? EMPTY_VALUE : margin);
   #else 
      return this.MarginFree()-::AccountFreeMarginCheck(symbol,ENUM_ORDER_TYPE(action%2),volume);
   #endif
  }
//+------------------------------------------------------------------+
