﻿// ============================================================================
// ============================================================================

#define MQL4

#ifndef RU_RU_MQH
#define RU_RU_MQH

#ifndef FRAMEWORK_RU_RU_MQH
#define FRAMEWORK_RU_RU_MQH

#define FRAMEWORK_LOCALIZATION_REWRITE

#define LOGGER_MSG_ERROR "Ошибка"
#define LOGGER_MSG_INFO "Инфо"
#define LOGGER_MSG_DEBUG "Отладка"
#define LOGGER_MSG_ALERT "Предупреждение"

#define FRAMEWORK_MSG_REASON_PROGRAM "[REASON_PROGRAM] - Эксперт прекратил свою работу, вызвав функцию ExpertRemove()"
#define FRAMEWORK_MSG_REASON_REMOVE "[REASON_REMOVE] - Программа удалена с графика"
#define FRAMEWORK_MSG_REASON_RECOMPILE "[REASON_RECOMPILE] - Программа перекомпилирована"
#define FRAMEWORK_MSG_REASON_CHARTCHANGE "[REASON_CHARTCHANGE] - Cимвол или период графика был изменен"
#define FRAMEWORK_MSG_REASON_CHARTCLOSE "[REASON_CHARTCLOSE] - График закрыт"
#define FRAMEWORK_MSG_REASON_PARAMETERS "[REASON_PARAMETERS] - Входные параметры были изменены пользователем"
#define FRAMEWORK_MSG_REASON_ACCOUNT "[REASON_ACCOUNT] - Активирован другой счет либо произошло переподключение к торговому серверу вследствие изменения настроек счета"
#define FRAMEWORK_MSG_REASON_TEMPLATE "[REASON_TEMPLATE] - Применен другой шаблон графика"
#define FRAMEWORK_MSG_REASON_INITFAILED "[REASON_INITFAILED] - В процессе работы бота произошла ошибка"
#define FRAMEWORK_MSG_REASON_CLOSE "[REASON_CLOSE] - Терминал был закрыт"

#define FRAMEWORK_MSG_ERROR_TRADE_TIMEOUT "[ERROR_TRADE_TIMEOUT] - Истек срок ожидания совершения сделки"
#define FRAMEWORK_MSG_ERROR_INVALID_PRICE "[ERROR_INVALID_PRICE] - Неправильная цена"
#define FRAMEWORK_MSG_ERROR_INVALID_STOPS "[ERROR_INVALID_STOPS] - Неправильные стопы"
#define FRAMEWORK_MSG_ERROR_INVALID_TRADE_VOLUME "[ERROR_INVALID_TRADE_VOLUME] - Неправильный объем"
#define FRAMEWORK_MSG_ERROR_MARKET_CLOSED "[ERROR_MARKET_CLOSED] - Рынок закрыт"
#define FRAMEWORK_MSG_ERROR_TRADE_DISABLED "[ERROR_TRADE_DISABLED] - Торговля запрещена"
#define FRAMEWORK_MSG_ERROR_NOT_ENOUGH_MONEY "[ERROR_NOT_ENOUGH_MONEY] - Недостаточно денег для совершения операции"
#define FRAMEWORK_MSG_ERROR_OFF_QUOTES "[ERROR_OFF_QUOTES] - Нет цен"
#define FRAMEWORK_MSG_ERROR_BROKER_BUSY "[ERROR_BROKER_BUSY] - Брокер занят"
#define FRAMEWORK_MSG_ERROR_REQUOTE "[ERROR_REQUOTE] - Новые цены"
#define FRAMEWORK_MSG_ERROR_ORDER_LOCKED "[ERROR_ORDER_LOCKED] - Ордер заблокирован и уже обрабатывается"
#define FRAMEWORK_MSG_ERROR_LONG_POSITIONS_ONLY_ALLOWED "[ERROR_LONG_POSITIONS_ONLY_ALLOWED] - Разрешена только покупка"
#define FRAMEWORK_MSG_ERROR_TOO_MANY_REQUESTS "[ERROR_TOO_MANY_REQUESTS] - Слишком много запросов"
#define FRAMEWORK_MSG_ERROR_TRADE_MODIFY_DENIED "[ERROR_TRADE_MODIFY_DENIED] - Модификация запрещена, так как ордер слишком близок к рынку"
#define FRAMEWORK_MSG_ERROR_TRADE_CONTEXT_BUSY "[ERROR_TRADE_CONTEXT_BUSY] - Подсистема торговли занята"
#define FRAMEWORK_MSG_ERROR_TRADE_EXPIRATION_DENIED "[ERROR_TRADE_EXPIRATION_DENIED] - Использование даты истечения ордера запрещено брокером"
#define FRAMEWORK_MSG_ERROR_TRADE_TOO_MANY_ORDERS "[ERROR_TRADE_TOO_MANY_ORDERS] - Количество открытых и отложенных ордеров достигло предела, установленного брокеромм"
#define FRAMEWORK_MSG_ERROR_TRADE_HEDGE_PROHIBITED "[ERROR_TRADE_HEDGE_PROHIBITED] - Попытка открыть противоположный ордер в случае, если хеджирование запрещено"
#define FRAMEWORK_MSG_ERROR_TRADE_PROHIBITED_BY_FIFO "[ERROR_TRADE_PROHIBITED_BY_FIFO] - Попытка закрыть позицию по инструменту в противоречии с правилом FIFO"
#define FRAMEWORK_MSG_ERROR_WRONG_FUNCTION_POINTER "[ERROR_WRONG_FUNCTION_POINTER] - Неправильный указатель функции"
#define FRAMEWORK_MSG_ERROR_ARRAY_INDEX_OUT_OF_RANGE "[ERROR_ARRAY_INDEX_OUT_OF_RANGE] - Индекс массива - вне диапазона"
#define FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_CALL_STACK "[ERROR_NO_MEMORY_FOR_CALL_STACK] - Нет памяти для стека функций"
#define FRAMEWORK_MSG_ERROR_RECURSIVE_STACK_OVERFLOW "[ERROR_RECURSIVE_STACK_OVERFLOW] - Переполнение стека после рекурсивного вызова"
#define FRAMEWORK_MSG_ERROR_NOT_ENOUGH_STACK_FOR_PARAM "[ERROR_NOT_ENOUGH_STACK_FOR_PARAM] - На стеке нет памяти для передачи параметров"
#define FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_PARAM_STRING "[ERROR_NO_MEMORY_FOR_PARAM_STRING] - Нет памяти для строкового параметра"
#define FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_TEMP_STRING "[ERROR_NO_MEMORY_FOR_TEMP_STRING] - Нет памяти для временной строки"
#define FRAMEWORK_MSG_ERROR_NOT_INITIALIZED_STRING "[ERROR_NOT_INITIALIZED_STRING] - Неинициализированная строка"
#define FRAMEWORK_MSG_ERROR_NOT_INITIALIZED_ARRAYSTRING "[ERROR_NOT_INITIALIZED_ARRAYSTRING] - Неинициализированная строка в массиве"
#define FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_ARRAYSTRING "[ERROR_NO_MEMORY_FOR_ARRAYSTRING] - Нет памяти для строкового массива"
#define FRAMEWORK_MSG_ERROR_TOO_LONG_STRING "[ERROR_TOO_LONG_STRING] - Слишком длинная строка"
#define FRAMEWORK_MSG_ERROR_REMAINDER_FROM_ZERO_DIVIDE "[ERROR_REMAINDER_FROM_ZERO_DIVIDE] - Остаток от деления на ноль"
#define FRAMEWORK_MSG_ERROR_ZERO_DIVIDE "[ERROR_ZERO_DIVIDE] - Деление на ноль"
#define FRAMEWORK_MSG_ERROR_UNKNOWN_COMMAND "[ERROR_UNKNOWN_COMMAND] - Неизвестная команда"
#define FRAMEWORK_MSG_ERROR_WRONG_JUMP "[ERROR_WRONG_JUMP] - Неправильный переход"
#define FRAMEWORK_MSG_ERROR_NOT_INITIALIZED_ARRAY "[ERROR_NOT_INITIALIZED_ARRAY] - Неинициализированный массив"
#define FRAMEWORK_MSG_ERROR_DLL_CALLS_NOT_ALLOWED "[ERROR_DLL_CALLS_NOT_ALLOWED] - Вызовы DLL не разрешены"
#define FRAMEWORK_MSG_ERROR_CANNOT_LOAD_LIBRARY "[ERROR_CANNOT_LOAD_LIBRARY]  Невозможно загрузить библиотеку"
#define FRAMEWORK_MSG_ERROR_CANNOT_CALL_FUNCTION "[ERROR_CANNOT_CALL_FUNCTION] - Невозможно вызвать функцию"
#define FRAMEWORK_MSG_ERROR_EXTERNAL_CALLS_NOT_ALLOWED "[ERROR_EXTERNAL_CALLS_NOT_ALLOWED] - Вызовы внешних библиотечных функций не разрешены"
#define FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_RETURNED_STR "[ERROR_NO_MEMORY_FOR_RETURNED_STR] - Недостаточно памяти для строки, возвращаемой из функции"
#define FRAMEWORK_MSG_ERROR_SYSTEM_BUSY "[ERROR_SYSTEM_BUSY] - Система занята"
#define FRAMEWORK_MSG_ERROR_DLLFUNC_CRITICALERROR "[ERROR_DLLFUNC_CRITICALERROR]"
#define FRAMEWORK_MSG_ERROR_INTERNAL_ERROR "[ERROR_INTERNAL_ERROR] - Внутренняя ошибка"
#define FRAMEWORK_MSG_ERROR_OUT_OF_MEMORY "[ERROR_OUT_OF_MEMORY] - Нет памяти"
#define FRAMEWORK_MSG_ERROR_INVALID_POINTER "[ERROR_INVALID_POINTER] - Неверный указатель"
#define FRAMEWORK_MSG_ERROR_FORMAT_TOO_MANY_FORMATTERS "[ERROR_FORMAT_TOO_MANY_FORMATTERS] - Слишком много параметров форматирования строки"
#define FRAMEWORK_MSG_ERROR_FORMAT_TOO_MANY_PARAMETERS "[ERROR_FORMAT_TOO_MANY_PARAMETERS] - Число параметров превышает число параметров форматирования строки"
#define FRAMEWORK_MSG_ERROR_ARRAY_INVALID "[ERROR_ARRAY_INVALID] - Неверный массив"
#define FRAMEWORK_MSG_ERROR_CHART_NOREPLY "[ERROR_CHART_NOREPLY] - График не отвечает"
#define FRAMEWORK_MSG_ERROR_INVALID_FUNCTION_PARAMSCNT "[ERROR_INVALID_FUNCTION_PARAMSCNT] - Неправильное количество параметров функции"
#define FRAMEWORK_MSG_ERROR_INVALID_FUNCTION_PARAMVALUE "[ERROR_INVALID_FUNCTION_PARAMVALUE] - Недопустимое значение параметра функции"
#define FRAMEWORK_MSG_ERROR_STRING_FUNCTION_INTERNAL "[ERROR_STRING_FUNCTION_INTERNAL] - Внутренняя ошибка строковой функции"
#define FRAMEWORK_MSG_ERROR_SOME_ARRAY_ERROR "[ERROR_SOME_ARRAY_ERROR] - Ошибка массива"
#define FRAMEWORK_MSG_ERROR_INCORRECT_SERIESARRAY_USING "[ERROR_INCORRECT_SERIESARRAY_USING] - Неправильное использование массива-таймсерии"
#define FRAMEWORK_MSG_ERROR_CUSTOM_INDICATOR_ERROR "[ERROR_CUSTOM_INDICATOR_ERROR] - Ошибка пользовательского индикатора"
#define FRAMEWORK_MSG_ERROR_INCOMPATIBLE_ARRAYS "[ERROR_INCOMPATIBLE_ARRAYS] - Массивы несовместимы"
#define FRAMEWORK_MSG_ERROR_GLOBAL_VARIABLES_PROCESSING "[ERROR_GLOBAL_VARIABLES_PROCESSING] - Ошибка обработки глобальных переменных"
#define FRAMEWORK_MSG_ERROR_GLOBAL_VARIABLE_NOT_FOUND "[ERROR_GLOBAL_VARIABLE_NOT_FOUND] - Глобальная переменная не обнаружена"
#define FRAMEWORK_MSG_ERROR_FUNC_NOT_ALLOWED_IN_TESTING "[ERROR_FUNC_NOT_ALLOWED_IN_TESTING] - Функция не разрешена в тестовом режиме"
#define FRAMEWORK_MSG_ERROR_FUNCTION_NOT_CONFIRMED "[ERROR_FUNCTION_NOT_CONFIRMED] - Функция не разрешена"
#define FRAMEWORK_MSG_ERROR_SEND_MAIL_ERROR "[ERROR_SEND_MAIL_ERROR] - Ошибка отправки почты"
#define FRAMEWORK_MSG_ERROR_STRING_PARAMETER_EXPECTED "[ERROR_STRING_PARAMETER_EXPECTED] - Ожидается параметр типа string"
#define FRAMEWORK_MSG_ERROR_INTEGER_PARAMETER_EXPECTED "[ERROR_INTEGER_PARAMETER_EXPECTED] - Ожидается параметр типа integer"
#define FRAMEWORK_MSG_ERROR_DOUBLE_PARAMETER_EXPECTED "[ERROR_DOUBLE_PARAMETER_EXPECTED] - Ожидается параметр типа double"
#define FRAMEWORK_MSG_ERROR_ARRAY_AS_PARAMETER_EXPECTED "[ERROR_ARRAY_AS_PARAMETER_EXPECTED] - В качестве параметра ожидается массив"
#define FRAMEWORK_MSG_ERROR_HISTORY_WILL_UPDATED "[ERROR_HISTORY_WILL_UPDATED] - Запрошенные исторические данные в состоянии обновления"
#define FRAMEWORK_MSG_ERROR_TRADE_ERROR "[ERROR_TRADE_ERROR] - Ошибка при выполнении торговой операции"
#define FRAMEWORK_MSG_ERROR_RESOURCE_NOT_FOUND "[ERROR_RESOURCE_NOT_FOUND] - Ресурс не найден"
#define FRAMEWORK_MSG_ERROR_RESOURCE_NOT_SUPPORTED "[ERROR_RESOURCE_NOT_SUPPORTED] - Ресурс не поддерживается"
#define FRAMEWORK_MSG_ERROR_RESOURCE_DUPLICATED "[ERROR_RESOURCE_DUPLICATED] - Дубликат ресурса"
#define FRAMEWORK_MSG_ERROR_INDICATOR_CANNOT_INIT "[ERROR_INDICATOR_CANNOT_INIT] - Ошибка инициализации пользовательского индикатора"
#define FRAMEWORK_MSG_ERROR_INDICATOR_CANNOT_LOAD "[ERROR_INDICATOR_CANNOT_LOAD] - Ошибка загрузки пользовательского индикатора"
#define FRAMEWORK_MSG_ERROR_NO_HISTORY_DATA "[ERROR_NO_HISTORY_DATA] - Нет исторических данных"
#define FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_HISTORY "[ERROR_NO_MEMORY_FOR_HISTORY] - Не хватает памяти для исторических данных"
#define FRAMEWORK_MSG_ERROR_END_OF_FILE "[ERROR_END_OF_FILE] - Конец файла"
#define FRAMEWORK_MSG_ERROR_SOME_FILE_ERROR "[ERROR_SOME_FILE_ERROR] - Ошибка при работе с файлом"
#define FRAMEWORK_MSG_ERROR_WRONG_FILE_NAME "[ERROR_WRONG_FILE_NAME] - Неправильное имя файла"
#define FRAMEWORK_MSG_ERROR_TOO_MANY_OPENED_FILES "[ERROR_TOO_MANY_OPENED_FILES] - Слишком много открытых файлов"
#define FRAMEWORK_MSG_ERROR_CANNOT_OPEN_FILE "[ERROR_CANNOT_OPEN_FILE] - Невозможно открыть файл"
#define FRAMEWORK_MSG_ERROR_INCOMPATIBLE_FILEACCESS "[ERROR_INCOMPATIBLE_FILEACCESS] - Несовместимый режим доступа к файлу"
#define FRAMEWORK_MSG_ERROR_NO_ORDER_SELECTED "[ERROR_NO_ORDER_SELECTED] - Ни один ордер не выбран"
#define FRAMEWORK_MSG_ERROR_UNKNOWN_SYMBOL "[ERROR_UNKNOWN_SYMBOL] - Неизвестный символ"
#define FRAMEWORK_MSG_ERROR_INVALID_PRICE_PARAM "[ERROR_INVALID_PRICE_PARAM] - Неправильный параметр цены для торговой функцииь"
#define FRAMEWORK_MSG_ERROR_INVALID_TICKET "[ERROR_INVALID_TICKET] - Неверный номер тикета"
#define FRAMEWORK_MSG_ERROR_TRADE_NOT_ALLOWED "[ERROR_TRADE_NOT_ALLOWED] - орговля не разрешена. Необходимо включить опцию 'Разрешить советнику торговать' в свойствах эксперта"
#define FRAMEWORK_MSG_ERROR_LONGS_NOT_ALLOWED "[ERROR_LONGS_NOT_ALLOWED] - Ордера на покупку не разрешены. Необходимо проверить свойства эксперта"
#define FRAMEWORK_MSG_ERROR_SHORTS_NOT_ALLOWED "[ERROR_SHORTS_NOT_ALLOWED] - Ордера на продажу не разрешены. Необходимо проверить свойства эксперта"
#define FRAMEWORK_MSG_ERROR_TRADE_EXPERT_DISABLED_BY_SERVER "[ERROR_TRADE_EXPERT_DISABLED_BY_SERVER] - Автоматическая торговля с помощью экспертов/скриптов запрещена на стороне сервера"
#define FRAMEWORK_MSG_ERROR_OBJECT_ALREADY_EXISTS "[ERROR_OBJECT_ALREADY_EXISTS] - Объект уже существует"
#define FRAMEWORK_MSG_ERROR_UNKNOWN_OBJECT_PROPERTY "[ERROR_UNKNOWN_OBJECT_PROPERTY] - Запрошено неизвестное свойство объекта"
#define FRAMEWORK_MSG_ERROR_OBJECT_DOES_NOT_EXIST "[ERROR_OBJECT_DOES_NOT_EXIST] - Объект не существует"
#define FRAMEWORK_MSG_ERROR_UNKNOWN_OBJECT_TYPE "[ERROR_UNKNOWN_OBJECT_TYPE] - Неизвестный тип объекта"
#define FRAMEWORK_MSG_ERROR_NO_OBJECT_NAME "[ERROR_NO_OBJECT_NAME] - Нет имени объекта"
#define FRAMEWORK_MSG_ERROR_OBJECT_COORDINATES_ERROR "[ERROR_OBJECT_COORDINATES_ERROR] - Ошибка координат объекта"
#define FRAMEWORK_MSG_ERROR_NO_SPECIFIED_SUBWINDOW "[ERROR_NO_SPECIFIED_SUBWINDOW] - Не найдено указанное подокно"
#define FRAMEWORK_MSG_ERROR_SOME_OBJECT_ERROR "[ERROR_SOME_OBJECT_ERROR] - Ошибка при работе с объектом"
#define FRAMEWORK_MSG_ERROR_CHART_PROP_INVALID "[ERROR_CHART_PROP_INVALID] - Неизвестное свойство графика"
#define FRAMEWORK_MSG_ERROR_CHART_NOT_FOUND "[ERROR_CHART_NOT_FOUND] - График не найден"
#define FRAMEWORK_MSG_ERROR_CHARTWINDOW_NOT_FOUND "[ERROR_CHARTWINDOW_NOT_FOUND] - Не найдено подокно графика"
#define FRAMEWORK_MSG_ERROR_CHARTINDICATOR_NOT_FOUND "[ERROR_CHARTINDICATOR_NOT_FOUND] - Индикатор не найден"
#define FRAMEWORK_MSG_ERROR_SYMBOL_SELECT "[ERROR_SYMBOL_SELECT] - Ошибка выбора инструмента"
#define FRAMEWORK_MSG_ERROR_NOTIFICATION_ERROR "[ERROR_NOTIFICATION_ERROR] - Ошибка отправки push-уведомления"
#define FRAMEWORK_MSG_ERROR_NOTIFICATION_PARAMETER "[ERROR_NOTIFICATION_PARAMETER] - Ошибка параметров push-уведомления"
#define FRAMEWORK_MSG_ERROR_NOTIFICATION_SETTINGS "[ERROR_NOTIFICATION_SETTINGS] - Уведомления запрещены"
#define FRAMEWORK_MSG_ERROR_NOTIFICATION_TOO_FREQUENT "[ERROR_NOTIFICATION_TOO_FREQUENT] - Слишком частые запросы отсылки push-уведомлений"
#define FRAMEWORK_MSG_ERROR_FILE_TOO_MANY_OPENED "[ERROR_FILE_TOO_MANY_OPENED] - Слишком много открытых файлов"
#define FRAMEWORK_MSG_ERROR_FILE_WRONG_FILENAME "[ERROR_FILE_WRONG_FILENAME] - Неверное имя файла"
#define FRAMEWORK_MSG_ERROR_FILE_TOO_LONG_FILENAME "[ERROR_FILE_TOO_LONG_FILENAME] - Слишком длинное имя файла"
#define FRAMEWORK_MSG_ERROR_FILE_CANNOT_OPEN "[ERROR_FILE_CANNOT_OPEN] - Ошибка открытия файла"
#define FRAMEWORK_MSG_ERROR_FILE_BUFFER_ALLOCATION_ERROR "[ERROR_FILE_BUFFER_ALLOCATION_ERROR] - Ошибка размещения буфера текстового файла"
#define FRAMEWORK_MSG_ERROR_FILE_CANNOT_DELETE "[ERROR_FILE_CANNOT_DELETE] - Ошибка удаления файла"
#define FRAMEWORK_MSG_ERROR_FILE_INVALID_HANDLE "[ERROR_FILE_INVALID_HANDLE] - Неверный хендл файла (файл закрыт или не был открыт)"
#define FRAMEWORK_MSG_ERROR_FILE_WRONG_HANDLE "[ERROR_FILE_WRONG_HANDLE] - Неверный хендл файла (индекс хендла отсутствует в таблице)"
#define FRAMEWORK_MSG_ERROR_FILE_NOT_TOWRITE "[ERROR_FILE_NOT_TOWRITE] - Файл должен быть открыт с флагом FILE_WRITE"
#define FRAMEWORK_MSG_ERROR_FILE_NOT_TOREAD "[ERROR_FILE_NOT_TOREAD] - Файл должен быть открыт с флагом FILE_READ"
#define FRAMEWORK_MSG_ERROR_FILE_NOT_BIN "[ERROR_FILE_NOT_BIN] - Файл должен быть открыт с флагом FILE_BIN"
#define FRAMEWORK_MSG_ERROR_FILE_NOT_TXT "[ERROR_FILE_NOT_TXT] - Файл должен быть открыт с флагом FILE_TXT"
#define FRAMEWORK_MSG_ERROR_FILE_NOT_TXTORCSV "[ERROR_FILE_NOT_TXTORCSV] - Файл должен быть открыт с флагом FILE_TXT или FILE_CSV"
#define FRAMEWORK_MSG_ERROR_FILE_NOT_CSV "[ERROR_FILE_NOT_CSV] - Файл должен быть открыт с флагом FILE_CSV"
#define FRAMEWORK_MSG_ERROR_FILE_READ_ERROR "[ERROR_FILE_READ_ERROR] - Ошибка чтения файла"
#define FRAMEWORK_MSG_ERROR_FILE_WRITE_ERROR "[ERROR_FILE_WRITE_ERROR] - Ошибка записи файла"
#define FRAMEWORK_MSG_ERROR_FILE_BIN_STRINGSIZE "[ERROR_FILE_BIN_STRINGSIZEERROR_FILE_BIN_STRINGSIZE] - Размер строки должен быть указан для двоичных файлов"
#define FRAMEWORK_MSG_ERROR_FILE_INCOMPATIBLE "[ERROR_FILE_INCOMPATIBLE] - Неверный тип файла (для строковых массивов-TXT, для всех других-BIN)"
#define FRAMEWORK_MSG_ERROR_FILE_IS_DIRECTORY "[ERROR_FILE_IS_DIRECTORY] - Файл является директорией"
#define FRAMEWORK_MSG_ERROR_FILE_NOT_EXIST "[ERROR_FILE_NOT_EXIST] - Файл не существует"
#define FRAMEWORK_MSG_ERROR_FILE_CANNOT_REWRITE "[ERROR_FILE_CANNOT_REWRITE] - Файл не может быть перезаписан"
#define FRAMEWORK_MSG_ERROR_FILE_WRONG_DIRECTORYNAME "[ERROR_FILE_WRONG_DIRECTORYNAME] - Неверное имя директории"
#define FRAMEWORK_MSG_ERROR_FILE_DIRECTORY_NOT_EXIST "[ERROR_FILE_DIRECTORY_NOT_EXIST] - Директория не существует"
#define FRAMEWORK_MSG_ERROR_FILE_NOT_DIRECTORY "[ERROR_FILE_NOT_DIRECTORY] - Указанный файл не является директорией"
#define FRAMEWORK_MSG_ERROR_FILE_CANNOT_DELETE_DIRECTORY "[ERROR_FILE_CANNOT_DELETE_DIRECTORY] - Ошибка удаления директории"
#define FRAMEWORK_MSG_ERROR_FILE_CANNOT_CLEAN_DIRECTORY "[ERROR_FILE_CANNOT_CLEAN_DIRECTORY] - Ошибка очистки директории"
#define FRAMEWORK_MSG_ERROR_FILE_STRINGRESIZE_ERROR "[ERROR_FILE_STRINGRESIZE_ERROR] - Ошибка изменения размера строки"
#define FRAMEWORK_MSG_ERROR_FILE_STRUCT_WITH_OBJECTS "[ERROR_FILE_STRUCT_WITH_OBJECTS] - Структура содержит строки или динамические массивы"
#define FRAMEWORK_MSG_ERROR_WEBREQUEST_INVALID_ADDRESS "[ERROR_WEBREQUEST_INVALID_ADDRESS] - URL не прошел проверку"
#define FRAMEWORK_MSG_ERROR_WEBREQUEST_CONNECT_FAILED "[ERROR_WEBREQUEST_CONNECT_FAILED] - Не удалось подключиться к указанному URL"
#define FRAMEWORK_MSG_ERROR_WEBREQUEST_TIMEOUT "[ERROR_WEBREQUEST_TIMEOUT] - Превышен таймаут получения данных"
#define FRAMEWORK_MSG_ERROR_WEBREQUEST_REQUEST_FAILED "[ERROR_WEBREQUEST_REQUEST_FAILED] - Ошибка в результате выполнения HTTP запроса"
#define FRAMEWORK_MSG_ERROR_NOT_FOUND "Ошибка не опознана"

#endif

#define SRC_SETKA_TERMINAL_VERSION_MSG "Билд терминала %s"
#define SRC_SETKA_VERSION_MSG "Версия %s (%s) от %s"
#define SRC_SETKA_TRADE_NOT_ALLOWED "Торговля с помощью советника запрещенна настройками терминала"
#define SRC_SETKA_MIN_LOT "Минимальный лот %f"
#define SRC_SETKA_COUNT_SYMBOL_FOR_AVG  "Кол-во символов лота для округления %d"
#define SRC_SETKA_NOT_GOOD_LOTSTEP "Неправильный минимальный шаг сетки %f"
#define SRC_SETKA_INIT_COMPLETED "Инициализация прошла успешно"
#define SRC_SETKA_DEINIT_REASON "Работа бота завершена. Тип завершения: %s"
#define SRC_SETKA_NO_MONEY "Пополните торговый счет"

#define SRC_SETKA_DRAWDOWN_MSG "Жду снижения просадки. Просадка %s"
#define SRC_SETKA_DRAWDOWN_CLOSE_ALL_BY_DRAWDOWN_MSG "Просадка %s достигла %s предельного значения. Закрываю ордера."
#define SRC_SETKA_DRAWDOWN_CLOSE_ALL_BY_PROFIT_MSG "Прибыль %s достигла %s предельного значения. Закрываю ордера."
#define SRC_SETKA_DRAWDOWN_CLOSE_ALL_STOP_TRADE_MSG "Прекращаю работу после закрытия всех позиций."

#define SRC_SETKA_STOP_DRAWDOWN_ON "Просадка %s достигла %s значения включения блокировки торговли."
#define SRC_SETKA_STOP_DRAWDOWN_OFF "Просадка %s достигла %s значения отключения блокировки торговли."

#define SRC_SETKA_VALID_NOT_GOOD "Неправильно задан один или несколько параметров."
#define SRC_SETKA_TEST_NOT_GOOD "Не пройдены тесты на правильность работы основных функций."
#define SRC_SETKA_TEST_GOOD "Тесты на правильность задания параметров и работы основных функций прошли успешно."
#define SRC_SETKA_MARKET_CLOSE "Рынок закрыт"
#define SRC_SETKA_MARKET_CLOSE_ERROR "Рынок закрыт отменяю все состояния"

#define SRC_SETKA_SYMBOL_TRADE_MODE_DISABLED "Торговля по символу запрещена"
#define SRC_SETKA_SYMBOL_TRADE_MODE_LONGONLY "Разрешены только покупки"
#define SRC_SETKA_SYMBOL_TRADE_MODE_SHORTONLY "Разрешены только продажи"
#define SRC_SETKA_SYMBOL_TRADE_MODE_CLOSEONLY "Разрешены только операции закрытия позиций"

#define SRC_SETKA_ACCOUNT_COMPANY "Счет зарегистрирован в компании %s"
#define SRC_SETKA_ACCOUNT_CURRENCY "Валюта счета %s"
#define SRC_SETKA_ACCOUNT_LEVERAGE "Кредитное плечо 1:%s"
#define SRC_SETKA_ACCOUNT_NUMBER_ENCODED "Шифрованный номер счета %s"
#define SRC_SETKA_ACCOUNT_SERVER "Сервер %s"
#define SRC_SETKA_ACCOUNT_STOPOUT "Уровень стопаута %s"
#define SRC_SETKA_ACCOUNT_STOPOUT_MODE "Режим расчета стопаута %s"
#define SRC_SETKA_BID "Bid %s"
#define SRC_SETKA_ASK "Ask %s"

#define SRC_SETKA_MODE_LOW "(MODE_LOW) Минимальная дневная цена - %s"
#define SRC_SETKA_MODE_HIGH "(MODE_HIGH) Максимальная дневная цена - %s"
#define SRC_SETKA_MODE_TIME "(MODE_TIME) Время поступления последней котировки - %s"
#define SRC_SETKA_MODE_BID "(MODE_BID) Последняя поступившая цена предложения - %s"
#define SRC_SETKA_MODE_ASK "(MODE_ASK) Последняя поступившая цена продажи - %s"
#define SRC_SETKA_MODE_POINT "(MODE_POINT) Размер пункта в валюте котировки - %s"
#define SRC_SETKA_MODE_DIGITS "(MODE_DIGITS) Количество цифр после запятой в цене инструмента - %s"
#define SRC_SETKA_MODE_SPREAD "(MODE_SPREAD) Спрэд в пунктах - %s"
#define SRC_SETKA_MODE_STOPLEVEL "(MODE_STOPLEVEL) Минимально допустимый уровень стоп-лосса/тейк-профита в пунктах - %s"
#define SRC_SETKA_MODE_LOTSIZE "(MODE_LOTSIZE) Размер контракта в базовой валюте инструмента - %s"
#define SRC_SETKA_MODE_TICKVALUE "(MODE_TICKVALUE) Размер минимального изменения цены инструмента в валюте депозита - %s"
#define SRC_SETKA_MODE_TICKSIZE "(MODE_TICKSIZE) Минимальный шаг изменения цены инструмента в пунктах - %s"
#define SRC_SETKA_MODE_SWAPLONG "(MODE_SWAPLONG) Размер свопа для ордеров на покупку - %s"
#define SRC_SETKA_MODE_SWAPSHORT "(MODE_SWAPSHORT) Размер свопа для ордеров на продажу - %s"
#define SRC_SETKA_MODE_STARTING "(MODE_STARTING) Календарная дата начала торгов (обычно используется для фьючерсов) - %s"
#define SRC_SETKA_MODE_EXPIRATION "(MODE_EXPIRATION) Календарная дата конца торгов (обычно используется для фьючерсов) - %s"
#define SRC_SETKA_MODE_TRADEALLOWED "(MODE_TRADEALLOWED) Разрешение торгов по указанному инструменту - %s"
#define SRC_SETKA_MODE_MINLOT "(MODE_MINLOT) Минимальный размер лота - %s"
#define SRC_SETKA_MODE_LOTSTEP "(MODE_LOTSTEP) Шаг изменения размера лота - %s"
#define SRC_SETKA_MODE_MAXLOT "(MODE_MAXLOT) Максимальный размер лота - %s"
#define SRC_SETKA_MODE_SWAPTYPE "(MODE_SWAPTYPE) Метод вычисления свопов - %s"
#define SRC_SETKA_MODE_PROFITCALCMODE "(MODE_PROFITCALCMODE) Способ расчета прибыли - %s"
#define SRC_SETKA_MODE_MARGINCALCMODE "(MODE_MARGINCALCMODE) Способ расчета залоговых средств - %s"
#define SRC_SETKA_MODE_MARGININIT "(MODE_MARGININIT) Способ расчета залоговых средств - %s"
#define SRC_SETKA_MODE_MARGINMAINTENANCE "(MODE_MARGINMAINTENANCE) Начальные залоговые требования для 1 лота - %s"
#define SRC_SETKA_MODE_MARGINHEDGED "(MODE_MARGINHEDGED) Размер залоговых средств для поддержки открытых ордеров в расчете на 1 лот - %s"
#define SRC_SETKA_MODE_MARGINREQUIRED "(MODE_MARGINREQUIRED) Размер свободных средств, необходимых для открытия 1 лота на покупку - %s"
#define SRC_SETKA_MODE_FREEZELEVEL "(MODE_FREEZELEVEL) Уровень заморозки ордеров в пунктах - %s"

#define SRC_HANDLER_BASE_SHORT "Продажа"
#define SRC_HANDLER_BASE_LONG "Покупка"
#define SRC_HANDLER_BASE_NOT_GOOD_LOT "Не достаточно средств для открытия ордера с лотом %f"
#define SRC_HANDLER_BASE_NOT_GOOD_STOP_LOT "Не достаточно средств для открытия отложенного ордера с лотом %f"
#define SRC_HANDLER_BASE_UPDATE_TP "Обновляю ТР %s -> %s"
#define SRC_HANDLER_BASE_TIMER_UPDATE_TP "Устанавливаю ТР %s -> %s по таймеру."
#define SRC_HANDLER_BASE_TRY_OPEN_LVL "Пробуют открыть колено № %s, шаг %s, комментарий '%s'"
#define SRC_HANDLER_BASE_VERY_STRONG_MOTION "Очень сильное движение цены, выставление ордера откладывается. Проскальзование %f, шаг сетки %f, спред %f."
#define SRC_HANDLER_BASE_ERROR_UPDATE_TP "При попытке изменить ТР произошла ошибка: %s"
#define SRC_HANDLER_BASE_ERROR_OPEN_LVL "При попытке открыть ордер произошла ошибка: %s"
#define SRC_HANDLER_BASE_OPENED_NEW_CANDLE_NO_SIGNAL "Cигнал на вход отсутствует"
#define SRC_HANDLER_BASE_BAD_PRICE "Цена стала хуже предыдущей. Текущая %s, прошлая %s"
#define SRC_HANDLER_BASE_PRICE_GOTO_START "Цена ушла обратно к предыдущему ордеру. Текущая %s, прошлая %s"
#define SRC_HANDLER_BASE_SPREAD_NOT_GOOD "Спред %d выше разрешенного %d. Пауза %d сек, до %s."
#define SRC_HANDLER_BASE_VOL_NOT_GOOD "Размер свечи %f выше разрешенного %d. Пауза %d сек, до %s."
#define SRC_HANDLER_BASE_TIMER_STOP_ON_CLOSE "Засыпаю на %d мин. из-за закрытия сетки."
#define SRC_HANDLER_BASE_TIMER_CLOSE_ORDERS "Через %d сек. буду пробовать закрыть сетку"
#define SRC_HANDLER_BASE_ERROR_CLOSE_ORDERS "При попытке закрыть ордер произошла ошибка: %s"
#define SRC_HANDLER_BASE_TRY_OPEN_STOP_LVL "Пробуют выставить отложенное колено № %s, шаг %s, лот %s, комментарий '%s'"

#define SRC_HANDLER_BASE_DETECT_GAP "Обнаружен гэп от %s до %s ( %s ) превышающий шаг %s на %s%% ( минимальное расстояние от рынка %s )."

#define SRC_HANDLER_BASE_FAIL_SLIPPAGE_OPEN_LVL "Не удалось открыть ордер из-за проскальзования."
#define SRC_HANDLER_BASE_FAIL_EXIT_OPEN_LVL "Выставление ордера отменено."
#define SRC_HANDLER_BASE_MAX_PAIR_BLOCK "Достигнут предел %d одновременно открытых пар. Открытие сетки откладывается."

#define SRC_HANDLER_BASE_CURRENCY_BLOCK_LONG "Покупка %s %d раз(а), продажа %s %d раз(а). Открытие сетки откладывается."
#define SRC_HANDLER_BASE_CURRENCY_BLOCK_SHORT "Продажа %s %d раз(а), покупка %s %d раз(а). Открытие сетки откладывается."

#define SRC_HANDLER_BASE_DRAWDOWN_BLOCK "Просадка счета %s%% выше разрешенного значения %d%%. Открытие сетки откладывается."
#define SRC_HANDLER_BASE_DRAWDOWN_BLOCK_OFF "Просадка счета %s%% опустилась ниже значения %d%%. Блокировка на открытие первого ордера отключена."

#define SRC_HANDLER_BASE_TRADE_PAUSE "Торговля запрещена c %s до %s"
#define SRC_HANDLER_BASE_MODULE_CLOSE_START "Блок контроля закрытия сетки начал работу"
#define SRC_HANDLER_BASE_MODULE_CLOSE_ERROR "Блок контроля не смог закрыть сетку."
#define SRC_HANDLER_BASE_MODULE_CLOSE_COMPLETE "Блок контроля завершил работу"
#define SRC_HANDLER_BASE_FREE_MAGIN_CHECK_NEW_ORDER "При открытии ордера №%s по цене %s и лоту %s будет доступна маржа %s"
#define SRC_HANDLER_BASE_TP_SKIP_ORDER_STOP "При расчете ТР %i отложенных ордеров близких к первому ордеру не было учтено так как они находятся за линией ТР"
#define SRC_HANDLER_BASE_CALC_LOT_LOWEST "Расчетный лот %s меньше последнего %s. Применяю множитель %s к последнему."
#define SRC_HANDLER_BASE_NO_MONEY_ON_INC_LOT "Недостаточно денег для открытия постгэпового ордера с лотом %s. Пробую открыть обычный ордер."
#define SRC_HANDLER_BASE_ERROR_INVALID_STOPS "Цена отложенного ордера %s слишком близка к рынку. Минимальное расстояние от рыночной цены %s"
#define SRC_HANDLER_BASE_NOT_CLOSE_ORDER_STOP "Обнаружены не удаленные отложенные ордера в кол-ве %s."
#define SRC_HANDLER_BASE_PRICE_REACED_TP "Цена %s достигла линии ТP %s. Запускаю модуль закрытия."
#define SRC_HANDLER_BASE_SHOW_CALC_STOP_ORDER "Отложенный ордер №%s по цене %s с лотом %s (шаг %s)."
#define SRC_HANDLER_BASE_SHOW_CALC_STOP_ORDER_WITH_TIKET "Отложенный ордер №%s (%s) по цене %s с лотом %s (шаг %s)."

#define SRC_HANDLER_BASE_ALIGMENT "Требуется переставить отложенные ордера."
#define SRC_HANDLER_BASE_SHOW_ALIGMENT_STOP_ORDER "Отложенный ордер №%s (%s) %s -> %s"

#define SRC_HANDLER_BASE_NOT_COMPLETE_STOP_ORDER "Не удалось выставить отложенный ордер №%s по цене %s с лотом %s (шаг %s). Следующая попытка будет на новом тике."
#define SRC_HANDLER_BASE_STOP_ORDER_CLEAR "Цена %s достигла отложенного ордера №%s по цене %s с лотом %s (шаг %s), переходим к попытке выставить обычный ордер."
#define SRC_HANDLER_BASE_DELETE_STOP_ORDER "Удаляю лиiний отложенный ордер №%s"
#define SRC_HANDLER_BASE_CANCEL_LEVERAGE "Текущее кредитное плечо 1:%s меньше разрешенного 1:%s. Выставление первого ордера отменено."
#define SRC_HANDLER_BASE_CANCEL_MIN_TIME_STEP "Ближайшее время открытия нового ордера %s. Выставление ордера отменено."
#define SRC_HANDLER_BASE_CANCEL_CANDLE_SIZE_MIN "Размер свечей %d меньше допустимого значения %d. Выставление первого ордера отменено."
#define SRC_HANDLER_BASE_CANCEL_CANDLE_SIZE_MAX "Размер свечей %d больше допустимого значения %d. Выставление первого ордера отменено."
#define SRC_HANDLER_BASE_RESET_STATE_CLOSE_ORDER "Закрытие позиции (ордеров) отменено"

#define SRC_ORDER_TRADE_CONTEXT_BUSY "Подсистема торговли занята."
#define SRC_ORDER_TRADE_CONTEXT_BUSY_EXIT "Подсистема торговли занята. Выход из ожидания."
#define SRC_ORDER_TRY_CLOSE_ORDER "Пробую закрыть ордер №%s."

#define SRC_ORDER_TRY_SET_TP  "№%s пробую установить TP ( %s => %s )."
#define SRC_ORDER_TRY_SET_TP_EQUALS "№%s ТР соответсвует %s"
#define SRC_ORDER_TRY_SET_TP_WITH_SL "№%s пробую установить страховочные TP ( %s ) и SL ( %s ) для отложенного ордера."
#define SRC_ORDER_TRY_SET_TP_WITH_SL_EQUALS "№%s страховочные ТР ( %s ) и SL ( %s ) для отложенного ордера соответсвуют."

#define SRC_ORDER_FAIL_CLOSE_ORDER "Не удалось закрыть ордер."

#define SRC_DEFINES_VALID_MSG "%s = %s"
#define SRC_DEFINES_ERROR_MSG "Неправильное значение параметра %s оно должно удовлетворять условию:\n%s"
#define SRC_DEFINES_OR " или "
#define SRC_DEFINES_AND " и "
#define SRC_DEFINES_EQUALLY " = "
#define SRC_DEFINES_NOT_EQUALLY " не равно "
#define SRC_DEFINES_ERROR_INPUT "Ошибка входных параметров"
#define SRC_DEFINES_REFLECT_SELL_SETTINGS_TO_BUY "Для buy настроек копируются следующие sell настройки:"

#define SRC_SCHEDULER_IS_NOT_TRADE_TIME_ON_WEEK "Опция Trade. Бот ожидает разрешенного времени торговли для первых ордеров сеток ( %s %02d:%02d - %s %02d:%02d )."
#define SRC_SCHEDULER_NEW_POSITION_PAUSE "Опция NewPositionPause. Боту запрещено открывать новую позицию ( %s - %s )."
#define SRC_SCHEDULER_IS_TRADE_PAUSE "Опция TradePause. Боту запрещено открывать любые ордера ( %s - %s )."
#define SRC_SCHEDULER_IS_NOR_INTRADAY "Опция IntraDay. Бот ожидает разрешенного времени торговли для первых ордеров сеток ( %02d:%02d - %02d:%02d )."
#define SRC_SCHEDULER_IS_NOR_INTRADAY_STOP_TRADE "Опция IntraDayStopTrade. Бот ожидает окончания запрещенного времени торговли ( %02d:%02d - %02d:%02d )."
#define SRC_SCHEDULER_CLOSE_ALLORDERS_EVERYDAY "Опция CloseAllOrders_EveryDay. Бот активирует модуль закрытия сеток ( %02d:%02d )."
#define SRC_SCHEDULER_SUNDAY "Воскресенье"
#define SRC_SCHEDULER_MONDAY "Понедельник"
#define SRC_SCHEDULER_TUESDAY "Вторник"
#define SRC_SCHEDULER_WEDNESDAY "Среда"
#define SRC_SCHEDULER_THURSDAY "Четверг"
#define SRC_SCHEDULER_FRIDAY "Пятница"
#define SRC_SCHEDULER_SATURDAY "Суббота"

#endif
#ifndef FRAMEWORK_MQH
#define FRAMEWORK_MQH

#ifndef FRAMEWORK_TOOL_CACHE_MQH
#define FRAMEWORK_TOOL_CACHE_MQH

#define TOOL_CACHED( type, name, action ) \
	static type name; \
	static int name##_instance_saved; \
	if( name##_instance_saved != _tool_instance_state ){ \
		name##_instance_saved = _tool_instance_state; \
		action; \
	} \
	return name;

#define TOOL_CACHED_TICK( type, name, action ) \
	static type name; \
	static int name##_tick_saved; \
	if( name##_tick_saved != _tool_tick_state ){ \
		name##_tick_saved= _tool_tick_state; \
		action; \
	} \
	return name;

#define TOOL_CACHED_TICK_TESTING( type, name, action ) \
	static type name; \
	static int name##_tick_saved; \
	static bool name##_testing_saved; \
	if(layer_account::is_testing() \
			|| layer_account::is_optimization()) { \
		if(!name##_testing_saved) { \
			name##_testing_saved = true;	\
			action; \
		} \
	} \
	else if( name##_tick_saved != _tool_tick_state ){ \
		name##_tick_saved = _tool_tick_state; \
		action; \
	} \
	return name;

#define TOOL_CACHED_INSTANCE( type, name, action ) \
	private: \
	type _##name; \
	int _##name##_instance_saved; \
	public: \
	type name() { \
		if( _##name##_instance_saved != _tool_instance_state ){ \
			_##name##_instance_saved = _tool_instance_state; \
			action; \
		} \
		return _##name; \
	}

#define TOOL_CACHED_INSTANCE_TICK( type, name, action ) \
	private: \
	type _##name; \
	int _##name##_tick_saved; \
	public: \
	type name() { \
		if( _##name##_tick_saved != _tool_tick_state ){ \
			_##name##_tick_saved = _tool_tick_state; \
			action; \
		} \
		return _##name; \
	}

int _tool_instance_state = -512;
int _tool_tick_state = -256;

class tool_cache {
public:
	static void update_instance_state() {
		_tool_instance_state += 1;
	}

	static void update_tick_state() {
		_tool_tick_state += 1;
	}
};

#endif

#ifndef FRAMEWORK_ENUM_MQH
#define FRAMEWORK_ENUM_MQH

#ifndef FRAMEWORK_ENUM_CANDLE_VALUE_TYPE_MQH
#define FRAMEWORK_ENUM_CANDLE_VALUE_TYPE_MQH

enum enum_candle_value_type {
	candle_value_low,
	candle_value_close,
	candle_value_open,
	candle_value_high,
	candle_value_time
};

#endif
#ifndef FRAMEWORK_ENUM_LOG_MQH
#define FRAMEWORK_ENUM_LOG_MQH

enum enum_log {
	log_none = 0,
	log_normal = 1,
	log_error = 2,
	log_alert = 3,
	log_debug = 4
};

#endif
#ifndef FRAMEWORK_ENUM_MARGIN_TYPE_MQH
#define FRAMEWORK_ENUM_MARGIN_TYPE_MQH

enum enum_margin_calc_type {
	margin_calc_type_forex = 0, // Forex
	margin_calc_type_cfd = 1, // CFD
	margin_calc_type_futures = 2, // Futures
	margin_calc_type_cfd_on_indexes = 3 // CFD РЅР° РёРЅРґРµРєСЃС‹
};

#endif
#ifndef FRAMEWORK_ENUM_ORDER_OPERATION_TYPE_MQH
#define FRAMEWORK_ENUM_ORDER_OPERATION_TYPE_MQH

enum enum_order_operation_type {
	order_operation_none = -255,
	order_operation_buy = 255,
	order_operation_sell = 254,
	order_operation_buy_stop = 253,
	order_operation_buy_limit = 252,
	order_operation_sell_stop = 251,
	order_operatione_sell_limit = 250
};

#endif
#ifndef FRAMEWORK_ENUM_PROFIT_CALC_TYPE_MQH
#define FRAMEWORK_ENUM_PROFIT_CALC_TYPE_MQH

enum enum_profit_calc_type {
	profit_calc_type_forex = 0, // Forex
	profit_calc_type_cfd = 1, // CFD
	profit_calc_type_futures = 2 // Futures
};

#endif
#ifndef FRAMEWORK_ENUM_SWAP_TYPE_MQH
#define FRAMEWORK_ENUM_SWAP_TYPE_MQH

enum enum_swap_type {
	swap_type_in_points = 0, // РІ РїСѓРЅРєС‚Р°С…
	swap_type_in_base_symbol_currency = 1, // РІ Р±Р°Р·РѕРІРѕР№ РІР°Р»СЋС‚Рµ РёРЅСЃС‚СЂСѓРјРµРЅС‚
	swap_type_in_percent = 2, // РІ РїСЂРѕС†РµРЅС‚Р°С…
	swap_type_in_margin_currency = 3 // РІ РІР°Р»СЋС‚Рµ Р·Р°Р»РѕРіРѕРІС‹С… СЃСЂРµРґСЃС‚РІ
};

#endif
#ifndef FRAMEWORK_ENUM_TRADE_MODE_TYPE_MQH
#define FRAMEWORK_ENUM_TRADE_MODE_TYPE_MQH

enum enum_trade_mode_type {
	trade_mode_type_disabled = SYMBOL_TRADE_MODE_DISABLED, // РўРѕСЂРіРѕРІР»СЏ РїРѕ СЃРёРјРІРѕР»Сѓ Р·Р°РїСЂРµС‰РµРЅР°
	trade_mode_type_long_only = SYMBOL_TRADE_MODE_LONGONLY, // Р Р°Р·СЂРµС€РµРЅС‹ С‚РѕР»СЊРєРѕ РїРѕРєСѓРїРєРё
	trade_mode_type_short_only = SYMBOL_TRADE_MODE_SHORTONLY, // Р Р°Р·СЂРµС€РµРЅС‹ С‚РѕР»СЊРєРѕ РїСЂРѕРґР°Р¶Рё
	trade_mode_type_close_only = SYMBOL_TRADE_MODE_CLOSEONLY, // Р Р°Р·СЂРµС€РµРЅС‹ С‚РѕР»СЊРєРѕ РѕРїРµСЂР°С†РёРё Р·Р°РєСЂС‹С‚РёСЏ РїРѕР·РёС†РёР№
	trade_mode_type_full = SYMBOL_TRADE_MODE_FULL // РќРµС‚ РѕРіСЂР°РЅРёС‡РµРЅРёР№ РЅР° С‚РѕСЂРіРѕРІС‹Рµ РѕРїРµСЂР°С†Рё
};

#endif
#ifndef FRAMEWORK_ENUM_TRADE_RESULT_MQH
#define FRAMEWORK_ENUM_TRADE_RESULT_MQH

enum enum_trade_result {
	trade_result_context_busy = -2,
	trade_result_error = -1,
	trade_result_no = 0,
	trade_result_ok = 1
};

#endif

#endif
#ifndef FRAMEWORK_EXTENSION_MQH
#define FRAMEWORK_EXTENSION_MQH

#ifndef FRAMEWORK_EXT_STRING_MQH
#define FRAMEWORK_EXT_STRING_MQH

#define EXT_STRING_EMPTY ""

#define dtos(value) DoubleToString(value, layer_account::digits())
#define ttos(value) TimeToString( value, TIME_DATE | TIME_MINUTES | TIME_SECONDS )
#define itos(value) IntegerToString(value)

#define ext_string_equals( first, second, check_case ) (StringCompare ( first, second, check_case ) == 0)

class ext_string {
public:
	static string replace ( string value, string find, string replaced ) {
		StringReplace ( value, find, replaced );
		return value;
	}

	static double truncate_real_part ( double value, int count ) {
		string buffer = DoubleToString ( value );
		int length = StringLen ( buffer );
		int index_of = StringFind ( buffer, ".", 0 );

		if ( length - index_of + 1 <= count ) {
			return value;
		}

		buffer = StringSubstr ( buffer, 0, index_of + 1 + count );
		return StringToDouble ( buffer );
	}

	static string get_sha256 ( string value ) {
		uchar data[];
		StringToCharArray ( value, data );
		ArrayResize ( data, ArraySize ( data ) - 1 );

		uchar key[1] = {0};

		uchar result[];
		CryptEncode ( CRYPT_HASH_SHA256, data, key, result );

		string resultStr = EXT_STRING_EMPTY;

		for ( int i = 0; i < ArraySize ( result ); i++ ) {
			resultStr += StringFormat ( "%02x", result[i] );
		}

		return resultStr;
	}
};

class str_builder {
private:
	string source;
public:
	str_builder() {
		source = EXT_STRING_EMPTY;
	}

	void append ( string value ) {
		source += value;
	}

	void append_line ( string value ) {
		source += value + "\r\n";
	}

	string to_str() {
		return source;
	}
};

#endif

#endif
// This file is part of InGrid.
// Copyright (C) 2016 Sergey Degtev dev.greenforest@gmail.com, Evgen Dubrov dalertpay@gmail.com

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see http://www.gnu.org/licenses/

#ifndef FRAMEWORK_COMMON_MQH
#define FRAMEWORK_COMMON_MQH

#ifndef FRAMEWORK_TIME_MQH
#define FRAMEWORK_TIME_MQH

class time {
public:
	static int get_seconds_from_time_frame ( ENUM_TIMEFRAMES time_frame ) {
		return time_frame * 60;
	}
};


#endif
#ifndef FRAMEWORK_LOG_MQH
#define FRAMEWORK_LOG_MQH

#ifndef FRAMEWORK_LOCALIZATION_REWRITE
#define LOGGER_MSG_ERROR "E"
#define LOGGER_MSG_INFO "I"
#define LOGGER_MSG_DEBUG "D"
#define LOGGER_MSG_ALERT "A"
#endif

#ifdef FOR_OPTIMIZATION
#define log_print(message)
#define log_print_v(verb, message)
#define log_print_k(key, message)
#define log_print_vk(verb, key, message)
#define log_error(message)
#define log_error_k(message)
#define log_info(message)
#define log_info_k(message)
#define log_info_k2(key, message)
#define log_info_ex(message)
#define log_info_ex_k(message)
#define log_debug(message)
#define log_debug_k(message)
#define log_alert(message)
#define log_alert_k(message)
#define log_set_msg_key(key)
#else
#define log_print(message) log_print_without_dublicate ( message )
#define log_print_v(verb, message) if ( LogVerbose >= verb ) log_print( message )
#define log_print_k(key, message) log_print( StringFormat ( "%s - %s", key, message ) )
#define log_print_vk(verb, key, message) if ( LogVerbose >= verb ) log_print_k(key, message)
#define log_error(message) log_print_vk ( 1, StringFormat ( "[%s]", LOGGER_MSG_ERROR ), message )
#define log_error_k(key, message) log_print_vk ( 1, StringFormat ( "[%s]%s", SRC_LOG_ERROR, key ), message )
#define log_info(message) log_print_vk( 2, StringFormat ( "[%s]", LOGGER_MSG_INFO ), message )

#define log_info_k(message) log_print_vk ( 2, StringFormat ( "[%s]%s", LOGGER_MSG_INFO, log_current_msg_key ), message )
#define log_info_k2(key, message) log_print_vk ( 2, StringFormat ( "[%s]%s[%s]", LOGGER_MSG_INFO, log_current_msg_key, key ), message )

#define log_info_ex(message) log_print_vk ( 3, StringFormat ( "[%s]", LOGGER_MSG_INFO ), message )
#define log_info_ex_k(message) log_print_vk ( 3, StringFormat ( "[%s]%s", LOGGER_MSG_INFO, log_current_msg_key ), message )
#define log_debug(message) log_print_vk ( 4, StringFormat ( "[%s]", LOGGER_MSG_DEBUG ), message )
#define log_debug_k(message) log_print_vk ( 4, StringFormat ( "[%s]%s", LOGGER_MSG_DEBUG, log_current_msg_key ), message )

#define log_alert(message) \
	if( LogVerbose >= 1 ){ \
		string saved_message = StringFormat( "[%s] - %s", LOGGER_MSG_ALERT, message ); \
		ALERT_PUSH( saved_message ); \
		log_print( saved_message ); \
	}

#define log_alert_k(message) \
	if( LogVerbose >= 1 ){ \
		string saved_message = StringFormat( "%s[%s] - %s", log_current_msg_key, LOGGER_MSG_ALERT, message ); \
		ALERT_PUSH( saved_message ); \
		log_print( saved_message ); \
	}

#define log_set_msg_key(key) log_current_msg_key = key

string log_current_msg_key;
void log_print_without_dublicate ( string msg )
{
	static string double_last_msg;
	static string last_msg;

	if ( !ext_string_equals ( last_msg, msg, false )
			&& !ext_string_equals ( double_last_msg, msg, false ) ) {
		double_last_msg = last_msg;
		last_msg = msg;

		Print ( msg );
	}
}
#endif

#endif
#ifndef FRAMEWORK_ALERT_MQH
#define FRAMEWORK_ALERT_MQH

#ifdef FOR_OPTIMIZATION

#define ALERT_PUSH( message )

#else

#define ALERT_PUSH( message ) \
	Alert(StringFormat("[%s] - %s", \
					   CURRENT_SYMBOL, \
					   message) )

#endif

#endif
#ifndef FRAMEWORK_DISPOSABLE_OBJ_MQH
#define FRAMEWORK_DISPOSABLE_OBJ_MQH

class disposable_obj {
public:
	virtual void dispose() {}
};

#endif
#ifndef FRAMEWORK_TIMER_MQH
#define FRAMEWORK_TIMER_MQH

class timer_t : public disposable_obj {
private:
	int _interval_in_sec;
	datetime _start;

public:
	timer_t() {
		reset();
	}

	void reset() {
		_start = layer::time_current();
	}

	void set_zero() {
		_start = _start - _interval_in_sec;
	}

	bool is_elapsed() {
		return get_distance() >= _interval_in_sec;
	}

	int get_distance() {
		return time_get_distance_in_sec ( layer::time_current(), _start );
	}

	datetime ent_time() {
		return _start + _interval_in_sec;
	}

	static timer_t *create ( int interval_in_sec ) {
		return timer_t::create ( layer::time_current(), interval_in_sec );
	}

	static timer_t *create ( datetime start, int interval_in_sec ) {
		timer_t *result = new timer_t();
		result._start = start;
		result._interval_in_sec = interval_in_sec;
		return result;
	}
};

int time_get_distance_in_sec ( datetime end, datetime start )
{
	return ( int ) ( end - start );
}

#endif

#endif
#ifndef FRAMEWORK_COLLECTION_MQH
#define FRAMEWORK_COLLECTION_MQH

#ifndef FRAMEWORK_LIST_MQH
#define FRAMEWORK_LIST_MQH

#define COMMA ,

#define LIST_FOREACH(list_foreach_collection, list_foreach_iterator_type, list_foreach_iterator_item_name, list_foreach_action) \
	for(int list_foreach_iterator = 0; list_foreach_iterator < list_foreach_collection.count; list_foreach_iterator++){ \
		list_foreach_iterator_type list_foreach_iterator_item_name = list_foreach_collection.items[list_foreach_iterator]; \
		list_foreach_action; \
	}

#define LIST_FOREACH_REVERSE(list_foreach_revese_collection, list_foreach_reverse_iterator_type, list_foreach_reverce_iterator_item_name, list_foreach_reverse_action) \
	for(int list_foreach_reverse_iterator = list_foreach_revese_collection.count - 1; list_foreach_reverse_iterator >= 0; list_foreach_reverse_iterator--){ \
		list_foreach_reverse_iterator_type list_foreach_reverce_iterator_item_name = list_foreach_revese_collection.items[list_foreach_reverse_iterator]; \
		list_foreach_reverse_action; \
	}

#define LIST_FOREACH2(dasdasda, iterate_type_kkkcvx, iterate_item_qwekwed, kfdsfodsi) \
	for(int i_kdaskdgfgf = 0; i_kdaskdgfgf < dasdasda.count; i_kdaskdgfgf++){ \
		iterate_type_kkkcvx iterate_item_qwekwed = dasdasda.items[i_kdaskdgfgf]; \
		kfdsfodsi; \
	}

#define LIST_WHERE(items_dsadasdasln, result_name_dsadasd, iterate_type_dsda, iterate_item_sdadasd, predicate_dsadada) \
	list<iterate_type_dsda>* result_name_dsadasd = new list<iterate_type_dsda>(); \
	for(int i = 0; i < items_dsadasdasln.count; i++){ \
		iterate_type_dsda iterate_item_sdadasd = items_dsadasdasln.items[i]; \
		if(predicate_dsadada){ \
			result_name_dsadasd.add(iterate_item_sdadasd); \
		} \
	}

#define LIST_ACTION_WHERE(list, iterate_type, iterate_name, predicate, action) \
	for(int i = 0; i < list.count; i++){ \
		iterate_type iterate_name = list.items[i]; \
		if(predicate) \
			action; \
	}

#define LIST_SORT_BUBBLE(list, field, asc) \
	if ( asc ) { \
		LIST_SORT_BUBBLE_ASC ( list, open_price ); \
	} else { \
		LIST_SORT_BUBBLE_DESC ( list, open_price ); \
	}

#define LIST_SORT_BUBBLE_ASC(list, field) \
	for(int i = 0; i < list.count - 1; i++){ \
		bool any_change = false; \
		for ( int j = 0; j < list.count - i - 1; j++ ){ \
			if ( list.items[j].##field > list.items[j + 1].##field ) { \
				list.swap ( j, j + 1 ); \
				any_change = true; \
			} \
		} \
		if ( !any_change ) \
			break; \
	}

#define LIST_SORT_BUBBLE_DESC(list, field) \
	for(int i = 0; i < list.count - 1; i++){ \
		bool any_change = false; \
		for ( int j = 0; j < list.count - i - 1; j++ ){ \
			if ( list.items[j].##field < list.items[j + 1].##field ) { \
				list.swap ( j, j + 1 ); \
				any_change = true; \
			} \
		} \
		if ( !any_change ) \
			break; \
	}

#define LIST_SORT_INSERT_ASC(list, field) \
	for(int i = 1; i < list.count; i++) \
		for ( int j = i; j > 0 &&  list.items[j - 1].##field > list.items[j].##field; j-- ) \
			list.swap ( j - 1, j );

#define LIST_SORT_INSERT_DESC(list, field) \
	for(int i = 1; i < list.count; i++) \
		for ( int j = i; j > 0 &&  list.items[j - 1].##field < list.items[j].##field; j-- ) \
			list.swap ( j - 1, j );


#define LIST_FIRST_INDEX_OF(list,result,iterator_type,iterator,predicate) \
	int result = -1;\
	for(int dasdkljmfdsljfds = 0; dasdkljmfdsljfds < list.count; dasdkljmfdsljfds++){\
		iterator_type iterator = list.items[dasdkljmfdsljfds];\
		if((predicate)){ \
			result = dasdkljmfdsljfds;\
			break; \
		}\
	}

#define LIST_LAST_INDEX_OF(list,result,iterator_type,iterator,predicate) \
	int result = -1;\
	for(int dasdkljmfdsljfds = 0; dasdkljmfdsljfds < list.count; dasdkljmfdsljfds++){\
		iterator_type iterator = list.items[dasdkljmfdsljfds];\
		if((predicate)) \
			result = dasdkljmfdsljfds;\
	}

#define LIST_JOIN(left_list,right_list,left_iterator_type, left_iterator_name, right_iterator_type, right_iterator_name, predicate, action) \
	for(int i = 0; i < left_list.count; i++){ \
		left_iterator_type left_iterator_name = left_list.items[i]; \
		for(int j = 0; j < right_list.count; j++){ \
			right_iterator_type right_iterator_name = right_list.items[j]; \
			if((predicate)) \
				action; \
		} \
	}

#define LIST_COUNT(list, result, iterator_type, iterator, predicate) \
	int result = 0; \
	for(int i = 0; i < list.count; i++){ \
		iterator_type iterator = list.items[i]; \
		if(predicate) \
			result += 1; \
	}

#define LIST_SUM(list, result_type, result_name, result_default, iterator_type, iterator, field) \
	result_type result_name = result_default; \
	for(int i = 0; i < list.count; i++) { \
		iterator_type iterator = list.items[i]; \
		result_name += field; \
	} \

#define LIST_SUM_EX(list, result_with_type, iterator_type, iterator, action) \
	result_with_type; \
	for(int i = 0; i < list.count; i++){ \
		iterator_type iterator = list.items[i]; \
		action; \
	}

#define LIST_AVG(list, result_type, result_name, result_default, iterator_type, iterator, field) \
	result_type result_name = result_default; \
	for(int i = 0; i < list.count; i++) { \
		iterator_type iterator = list.items[i]; \
		result_name += field; \
	} \
	result_name /= list.count;

#define LIST_MIN(list, result_type, result_name, result_default, iterator_type, iterator, field) \
	result_type result_name = result_default; \
	for(int i = 0; i < list.count; i++) { \
		iterator_type iterator = list.items[i]; \
		if(i == 0) \
			result_name = field; \
		else if(result_name > field) \
			result_name = field; \
	}

#define LIST_MAX(list, result_type, result_name, result_default, iterator_type, iterator, field) \
	result_type result_name = result_default; \
	for(int i = 0; i < list.count; i++) { \
		iterator_type iterator = list.items[i]; \
		if(i == 0) \
			result_name = field; \
		else if(result_name < field) \
			result_name = field; \
	}

#define LIST_FIRST_OR_DEFAULT(list,result,iterator_type,iterator,predicate) \
	iterator_type result = NULL;\
	for(int dasdkljmfdsljfds = 0; dasdkljmfdsljfds < list.count; dasdkljmfdsljfds++){\
		iterator_type iterator = list.items[dasdkljmfdsljfds];\
		if((predicate)){ \
			result = iterator;\
			break; \
		}\
	}

#define LIST_CONTAINS(list,result,contains_check_item) \
	bool result = false; \
	for(int dasdkljmfdsljfds = 0; dasdkljmfdsljfds < list.count; dasdkljmfdsljfds++){ \
		if(contains_check_item == list.items[dasdkljmfdsljfds]){ \
			result = true; \
			break; \
		}\
	}

#define LIST_ANY(list,result,iterator_type,iterator,predicate) \
	bool result = false; \
	for(int dasdkljmfdsljfds = 0; dasdkljmfdsljfds < list.count; dasdkljmfdsljfds++){ \
		iterator_type iterator = list.items[dasdkljmfdsljfds];\
		if((predicate)){ \
			result = true; \
			break; \
		}\
	}

#define LIST_ALL(list,result,iterator_type,iterator,predicate) \
	bool result = true; \
	for(int dasdkljmfdsljfds = 0; dasdkljmfdsljfds < list.count; dasdkljmfdsljfds++){ \
		iterator_type iterator = list.items[dasdkljmfdsljfds];\
		if(!(predicate)){ \
			result = false; \
			break; \
		}\
	}

template<typename t_left, typename t_right>
class left_right_t : public disposable_obj {
public:
	t_left left;
	t_right right;
};

#define LIST_LEFT_JOIN(result_name, left_list, right_list,left_iterator_type, left_iterator_name, right_iterator_type, right_iterator_name, predicate) \
	list<left_right_t<left_iterator_type,right_iterator_type>*>* result_name = new list<left_right_t<left_iterator_type,right_iterator_type>*>(); \
	for(int i = 0; i < left_list.count; i++){ \
		left_iterator_type left_iterator_name = left_list.items[i]; \
		for(int j = 0; j < right_list.count; j++){ \
			right_iterator_type right_iterator_name = right_list.items[j]; \
			if((predicate)) { \
				left_right_t<left_iterator_type,right_iterator_type>* for_add = new left_right_t<left_iterator_type,right_iterator_type>(); \
				for_add.left = left_iterator_name; \
				for_add.right = right_iterator_name; \
				result_name.add(for_add); \
			} \
		} \
	} \
	for(int i = 0; i < left_list.count; i++){ \
		left_iterator_type left_iterator_name = left_list.items[i]; \
		LIST_ANY( result_name, \
				  left_contains, \
				  left_right_t<left_iterator_type COMMA right_iterator_type>*, \
				  item, \
				  item.left == left_iterator_name ); \
		if(!left_contains){ \
			left_right_t<left_iterator_type,right_iterator_type>* for_add = new left_right_t<left_iterator_type,right_iterator_type>(); \
			for_add.left = left_iterator_name; \
			for_add.right = NULL; \
			result_name.add(for_add); \
		} \
	}

#define GET_VALUE_OR_DEFAULT(item, action) \
	item == NULL ? NULL : action

#define GET_VALUE_OR_MANUAL(item, action, manual) \
	item == NULL ? manual : action

#define ACTION_ON_VALUE_OR_DEFAULT(item, action) \
	if(item != NULL) { \
		action; \
	}

#define ACTION_ON_NONVALUE_OR_DEFAULT(item, action) \
	if(item == NULL) { \
		action; \
	}

template<typename T>
class list_without_ptr : public disposable_obj {
public:
	int _capacity;
	int _capacity_step;
	int position;
	int count;
	T items[];

	list_without_ptr() {
		_capacity = 3;
		_capacity_step = _capacity;

		ArrayResize ( items, _capacity );
	}

	list_without_ptr ( int capacity ) {
		_capacity = capacity;
		_capacity_step = _capacity;

		ArrayResize ( items, _capacity );
	}

	void add ( T value ) {
		if ( count + 1 > _capacity ) {
			_capacity += _capacity_step;
			ArrayResize ( items, _capacity );
		}

		items[count++] = value;
	}

	void clear() {
		position = 0;
		count = 0;
	}

	T get ( int index ) {
		return items[index];
	}
};

template<typename T>
class list : public disposable_obj {
public:
	int _capacity;
	int _capacity_step;
	int position;
	int count;
	T items[];

	~list() {
		clear();
	}

	list() {
		_capacity = 3;
		_capacity_step = 3;

		ArrayResize ( items, _capacity );
	}

	list ( int capacity ) {
		_capacity = capacity;
		_capacity_step = 3;

		ArrayResize ( items, _capacity );
	}

	list ( int capacity,
		   int capacity_step ) {
		_capacity = capacity;
		_capacity_step = capacity_step;

		ArrayResize ( items, _capacity );
	}

	void add ( T value ) {
		if ( count + 1 > _capacity ) {
			_capacity += _capacity_step;
			ArrayResize ( items, _capacity );
		}

		items[count++] = value;
	}

	void delete_at ( int index ) {
		if ( index > count - 1 ) {
			return;
		}

		items[index] = NULL;

		for ( int i = index; i < count - 1; i++ ) {
			swap ( i, i + 1 );
		}

		int new_count = ArraySize ( items ) - 1;
		ArrayResize ( items, new_count );
		count = new_count;
	}

	void clear() {
		LIST_FOREACH ( this, T, item, {
			if ( item != NULL && CheckPointer ( item ) != POINTER_INVALID ) {
				delete item;
			}
		} );

		position = 0;
		count = 0;
	}

	void clear_without_dispoce() {
		position = 0;
		count = 0;
	}

	T pop() {
		return count == 0 ? NULL : items[count--];
	}

	void pop ( T value ) {
		LIST_FIRST_INDEX_OF ( this, delete_item_index, T, item, item == value );
		delete_at ( delete_item_index );
	}

	T get() {
		return position >= count ? NULL : items[position];
	}

	T first_or_default() {
		return count == 0 ? NULL : items[0];
	}

	T last_or_default() {
		return count == 0 ? NULL : items[count - 1];
	}

	list<T> *skip ( int skip_count ) {
		list<T> *result = new list<T> ( count - skip_count );

		for ( int i = skip_count - 1; i < count; i++ ) {
			result.add ( items[i] );
		}

		return result;
	}

	list<T> *take ( int take_count ) {
		list<T> *result = new list<T> ( take_count );

		for ( int i = 0; i < take_count; i++ ) {
			result.add ( items[i] );
		}

		return result;
	}

	void swap ( int first_pos, int second_pos ) {
		if ( first_pos >= count
				|| second_pos >= count ) {
			return;
		}

		T swap_item = items[first_pos];
		items[first_pos] = items[second_pos];
		items[second_pos] = swap_item;
	}

	void swap ( int swap_pos ) {
		swap ( position, swap_pos );
	}
};

#endif
#ifndef FRAMEWORK_MAP_MQH
#define FRAMEWORK_MAP_MQH

template<typename T1, typename T2>
class kvp {
public:
	T1 item1;
	T2 item2;
};

//TODO: РЅСѓР¶РЅРѕ СЃРґРµР»Р°С‚СЊ РїСЂР°РІРёР»СЊРЅС‹Р№ map РЅР° РѕСЃРЅРѕРІРµ hash code Рё РґРµСЂРµРІР°
template<typename TKey, typename TValue>
class map : public disposable_obj {
private:
	list<kvp<TKey, TValue>*> *_items;

public:
	~map() {
		if ( _items != NULL && CheckPointer ( _items ) != POINTER_INVALID ) {
			delete _items;
		}
	}

	map() {
		_items = new list<kvp<TKey, TValue>*> ( 3 );
	}

	map ( int capacity ) {
		_items = new list<kvp<TKey, TValue>*> ( capacity );
	}

	int count() {
		return _items.count;
	}

	bool pushIf ( TKey key, TValue value ) {
		LIST_FIRST_OR_DEFAULT ( _items, exists_item, kvp<TKey COMMA TValue> *, item, item.item1 == key );

		if ( exists_item != NULL ) {
			return false;
		}

		kvp<TKey, TValue> *result = new kvp<TKey, TValue>();
		result.item1 = key;
		result.item2 = value;

		_items.add ( result );
		return true;
	}

	TValue get_value_or_default ( TKey key ) {
		LIST_FIRST_OR_DEFAULT ( _items, exists_item, kvp<TKey COMMA TValue> *, item, item.item1 == key );
		return GET_VALUE_OR_DEFAULT ( exists_item, exists_item.item2 );
	}

	bool contains_key ( TKey key ) {
		LIST_FIRST_OR_DEFAULT ( _items, exists_item, kvp<TKey COMMA TValue> *, item, item.item1 == key );
		return exists_item != NULL;
	}
};

#endif

#endif
#ifndef FRAMEWORK_GC_MQH
#define FRAMEWORK_GC_MQH

#define GC_CHECK_PTR( ptr ) (ptr != NULL && CheckPointer ( ptr ) != POINTER_INVALID)
#define GC_DISPOSE_IF( value ) \
	if(GC_CHECK_PTR(value)){ \
		delete value; \
		value = NULL; \
	}

enum gc_dispose_type {
	gc_dispose_type_on_end_tick,
	gc_dispose_type_on_end_deinit
};

list<disposable_obj *> *gc_dispose_on_end_tick;
list<disposable_obj *> *gc_dispose_on_end_deinit;

class gc {
public:
	static void init() {
		gc_dispose_on_end_tick = new list<disposable_obj *> ( 100 );
		gc_dispose_on_end_deinit = new list<disposable_obj *> ( 100 );
	}

	static void deinit() {
		GC_DISPOSE_IF ( gc_dispose_on_end_tick );
		GC_DISPOSE_IF ( gc_dispose_on_end_deinit );
	}

	static void dispose(  ) {
		list<disposable_obj *> *items = get_list_by_type ( gc_dispose_type_on_end_tick );

		LIST_FOREACH ( items, disposable_obj *, item, {
			if ( GC_CHECK_PTR ( item ) ) {
				item.dispose();
				delete item;
			}
		} );

		items.clear();
	}

	static void push ( gc_dispose_type type, disposable_obj *obj ) {
		get_list_by_type ( type ).add ( obj );
	}

	static void pop ( gc_dispose_type type, disposable_obj *obj ) {
		list<disposable_obj *> *items = get_list_by_type ( type );
		LIST_FIRST_INDEX_OF ( items, delete_index, disposable_obj *, item, item == obj );

		if ( delete_index != -1 ) {
			items.delete_at ( delete_index );
		}
	}

private:
	static list<disposable_obj *> *get_list_by_type ( gc_dispose_type type ) {
		switch ( type ) {
			case gc_dispose_type_on_end_tick:
				return gc_dispose_on_end_tick;

			case gc_dispose_type_on_end_deinit:
				return gc_dispose_on_end_deinit;

			default:
				return NULL;
		}

	}
};

#endif
#ifndef FRAMEWORK_KERNEL_MQH
#define FRAMEWORK_KERNEL_MQH

#define CURRENT_SYMBOL layer_order::get_order_layer_symbol_current_symbol().full

#ifdef MQL4
#ifndef FRAMEWORK_KERNEL_TIME_MQH
#define FRAMEWORK_KERNEL_TIME_MQH

class kernel_time {
public:
	static int get_hour ( datetime value ) {
		return TimeHour ( value );
	}

	static int get_minute ( datetime value ) {
		return TimeMinute ( value );
	}

	static int get_day_of_week() {
		return DayOfWeek();
	}
};

#endif
#ifndef FRAMEWORK_KERNEL_ERROR_MQH
#define FRAMEWORK_KERNEL_ERROR_MQH

#define ERROR_NO_ERROR ERR_NO_ERROR
#define ERROR_NO_MQLERROR ERR_NO_MQLERROR
#define ERROR_TRADE_TIMEOUT ERR_TRADE_TIMEOUT
#define ERROR_INVALID_PRICE ERR_INVALID_PRICE
#define ERROR_INVALID_STOPS ERR_INVALID_STOPS
#define ERROR_INVALID_TRADE_VOLUME ERR_INVALID_TRADE_VOLUME
#define ERROR_MARKET_CLOSED ERR_MARKET_CLOSED
#define ERROR_TRADE_DISABLED ERR_TRADE_DISABLED
#define ERROR_NOT_ENOUGH_MONEY ERR_NOT_ENOUGH_MONEY
#define ERROR_OFF_QUOTES ERR_OFF_QUOTES
#define ERROR_BROKER_BUSY ERR_BROKER_BUSY
#define ERROR_REQUOTE ERR_REQUOTE
#define ERROR_ORDER_LOCKED ERR_ORDER_LOCKED
#define ERROR_LONG_POSITIONS_ONLY_ALLOWED ERR_LONG_POSITIONS_ONLY_ALLOWED
#define ERROR_TOO_MANY_REQUESTS ERR_TOO_MANY_REQUESTS
#define ERROR_TRADE_MODIFY_DENIED ERR_TRADE_MODIFY_DENIED
#define ERROR_TRADE_CONTEXT_BUSY ERR_TRADE_CONTEXT_BUSY
#define ERROR_TRADE_EXPIRATION_DENIED ERR_TRADE_EXPIRATION_DENIED
#define ERROR_TRADE_TOO_MANY_ORDERS ERR_TRADE_TOO_MANY_ORDERS
#define ERROR_TRADE_HEDGE_PROHIBITED ERR_TRADE_HEDGE_PROHIBITED
#define ERROR_TRADE_PROHIBITED_BY_FIFO ERR_TRADE_PROHIBITED_BY_FIFO
#define ERROR_WRONG_FUNCTION_POINTER ERR_WRONG_FUNCTION_POINTER
#define ERROR_ARRAY_INDEX_OUT_OF_RANGE ERR_ARRAY_INDEX_OUT_OF_RANGE
#define ERROR_NO_MEMORY_FOR_CALL_STACK ERR_NO_MEMORY_FOR_CALL_STACK
#define ERROR_RECURSIVE_STACK_OVERFLOW ERR_RECURSIVE_STACK_OVERFLOW
#define ERROR_NOT_ENOUGH_STACK_FOR_PARAM ERR_NOT_ENOUGH_STACK_FOR_PARAM
#define ERROR_NO_MEMORY_FOR_PARAM_STRING ERR_NO_MEMORY_FOR_PARAM_STRING
#define ERROR_NO_MEMORY_FOR_TEMP_STRING ERR_NO_MEMORY_FOR_TEMP_STRING
#define ERROR_NOT_INITIALIZED_STRING ERR_NOT_INITIALIZED_STRING
#define ERROR_NOT_INITIALIZED_ARRAYSTRING ERR_NOT_INITIALIZED_ARRAYSTRING
#define ERROR_NO_MEMORY_FOR_ARRAYSTRING ERR_NO_MEMORY_FOR_ARRAYSTRING
#define ERROR_TOO_LONG_STRING ERR_TOO_LONG_STRING
#define ERROR_REMAINDER_FROM_ZERO_DIVIDE ERR_REMAINDER_FROM_ZERO_DIVIDE
#define ERROR_ZERO_DIVIDE ERR_ZERO_DIVIDE
#define ERROR_UNKNOWN_COMMAND ERR_UNKNOWN_COMMAND
#define ERROR_WRONG_JUMP ERR_WRONG_JUMP
#define ERROR_NOT_INITIALIZED_ARRAY ERR_NOT_INITIALIZED_ARRAY
#define ERROR_DLL_CALLS_NOT_ALLOWED ERR_DLL_CALLS_NOT_ALLOWED
#define ERROR_CANNOT_LOAD_LIBRARY ERR_CANNOT_LOAD_LIBRARY
#define ERROR_CANNOT_CALL_FUNCTION ERR_CANNOT_CALL_FUNCTION
#define ERROR_EXTERNAL_CALLS_NOT_ALLOWED ERR_EXTERNAL_CALLS_NOT_ALLOWED
#define ERROR_NO_MEMORY_FOR_RETURNED_STR ERR_NO_MEMORY_FOR_RETURNED_STR
#define ERROR_SYSTEM_BUSY ERR_SYSTEM_BUSY
#define ERROR_DLLFUNC_CRITICALERROR ERR_DLLFUNC_CRITICALERROR
#define ERROR_INTERNAL_ERROR ERR_INTERNAL_ERROR
#define ERROR_OUT_OF_MEMORY ERR_OUT_OF_MEMORY
#define ERROR_INVALID_POINTER ERR_INVALID_POINTER
#define ERROR_FORMAT_TOO_MANY_FORMATTERS ERR_FORMAT_TOO_MANY_FORMATTERS
#define ERROR_FORMAT_TOO_MANY_PARAMETERS ERR_FORMAT_TOO_MANY_PARAMETERS
#define ERROR_ARRAY_INVALID ERR_ARRAY_INVALID
#define ERROR_CHART_NOREPLY ERR_CHART_NOREPLY
#define ERROR_INVALID_FUNCTION_PARAMSCNT ERR_INVALID_FUNCTION_PARAMSCNT
#define ERROR_INVALID_FUNCTION_PARAMVALUE ERR_INVALID_FUNCTION_PARAMVALUE
#define ERROR_STRING_FUNCTION_INTERNAL ERR_STRING_FUNCTION_INTERNAL
#define ERROR_SOME_ARRAY_ERROR ERR_SOME_ARRAY_ERROR
#define ERROR_INCORRECT_SERIESARRAY_USING ERR_INCORRECT_SERIESARRAY_USING
#define ERROR_CUSTOM_INDICATOR_ERROR ERR_CUSTOM_INDICATOR_ERROR
#define ERROR_INCOMPATIBLE_ARRAYS ERR_INCOMPATIBLE_ARRAYS
#define ERROR_GLOBAL_VARIABLES_PROCESSING ERR_GLOBAL_VARIABLES_PROCESSING
#define ERROR_GLOBAL_VARIABLE_NOT_FOUND ERR_GLOBAL_VARIABLE_NOT_FOUND
#define ERROR_FUNC_NOT_ALLOWED_IN_TESTING ERR_FUNC_NOT_ALLOWED_IN_TESTING
#define ERROR_FUNCTION_NOT_CONFIRMED ERR_FUNCTION_NOT_CONFIRMED
#define ERROR_SEND_MAIL_ERROR ERR_SEND_MAIL_ERROR
#define ERROR_STRING_PARAMETER_EXPECTED ERR_STRING_PARAMETER_EXPECTED
#define ERROR_INTEGER_PARAMETER_EXPECTED ERR_INTEGER_PARAMETER_EXPECTED
#define ERROR_DOUBLE_PARAMETER_EXPECTED ERR_DOUBLE_PARAMETER_EXPECTED
#define ERROR_ARRAY_AS_PARAMETER_EXPECTED ERR_ARRAY_AS_PARAMETER_EXPECTED
#define ERROR_TRADE_ERROR ERR_TRADE_ERROR
#define ERROR_RESOURCE_NOT_FOUND ERR_RESOURCE_NOT_FOUND
#define ERROR_RESOURCE_NOT_SUPPORTED ERR_RESOURCE_NOT_SUPPORTED
#define ERROR_RESOURCE_DUPLICATED ERR_RESOURCE_DUPLICATED
#define ERROR_INDICATOR_CANNOT_INIT ERR_INDICATOR_CANNOT_INIT
#define ERROR_INDICATOR_CANNOT_LOAD ERR_INDICATOR_CANNOT_LOAD
#define ERROR_NO_HISTORY_DATA ERR_NO_HISTORY_DATA
#define ERROR_NO_MEMORY_FOR_HISTORY ERR_NO_MEMORY_FOR_HISTORY
#define ERROR_END_OF_FILE ERR_END_OF_FILE
#define ERROR_SOME_FILE_ERROR ERR_SOME_FILE_ERROR
#define ERROR_WRONG_FILE_NAME ERR_WRONG_FILE_NAME
#define ERROR_TOO_MANY_OPENED_FILES ERR_TOO_MANY_OPENED_FILES
#define ERROR_CANNOT_OPEN_FILE ERR_CANNOT_OPEN_FILE
#define ERROR_INCOMPATIBLE_FILEACCESS ERR_INCOMPATIBLE_FILEACCESS
#define ERROR_NO_ORDER_SELECTED ERR_NO_ORDER_SELECTED
#define ERROR_UNKNOWN_SYMBOL ERR_UNKNOWN_SYMBOL
#define ERROR_INVALID_PRICE_PARAM ERR_INVALID_PRICE_PARAM
#define ERROR_INVALID_TICKET ERR_INVALID_TICKET
#define ERROR_TRADE_NOT_ALLOWED ERR_TRADE_NOT_ALLOWED
#define ERROR_LONGS_NOT_ALLOWED ERR_LONGS_NOT_ALLOWED
#define ERROR_SHORTS_NOT_ALLOWED ERR_SHORTS_NOT_ALLOWED
#define ERROR_TRADE_EXPERT_DISABLED_BY_SERVER ERR_TRADE_EXPERT_DISABLED_BY_SERVER
#define ERROR_OBJECT_ALREADY_EXISTS ERR_OBJECT_ALREADY_EXISTS
#define ERROR_UNKNOWN_OBJECT_PROPERTY ERR_UNKNOWN_OBJECT_PROPERTY
#define ERROR_OBJECT_DOES_NOT_EXIST ERR_OBJECT_DOES_NOT_EXIST
#define ERROR_UNKNOWN_OBJECT_TYPE ERR_UNKNOWN_OBJECT_TYPE
#define ERROR_NO_OBJECT_NAME ERR_NO_OBJECT_NAME
#define ERROR_OBJECT_COORDINATES_ERROR ERR_OBJECT_COORDINATES_ERROR
#define ERROR_NO_SPECIFIED_SUBWINDOW ERR_NO_SPECIFIED_SUBWINDOW
#define ERROR_SOME_OBJECT_ERROR ERR_SOME_OBJECT_ERROR
#define ERROR_CHART_PROP_INVALID ERR_CHART_PROP_INVALID
#define ERROR_CHART_NOT_FOUND ERR_CHART_NOT_FOUND
#define ERROR_CHARTWINDOW_NOT_FOUND ERR_CHARTWINDOW_NOT_FOUND
#define ERROR_CHARTINDICATOR_NOT_FOUND ERR_CHARTINDICATOR_NOT_FOUND
#define ERROR_SYMBOL_SELECT ERR_SYMBOL_SELECT
#define ERROR_NOTIFICATION_ERROR ERR_NOTIFICATION_ERROR
#define ERROR_NOTIFICATION_PARAMETER ERR_NOTIFICATION_PARAMETER
#define ERROR_NOTIFICATION_SETTINGS ERR_NOTIFICATION_SETTINGS
#define ERROR_NOTIFICATION_TOO_FREQUENT ERR_NOTIFICATION_TOO_FREQUENT
#define ERROR_FILE_TOO_MANY_OPENED ERR_FILE_TOO_MANY_OPENED
#define ERROR_FILE_WRONG_FILENAME ERR_FILE_WRONG_FILENAME
#define ERROR_FILE_TOO_LONG_FILENAME ERR_FILE_TOO_LONG_FILENAME
#define ERROR_FILE_CANNOT_OPEN ERR_FILE_CANNOT_OPEN
#define ERROR_FILE_BUFFER_ALLOCATION_ERROR ERR_FILE_BUFFER_ALLOCATION_ERROR
#define ERROR_FILE_CANNOT_DELETE ERR_FILE_CANNOT_DELETE
#define ERROR_FILE_INVALID_HANDLE ERR_FILE_INVALID_HANDLE
#define ERROR_FILE_WRONG_HANDLE ERR_FILE_WRONG_HANDLE
#define ERROR_FILE_NOT_TOREAD ERR_FILE_NOT_TOREAD
#define ERROR_FILE_NOT_BIN ERR_FILE_NOT_BIN
#define ERROR_FILE_NOT_TXT ERR_FILE_NOT_TXT
#define ERROR_FILE_NOT_TXTORCSV ERR_FILE_NOT_TXTORCSV
#define ERROR_FILE_NOT_CSV ERR_FILE_NOT_CSV
#define ERROR_FILE_READ_ERROR ERR_FILE_READ_ERROR
#define ERROR_FILE_WRITE_ERROR ERR_FILE_WRITE_ERROR
#define ERROR_FILE_BIN_STRINGSIZE ERR_FILE_BIN_STRINGSIZE
#define ERROR_FILE_INCOMPATIBLE ERR_FILE_INCOMPATIBLE
#define ERROR_FILE_IS_DIRECTORY ERR_FILE_IS_DIRECTORY
#define ERROR_FILE_NOT_EXIST ERR_FILE_NOT_EXIST
#define ERROR_FILE_CANNOT_REWRITE ERR_FILE_CANNOT_REWRITE
#define ERROR_FILE_WRONG_DIRECTORYNAME ERR_FILE_WRONG_DIRECTORYNAME
#define ERROR_FILE_DIRECTORY_NOT_EXIST ERR_FILE_DIRECTORY_NOT_EXIST
#define ERROR_FILE_NOT_DIRECTORY ERR_FILE_NOT_DIRECTORY
#define ERROR_FILE_CANNOT_DELETE_DIRECTORY ERR_FILE_CANNOT_DELETE_DIRECTORY
#define ERROR_FILE_CANNOT_CLEAN_DIRECTORY ERR_FILE_CANNOT_CLEAN_DIRECTORY
#define ERROR_FILE_STRINGRESIZE_ERROR ERR_FILE_STRINGRESIZE_ERROR
#define ERROR_FILE_STRUCT_WITH_OBJECTS ERR_FILE_STRUCT_WITH_OBJECTS
#define ERROR_WEBREQUEST_INVALID_ADDRESS ERR_WEBREQUEST_INVALID_ADDRESS
#define ERROR_WEBREQUEST_CONNECT_FAILED ERR_WEBREQUEST_CONNECT_FAILED
#define ERROR_WEBREQUEST_TIMEOUT ERR_WEBREQUEST_TIMEOUT
#define ERROR_WEBREQUEST_REQUEST_FAILED ERR_WEBREQUEST_REQUEST_FAILED
#define ERROR_HISTORY_WILL_UPDATED ERR_HISTORY_WILL_UPDATED
#define ERROR_FILE_NOT_TOWRITE ERR_FILE_NOT_TOWRITE

#endif
#ifndef FRAMEWORK_KERNEL_ACCOUNT_MQH
#define FRAMEWORK_KERNEL_ACCOUNT_MQH

class kernel_account {
public:
	static string company() {
		return AccountCompany();
	}

	static string server() {
		return AccountServer();
	}

	static int stopout_level() {
		return AccountStopoutLevel();
	}

	static int stopout_mode() {
		return AccountStopoutMode();
	}

	static double balance() {
		return AccountBalance();
	}

	static double equity() {
		return AccountEquity();
	}

	static long number() {
		return AccountNumber();
	}

	static string currency() {
		return AccountCurrency();
	}

	static bool is_testing() {
		return IsTesting();
	}

	static bool is_optimization() {
		return IsOptimization();
	}

	static bool is_trade_allowed() {
		return IsTradeAllowed();
	}

	static int digits() {
		return Digits;
	}

	static double free_margin() {
		return AccountFreeMargin();
	}

	static double free_margin_check ( string symbol,
									  enum_order_operation_type order_type,
									  double lot ) {
		return AccountFreeMarginCheck ( symbol,
										kernel_order::convert_order_operation_type ( order_type ),
										lot );
	}

	static int leverage() {
		return AccountLeverage();
	}
};

#endif
#ifndef FRAMEWORK_KERNEL_ORDER_MQH
#define FRAMEWORK_KERNEL_ORDER_MQH

class kernel_order {
public:
	static int count() {
		return OrdersTotal();
	}

	static int count_history() {
		return OrdersHistoryTotal();
	}

	static bool select_by_index ( int tiket ) {
		return OrderSelect ( tiket, SELECT_BY_POS, MODE_TRADES );
	}

	static bool select_by_ticket ( int tiket ) {
		return OrderSelect ( tiket, SELECT_BY_TICKET, MODE_TRADES );
	}

	static bool select_by_index_history ( int tiket ) {
		return OrderSelect ( tiket, SELECT_BY_POS, MODE_HISTORY );
	}

	static bool select_by_ticket_history ( int tiket ) {
		return OrderSelect ( tiket, SELECT_BY_TICKET, MODE_HISTORY );
	}

	static int send ( int magic_number,
					  enum_order_operation_type order_type,
					  double price,
					  double lot,
					  int slippage,
					  string comment,
					  color col ) {
		return OrderSend ( CURRENT_SYMBOL,
						   convert_order_operation_type ( order_type ),
						   lot,
						   price,
						   slippage,
						   0,
						   0,
						   comment,
						   magic_number,
						   0,
						   col );
	}

	static int send_stop ( int magic_number,
						   enum_order_operation_type order_stop_type,
						   double price,
						   double lot,
						   string comment,
						   color col ) {
		return OrderSend ( CURRENT_SYMBOL,
						   convert_order_operation_type ( order_stop_type ),
						   lot,
						   price,
						   0,
						   0,
						   0,
						   comment,
						   magic_number,
						   0,
						   col );
	}

	static bool set_price ( int ticket,
							double price,
							color order_color ) {
		if ( !select_by_ticket ( ticket ) ) {
			return false;
		}

		if ( layer::correct_price ( price ) == OrderOpenPrice()  ) {
			return true;
		}

		return OrderModify ( ticket,
							 price,
							 OrderStopLoss(),
							 OrderTakeProfit(),
							 0,
							 order_color );
	}

	static bool delete_stop ( int ticket,
							  color order_color ) {
		return select_by_ticket ( ticket )
			   && OrderDelete ( ticket,
								order_color );
	}

	static bool close ( int ticket,
						double lot,
						double price_close,
						int slippage,
						color order_color ) {
		return select_by_ticket ( ticket )
			   && OrderClose ( ticket,
							   lot,
							   price_close,
							   slippage,
							   order_color );
	}

	static bool set_tp ( int magic_number,
						 int ticket,
						 double tp ) {
		return select_by_ticket ( ticket )
			   && OrderModify ( ticket,
								OrderOpenPrice(),
								OrderStopLoss(),
								tp,
								0,
								Yellow );
	}

	static bool set_sl_tp ( int ticket,
							double sl,
							double tp ) {
		return select_by_ticket ( ticket )
			   && OrderModify ( ticket,
								OrderOpenPrice(),
								sl,
								tp,
								0,
								Yellow );
	}

	static bool set_sl_tp_price ( int ticket,
								  double sl,
								  double tp,
								  double price ) {
		return select_by_ticket ( ticket )
			   && OrderModify ( ticket,
								price,
								sl,
								tp,
								0,
								Yellow );
	}

	static string symbol() {
		return OrderSymbol();
	}

	static long magic_number() {
		return OrderMagicNumber();
	}

	static enum_order_operation_type type() {
		return convert_to_order_operation_type ( OrderType() );
	}

	static int ticket() {
		return OrderTicket();
	}

	static double lots() {
		return OrderLots();
	}

	static double open_price() {
		return OrderOpenPrice();
	}

	static double take_profit() {
		return OrderTakeProfit();
	}

	static double stop_loss() {
		return OrderStopLoss();
	}

	static double commission() {
		return OrderCommission();
	}

	static double swap() {
		return OrderSwap();
	}

	static datetime open_time() {
		return OrderOpenTime();
	}

	static datetime close_time() {
		return OrderCloseTime();
	}

	static int convert_order_operation_type ( enum_order_operation_type type ) {
		switch ( type ) {
			case order_operation_buy:
				return OP_BUY;

			case order_operation_sell:
				return OP_SELL;

			case order_operation_buy_stop:
				return OP_BUYSTOP;

			case order_operation_buy_limit:
				return OP_BUYLIMIT;

			case order_operation_sell_stop:
				return OP_SELLSTOP;

			case order_operatione_sell_limit:
				return OP_SELLLIMIT;

			case order_operation_none:
			default:
				return -1;
		}
	}

private:
	static enum_order_operation_type convert_to_order_operation_type ( int type ) {
		switch ( type ) {
			case OP_BUY:
				return order_operation_buy;

			case OP_SELL:
				return order_operation_sell;

			case OP_BUYSTOP:
				return order_operation_buy_stop;

			case OP_BUYLIMIT:
				return order_operation_buy_limit;

			case OP_SELLSTOP:
				return order_operation_sell_stop;

			case OP_SELLLIMIT:
				return order_operatione_sell_limit;

			default:
				return order_operation_none;
		}
	}
};

#endif
#ifndef FRAMEWORK_KERNEL_MARKET_MQH
#define FRAMEWORK_KERNEL_MARKET_MQH

class kernel_market {
public:
	static double price_buy ( string symbol ) {
		return MarketInfo ( symbol, MODE_ASK );
	}

	static double price_sell ( string symbol ) {
		return MarketInfo ( symbol, MODE_BID );
	}

	static double price_day_min ( string symbol ) {
		return MarketInfo ( symbol, MODE_LOW );
	}

	static double price_day_min ( ) {
		return price_day_min ( CURRENT_SYMBOL );
	}

	static double price_day_max ( string symbol ) {
		return MarketInfo ( symbol, MODE_HIGH );
	}

	static double price_day_max ( ) {
		return price_day_max ( CURRENT_SYMBOL );
	}

	static double tick_value ( string symbol ) {
		return MarketInfo ( symbol, MODE_TICKVALUE );
	}

	static double tick_value () {
		return tick_value ( CURRENT_SYMBOL );
	}

	static double tick_size ( string symbol ) {
		return MarketInfo ( symbol, MODE_TICKSIZE );
	}

	static double tick_size () {
		return tick_size ( CURRENT_SYMBOL );
	}

	static datetime tick_last_time ( string symbol ) {
		return ( datetime ) MarketInfo ( symbol, MODE_TIME );
	}

	static datetime tick_last_time () {
		return tick_last_time ( CURRENT_SYMBOL );
	}

	static double lot_min ( string symbol ) {
		return MarketInfo ( symbol, MODE_MINLOT );
	}

	static double lot_min () {
		return lot_min ( CURRENT_SYMBOL );
	}

	static double lot_size ( string symbol ) {
		return MarketInfo ( symbol, MODE_LOTSIZE );
	}

	static double lot_size () {
		return lot_size ( CURRENT_SYMBOL );
	}

	static double lot_step ( string symbol ) {
		return MarketInfo ( symbol, MODE_LOTSTEP );
	}

	static double lot_step () {
		return lot_step ( CURRENT_SYMBOL );
	}

	static double lot_max ( string symbol ) {
		return MarketInfo ( symbol, MODE_MAXLOT );
	}

	static double lot_max () {
		return lot_max ( CURRENT_SYMBOL );
	}

	static enum_swap_type swap_type ( string symbol ) {
		return ( enum_swap_type ) MarketInfo ( symbol, MODE_SWAPTYPE );
	}

	static enum_swap_type swap_type () {
		return swap_type ( CURRENT_SYMBOL );
	}

	static double swap_long ( string symbol ) {
		return MarketInfo ( symbol, MODE_SWAPLONG );
	}

	static double swap_long ( ) {
		return swap_long ( CURRENT_SYMBOL );
	}

	static double swap_short ( string symbol ) {
		return MarketInfo ( symbol, MODE_SWAPSHORT );
	}

	static double swap_short ( ) {
		return swap_short ( CURRENT_SYMBOL );
	}

	static enum_margin_calc_type margin_calc_type ( string symbol ) {
		return ( enum_margin_calc_type ) MarketInfo ( symbol, MODE_MARGINCALCMODE );
	}

	static enum_margin_calc_type margin_calc_type () {
		return margin_calc_type ( CURRENT_SYMBOL );
	}

	static double margin_required ( string symbol ) {
		return MarketInfo ( symbol, MODE_MARGINREQUIRED );
	}

	static double margin_required ( ) {
		return margin_required ( CURRENT_SYMBOL );
	}

	static double margin_hedged ( string symbol ) {
		return MarketInfo ( symbol, MODE_MARGINHEDGED );
	}

	static double margin_hedged (  ) {
		return margin_hedged ( CURRENT_SYMBOL );
	}

	static double margin_maintenance ( string symbol ) {
		return MarketInfo ( symbol, MODE_MARGINMAINTENANCE );
	}

	static double margin_maintenance () {
		return margin_maintenance ( CURRENT_SYMBOL );
	}

	static double margin_init ( string symbol ) {
		return MarketInfo ( symbol, MODE_MARGININIT );
	}

	static double margin_init () {
		return margin_init ( CURRENT_SYMBOL );
	}

	static double point ( string symbol ) {
		return MarketInfo ( symbol, MODE_POINT );
	}

	static double point () {
		return point ( CURRENT_SYMBOL );
	}

	static datetime starting ( string symbol ) {
		return ( datetime ) MarketInfo ( symbol, MODE_STARTING );
	}

	static datetime starting ( ) {
		return ( datetime ) starting ( CURRENT_SYMBOL );
	}

	static datetime expiration ( string symbol ) {
		return ( datetime ) MarketInfo ( symbol, MODE_EXPIRATION );
	}

	static datetime expiration () {
		return ( datetime ) expiration ( CURRENT_SYMBOL );
	}

	static bool trade_allowed ( string symbol ) {
		return MarketInfo ( symbol, MODE_TRADEALLOWED );
	}

	static bool trade_allowed () {
		return trade_allowed ( CURRENT_SYMBOL );
	}

	static double stop_level ( string symbol ) {
		return MarketInfo ( symbol, MODE_STOPLEVEL );
	}

	static double stop_level () {
		return stop_level ( CURRENT_SYMBOL );
	}

	static double freeze_level ( string symbol ) {
		return MarketInfo ( symbol, MODE_FREEZELEVEL );
	}

	static double freeze_level () {
		return freeze_level ( CURRENT_SYMBOL );
	}

	static int spread ( string symbol ) {
		return ( int ) MarketInfo ( symbol, MODE_SPREAD );
	}

	static int spread () {
		return spread ( CURRENT_SYMBOL );
	}

	static int digits ( string symbol ) {
		return ( int ) MarketInfo ( symbol, MODE_DIGITS );
	}

	static int digits () {
		return ( int ) digits ( CURRENT_SYMBOL );
	}

	static enum_profit_calc_type profit_calc_type ( string symbol ) {
		return ( enum_profit_calc_type ) MarketInfo ( symbol, MODE_PROFITCALCMODE );
	}

	static enum_profit_calc_type profit_calc_type () {
		return profit_calc_type ( CURRENT_SYMBOL );
	}
};

#endif
#ifndef FRAMEWORK_KERNEL_SYMBOL_MQH
#define FRAMEWORK_KERNEL_SYMBOL_MQH

class kernel_symbol {
public:
	static enum_trade_mode_type trade_mode ( string symbol ) {
		return ( enum_trade_mode_type ) SymbolInfoInteger ( symbol, SYMBOL_TRADE_MODE );
	}

	/*
	    static trade_mode_type trade_mode() {
		return trade_mode ( CURRENT_SYMBOL );
	    }
	*/

	static string currency_base ( string symbol ) {
		return SymbolInfoString ( symbol, SYMBOL_CURRENCY_BASE );
	}

	/*
	    static string currency_base ( ){
		return SymbolInfoString ( CURRENT_SYMBOL, SYMBOL_CURRENCY_BASE );
	    }
	*/

	static string currency_profit ( string symbol ) {
		return SymbolInfoString ( symbol, SYMBOL_CURRENCY_PROFIT );
	}

	/*
	    static string currency_profit ( ){
		return SymbolInfoString ( CURRENT_SYMBOL, SYMBOL_CURRENCY_PROFIT );
	    }
	*/
};

#endif
#ifndef FRAMEWORK_KERNEL_QUOTES_MQH
#define FRAMEWORK_KERNEL_QUOTES_MQH

class kernel_quotes {
public:
	static double get_candle_value ( string symbol,
									 ENUM_TIMEFRAMES time_frame,
									 enum_candle_value_type type,
									 int shift ) {
		switch ( type ) {
			case candle_value_low:
				return iLow ( symbol, time_frame, shift );

			case candle_value_close:
				return iClose ( symbol, time_frame, shift );

			case candle_value_open:
				return iOpen ( symbol, time_frame, shift );

			case candle_value_high:
				return iHigh ( symbol, time_frame, shift );

			default:
				return -1;
		}
	}

	static datetime get_candle_open_time ( string symbol,
										   ENUM_TIMEFRAMES time_frame,
										   int shift ) {
		return iTime ( symbol, time_frame, shift );
	}
};

#endif
#endif

#ifdef MQL5
#ifndef FRAMEWORK_KERNEL_TIME_MQH
#define FRAMEWORK_KERNEL_TIME_MQH

class kernel_time {
public:
	static int get_hour ( datetime value ) {
		MqlDateTime result;
		TimeToStruct ( value, result );
		return result.hour;
	}

	static int get_minute ( datetime value ) {
		MqlDateTime result;
		TimeToStruct ( value, result );
		return result.min;
	}

	static int get_day_of_week() {
		MqlDateTime result;
		TimeCurrent ( result );
		return result.day_of_week;
	}
};

#endif
#ifndef FRAMEWORK_KERNEL_ERROR_MQH
#define FRAMEWORK_KERNEL_ERROR_MQH

#define ERROR_NO_ERROR -1
#define ERROR_NO_MQLERROR -2
#define ERROR_TRADE_TIMEOUT -3
#define ERROR_INVALID_PRICE -4
#define ERROR_INVALID_STOPS -5
#define ERROR_INVALID_TRADE_VOLUME -6
#define ERROR_MARKET_CLOSED -7
#define ERROR_TRADE_DISABLED -8
#define ERROR_NOT_ENOUGH_MONEY -9
#define ERROR_OFF_QUOTES -10
#define ERROR_BROKER_BUSY -11
#define ERROR_REQUOTE -12
#define ERROR_ORDER_LOCKED -13
#define ERROR_LONG_POSITIONS_ONLY_ALLOWED -14
#define ERROR_TOO_MANY_REQUESTS -15
#define ERROR_TRADE_MODIFY_DENIED -16
#define ERROR_TRADE_CONTEXT_BUSY -17
#define ERROR_TRADE_EXPIRATION_DENIED -18
#define ERROR_TRADE_TOO_MANY_ORDERS -19
#define ERROR_TRADE_HEDGE_PROHIBITED -21
#define ERROR_TRADE_PROHIBITED_BY_FIFO -22
#define ERROR_WRONG_FUNCTION_POINTER -23
#define ERROR_ARRAY_INDEX_OUT_OF_RANGE -24
#define ERROR_NO_MEMORY_FOR_CALL_STACK -25
#define ERROR_RECURSIVE_STACK_OVERFLOW -26
#define ERROR_NOT_ENOUGH_STACK_FOR_PARAM -27
#define ERROR_NO_MEMORY_FOR_PARAM_STRING -28
#define ERROR_NO_MEMORY_FOR_TEMP_STRING -29
#define ERROR_NOT_INITIALIZED_STRING -30
#define ERROR_NOT_INITIALIZED_ARRAYSTRING -31
#define ERROR_NO_MEMORY_FOR_ARRAYSTRING -32
#define ERROR_TOO_LONG_STRING -33
#define ERROR_REMAINDER_FROM_ZERO_DIVIDE -34
#define ERROR_ZERO_DIVIDE -35
#define ERROR_UNKNOWN_COMMAND -36
#define ERROR_WRONG_JUMP -37
#define ERROR_NOT_INITIALIZED_ARRAY -38
#define ERROR_DLL_CALLS_NOT_ALLOWED -39
#define ERROR_CANNOT_LOAD_LIBRARY -40
#define ERROR_CANNOT_CALL_FUNCTION -41
#define ERROR_EXTERNAL_CALLS_NOT_ALLOWED -42
#define ERROR_NO_MEMORY_FOR_RETURNED_STR -43
#define ERROR_SYSTEM_BUSY -44
#define ERROR_DLLFUNC_CRITICALERROR -45
#define ERROR_INTERNAL_ERROR -46
#define ERROR_OUT_OF_MEMORY -47
#define ERROR_INVALID_POINTER -48
#define ERROR_FORMAT_TOO_MANY_FORMATTERS -49
#define ERROR_FORMAT_TOO_MANY_PARAMETERS -50
#define ERROR_ARRAY_INVALID -51
#define ERROR_CHART_NOREPLY -52
#define ERROR_INVALID_FUNCTION_PARAMSCNT -53
#define ERROR_INVALID_FUNCTION_PARAMVALUE -54
#define ERROR_STRING_FUNCTION_INTERNAL -55
#define ERROR_SOME_ARRAY_ERROR -56
#define ERROR_INCORRECT_SERIESARRAY_USING -57
#define ERROR_CUSTOM_INDICATOR_ERROR -58
#define ERROR_INCOMPATIBLE_ARRAYS -59
#define ERROR_GLOBAL_VARIABLES_PROCESSING -60
#define ERROR_GLOBAL_VARIABLE_NOT_FOUND -61
#define ERROR_FUNC_NOT_ALLOWED_IN_TESTING -62
#define ERROR_FUNCTION_NOT_CONFIRMED -63
#define ERROR_SEND_MAIL_ERROR -64
#define ERROR_STRING_PARAMETER_EXPECTED -65
#define ERROR_INTEGER_PARAMETER_EXPECTED -66
#define ERROR_DOUBLE_PARAMETER_EXPECTED -67
#define ERROR_ARRAY_AS_PARAMETER_EXPECTED -68
#define ERROR_TRADE_ERROR -69
#define ERROR_RESOURCE_NOT_FOUND -70
#define ERROR_RESOURCE_NOT_SUPPORTED -71
#define ERROR_RESOURCE_DUPLICATED -72
#define ERROR_INDICATOR_CANNOT_INIT -73
#define ERROR_INDICATOR_CANNOT_LOAD -74
#define ERROR_NO_HISTORY_DATA -75
#define ERROR_NO_MEMORY_FOR_HISTORY -76
#define ERROR_END_OF_FILE -77
#define ERROR_SOME_FILE_ERROR -78
#define ERROR_WRONG_FILE_NAME -79
#define ERROR_TOO_MANY_OPENED_FILES -80
#define ERROR_CANNOT_OPEN_FILE -81
#define ERROR_INCOMPATIBLE_FILEACCESS -82
#define ERROR_NO_ORDER_SELECTED -83
#define ERROR_UNKNOWN_SYMBOL -84
#define ERROR_INVALID_PRICE_PARAM -85
#define ERROR_INVALID_TICKET -86
#define ERROR_TRADE_NOT_ALLOWED -87
#define ERROR_LONGS_NOT_ALLOWED -88
#define ERROR_SHORTS_NOT_ALLOWED -89
#define ERROR_TRADE_EXPERT_DISABLED_BY_SERVER -90
#define ERROR_OBJECT_ALREADY_EXISTS -91
#define ERROR_UNKNOWN_OBJECT_PROPERTY -92
#define ERROR_OBJECT_DOES_NOT_EXIST -93
#define ERROR_UNKNOWN_OBJECT_TYPE -94
#define ERROR_NO_OBJECT_NAME -95
#define ERROR_OBJECT_COORDINATES_ERROR -96
#define ERROR_NO_SPECIFIED_SUBWINDOW -97
#define ERROR_SOME_OBJECT_ERROR -98
#define ERROR_CHART_PROP_INVALID -99
#define ERROR_CHART_NOT_FOUND -100
#define ERROR_CHARTWINDOW_NOT_FOUND -101
#define ERROR_CHARTINDICATOR_NOT_FOUND -102
#define ERROR_SYMBOL_SELECT -103
#define ERROR_NOTIFICATION_ERROR -104
#define ERROR_NOTIFICATION_PARAMETER -105
#define ERROR_NOTIFICATION_SETTINGS -106
#define ERROR_NOTIFICATION_TOO_FREQUENT -107
#define ERROR_FILE_TOO_MANY_OPENED -108
#define ERROR_FILE_WRONG_FILENAME -109
#define ERROR_FILE_TOO_LONG_FILENAME -110
#define ERROR_FILE_CANNOT_OPEN -111
#define ERROR_FILE_BUFFER_ALLOCATION_ERROR -112
#define ERROR_FILE_CANNOT_DELETE -113
#define ERROR_FILE_INVALID_HANDLE -114
#define ERROR_FILE_WRONG_HANDLE -115
#define ERROR_FILE_NOT_TOREAD -116
#define ERROR_FILE_NOT_BIN -117
#define ERROR_FILE_NOT_TXT -118
#define ERROR_FILE_NOT_TXTORCSV -119
#define ERROR_FILE_NOT_CSV -120
#define ERROR_FILE_READ_ERROR -121
#define ERROR_FILE_WRITE_ERROR -122
#define ERROR_FILE_BIN_STRINGSIZE -123
#define ERROR_FILE_INCOMPATIBLE -124
#define ERROR_FILE_IS_DIRECTORY -125
#define ERROR_FILE_NOT_EXIST -126
#define ERROR_FILE_CANNOT_REWRITE -127
#define ERROR_FILE_WRONG_DIRECTORYNAME -128
#define ERROR_FILE_DIRECTORY_NOT_EXIST -129
#define ERROR_FILE_NOT_DIRECTORY -130
#define ERROR_FILE_CANNOT_DELETE_DIRECTORY -131
#define ERROR_FILE_CANNOT_CLEAN_DIRECTORY -132
#define ERROR_FILE_STRINGRESIZE_ERROR -133
#define ERROR_FILE_STRUCT_WITH_OBJECTS -134
#define ERROR_WEBREQUEST_INVALID_ADDRESS -135
#define ERROR_WEBREQUEST_CONNECT_FAILED -136
#define ERROR_WEBREQUEST_TIMEOUT -137
#define ERROR_WEBREQUEST_REQUEST_FAILED -138
#define ERROR_HISTORY_WILL_UPDATED -139
#define ERROR_FILE_NOT_TOWRITE -140

#endif
#ifndef FRAMEWORK_KERNEL_ACCOUNT_MQH
#define FRAMEWORK_KERNEL_ACCOUNT_MQH

class kernel_account {
public:
	static string company() {
		return AccountInfoString ( ACCOUNT_COMPANY );
	}

	static string server() {
		return AccountInfoString ( ACCOUNT_SERVER );
	}

	static int stopout_level() {
		return AccountInfoDouble ( ACCOUNT_MARGIN_SO_SO );
	}

	static int stopout_mode() {
		return AccountInfoInteger ( ACCOUNT_MARGIN_SO_MODE );
	}

	static double balance() {
		return AccountInfoDouble ( ACCOUNT_BALANCE );
	}

	static double equity() {
		return AccountInfoDouble ( ACCOUNT_EQUITY );
	}

	static long number() {
		return AccountInfoInteger ( ACCOUNT_LOGIN );
	}

	static string currency() {
		return AccountInfoString ( ACCOUNT_CURRENCY );
	}

	static bool is_testing() {
		return MQLInfoInteger ( ( int ) MQL5_TESTING );
	}

	static bool is_optimization() {
		return MQLInfoInteger ( ( int ) MQL5_OPTIMIZATION );
	}

	static bool is_trade_allowed() {
		return MQLInfoInteger ( ( int ) MQL5_TRADE_ALLOWED );
	}

	static int digits() {
		return _Digits;
	}

	static double free_margin() {
		return AccountInfoDouble ( ACCOUNT_MARGIN_FREE );
	}

	static double free_margin_check ( string symbol,
									  enum_order_operation_type order_type,
									  double lot ) {
		return -1;
	}

	static int leverage() {
		return AccountInfoInteger ( ACCOUNT_LEVERAGE );
	}
};

#endif
#ifndef FRAMEWORK_KERNEL_ORDER_MQH
#define FRAMEWORK_KERNEL_ORDER_MQH

ulong _kernel_order_current_ticket = -255;

class kernel_order {
public:
	static int count() {
		return HistoryOrdersTotal();
	}

	static int count_history() {
		return HistoryOrdersTotal();
	}

	static bool select_by_index ( int index ) {
		return ( _kernel_order_current_ticket = HistoryOrderGetTicket ( index ) ) > 0
			   && PositionSelectByTicket ( position_id() );
	}

	static bool select_by_ticket ( int ticket ) {
		_kernel_order_current_ticket = ticket;
		Print ( StringFormat ( "Pos %d", position_id() ) );


		return ( _kernel_order_current_ticket = ticket ) > 0
			   && PositionSelectByTicket ( position_id() );
	}

	static bool select_by_index_history ( int index ) {
		return ( _kernel_order_current_ticket = HistoryOrderGetTicket ( index ) ) > 0;
	}

	static bool select_by_ticket_history ( int ticket ) {
		return HistoryOrderSelect ( _kernel_order_current_ticket = ticket );
	}

	static int send ( int magic_number,
					  enum_order_operation_type order_type,
					  double price,
					  double lot,
					  int slippage,
					  string comment,
					  color col ) {
		MqlTradeRequest request;
		request.action = TRADE_ACTION_DEAL;
		request.magic = magic_number;
		request.order = 0;
		request.symbol = CURRENT_SYMBOL;
		request.volume = lot;
		request.price = price;
		request.stoplimit = 0.0;
		request.sl = 0.0;
		request.tp = 0.0;
		request.deviation = slippage;
		request.type = convert_order_operation_type ( order_type );
		request.type_filling = ORDER_FILLING_FOK;
		request.type_time = ORDER_TIME_GTC;
		request.expiration = 0;
		request.comment = comment;
		request.position = 0;
		request.position_by = 0;

		MqlTradeResult  result;

		if ( OrderSend ( request, result ) ) {
			if ( result.retcode == TRADE_RETCODE_DONE ) {
				return result.order;
			}

			Print ( StringFormat ( "RetCode %d", result.retcode ) );
		}

		return -1;
	}

	static int send_stop ( int magic_number,
						   enum_order_operation_type order_stop_type,
						   double price,
						   double lot,
						   string comment,
						   color col ) {
		return -1;
	}

	static bool set_price ( int ticket,
							double price,
							color order_color ) {
		return false;
	}

	static bool delete_stop ( int ticket,
							  color order_color ) {
		MqlTradeRequest request;
		request.action = TRADE_ACTION_REMOVE;
		request.order = ticket;

		MqlTradeResult  result;
		return OrderSend ( request, result );
	}

	static bool close ( int ticket,
						double lot,
						double price_close,
						double slippage,
						color order_color ) {
		return false;
	}

	static bool set_tp ( int magic_number,
						 int ticket,
						 double tp ) {
		MqlTradeRequest request;
		request.action = TRADE_ACTION_SLTP;
		request.symbol = CURRENT_SYMBOL;
		request.order = ticket;
		request.tp = tp;
		request.sl = 0.0;
		request.magic = magic_number;

		MqlTradeResult  result;
		return OrderSend ( request, result );
	}

	static bool set_sl_tp ( int ticket,
							double sl,
							double tp ) {
		MqlTradeRequest request;
		request.action = TRADE_ACTION_SLTP;
		request.order = ticket;
		request.sl = sl;
		request.tp = tp;

		MqlTradeResult  result;
		return OrderSend ( request, result );
	}

	static bool set_sl_tp_price ( int ticket,
								  double sl,
								  double tp,
								  double price ) {
		MqlTradeRequest request;
		request.action = TRADE_ACTION_MODIFY;
		request.order = ticket;
		request.price = price;
		request.sl = sl;
		request.tp = tp;

		MqlTradeResult  result;
		return OrderSend ( request, result );
	}

	static string symbol() {
		return HistoryOrderGetString ( _kernel_order_current_ticket, ORDER_SYMBOL );
	}

	static long magic_number() {
		return HistoryOrderGetInteger ( _kernel_order_current_ticket, ORDER_MAGIC );
	}

	static enum_order_operation_type type() {
		return convert_to_order_operation_type ( ( ENUM_ORDER_TYPE ) HistoryOrderGetInteger ( _kernel_order_current_ticket, ORDER_TYPE ) );
	}

	static ulong ticket() {
		return _kernel_order_current_ticket;
	}

	static double lots() {
		return HistoryOrderGetDouble ( _kernel_order_current_ticket, ORDER_VOLUME_INITIAL );
	}

	static double open_price() {
		return HistoryOrderGetDouble ( _kernel_order_current_ticket, ORDER_PRICE_OPEN );
	}

	static double take_profit() {
		return HistoryOrderGetDouble ( _kernel_order_current_ticket, ORDER_TP );
	}

	static double stop_loss() {
		return HistoryOrderGetDouble ( _kernel_order_current_ticket, ORDER_SL );
	}

	static double commission() {
		return 0.0;
	}

	static double swap() {
		return 0.0;
	}

	static datetime open_time() {
		return HistoryOrderGetInteger ( _kernel_order_current_ticket, ORDER_TIME_SETUP );
	}

	static datetime close_time() {
		return HistoryOrderGetInteger ( _kernel_order_current_ticket, ORDER_TIME_DONE );
	}

	static int position_id() {
		return HistoryOrderGetInteger ( _kernel_order_current_ticket, ORDER_POSITION_ID );
	}

private:
	static enum_order_operation_type convert_to_order_operation_type ( ENUM_ORDER_TYPE type ) {
		switch ( type ) {
			case ORDER_TYPE_BUY:
				return order_operation_buy;

			case ORDER_TYPE_SELL:
				return order_operation_sell;

			case ORDER_TYPE_BUY_STOP:
				return order_operation_buy_stop;

			case ORDER_TYPE_BUY_LIMIT:
				return order_operation_buy_limit;

			case ORDER_TYPE_SELL_STOP:
				return order_operation_sell_stop;

			case ORDER_TYPE_SELL_LIMIT:
				return order_operatione_sell_limit;

			default:
				return order_operation_none;
		}
	}

	static ENUM_ORDER_TYPE convert_order_operation_type ( enum_order_operation_type type ) {
		switch ( type ) {
			case order_operation_buy:
				return ORDER_TYPE_BUY;

			case order_operation_sell:
				return ORDER_TYPE_SELL;

			case order_operation_buy_stop:
				return ORDER_TYPE_BUY_STOP;

			case order_operation_buy_limit:
				return ORDER_TYPE_BUY_LIMIT;

			case order_operation_sell_stop:
				return ORDER_TYPE_SELL_STOP;

			case order_operatione_sell_limit:
				return ORDER_TYPE_SELL_LIMIT;

			case order_operation_none:
			default:
				return -1;
		}
	}
};

#endif
#ifndef FRAMEWORK_KERNEL_MARKET_MQH
#define FRAMEWORK_KERNEL_MARKET_MQH

class kernel_market {
public:
	static double price_buy ( string symbol ) {
		MqlTick last_tick;
		SymbolInfoTick ( symbol, last_tick );
		return last_tick.ask;
	}

	static double price_sell ( string symbol ) {
		MqlTick last_tick;
		SymbolInfoTick ( symbol, last_tick );
		return last_tick.bid;
	}

	static double price_day_min ( string symbol ) {
		return SymbolInfoDouble ( symbol, SYMBOL_LASTLOW );
	}

	static double price_day_min ( ) {
		return price_day_min ( CURRENT_SYMBOL );
	}

	static double price_day_max ( string symbol ) {
		return SymbolInfoDouble ( symbol, SYMBOL_LASTHIGH );
	}

	static double price_day_max ( ) {
		return price_day_max ( CURRENT_SYMBOL );
	}

	static double tick_value ( string symbol ) {
		return SymbolInfoDouble ( symbol, SYMBOL_TRADE_TICK_VALUE );
	}

	static double tick_value () {
		return tick_value ( CURRENT_SYMBOL );
	}

	static double tick_size ( string symbol ) {
		return SymbolInfoDouble ( symbol, SYMBOL_TRADE_TICK_SIZE );
	}

	static double tick_size () {
		return tick_size ( CURRENT_SYMBOL );
	}

	static datetime tick_last_time ( string symbol ) {
		return SymbolInfoInteger ( symbol, SYMBOL_TIME );
	}

	static datetime tick_last_time () {
		return tick_last_time ( CURRENT_SYMBOL );
	}

	static double lot_min ( string symbol ) {
		return SymbolInfoDouble ( symbol, SYMBOL_VOLUME_MIN );
	}

	static double lot_min () {
		return lot_min ( CURRENT_SYMBOL );
	}

	static double lot_size ( string symbol ) {
		return SymbolInfoDouble ( symbol, SYMBOL_TRADE_CONTRACT_SIZE );
	}

	static double lot_size () {
		return lot_size ( CURRENT_SYMBOL );
	}

	static double lot_step ( string symbol ) {
		return SymbolInfoDouble ( symbol, SYMBOL_VOLUME_STEP );
	}

	static double lot_step () {
		return lot_size ( CURRENT_SYMBOL );
	}

	static double lot_max ( string symbol ) {
		return SymbolInfoDouble ( symbol, SYMBOL_VOLUME_MAX );
	}

	static double lot_max () {
		return lot_max ( CURRENT_SYMBOL );
	}

	static enum_swap_type swap_type ( string symbol ) {
		return ( enum_swap_type ) SymbolInfoInteger ( symbol, SYMBOL_SWAP_MODE );
	}

	static enum_swap_type swap_type () {
		return swap_type ( CURRENT_SYMBOL );
	}

	static double swap_long ( string symbol ) {
		return SymbolInfoDouble ( symbol, SYMBOL_SWAP_LONG );
	}

	static double swap_long ( ) {
		return swap_long ( CURRENT_SYMBOL );
	}

	static double swap_short ( string symbol ) {
		return SymbolInfoDouble ( symbol, SYMBOL_SWAP_SHORT );
	}

	static double swap_short ( ) {
		return swap_short ( CURRENT_SYMBOL );
	}

	static enum_margin_calc_type margin_calc_type ( string symbol ) {
		return margin_calc_type_forex;
	}

	static enum_margin_calc_type margin_calc_type () {
		return margin_calc_type_forex;
	}

	static double margin_required ( string symbol ) {
		double result = -255;
		double request_result = OrderCalcMargin ( ORDER_TYPE_BUY,
								symbol,
								1.0,
								price_buy ( symbol ),
								result );

		if ( !request_result ) {
			Print ( StringFormat ( "%d", layer_error::get_last() ) );
		}

		return result;
	}

	static double margin_required ( ) {
		return 0.0;
	}

	static double margin_hedged ( string symbol ) {
		return SymbolInfoDouble ( symbol, SYMBOL_MARGIN_HEDGED );
	}

	static double margin_hedged (  ) {
		return SymbolInfoDouble ( CURRENT_SYMBOL, SYMBOL_MARGIN_HEDGED );
	}

	static double margin_maintenance ( string symbol ) {
		return SymbolInfoDouble ( symbol, SYMBOL_MARGIN_MAINTENANCE );
	}

	static double margin_maintenance () {
		return SymbolInfoDouble ( CURRENT_SYMBOL, SYMBOL_MARGIN_MAINTENANCE );
	}

	static double margin_init ( string symbol ) {
		return SymbolInfoDouble ( symbol, SYMBOL_MARGIN_INITIAL );
	}

	static double margin_init () {
		return SymbolInfoDouble ( CURRENT_SYMBOL, SYMBOL_MARGIN_INITIAL );
	}

	static double point ( string symbol ) {
		return SymbolInfoDouble ( symbol, SYMBOL_POINT );
	}

	static double point () {
		return point ( CURRENT_SYMBOL );
	}

	static datetime starting ( string symbol ) {
		return 0;
	}

	static datetime starting ( ) {
		return 0;
	}

	static datetime expiration ( string symbol ) {
		return 0;
	}

	static datetime expiration () {
		return 0;
	}

	static bool trade_allowed ( string symbol ) {
		return false;
	}

	static bool trade_allowed () {
		return false;
	}

	static double stop_level ( string symbol ) {
		return SymbolInfoInteger ( symbol, SYMBOL_TRADE_STOPS_LEVEL );
	}

	static double stop_level () {
		return stop_level ( CURRENT_SYMBOL );
	}

	static double freeze_level ( string symbol ) {
		return SymbolInfoInteger ( symbol, SYMBOL_TRADE_FREEZE_LEVEL );
	}

	static double freeze_level () {
		return freeze_level ( CURRENT_SYMBOL );
	}

	static int spread ( string symbol ) {
		return SymbolInfoInteger ( symbol, SYMBOL_SPREAD );
	}

	static int spread () {
		return spread ( CURRENT_SYMBOL );
	}

	static int digits ( string symbol ) {
		return SymbolInfoInteger ( symbol, SYMBOL_DIGITS );
	}

	static int digits () {
		return digits ( CURRENT_SYMBOL );
	}

	static enum_profit_calc_type profit_calc_type ( string symbol ) {
		return ( enum_profit_calc_type ) SymbolInfoInteger ( symbol, SYMBOL_TRADE_CALC_MODE );
	}

	static enum_profit_calc_type profit_calc_type () {
		return profit_calc_type ( CURRENT_SYMBOL );
	}
};

#endif
#ifndef FRAMEWORK_KERNEL_SYMBOL_MQH
#define FRAMEWORK_KERNEL_SYMBOL_MQH

class kernel_symbol {
public:
	static enum_trade_mode_type trade_mode ( string symbol ) {
		return ( enum_trade_mode_type ) SymbolInfoInteger ( symbol, SYMBOL_TRADE_MODE );
	}

	/*
	    static trade_mode_type trade_mode() {
		return trade_mode ( CURRENT_SYMBOL );
	    }
	*/

	static string currency_base ( string symbol ) {
		return SymbolInfoString ( symbol, SYMBOL_CURRENCY_BASE );
	}

	/*
	    static string currency_base ( ){
		return SymbolInfoString ( CURRENT_SYMBOL, SYMBOL_CURRENCY_BASE );
	    }
	*/

	static string currency_profit ( string symbol ) {
		return SymbolInfoString ( symbol, SYMBOL_CURRENCY_PROFIT );
	}

	/*
	    static string currency_profit ( ){
		return SymbolInfoString ( CURRENT_SYMBOL, SYMBOL_CURRENCY_PROFIT );
	    }
	*/
};

#endif
#ifndef FRAMEWORK_KERNEL_QUOTES_MQH
#define FRAMEWORK_KERNEL_QUOTES_MQH

class kernel_quotes {
public:
	static double get_candle_value ( string symbol,
									 ENUM_TIMEFRAMES time_frame,
									 enum_candle_value_type type,
									 int shift ) {
		switch ( type ) {
			case candle_value_low: {
				double result[];
				return CopyLow ( symbol, TFMigrate ( time_frame ), shift, 1, result ) > 0 ? result[0] : -1;
			}

			case candle_value_close: {
				double result[];
				return CopyClose ( symbol, TFMigrate ( time_frame ), shift, 1, result ) > 0 ? result[0] : -1;
			}

			case candle_value_open: {
				double result[];
				return CopyOpen ( symbol, TFMigrate ( time_frame ), shift, 1, result ) > 0 ? result[0] : -1;
			}

			case candle_value_high: {
				double result[];
				return CopyHigh ( symbol, TFMigrate ( time_frame ), shift, 1, result ) > 0 ? result[0] : -1;
			}

			default:
				return -1;
		}
	}

	static datetime get_candle_open_time ( string symbol,
										   ENUM_TIMEFRAMES time_frame,
										   int shift ) {
		long result[];
		return CopyTime ( symbol, TFMigrate ( time_frame ), shift, 1, result ) > 0 ? result[0] : -1;
	}

private:
	static ENUM_TIMEFRAMES TFMigrate ( int time_frame ) {
		switch ( time_frame ) {
			case 0:
				return ( PERIOD_CURRENT );

			case 1:
				return ( PERIOD_M1 );

			case 5:
				return ( PERIOD_M5 );

			case 15:
				return ( PERIOD_M15 );

			case 30:
				return ( PERIOD_M30 );

			case 60:
				return ( PERIOD_H1 );

			case 240:
				return ( PERIOD_H4 );

			case 1440:
				return ( PERIOD_D1 );

			case 10080:
				return ( PERIOD_W1 );

			case 43200:
				return ( PERIOD_MN1 );

			case 2:
				return ( PERIOD_M2 );

			case 3:
				return ( PERIOD_M3 );

			case 4:
				return ( PERIOD_M4 );

			case 6:
				return ( PERIOD_M6 );

			case 10:
				return ( PERIOD_M10 );

			case 12:
				return ( PERIOD_M12 );

			case 16385:
				return ( PERIOD_H1 );

			case 16386:
				return ( PERIOD_H2 );

			case 16387:
				return ( PERIOD_H3 );

			case 16388:
				return ( PERIOD_H4 );

			case 16390:
				return ( PERIOD_H6 );

			case 16392:
				return ( PERIOD_H8 );

			case 16396:
				return ( PERIOD_H12 );

			case 16408:
				return ( PERIOD_D1 );

			case 32769:
				return ( PERIOD_W1 );

			case 49153:
				return ( PERIOD_MN1 );

			default:
				return ( PERIOD_CURRENT );
		}
	}
};

#endif
#endif

#endif
#ifndef FRAMEWORK_LAYER_MQH
#define FRAMEWORK_LAYER_MQH

#ifndef FRAMEWORK_LAYER_ERROR_MQH
#define FRAMEWORK_LAYER_ERROR_MQH

int _layer_error_last;

class layer_error {
public:
	static void reset() {
		_layer_error_last = -1;
	}

	static int get_last() {
		return _layer_error_last = GetLastError();
	}

	static int get_last_saved() {
		return _layer_error_last;
	}

	static string get_last_saved_string() {
		return error_get_last ( get_last_saved() );
	}
};

#endif
#ifndef FRAMEWORK_LAYER_SYMBOL_MQH
#define FRAMEWORK_LAYER_SYMBOL_MQH

class layer_symbol {
public:
	static enum_trade_mode_type trade_mode ( string symbol ) {
		TOOL_CACHED_TICK_TESTING ( enum_trade_mode_type,
								   _trade_mode,
								   _trade_mode = kernel_symbol::trade_mode ( symbol ) );
	}
};

#endif
#ifndef FRAMEWORK_LAYER_MARKET_MQH
#define FRAMEWORK_LAYER_MARKET_MQH

class layer_market {
public:
	static double lot_min() {
		TOOL_CACHED ( double,
					  _lot_min,
					  _lot_min = kernel_market::lot_min ( CURRENT_SYMBOL ) );
	}

	static double lot_max()  {
		TOOL_CACHED ( double,
					  _lot_max,
					  _lot_max = kernel_market::lot_max ( CURRENT_SYMBOL ) );
	}

	static double lot_size() {
		TOOL_CACHED ( double,
					  _lot_size,
					  _lot_size = kernel_market::lot_size ( CURRENT_SYMBOL ) );
	}

	static double lot_step() {
		TOOL_CACHED ( double,
					  _lot_step,
					  _lot_step = kernel_market::lot_step ( CURRENT_SYMBOL ) );
	}

	static double tick_value() {
		TOOL_CACHED ( double,
					  _tick_value,
					  _tick_value = kernel_market::tick_value ( CURRENT_SYMBOL ) );
	}

	static double tick_size() {
		TOOL_CACHED ( double,
					  _tick_size,
					  _tick_size = kernel_market::tick_size ( CURRENT_SYMBOL ) );
	}

	static double stop_level() {
		TOOL_CACHED ( double,
					  _stop_level,
					  _stop_level = kernel_market::stop_level ( CURRENT_SYMBOL ) );
	}

	static double margin_required() {
		TOOL_CACHED ( double,
					  _margin_required,
					  _margin_required = kernel_market::margin_required ( CURRENT_SYMBOL ) );
	}

	static double freeze_level ( ) {
		TOOL_CACHED ( double,
					  _freeze_level,
					  _freeze_level = kernel_market::freeze_level ( CURRENT_SYMBOL ) );
	}

	static int spread() {
		TOOL_CACHED_TICK ( int,
						   _spread,
						   _spread = kernel_market::spread ( CURRENT_SYMBOL ) );
	}

	static double point() {
		TOOL_CACHED ( double,
					  _point,
					  _point = kernel_market::point ( ) );
	}

	static double price_buy() {
		TOOL_CACHED_TICK ( double,
						   _price_buy,
						   _price_buy = kernel_market::price_buy ( CURRENT_SYMBOL ) );
	}

	static double price_sell() {
		TOOL_CACHED_TICK ( double,
						   _price_sell,
						   _price_sell = kernel_market::price_sell ( CURRENT_SYMBOL ) );
	}

	static double price_open ( enum_order_operation_type order_type ) {
		return order::is_buy_direction ( order_type ) ?
			   price_buy() :
			   price_sell();
	}

	static double price_close ( enum_order_operation_type order_type ) {
		return order::is_buy_direction ( order_type ) ?
			   price_sell() :
			   price_buy();
	}

	static double to_points ( double pips ) {
		return pips * layer_market::point();
	}

	static int to_pips ( double points ) {
		return ( int ) ( points / layer_market::point() );
	}

	static double price_for_point_per_lot () {
		return layer_market::tick_value ()
			   / layer_market::tick_size ();
	}

	static double min_distance_from_open_price_p ( string symbol, int max_spread ) {
		double result = layer_market::stop_level ();

		if ( result != 0.000000 ) {
			return layer_market::to_points ( result );
		}

		result = layer_market::freeze_level ();

		if ( result != 0.000000 ) {
			return layer_market::to_points ( result );
		}

		result = layer_market::spread () * 2;

		if ( result > max_spread ) {
			return layer_market::to_points ( result );
		}

		return layer_market::to_points ( max_spread );
	}

	static bool is_closed() {
		return layer_error::get_last_saved() == ERROR_MARKET_CLOSED;
	}
};

#endif
#ifndef FRAMEWORK_LAYER_ACCOUNT_MQH
#define FRAMEWORK_LAYER_ACCOUNT_MQH

class layer_account {
public:
	static string currency() {
		TOOL_CACHED ( string,
					  _currency,
					  _currency = kernel_account::currency() );
	}

	static bool is_trade_allowed() {
		TOOL_CACHED_TICK ( bool,
						   _is_trade_allowed,
						   _is_trade_allowed = kernel_account::is_trade_allowed() );
	}

	static bool is_testing() {
		TOOL_CACHED ( bool,
					  _is_testing,
					  _is_testing = kernel_account::is_testing() );
	}

	static bool is_optimization() {
		TOOL_CACHED ( bool,
					  _is_optimization,
					  _is_optimization = kernel_account::is_optimization() );
	}

	static int digits() {
		TOOL_CACHED ( int,
					  _digits,
					  _digits = kernel_account::digits() );
	}

	static int bit_multiplier() {
		TOOL_CACHED ( int,
					  _bit_multiplier,
					  _bit_multiplier = layer_account::digits() == 3 || layer_account::digits() == 5  ? 10 : 1 );
	}

	static double profit_clear_currency() {
		TOOL_CACHED_TICK ( double,
		_profit_currency, {
			_profit_currency = 0.0;

			list<layer_order_data *> *directions = layer_order::get_all();
			LIST_FOREACH ( directions, layer_order_data *, item, {
				_profit_currency += item.profit_clear_currency();
			} );
		} );
	}

	static double profit_clear_percent() {
		TOOL_CACHED_TICK ( double,
		_profit_percent, {
			_profit_percent = profit_clear_currency() / ( kernel_account::balance() / 100.0 ) ;
		} );
	}

	static double drawdown_currency() {
		return profit_clear_currency() * -1;
	}

	static double drawdown_percent() {
		return profit_clear_percent() * -1;
	}
};

#endif
#ifndef FRAMEWORK_LAYER_ORDER_MQH
#define FRAMEWORK_LAYER_ORDER_MQH

#ifndef FRAMEWORK_ORDER_MQH
#define FRAMEWORK_ORDER_MQH

class order : public disposable_obj {
public:
	string symbol;
	long magic_number;
	enum_order_operation_type order_type;
	int ticket;
	double lot;
	double open_price;
	double stop_loss;
	double take_profit;
	double commission;
	double swap;
	datetime open_time;
	datetime close_time;
	int lvl;

	void reset() {
		symbol = EXT_STRING_EMPTY;
		magic_number = 0;
		order_type = order_operation_none;
		ticket = 0;
		lot = 0.0000;
		open_price = 0.0000;
		stop_loss = 0.0000;
		take_profit = 0.0000;
		commission = 0.0000;
		swap = 0.0000;
		lvl = 0;
	}

	static bool is_buy_direction ( enum_order_operation_type order_type ) {
		return order_type == order_operation_buy
			   || order_type == order_operation_buy_limit
			   || order_type == order_operation_buy_stop;
	}

	static bool is_order ( enum_order_operation_type order_type ) {
		return order_type == order_operation_buy
			   || order_type == order_operation_sell;
	}

	static bool is_order_stop ( enum_order_operation_type order_type ) {
		return order_type == order_operation_buy_stop
			   || order_type == order_operation_sell_stop;
	}

	static bool is_order_limit ( enum_order_operation_type order_type ) {
		return order_type == order_operation_buy_limit
			   || order_type == order_operatione_sell_limit;
	}

	static double get_profit_in_currency ( enum_order_operation_type order_type,
										   double open_price,
										   double lot,
										   double at_price ) {
		return tool_order::get_distance ( order_type,
										  open_price,
										  at_price )
			   * layer_market::price_for_point_per_lot ()
			   * lot;
	}

	static double get_profit_in_currency ( enum_order_operation_type order_type,
										   double open_price,
										   double lot ) {
		return get_profit_in_currency ( order_type,
										open_price,
										lot,
										layer_market::price_close ( order_type ) );
	}

	static color get_order_color ( enum_order_operation_type type ) {
		return order::is_buy_direction ( type ) ? Blue : Red;
	}

	bool is_buy_direction () {
		return is_buy_direction ( order_type );
	}

	bool is_order() {
		return is_order ( order_type );
	}

	bool is_order_stop () {
		return is_order_stop ( order_type );
	}

	double get_price() {
		return layer_market::price_close ( order_type );
	}

	double get_profit_in_currency () {
		return get_profit_in_currency ( get_price() );
	}

	double get_profit_clear_currency () {
		return get_profit_in_currency ( get_price() ) + commission + swap;
	}

	double get_profit_in_currency ( double at_price ) {
		return get_profit_in_currency ( order_type,
										open_price,
										lot,
										at_price );
	}

	bool is_before_line ( double line ) {
		return tool_order::is_price_before_line ( order_type,
				open_price,
				line );
	}

	double get_distance_from_open_price ( double price ) {
		return tool_order::get_distance ( order_type,
										  open_price,
										  price );
	}
};

#endif
#ifndef FRAMEWORK_ORDER_COUNT_MQH
#define FRAMEWORK_ORDER_COUNT_MQH

class order_count_t : public disposable_obj {
private:
	int _order;
	int _stop;
	int _limit;
	int _all;

public:
	int order() {
		return _order;
	}

	int stop() {
		return _stop;
	}

	int limit() {
		return _limit;
	}

	int all() {
		return _all;
	}

	order_count_t() {
		clear();
	}

	void clear() {
		_order = 0;
		_stop = 0;
		_limit = 0;
		_all = 0;
	}

	void inc_by_type ( enum_order_operation_type type ) {
		_all += 1;

		if ( order::is_order ( type ) ) {
			_order += 1;
		} else if ( order::is_order_stop ( type ) ) {
			_stop += 1;
		}  else {
			_limit += 1;
		}
	}

	void deinc_by_type ( enum_order_operation_type type ) {
		_all -= 1;

		if ( order::is_order ( type ) ) {
			_order -= 1;
		} else if ( order::is_order_stop ( type ) ) {
			_stop -= 1;
		}  else {
			_limit -= 1;
		}
	}
};

#endif
#ifndef FRAMEWORK_ORDER_OPERATION_MQH
#define FRAMEWORK_ORDER_OPERATION_MQH

enum order_operation_type_t {
	order_operation_type_none,
	order_operation_type_close,
	order_operation_type_update,
	order_operation_type_set_tp,
	order_operation_type_set_sl_tp,
	order_operation_type_open,
	order_operation_type_set_sl_tp_price,
};

class order_operation : public disposable_obj {
public:
	bool is_completed;
	int error;
	order_operation_type_t operation_type;
	int magic_number;
	int ticket;
	int lvl;
	enum_order_operation_type order_type;
	double lot;
	double price;
	double step_p;
	double stop_loss;
	double take_profit;
	int slippage;
	string comment;

	order_operation *clone() {
		order_operation *result = new order_operation();
		result.is_completed = is_completed;
		result.error = error;
		result.operation_type = operation_type;
		result.magic_number = magic_number;
		result.ticket = ticket;
		result.lvl = lvl;
		result.order_type = order_type;
		result.lot = lot;
		result.price = price;
		result.step_p = step_p;
		result.stop_loss = stop_loss;
		result.take_profit = take_profit;
		result.slippage = slippage;
		result.comment = comment;
		return result;
	}

	void reset() {
		is_completed = false;
		error = 0;
		operation_type = order_operation_type_none;
		magic_number = 0;
		ticket = 0;
		lvl = 0;
		order_type = order_operation_none;
		lot = 0;
		price = 0;
		step_p = 0;
		stop_loss = 0;
		take_profit = 0;
		slippage = 0;
		comment = EXT_STRING_EMPTY;
	}

	bool is_order_stop () {
		return order::is_order_stop ( order_type );
	}

	bool process() {
		is_completed = false;
		color order_color = order::get_order_color ( order_type );

		switch ( operation_type ) {
			case order_operation_type_none:
				is_completed = true;
				break;

			case order_operation_type_close:
				is_completed = kernel_order::delete_stop ( ticket,
							   order_color );
				break;

			case order_operation_type_update:
				is_completed = kernel_order::set_sl_tp_price ( ticket,
							   stop_loss,
							   take_profit,
							   price );
				break;

			case order_operation_type_open: {
				/*
				    if ( !free_margin_check ( orders_count, price, normalized_lot ) <= 0.0 ) {
					return false
				    }
				*/

				int responce_ticket = kernel_order::send_stop ( magic_number,
									  order_type,
									  price,
									  lot,
									  comment,
									  order_color );

				is_completed = responce_ticket != -1;

				if ( is_completed ) {
					ticket = responce_ticket;
				}

				break;
			}
		}

		if ( !is_completed ) {
			error = layer_error::get_last();
		}

		return is_completed;
	}
};

#endif
#ifndef FRAMEWORK_ORDER_LAYER_SYMBOL_MQH
#define FRAMEWORK_ORDER_LAYER_SYMBOL_MQH

class order_symbol : public disposable_obj {
public:
	string full;
	bool contains_buy;
	bool contains_sell;

	TOOL_CACHED_INSTANCE ( string, base, _base = kernel_symbol::currency_base ( full ) )
	TOOL_CACHED_INSTANCE ( string, profit, _profit = kernel_symbol::currency_profit ( full ) )

	bool check_base ( bool need_buy_direction, order_symbol *check_symbol ) {
		return ( need_buy_direction
				 && ( ( contains_buy
						&& ext_string_equals ( check_symbol.base(), base(), false ) )
					  || ( contains_sell
						   &&  ext_string_equals ( check_symbol.base(), profit(), false ) ) ) )
			   || ( !need_buy_direction
					&& ( ( contains_sell
						   && ext_string_equals ( check_symbol.base(), base(), false ) )
						 || ( contains_buy
							  && ext_string_equals ( check_symbol.base(), profit(), false ) ) ) );
	}

	bool check_profit ( bool need_buy_direction, order_symbol *check_symbol ) {
		return ( need_buy_direction
				 && ( ( contains_buy
						&& ext_string_equals ( check_symbol.profit(), profit(), false ) )
					  || ( contains_sell
						   && ext_string_equals ( check_symbol.profit(), base(), false ) ) ) )
			   || ( !need_buy_direction
					&& ( ( contains_sell
						   && ext_string_equals ( check_symbol.profit(), profit(), false ) )
						 || ( contains_buy
							  && ext_string_equals ( check_symbol.profit(), base(), false ) ) ) );
	}

	void set_contains_direction ( bool is_buy_direction ) {
		if ( is_buy_direction ) {
			contains_buy = true;
		} else {
			contains_sell = true;
		}
	}

	void reset_direction() {
		contains_buy = false;
		contains_sell = false;
	}

	static order_symbol *create ( string symbol ) {
		order_symbol *result = new order_symbol();
		result.full = symbol;
		return result;
	}
};

#endif
#ifndef FRAMEWORK_LAYER_ORDER_SETTING_MQH
#define FRAMEWORK_LAYER_ORDER_SETTING_MQH

class layer_order_setting : public disposable_obj {
public:
	int magic_number;
	enum_order_operation_type order_type;
	enum_order_operation_type order_stop_type;
	bool is_buy_direction;
	int max_orders;
	int max_trade_pairs;
	int currency_block;

	static layer_order_setting *create ( int max_orders,
										 int magic_number,
										 enum_order_operation_type order_type,
										 enum_order_operation_type order_stop_type,
										 int max_trade_pairs,
										 int currency_block ) {
		layer_order_setting *result = new layer_order_setting();
		result.magic_number = magic_number;
		result.order_type = order_type;
		result.order_stop_type = order_stop_type;
		result.is_buy_direction = order::is_buy_direction ( order_type );
		result.max_orders = max_orders;
		result.max_trade_pairs = max_trade_pairs;
		result.currency_block = currency_block;
		return result;
	}
};

#endif
#ifndef FRAMEWORK_LAYER_ORDER_DATA_MQH
#define FRAMEWORK_LAYER_ORDER_DATA_MQH

class layer_order_data : public disposable_obj {
public:
	layer_order_setting *settings;
	bool is_buy_direction;
	list<order *> *orders;
	order *min_order;
	order *max_order;
	bool is_sorted;
	order_count_t *count;

	~layer_order_data() {
		GC_DISPOSE_IF ( settings );
		GC_DISPOSE_IF ( orders );
		GC_DISPOSE_IF ( min_order );
		GC_DISPOSE_IF ( max_order );
		GC_DISPOSE_IF ( count );
	}

	void set ( layer_order_setting *in_settings ) {
		settings = in_settings;
		is_buy_direction = order::is_buy_direction ( in_settings.order_type );
		orders = new list<order *> ( in_settings.max_orders );
		min_order = NULL;
		max_order = NULL;
		is_sorted = false;
		count = new order_count_t();
	}

	void reset() {
		min_order = NULL;
		max_order = NULL;
		is_sorted = false;

		orders.clear_without_dispoce();
		count.clear();
	}

	TOOL_CACHED_INSTANCE_TICK ( double,
	profit_clear_currency, {
		_profit_clear_currency = 0.0;
		LIST_FOREACH ( orders, order *, item,

					   if ( item.is_order() )
					   _profit_clear_currency += item.get_profit_clear_currency()
					 );
	} );

	double drawdown_currency() {
		return profit_clear_currency() * -1;
	}
};

#endif

list<layer_order_data *> *order_layer_orders;
list<order_symbol *> *order_layer_symbols;

#ifdef FOR_OPTIMIZATION
#define LAYER_ORDER_CHECK_SYMBOL(sym) true
#define LAYER_ORDER_CHECK_MAGIC(mag) true
#else
#define LAYER_ORDER_CHECK_SYMBOL(sym) (kernel_order::symbol() == sym)
#define LAYER_ORDER_CHECK_MAGIC(mag) (kernel_order::magic_number() == mag)
#endif

#define LAYER_ORDER_CHECK_TYPE(order_type, order_stop_type) (kernel_order::type() == order_type || kernel_order::type() == order_stop_type)

class layer_order {
public:
	static void init() {
		order_layer_orders = new list<layer_order_data *> ( 2 );
		order_layer_orders.add ( new layer_order_data() );
		order_layer_orders.add ( new layer_order_data() );
		gc::push ( gc_dispose_type_on_end_deinit, order_layer_orders );
	}

	static order_symbol *get_order_layer_symbol_current_symbol() {
		TOOL_CACHED ( order_symbol *,
		_order_layer_symbol_current_symbol, {
			_order_layer_symbol_current_symbol = order_symbol::create ( Symbol() );
			gc::push ( gc_dispose_type_on_end_deinit, _order_layer_symbol_current_symbol );
		} );
	}

	static void push_settings ( layer_order_setting *settings_ptr ) {
		get_by_setting ( settings_ptr ).set ( settings_ptr );

		if ( settings_ptr.max_trade_pairs != 0
				|| settings_ptr.currency_block != 0 ) {
			ACTION_ON_NONVALUE_OR_DEFAULT ( order_layer_symbols, order_layer_symbols = new list<order_symbol *>() );
		}
	}

	static void refresh_all() {
		get_order_layer_symbol_current_symbol().reset_direction();
		ACTION_ON_VALUE_OR_DEFAULT ( order_layer_symbols, order_layer_symbols.clear() );
		LIST_FOREACH ( order_layer_orders, layer_order_data *, item, item.reset() );

		int magic_number = order_layer_orders.items[0].settings.magic_number;
		int ordersCount = kernel_order::count();

		for ( int i = 0; i < ordersCount; i++ ) {
			if ( !kernel_order::select_by_index ( i ) ) {
				continue;
			}

			if ( !LAYER_ORDER_CHECK_SYMBOL ( CURRENT_SYMBOL ) ) {
				if ( GC_CHECK_PTR ( order_layer_symbols ) ) {
					string symbol = kernel_order::symbol();
					LIST_FIRST_OR_DEFAULT ( order_layer_symbols, found_symbol, order_symbol *, item, item.full == symbol );

					if ( !GC_CHECK_PTR ( found_symbol ) ) {
						found_symbol = order_symbol::create ( symbol );
						order_layer_symbols.add ( found_symbol );
					}

					found_symbol.set_contains_direction ( order::is_buy_direction ( kernel_order::type() ) );
				}

				continue;
			}

			if ( !LAYER_ORDER_CHECK_MAGIC ( magic_number ) ) {
				continue;
			}

			LIST_FOREACH ( order_layer_orders, layer_order_data *, item, {
				if ( !LAYER_ORDER_CHECK_TYPE ( item.settings.order_type, item.settings.order_stop_type ) ) {
					continue;
				}

				order *for_add = factory_order::get();
				refresh_order ( for_add );

				if ( !GC_CHECK_PTR ( item.min_order )
						|| ( !item.is_buy_direction && for_add.open_price < item.min_order.open_price )
						|| ( item.is_buy_direction && for_add.open_price > item.min_order.open_price ) ) {
					item.min_order = for_add;
				}

				if ( !GC_CHECK_PTR ( item.max_order )
						|| ( !item.is_buy_direction && for_add.open_price > item.max_order.open_price )
						|| ( item.is_buy_direction && for_add.open_price < item.max_order.open_price ) ) {
					item.max_order = for_add;
				}

				item.orders.add ( for_add );
				item.count.inc_by_type ( for_add.order_type );

				ACTION_ON_VALUE_OR_DEFAULT ( order_layer_symbols, get_order_layer_symbol_current_symbol().set_contains_direction ( item.is_buy_direction ) );
				break;
			} );
		}
	}

	// Р’С‹Р·С‹РІР°РµС‚ РїРѕСЃР»Рµ СѓРґР°Р»РµРЅРёРµ РѕСЂРґРµСЂРѕРІ РЅР°РґРѕ Р±С‹ РєР°Рє С‚Рѕ СЌС‚Рѕ РѕР±С‹РіСЂР°С‚СЊ
	static void refresh ( layer_order_setting *settings_ptr ) {
		layer_order_data *pair = get_by_setting ( settings_ptr );

		pair.orders.clear_without_dispoce();
		pair.count.clear();

		int ordersCount = kernel_order::count();

		for ( int i = 0; i < ordersCount; i++ ) {
			if (  !kernel_order::select_by_index ( i )
					|| !LAYER_ORDER_CHECK_SYMBOL ( CURRENT_SYMBOL )
					|| !LAYER_ORDER_CHECK_MAGIC ( pair.settings.magic_number )
					|| !LAYER_ORDER_CHECK_TYPE ( pair.settings.order_type, pair.settings.order_stop_type ) ) {
				continue;
			}


			order *for_add = factory_order::get();
			refresh_order ( for_add );
			pair.orders.add ( for_add );
			pair.count.inc_by_type ( for_add.order_type );
		}
	}

	static void push ( layer_order_setting *settings_ptr, int ticket ) {
		if ( !kernel_order::select_by_ticket ( ticket ) ) {
			return;
		}

		layer_order_data *collection = get_by_setting ( settings_ptr );

		order *for_add = factory_order::get();
		refresh_order ( for_add );
		for_add.lvl = collection.orders.count + 1;

		collection.orders.add ( for_add );
		collection.max_order = for_add;
	}

	static void refresh ( layer_order_setting *settings_ptr, int ticket ) {
		if ( !kernel_order::select_by_ticket ( ticket )  ) {
			return;
		}

		list<order *> *orders = get ( settings_ptr );
		LIST_FIRST_OR_DEFAULT ( orders, result, order *, item, item.ticket == ticket );
		ACTION_ON_VALUE_OR_DEFAULT ( result, refresh_order ( result ) );
	}

	static list<order *> *get ( layer_order_setting *settings_ptr ) {
		layer_order_data *collection = get_by_setting ( settings_ptr );

		if ( !collection.is_sorted ) {
			collection.is_sorted = true;

			LIST_SORT_BUBBLE ( collection.orders,
							   open_price,
							   !collection.is_buy_direction );
			LIST_FOREACH2 ( collection.orders,
							order *,
							item,
							item.lvl = i_kdaskdgfgf + 1 );
		}

		return GET_VALUE_OR_DEFAULT ( collection, collection.orders );
	}

	static order_count_t *get_count ( layer_order_setting *settings_ptr ) {
		layer_order_data *collection = get_by_setting ( settings_ptr );
		return GET_VALUE_OR_DEFAULT ( collection, collection.count );
	}

	static order *get_min ( layer_order_setting *settings_ptr ) {
		layer_order_data *collection = get_by_setting ( settings_ptr );
		return GET_VALUE_OR_DEFAULT ( collection, collection.min_order );
	}

	static order *get_max ( layer_order_setting *settings_ptr ) {
		layer_order_data *collection = get_by_setting ( settings_ptr );
		return GET_VALUE_OR_DEFAULT ( collection, collection.max_order );
	}

	static int get_pair_count() {
		return GET_VALUE_OR_MANUAL ( order_layer_symbols, order_layer_symbols.count, 0 );
	}

	static int get_base_count ( bool is_buy_direction ) {
		if ( !GC_CHECK_PTR ( order_layer_symbols ) ) {
			return 0;
		}

		order_symbol *check_symbol = get_order_layer_symbol_current_symbol();
		LIST_COUNT ( order_layer_symbols,
					 result,
					 order_symbol *,
					 item,
					 item.check_base ( is_buy_direction, check_symbol ) );
		return result;
	}

	static int get_profit_count ( bool is_buy_direction  ) {
		if ( !GC_CHECK_PTR ( order_layer_symbols ) ) {
			return 0;
		}

		order_symbol *check_symbol = get_order_layer_symbol_current_symbol();
		LIST_COUNT ( order_layer_symbols,
					 result,
					 order_symbol *,
					 item,
					 item.check_profit ( is_buy_direction,  check_symbol  ) );
		return result;
	}

	static order *get_history_last_order ( layer_order_setting *settings_ptr ) {
		layer_order_data *pair = get_by_setting ( settings_ptr );

		for ( int i = kernel_order::count_history() - 1; i >= 0; i-- ) {
			if ( !kernel_order::select_by_index_history ( i )
					|| !LAYER_ORDER_CHECK_SYMBOL ( CURRENT_SYMBOL )
					|| !LAYER_ORDER_CHECK_MAGIC ( pair.settings.magic_number )
					|| !LAYER_ORDER_CHECK_TYPE ( pair.settings.order_type, pair.settings.order_stop_type ) ) {
				continue;
			}

			order *result = factory_order::get();
			refresh_order ( result );
			return result;
		}

		return NULL;
	}

	static bool close_all ( int magic_number,
							enum_order_operation_type order_type,
							enum_order_operation_type order_stop_type,
							int slippage ) {
		bool result = false;
		color order_color = order::get_order_color ( order_type );

		for ( int i = 0; i < 3 && !result; i++ ) {
			result = close_by_market ( magic_number,
									   order_type,
									   order_stop_type,
									   slippage,
									   order_color );
		}

		return result;
	}

	static bool close_by_market ( int magic_number,
								  enum_order_operation_type order_type,
								  enum_order_operation_type order_stop_type,
								  int slippage,
								  color order_color ) {
		for ( int i = kernel_order::count() - 1; i >= 0; i-- ) {
			if ( !kernel_order::select_by_index ( i ) ) {
				return false;
			}

			if ( !LAYER_ORDER_CHECK_SYMBOL ( CURRENT_SYMBOL )
					|| !LAYER_ORDER_CHECK_MAGIC ( magic_number )
					|| !LAYER_ORDER_CHECK_TYPE ( order_type, order_stop_type ) ) {
				continue;
			}

			log_info_k ( StringFormat ( SRC_ORDER_TRY_CLOSE_ORDER, IntegerToString ( kernel_order::ticket() ) ) );

			bool is_close = order::is_order_stop ( kernel_order::type() ) ?
							kernel_order::delete_stop ( kernel_order::ticket(), order_color ) :
							kernel_order::close ( kernel_order::ticket(),
												  kernel_order::lots(),
												  layer_market::price_close ( kernel_order::type() ),
												  slippage,
												  order_color );

			if ( !is_close ) {
				log_info_k ( SRC_ORDER_FAIL_CLOSE_ORDER );
				return false;
			}
		}

		return true;
	}

	static list<layer_order_data *> *get_all() {
		return order_layer_orders;
	}

	static layer_order_data *get_by_setting ( layer_order_setting *settings_ptr ) {
		return order_layer_orders.items[settings_ptr.order_type == order_operation_buy ? 0 : 1];
	}

private:

	static void refresh_order ( order *value ) {
		value.symbol = kernel_order::symbol();
		value.magic_number = kernel_order::magic_number();
		value.order_type = kernel_order::type();
		value.ticket = kernel_order::ticket();
		value.lot = kernel_order::lots();
		value.open_price = kernel_order::open_price();
		value.stop_loss = kernel_order::stop_loss();
		value.take_profit = kernel_order::take_profit();
		value.commission = kernel_order::commission();
		value.swap = kernel_order::swap();
		value.open_time = kernel_order::open_time();
		value.close_time = kernel_order::close_time();
	}
};

#endif

class layer {
public:
	static int account_leverage() {
		TOOL_CACHED_TICK ( int,
		_leverage, {
			double leverage_by_current_symbol = layer_market::tick_value ()
			* layer_market::price_buy()
			/ layer_market::margin_required ()
			/ layer_market::point();
			int casted_leverage = ( int ) MathFloor ( leverage_by_current_symbol );
			_leverage =  casted_leverage != 0 ? casted_leverage : kernel_account::leverage();
		} );
	}

	static datetime time_current() {
		TOOL_CACHED_TICK ( datetime,
						   _time_current,
						   _time_current = TimeCurrent() );
	}

	static double correct_price ( double value ) {
		return NormalizeDouble ( value, layer_account::digits() );
	}
};

#endif
#ifndef FRAMEWORK_TOOL_MQH
#define FRAMEWORK_TOOL_MQH

#ifndef FRAMEWORK_TOOL_CANDLE_MQH
#define FRAMEWORK_TOOL_CANDLE_MQH

enum candle_type {
	candle_type_bull,
	candle_type_bear,
	candle_type_zero
};

class tool_candle {
public:
	static candle_type get_candle_type ( double open_price, double close_price ) {
		if ( open_price < close_price ) {
			return candle_type_bull;
		} else if ( open_price > close_price ) {
			return candle_type_bear;
		}

		return candle_type_zero;
	}

	static candle_type get_candle_type ( string symbol, ENUM_TIMEFRAMES time_frame, int shift ) {
		return get_candle_type ( kernel_quotes::get_candle_value ( symbol, time_frame, candle_value_open, shift ),
								 kernel_quotes::get_candle_value ( symbol, time_frame, candle_value_close, shift ) );
	}

	static double get_candle_size ( double first, double second ) {
		return MathAbs ( first - second );
	}

	static double get_candle_size ( string symbol, ENUM_TIMEFRAMES time_frame, int shift ) {
		return get_candle_size ( kernel_quotes::get_candle_value ( symbol, time_frame, candle_value_high, shift ),
								 kernel_quotes::get_candle_value ( symbol, time_frame, candle_value_low, shift ) );
	}

	static int get_candle_size_p ( double first, double second ) {
		return layer_market::to_pips ( get_candle_size ( first, second ) );
	}

	static int get_candle_size_by_high_low_p ( string symbol, ENUM_TIMEFRAMES time_frame, int shift ) {
		return get_candle_size_p ( kernel_quotes::get_candle_value ( symbol, time_frame, candle_value_high, shift ),
								   kernel_quotes::get_candle_value ( symbol, time_frame, candle_value_low, shift ) );
	}

	static int get_candle_size_by_open_close_p ( string symbol, ENUM_TIMEFRAMES time_frame, int shift ) {
		return get_candle_size_p ( kernel_quotes::get_candle_value ( symbol, time_frame, candle_value_open, shift ),
								   kernel_quotes::get_candle_value ( symbol, time_frame, candle_value_close, shift ) );
	}

	static int get_merged_candle_size_by_high_low_p ( string symbol, ENUM_TIMEFRAMES time_frame, int first_shift, int end_shift ) {
		double low = kernel_quotes::get_candle_value ( symbol, time_frame, candle_value_low, end_shift );
		double high = kernel_quotes::get_candle_value ( symbol, time_frame, candle_value_high, end_shift );

		for ( int i = end_shift + 1; i <= first_shift; i++ ) {
			double low_check = kernel_quotes::get_candle_value ( symbol, time_frame, candle_value_low, i );
			double high_check = kernel_quotes::get_candle_value ( symbol, time_frame, candle_value_high, i );

			if ( low > low_check ) {
				low = low_check;
			}

			if ( high < high_check ) {
				high = high_check;
			}
		}

		return get_candle_size_p ( high, low );
	}

	static int get_merged_candle_size_by_open_close_p ( string symbol, ENUM_TIMEFRAMES time_frame, int first_shift, int end_shift ) {
		return get_candle_size_p ( kernel_quotes::get_candle_value ( symbol, time_frame, candle_value_open, first_shift ),
								   kernel_quotes::get_candle_value ( symbol, time_frame, candle_value_close, end_shift ) );
	}

	static datetime get_time ( string symbol, ENUM_TIMEFRAMES time_frame, int shift ) {
		return iTime ( symbol, time_frame, shift );
	}
};

#endif
#ifndef FRAMEWORK_TOOL_PRICE_MQH
#define FRAMEWORK_TOOL_PRICE_MQH

class tool_price {
public:
	static double get_sign ( double value ) {
		return value >= 0.000000 ? 1 : -1;
	}

	static double add_by_direction ( double start_direction, double value, double end_direction ) {
		return start_direction + ( get_sign ( end_direction - start_direction ) * value );
	}

	static double add_by_order_type_direction ( enum_order_operation_type order_type, double base, double value ) {
		return order::is_buy_direction ( order_type ) ?
			   base - value :
			   base + value;
	}

	static double deduct_by_order_type_direction ( enum_order_operation_type order_type, double base, double value ) {
		return order::is_buy_direction ( order_type ) ?
			   base + value :
			   base - value;
	}

	static double distance_by_type ( enum_order_operation_type order_type, double start, double end ) {
		return order::is_buy_direction ( order_type ) ?
			   start - end :
			   end - start;
	}
};

#endif
#ifndef FRAMEWORK_TOOL_MARGIN_MQH
#define FRAMEWORK_TOOL_MARGIN_MQH

class tool_margin {
private:
	static bool can_calc_margin ( string symbol ) {
		string account_currency = layer_account::currency();

		// РќР° РґР°РЅРЅС‹Р№ РјРѕРјРµРЅС‚ СЂР°Р±РѕС‚Р°РµРј С‚РѕР»СЊРєРѕ СЃ USD
		if ( account_currency != "USD" ) {
			return false;
		}

		// РЎРјРѕС‚СЂРёРј РґР°РЅРЅР°СЏ РїР°СЂР° СЃРѕСЃС‚РѕРёС‚ Р»Рё РёР· РІР°Р»СЋС‚С‹ СЃС‡РµС‚Р°
		return kernel_symbol::currency_base ( symbol ) == account_currency
			   || kernel_symbol::currency_profit ( symbol ) == account_currency;
	}

public:
	static double calc_margin ( layer_order_setting *order_settings,
								double before_line ) {
		list<order *> *orders = layer_order::get ( order_settings );
		LIST_SUM_EX ( orders, double result = 0.0, order *, item, {
			if ( !item.is_order_stop()
					|| !item.is_before_line ( before_line ) ) {
				continue;
			}

			double margin = calc_margin ( item.symbol, layer::account_leverage(), item.lot, item.open_price );
			result += margin;
			double profit = item.get_profit_in_currency();
			result -= profit;
		} );

		return result;
	}

	static double calc_margin ( string symbol, double leverage, double lot, double price ) {
		if ( !can_calc_margin ( symbol ) ) {
			return lot * layer_market::margin_required ();
		}

		bool is_left_currency = kernel_symbol::currency_base ( symbol ) == layer_account::currency();
		double price_for_lot = !is_left_currency ?
							   price * layer_market::lot_size () :
							   layer_market::lot_size ();
		return ( lot * price_for_lot ) / leverage;
	}
};

#endif
#ifndef FRAMEWORK_TOOL_ORDER_MQH
#define FRAMEWORK_TOOL_ORDER_MQH

class tool_order {
public:
	static double get_distance ( enum_order_operation_type order_type,
								 double start,
								 double end ) {
		return order::is_buy_direction ( order_type ) ?
			   end - start :
			   start - end;
	}

	static bool is_price_before_line ( enum_order_operation_type order_type,
									   double price,
									   double line ) {
		return order::is_buy_direction ( order_type ) ?
			   price < line :
			   line < price;
	}

	static double deduct_points_from_current_price ( enum_order_operation_type order_type,
			double points ) {
		return deduct_points ( order_type,
							   layer_market::price_close ( order_type ),
							   points );
	}

	static double deduct_points ( enum_order_operation_type order_type,
								  double price,
								  double points ) {
		return order::is_buy_direction ( order_type ) ?
			   price - points :
			   price + points;
	}

	static double add_points_to_current_price ( enum_order_operation_type order_type,
			double points ) {
		return add_point ( order_type,
						   layer_market::price_close ( order_type ),
						   points );
	}

	static double add_point ( enum_order_operation_type order_type,
							  double price,
							  double points ) {
		return order::is_buy_direction ( order_type ) ?
			   price + points :
			   price - points;
	}
};

#endif
#ifndef FRAMEWORK_TOOL_TAKE_PROFIT_MQH
#define FRAMEWORK_TOOL_TAKE_PROFIT_MQH

class tool_take_profit {
public:
	static double get_avg_price_by_lot_factor ( list<order *> *orders,
			int skip_stop_order_count,
			bool with_virtual_order = false,
			double virtual_price = 0.0,
			double virtual_lot = 0.0 ) {
		double result = 0,
			   lots = 0;
		order *last_order = NULL;

		for ( int i = 0; i < orders.count; i++ ) {
			last_order = orders.items[i];

			if ( skip_stop_order_count != 0
					&& last_order.is_order_stop () ) {
				skip_stop_order_count -= 1;
				continue;
			}

			result += last_order.open_price * last_order.lot;
			lots += last_order.lot;
		}

		if ( with_virtual_order
				&& orders.count > 0 ) {
			result += virtual_price * virtual_lot;
			lots += virtual_lot;
		}

		return result / lots;
	}

	static double get_level_without_loss ( list<order *> *orders,
										   int skip_stop_order_count,
										   bool with_virtual_order = false,
										   double virtual_price = 0.0,
										   double virtual_lot = 0.0 ) {
		double lots = 0.0;
		double profit = 0.0;
		order *last_order = NULL;

		for ( int i = 0; i < orders.count; i++ ) {
			last_order = orders.items[i];

			if ( skip_stop_order_count != 0
					&& last_order.is_order_stop () ) {
				skip_stop_order_count -= 1;
				continue;
			}

			profit += last_order.get_profit_in_currency();
			lots += last_order.lot;

			if ( last_order.is_order () ) {
				profit += last_order.commission + last_order.swap;
			}
		}

		if ( with_virtual_order
				&& orders.count > 0 ) {
			profit += order::get_profit_in_currency ( last_order.order_type,
					  virtual_price,
					  virtual_lot );
			lots += virtual_lot;
		}

		if ( profit == 0.0 ) {
			return layer_market::price_close ( last_order.order_type );
		}

		double profit_pips = ( profit / lots ) / layer_market::tick_value ();
		double profit_points = layer_market::to_points ( profit_pips );
		return tool_order::deduct_points_from_current_price ( last_order.order_type, profit_points );
	}
};

#endif

#endif
#ifndef FACTORY_MQH
#define FACTORY_MQH

#define FACTORY_TEMPLATE( type ) \
	list<type *> *_factory_##type##_objects; \
	int _factory_##type##_position; \
	\
	class factory_##type { \
	public: \
		static void init ( int count ) { \
			_factory_##type##_position = 0; \
			_factory_##type##_objects = new list<type *> ( count ); \
			gc::push ( gc_dispose_type_on_end_deinit, _factory_##type##_objects ); \
			\
			for ( int i = 0; i < count; i++ ) \
				_factory_##type##_objects.add ( new type() ); \
		} \
		\
		static void reset() { \
			_factory_##type##_position = 0; \
		} \
		\
		static type *get() { \
			type *result = NULL; \
			\
			if ( _factory_##type##_position == _factory_##type##_objects.count ) { \
				_factory_##type##_objects.add ( result = new type() ); \
			} else { \
				result = _factory_##type##_objects.items[_factory_##type##_position]; \
			} \
			\
			result.reset(); \
			_factory_##type##_position += 1; \
			return result; \
		} \
	} \

#ifndef FRAMEWORK_FACTORY_ORDER_MQH
#define FRAMEWORK_FACTORY_ORDER_MQH

FACTORY_TEMPLATE ( order );

#endif
#ifndef FRAMEWORK_FACTORY_ORDER_OPERATION_MQH
#define FRAMEWORK_FACTORY_ORDER_OPERATION_MQH

FACTORY_TEMPLATE ( order_operation );

#endif

#endif

#ifndef FRAMEWORK_REASON_MQH
#define FRAMEWORK_REASON_MQH

#ifndef FRAMEWORK_LOCALIZATION_REWRITE
#define FRAMEWORK_MSG_REASON_PROGRAM "[REASON_PROGRAM]"
#define FRAMEWORK_MSG_REASON_REMOVE "[REASON_REMOVE]"
#define FRAMEWORK_MSG_REASON_RECOMPILE "[REASON_RECOMPILE]"
#define FRAMEWORK_MSG_REASON_CHARTCHANGE "[REASON_CHARTCHANGE]"
#define FRAMEWORK_MSG_REASON_CHARTCLOSE "[REASON_CHARTCLOSE]"
#define FRAMEWORK_MSG_REASON_PARAMETERS "[REASON_PARAMETERS]"
#define FRAMEWORK_MSG_REASON_ACCOUNT "[REASON_ACCOUNT]"
#define FRAMEWORK_MSG_REASON_TEMPLATE "[REASON_TEMPLATE]"
#define FRAMEWORK_MSG_REASON_INITFAILED "[REASON_INITFAILED]"
#define FRAMEWORK_MSG_REASON_CLOSE "[REASON_CLOSE]"
#endif

string error_deinit_reason ( int reason_coder )
{
	switch ( reason_coder ) {
		case REASON_PROGRAM:
			return FRAMEWORK_MSG_REASON_PROGRAM;

		case REASON_REMOVE:
			return FRAMEWORK_MSG_REASON_REMOVE;

		case REASON_RECOMPILE:
			return FRAMEWORK_MSG_REASON_RECOMPILE;

		case REASON_CHARTCHANGE:
			return FRAMEWORK_MSG_REASON_CHARTCHANGE;

		case REASON_CHARTCLOSE:
			return FRAMEWORK_MSG_REASON_CHARTCLOSE;

		case REASON_PARAMETERS:
			return FRAMEWORK_MSG_REASON_PARAMETERS;

		case REASON_ACCOUNT:
			return FRAMEWORK_MSG_REASON_ACCOUNT;

		case REASON_TEMPLATE:
			return FRAMEWORK_MSG_REASON_TEMPLATE;

		case REASON_INITFAILED:
			return FRAMEWORK_MSG_REASON_INITFAILED;

		case REASON_CLOSE:
			return FRAMEWORK_MSG_REASON_CLOSE;

		default:
			return NULL;
	}
}

#endif
#ifndef FRAMEWORK_ERROR_MQH
#define FRAMEWORK_ERROR_MQH

#ifndef FRAMEWORK_LOCALIZATION_REWRITE
#define FRAMEWORK_MSG_ERROR_TRADE_TIMEOUT "[ERROR_TRADE_TIMEOUT]"
#define FRAMEWORK_MSG_ERROR_INVALID_PRICE "[ERROR_INVALID_PRICE]"
#define FRAMEWORK_MSG_ERROR_INVALID_STOPS "[ERROR_INVALID_STOPS]"
#define FRAMEWORK_MSG_ERROR_INVALID_TRADE_VOLUME "[ERROR_INVALID_TRADE_VOLUME]"
#define FRAMEWORK_MSG_ERROR_MARKET_CLOSED "[ERROR_MARKET_CLOSED]"
#define FRAMEWORK_MSG_ERROR_TRADE_DISABLED "[ERROR_TRADE_DISABLED]"
#define FRAMEWORK_MSG_ERROR_NOT_ENOUGH_MONEY "[ERROR_NOT_ENOUGH_MONEY]"
#define FRAMEWORK_MSG_ERROR_OFF_QUOTES "[ERROR_OFF_QUOTES]"
#define FRAMEWORK_MSG_ERROR_BROKER_BUSY "[ERROR_BROKER_BUSY]"
#define FRAMEWORK_MSG_ERROR_REQUOTE "[ERROR_REQUOTE]"
#define FRAMEWORK_MSG_ERROR_ORDER_LOCKED "[ERROR_ORDER_LOCKED]"
#define FRAMEWORK_MSG_ERROR_LONG_POSITIONS_ONLY_ALLOWED "[ERROR_LONG_POSITIONS_ONLY_ALLOWED]"
#define FRAMEWORK_MSG_ERROR_TOO_MANY_REQUESTS "[ERROR_TOO_MANY_REQUESTS]"
#define FRAMEWORK_MSG_ERROR_TRADE_MODIFY_DENIED "[ERROR_TRADE_MODIFY_DENIED]"
#define FRAMEWORK_MSG_ERROR_TRADE_CONTEXT_BUSY "[ERROR_TRADE_CONTEXT_BUSY]"
#define FRAMEWORK_MSG_ERROR_TRADE_EXPIRATION_DENIED "[ERROR_TRADE_EXPIRATION_DENIED]"
#define FRAMEWORK_MSG_ERROR_TRADE_TOO_MANY_ORDERS "[ERROR_TRADE_TOO_MANY_ORDERS]"
#define FRAMEWORK_MSG_ERROR_TRADE_HEDGE_PROHIBITED "[ERROR_TRADE_HEDGE_PROHIBITED]"
#define FRAMEWORK_MSG_ERROR_TRADE_PROHIBITED_BY_FIFO "[ERROR_TRADE_PROHIBITED_BY_FIFO]"
#define FRAMEWORK_MSG_ERROR_WRONG_FUNCTION_POINTER "[ERROR_WRONG_FUNCTION_POINTER]"
#define FRAMEWORK_MSG_ERROR_ARRAY_INDEX_OUT_OF_RANGE "[ERROR_ARRAY_INDEX_OUT_OF_RANGE]"
#define FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_CALL_STACK "[ERROR_NO_MEMORY_FOR_CALL_STACK]"
#define FRAMEWORK_MSG_ERROR_RECURSIVE_STACK_OVERFLOW "[ERROR_RECURSIVE_STACK_OVERFLOW]"
#define FRAMEWORK_MSG_ERROR_NOT_ENOUGH_STACK_FOR_PARAM "[ERROR_NOT_ENOUGH_STACK_FOR_PARAM]"
#define FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_PARAM_STRING "[ERROR_NO_MEMORY_FOR_PARAM_STRING]"
#define FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_TEMP_STRING "[ERROR_NO_MEMORY_FOR_TEMP_STRING]"
#define FRAMEWORK_MSG_ERROR_NOT_INITIALIZED_STRING "[ERROR_NOT_INITIALIZED_STRING]"
#define FRAMEWORK_MSG_ERROR_NOT_INITIALIZED_ARRAYSTRING "[ERROR_NOT_INITIALIZED_ARRAYSTRING]"
#define FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_ARRAYSTRING "[ERROR_NO_MEMORY_FOR_ARRAYSTRING]"
#define FRAMEWORK_MSG_ERROR_TOO_LONG_STRING "[ERROR_TOO_LONG_STRING]"
#define FRAMEWORK_MSG_ERROR_REMAINDER_FROM_ZERO_DIVIDE "[ERROR_REMAINDER_FROM_ZERO_DIVIDE]"
#define FRAMEWORK_MSG_ERROR_ZERO_DIVIDE "[ERROR_ZERO_DIVIDE]"
#define FRAMEWORK_MSG_ERROR_UNKNOWN_COMMAND "[ERROR_UNKNOWN_COMMAND]"
#define FRAMEWORK_MSG_ERROR_WRONG_JUMP "[ERROR_WRONG_JUMP]"
#define FRAMEWORK_MSG_ERROR_NOT_INITIALIZED_ARRAY "[ERROR_NOT_INITIALIZED_ARRAY]"
#define FRAMEWORK_MSG_ERROR_DLL_CALLS_NOT_ALLOWED "[ERROR_DLL_CALLS_NOT_ALLOWED]"
#define FRAMEWORK_MSG_ERROR_CANNOT_LOAD_LIBRARY "[ERROR_CANNOT_LOAD_LIBRARY]"
#define FRAMEWORK_MSG_ERROR_CANNOT_CALL_FUNCTION "[ERROR_CANNOT_CALL_FUNCTION]"
#define FRAMEWORK_MSG_ERROR_EXTERNAL_CALLS_NOT_ALLOWED "[ERROR_EXTERNAL_CALLS_NOT_ALLOWED]"
#define FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_RETURNED_STR "[ERROR_NO_MEMORY_FOR_RETURNED_STR]"
#define FRAMEWORK_MSG_ERROR_SYSTEM_BUSY "[ERROR_SYSTEM_BUSY]"
#define FRAMEWORK_MSG_ERROR_DLLFUNC_CRITICALERROR "[ERROR_DLLFUNC_CRITICALERROR]"
#define FRAMEWORK_MSG_ERROR_INTERNAL_ERROR "[ERROR_INTERNAL_ERROR]"
#define FRAMEWORK_MSG_ERROR_OUT_OF_MEMORY "[ERROR_OUT_OF_MEMORY]"
#define FRAMEWORK_MSG_ERROR_INVALID_POINTER "[ERROR_INVALID_POINTER]"
#define FRAMEWORK_MSG_ERROR_FORMAT_TOO_MANY_FORMATTERS "[ERROR_FORMAT_TOO_MANY_FORMATTERS]"
#define FRAMEWORK_MSG_ERROR_FORMAT_TOO_MANY_PARAMETERS "[ERROR_FORMAT_TOO_MANY_PARAMETERS]"
#define FRAMEWORK_MSG_ERROR_ARRAY_INVALID "[ERROR_ARRAY_INVALID]"
#define FRAMEWORK_MSG_ERROR_CHART_NOREPLY "[ERROR_CHART_NOREPLY]"
#define FRAMEWORK_MSG_ERROR_INVALID_FUNCTION_PARAMSCNT "[ERROR_INVALID_FUNCTION_PARAMSCNT]"
#define FRAMEWORK_MSG_ERROR_INVALID_FUNCTION_PARAMVALUE "[ERROR_INVALID_FUNCTION_PARAMVALUE]"
#define FRAMEWORK_MSG_ERROR_STRING_FUNCTION_INTERNAL "[ERROR_STRING_FUNCTION_INTERNAL]"
#define FRAMEWORK_MSG_ERROR_SOME_ARRAY_ERROR "[ERROR_SOME_ARRAY_ERROR]"
#define FRAMEWORK_MSG_ERROR_INCORRECT_SERIESARRAY_USING "[ERROR_INCORRECT_SERIESARRAY_USING]"
#define FRAMEWORK_MSG_ERROR_CUSTOM_INDICATOR_ERROR "[ERROR_CUSTOM_INDICATOR_ERROR]"
#define FRAMEWORK_MSG_ERROR_INCOMPATIBLE_ARRAYS "[ERROR_INCOMPATIBLE_ARRAYS]"
#define FRAMEWORK_MSG_ERROR_GLOBAL_VARIABLES_PROCESSING "[ERROR_GLOBAL_VARIABLES_PROCESSING]"
#define FRAMEWORK_MSG_ERROR_GLOBAL_VARIABLE_NOT_FOUND "[ERROR_GLOBAL_VARIABLE_NOT_FOUND]"
#define FRAMEWORK_MSG_ERROR_FUNC_NOT_ALLOWED_IN_TESTING "[ERROR_FUNC_NOT_ALLOWED_IN_TESTING]"
#define FRAMEWORK_MSG_ERROR_FUNCTION_NOT_CONFIRMED "[ERROR_FUNCTION_NOT_CONFIRMED]"
#define FRAMEWORK_MSG_ERROR_SEND_MAIL_ERROR "[ERROR_SEND_MAIL_ERROR]"
#define FRAMEWORK_MSG_ERROR_STRING_PARAMETER_EXPECTED "[ERROR_STRING_PARAMETER_EXPECTED]"
#define FRAMEWORK_MSG_ERROR_INTEGER_PARAMETER_EXPECTED "[ERROR_INTEGER_PARAMETER_EXPECTED]"
#define FRAMEWORK_MSG_ERROR_DOUBLE_PARAMETER_EXPECTED "[ERROR_DOUBLE_PARAMETER_EXPECTED]"
#define FRAMEWORK_MSG_ERROR_ARRAY_AS_PARAMETER_EXPECTED "[ERROR_ARRAY_AS_PARAMETER_EXPECTED]"
#define FRAMEWORK_MSG_ERROR_HISTORY_WILL_UPDATED "[ERROR_HISTORY_WILL_UPDATED]"
#define FRAMEWORK_MSG_ERROR_TRADE_ERROR "[ERROR_TRADE_ERROR]"
#define FRAMEWORK_MSG_ERROR_RESOURCE_NOT_FOUND "[ERROR_RESOURCE_NOT_FOUND]"
#define FRAMEWORK_MSG_ERROR_RESOURCE_NOT_SUPPORTED "[ERROR_RESOURCE_NOT_SUPPORTED]"
#define FRAMEWORK_MSG_ERROR_RESOURCE_DUPLICATED "[ERROR_RESOURCE_DUPLICATED]"
#define FRAMEWORK_MSG_ERROR_INDICATOR_CANNOT_INIT "[ERROR_INDICATOR_CANNOT_INIT]"
#define FRAMEWORK_MSG_ERROR_INDICATOR_CANNOT_LOAD "[ERROR_INDICATOR_CANNOT_LOAD]"
#define FRAMEWORK_MSG_ERROR_NO_HISTORY_DATA "[ERROR_NO_HISTORY_DATA]"
#define FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_HISTORY "[ERROR_NO_MEMORY_FOR_HISTORY]"
#define FRAMEWORK_MSG_ERROR_END_OF_FILE "[ERROR_END_OF_FILE]"
#define FRAMEWORK_MSG_ERROR_SOME_FILE_ERROR "[ERROR_SOME_FILE_ERROR]"
#define FRAMEWORK_MSG_ERROR_WRONG_FILE_NAME "[ERROR_WRONG_FILE_NAME]"
#define FRAMEWORK_MSG_ERROR_TOO_MANY_OPENED_FILES "[ERROR_TOO_MANY_OPENED_FILES]"
#define FRAMEWORK_MSG_ERROR_CANNOT_OPEN_FILE "[ERROR_CANNOT_OPEN_FILE]"
#define FRAMEWORK_MSG_ERROR_INCOMPATIBLE_FILEACCESS "[ERROR_INCOMPATIBLE_FILEACCESS]"
#define FRAMEWORK_MSG_ERROR_NO_ORDER_SELECTED "[ERROR_NO_ORDER_SELECTED]"
#define FRAMEWORK_MSG_ERROR_UNKNOWN_SYMBOL "[ERROR_UNKNOWN_SYMBOL]"
#define FRAMEWORK_MSG_ERROR_INVALID_PRICE_PARAM "[ERROR_INVALID_PRICE_PARAM]"
#define FRAMEWORK_MSG_ERROR_INVALID_TICKET "[ERROR_INVALID_TICKET]"
#define FRAMEWORK_MSG_ERROR_TRADE_NOT_ALLOWED "[ERROR_TRADE_NOT_ALLOWED]"
#define FRAMEWORK_MSG_ERROR_LONGS_NOT_ALLOWED "[ERROR_LONGS_NOT_ALLOWED]"
#define FRAMEWORK_MSG_ERROR_SHORTS_NOT_ALLOWED "[ERROR_SHORTS_NOT_ALLOWED]"
#define FRAMEWORK_MSG_ERROR_TRADE_EXPERT_DISABLED_BY_SERVER "[ERROR_TRADE_EXPERT_DISABLED_BY_SERVER]"
#define FRAMEWORK_MSG_ERROR_OBJECT_ALREADY_EXISTS "[ERROR_OBJECT_ALREADY_EXISTS]"
#define FRAMEWORK_MSG_ERROR_UNKNOWN_OBJECT_PROPERTY "[ERROR_UNKNOWN_OBJECT_PROPERTY]"
#define FRAMEWORK_MSG_ERROR_OBJECT_DOES_NOT_EXIST "[ERROR_OBJECT_DOES_NOT_EXIST]"
#define FRAMEWORK_MSG_ERROR_UNKNOWN_OBJECT_TYPE "[ERROR_UNKNOWN_OBJECT_TYPE]"
#define FRAMEWORK_MSG_ERROR_NO_OBJECT_NAME "[ERROR_NO_OBJECT_NAME]"
#define FRAMEWORK_MSG_ERROR_OBJECT_COORDINATES_ERROR "[ERROR_OBJECT_COORDINATES_ERROR]"
#define FRAMEWORK_MSG_ERROR_NO_SPECIFIED_SUBWINDOW "[ERROR_NO_SPECIFIED_SUBWINDOW]"
#define FRAMEWORK_MSG_ERROR_SOME_OBJECT_ERROR "[ERROR_SOME_OBJECT_ERROR]"
#define FRAMEWORK_MSG_ERROR_CHART_PROP_INVALID "[ERROR_CHART_PROP_INVALID]"
#define FRAMEWORK_MSG_ERROR_CHART_NOT_FOUND "[ERROR_CHART_NOT_FOUND]"
#define FRAMEWORK_MSG_ERROR_CHARTWINDOW_NOT_FOUND "[ERROR_CHARTWINDOW_NOT_FOUND]"
#define FRAMEWORK_MSG_ERROR_CHARTINDICATOR_NOT_FOUND "[ERROR_CHARTINDICATOR_NOT_FOUND]"
#define FRAMEWORK_MSG_ERROR_SYMBOL_SELECT "[ERROR_SYMBOL_SELECT]"
#define FRAMEWORK_MSG_ERROR_NOTIFICATION_ERROR "[ERROR_NOTIFICATION_ERROR]"
#define FRAMEWORK_MSG_ERROR_NOTIFICATION_PARAMETER "[ERROR_NOTIFICATION_PARAMETER]"
#define FRAMEWORK_MSG_ERROR_NOTIFICATION_SETTINGS "[ERROR_NOTIFICATION_SETTINGS]"
#define FRAMEWORK_MSG_ERROR_NOTIFICATION_TOO_FREQUENT "[ERROR_NOTIFICATION_TOO_FREQUENT]"
#define FRAMEWORK_MSG_ERROR_FILE_TOO_MANY_OPENED "[ERROR_FILE_TOO_MANY_OPENED]"
#define FRAMEWORK_MSG_ERROR_FILE_WRONG_FILENAME "[ERROR_FILE_WRONG_FILENAME]"
#define FRAMEWORK_MSG_ERROR_FILE_TOO_LONG_FILENAME "[ERROR_FILE_TOO_LONG_FILENAME]"
#define FRAMEWORK_MSG_ERROR_FILE_CANNOT_OPEN "[ERROR_FILE_CANNOT_OPEN]"
#define FRAMEWORK_MSG_ERROR_FILE_BUFFER_ALLOCATION_ERROR "[ERROR_FILE_BUFFER_ALLOCATION_ERROR]"
#define FRAMEWORK_MSG_ERROR_FILE_CANNOT_DELETE "[ERROR_FILE_CANNOT_DELETE]"
#define FRAMEWORK_MSG_ERROR_FILE_INVALID_HANDLE "[ERROR_FILE_INVALID_HANDLE]"
#define FRAMEWORK_MSG_ERROR_FILE_WRONG_HANDLE "[ERROR_FILE_WRONG_HANDLE]"
#define FRAMEWORK_MSG_ERROR_FILE_NOT_TOWRITE "[ERROR_FILE_NOT_TOWRITE]"
#define FRAMEWORK_MSG_ERROR_FILE_NOT_TOREAD "[ERROR_FILE_NOT_TOREAD]"
#define FRAMEWORK_MSG_ERROR_FILE_NOT_BIN "[ERROR_FILE_NOT_BIN]"
#define FRAMEWORK_MSG_ERROR_FILE_NOT_TXT "[ERROR_FILE_NOT_TXT]"
#define FRAMEWORK_MSG_ERROR_FILE_NOT_TXTORCSV "[ERROR_FILE_NOT_TXTORCSV]"
#define FRAMEWORK_MSG_ERROR_FILE_NOT_CSV "[ERROR_FILE_NOT_CSV]"
#define FRAMEWORK_MSG_ERROR_FILE_READ_ERROR "[ERROR_FILE_READ_ERROR]"
#define FRAMEWORK_MSG_ERROR_FILE_WRITE_ERROR "[ERROR_FILE_WRITE_ERROR]"
#define FRAMEWORK_MSG_ERROR_FILE_BIN_STRINGSIZE "[ERROR_FILE_BIN_STRINGSIZEERROR_FILE_BIN_STRINGSIZE]"
#define FRAMEWORK_MSG_ERROR_FILE_INCOMPATIBLE "[ERROR_FILE_INCOMPATIBLE]"
#define FRAMEWORK_MSG_ERROR_FILE_IS_DIRECTORY "[ERROR_FILE_IS_DIRECTORY]"
#define FRAMEWORK_MSG_ERROR_FILE_NOT_EXIST "[ERROR_FILE_NOT_EXIST]"
#define FRAMEWORK_MSG_ERROR_FILE_CANNOT_REWRITE "[ERROR_FILE_CANNOT_REWRITE]"
#define FRAMEWORK_MSG_ERROR_FILE_WRONG_DIRECTORYNAME "[ERROR_FILE_WRONG_DIRECTORYNAME]"
#define FRAMEWORK_MSG_ERROR_FILE_DIRECTORY_NOT_EXIST "[ERROR_FILE_DIRECTORY_NOT_EXIST]"
#define FRAMEWORK_MSG_ERROR_FILE_NOT_DIRECTORY "[ERROR_FILE_NOT_DIRECTORY]"
#define FRAMEWORK_MSG_ERROR_FILE_CANNOT_DELETE_DIRECTORY "[ERROR_FILE_CANNOT_DELETE_DIRECTORY]"
#define FRAMEWORK_MSG_ERROR_FILE_CANNOT_CLEAN_DIRECTORY "[ERROR_FILE_CANNOT_CLEAN_DIRECTORY]"
#define FRAMEWORK_MSG_ERROR_FILE_STRINGRESIZE_ERROR "[ERROR_FILE_STRINGRESIZE_ERROR]"
#define FRAMEWORK_MSG_ERROR_FILE_STRUCT_WITH_OBJECTS "[ERROR_FILE_STRUCT_WITH_OBJECTS]"
#define FRAMEWORK_MSG_ERROR_WEBREQUEST_INVALID_ADDRESS "[ERROR_WEBREQUEST_INVALID_ADDRESS]"
#define FRAMEWORK_MSG_ERROR_WEBREQUEST_CONNECT_FAILED "[ERROR_WEBREQUEST_CONNECT_FAILED]"
#define FRAMEWORK_MSG_ERROR_WEBREQUEST_TIMEOUT "[ERROR_WEBREQUEST_TIMEOUT]"
#define FRAMEWORK_MSG_ERROR_WEBREQUEST_REQUEST_FAILED "[ERROR_WEBREQUEST_REQUEST_FAILED]"
#define FRAMEWORK_MSG_ERROR_NOT_FOUND "[ERROR_NOT_FOUND]"
#endif

string error_get_last ( int error )
{
	switch ( error ) {
		case ERROR_NO_ERROR:
		case ERROR_NO_MQLERROR:
			return NULL;

		case ERROR_TRADE_TIMEOUT:
			return FRAMEWORK_MSG_ERROR_TRADE_TIMEOUT;

		case ERROR_INVALID_PRICE:
			return FRAMEWORK_MSG_ERROR_INVALID_PRICE;

		case ERROR_INVALID_STOPS:
			return FRAMEWORK_MSG_ERROR_INVALID_STOPS;

		case ERROR_INVALID_TRADE_VOLUME:
			return FRAMEWORK_MSG_ERROR_INVALID_TRADE_VOLUME;

		case ERROR_MARKET_CLOSED:
			return FRAMEWORK_MSG_ERROR_MARKET_CLOSED;

		case ERROR_TRADE_DISABLED:
			return FRAMEWORK_MSG_ERROR_TRADE_DISABLED;

		case ERROR_NOT_ENOUGH_MONEY:
			return FRAMEWORK_MSG_ERROR_NOT_ENOUGH_MONEY;

		case ERROR_OFF_QUOTES:
			return FRAMEWORK_MSG_ERROR_OFF_QUOTES;

		case ERROR_BROKER_BUSY:
			return FRAMEWORK_MSG_ERROR_BROKER_BUSY;

		case ERROR_REQUOTE:
			return FRAMEWORK_MSG_ERROR_REQUOTE;

		case ERROR_ORDER_LOCKED:
			return FRAMEWORK_MSG_ERROR_ORDER_LOCKED;

		case ERROR_LONG_POSITIONS_ONLY_ALLOWED:
			return FRAMEWORK_MSG_ERROR_LONG_POSITIONS_ONLY_ALLOWED;

		case ERROR_TOO_MANY_REQUESTS:
			return FRAMEWORK_MSG_ERROR_TOO_MANY_REQUESTS;

		case ERROR_TRADE_MODIFY_DENIED:
			return FRAMEWORK_MSG_ERROR_TRADE_MODIFY_DENIED;

		case ERROR_TRADE_CONTEXT_BUSY:
			return FRAMEWORK_MSG_ERROR_TRADE_CONTEXT_BUSY;

		case ERROR_TRADE_EXPIRATION_DENIED:
			return FRAMEWORK_MSG_ERROR_TRADE_EXPIRATION_DENIED;

		case ERROR_TRADE_TOO_MANY_ORDERS:
			return FRAMEWORK_MSG_ERROR_TRADE_TOO_MANY_ORDERS;

		case ERROR_TRADE_HEDGE_PROHIBITED:
			return FRAMEWORK_MSG_ERROR_TRADE_HEDGE_PROHIBITED;

		case ERROR_TRADE_PROHIBITED_BY_FIFO:
			return FRAMEWORK_MSG_ERROR_TRADE_PROHIBITED_BY_FIFO;

		case ERROR_WRONG_FUNCTION_POINTER:
			return FRAMEWORK_MSG_ERROR_WRONG_FUNCTION_POINTER;

		case ERROR_ARRAY_INDEX_OUT_OF_RANGE:
			return FRAMEWORK_MSG_ERROR_ARRAY_INDEX_OUT_OF_RANGE;

		case ERROR_NO_MEMORY_FOR_CALL_STACK:
			return FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_CALL_STACK;

		case ERROR_RECURSIVE_STACK_OVERFLOW:
			return FRAMEWORK_MSG_ERROR_RECURSIVE_STACK_OVERFLOW;

		case ERROR_NOT_ENOUGH_STACK_FOR_PARAM:
			return FRAMEWORK_MSG_ERROR_NOT_ENOUGH_STACK_FOR_PARAM;

		case ERROR_NO_MEMORY_FOR_PARAM_STRING:
			return FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_PARAM_STRING;

		case ERROR_NO_MEMORY_FOR_TEMP_STRING:
			return FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_TEMP_STRING;

		case ERROR_NOT_INITIALIZED_STRING:
			return FRAMEWORK_MSG_ERROR_NOT_INITIALIZED_STRING;

		case ERROR_NOT_INITIALIZED_ARRAYSTRING:
			return FRAMEWORK_MSG_ERROR_NOT_INITIALIZED_ARRAYSTRING;

		case ERROR_NO_MEMORY_FOR_ARRAYSTRING:
			return FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_ARRAYSTRING;

		case ERROR_TOO_LONG_STRING:
			return FRAMEWORK_MSG_ERROR_TOO_LONG_STRING;

		case ERROR_REMAINDER_FROM_ZERO_DIVIDE:
			return FRAMEWORK_MSG_ERROR_REMAINDER_FROM_ZERO_DIVIDE;

		case ERROR_ZERO_DIVIDE:
			return FRAMEWORK_MSG_ERROR_ZERO_DIVIDE;

		case ERROR_UNKNOWN_COMMAND:
			return FRAMEWORK_MSG_ERROR_UNKNOWN_COMMAND;

		case ERROR_WRONG_JUMP:
			return FRAMEWORK_MSG_ERROR_WRONG_JUMP;

		case ERROR_NOT_INITIALIZED_ARRAY:
			return FRAMEWORK_MSG_ERROR_NOT_INITIALIZED_ARRAY;

		case ERROR_DLL_CALLS_NOT_ALLOWED:
			return FRAMEWORK_MSG_ERROR_DLL_CALLS_NOT_ALLOWED;

		case ERROR_CANNOT_LOAD_LIBRARY:
			return FRAMEWORK_MSG_ERROR_CANNOT_LOAD_LIBRARY;

		case ERROR_CANNOT_CALL_FUNCTION:
			return FRAMEWORK_MSG_ERROR_CANNOT_CALL_FUNCTION;

		case ERROR_EXTERNAL_CALLS_NOT_ALLOWED:
			return FRAMEWORK_MSG_ERROR_EXTERNAL_CALLS_NOT_ALLOWED;

		case ERROR_NO_MEMORY_FOR_RETURNED_STR:
			return FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_RETURNED_STR;

		case ERROR_SYSTEM_BUSY:
			return FRAMEWORK_MSG_ERROR_SYSTEM_BUSY;

		case ERROR_DLLFUNC_CRITICALERROR:
			return FRAMEWORK_MSG_ERROR_DLLFUNC_CRITICALERROR;

		case ERROR_INTERNAL_ERROR:
			return FRAMEWORK_MSG_ERROR_INTERNAL_ERROR;

		case ERROR_OUT_OF_MEMORY:
			return FRAMEWORK_MSG_ERROR_OUT_OF_MEMORY;

		case ERROR_INVALID_POINTER:
			return FRAMEWORK_MSG_ERROR_INVALID_POINTER;

		case ERROR_FORMAT_TOO_MANY_FORMATTERS:
			return FRAMEWORK_MSG_ERROR_FORMAT_TOO_MANY_FORMATTERS;

		case ERROR_FORMAT_TOO_MANY_PARAMETERS:
			return FRAMEWORK_MSG_ERROR_FORMAT_TOO_MANY_PARAMETERS;

		case ERROR_ARRAY_INVALID:
			return FRAMEWORK_MSG_ERROR_ARRAY_INVALID;

		case ERROR_CHART_NOREPLY:
			return FRAMEWORK_MSG_ERROR_CHART_NOREPLY;

		case ERROR_INVALID_FUNCTION_PARAMSCNT:
			return FRAMEWORK_MSG_ERROR_INVALID_FUNCTION_PARAMSCNT;

		case ERROR_INVALID_FUNCTION_PARAMVALUE:
			return FRAMEWORK_MSG_ERROR_INVALID_FUNCTION_PARAMVALUE;

		case ERROR_STRING_FUNCTION_INTERNAL:
			return FRAMEWORK_MSG_ERROR_STRING_FUNCTION_INTERNAL;

		case ERROR_SOME_ARRAY_ERROR:
			return FRAMEWORK_MSG_ERROR_SOME_ARRAY_ERROR;

		case ERROR_INCORRECT_SERIESARRAY_USING:
			return FRAMEWORK_MSG_ERROR_INCORRECT_SERIESARRAY_USING;

		case ERROR_CUSTOM_INDICATOR_ERROR:
			return FRAMEWORK_MSG_ERROR_CUSTOM_INDICATOR_ERROR;

		case ERROR_INCOMPATIBLE_ARRAYS:
			return FRAMEWORK_MSG_ERROR_INCOMPATIBLE_ARRAYS;

		case ERROR_GLOBAL_VARIABLES_PROCESSING:
			return FRAMEWORK_MSG_ERROR_GLOBAL_VARIABLES_PROCESSING;

		case ERROR_GLOBAL_VARIABLE_NOT_FOUND:
			return FRAMEWORK_MSG_ERROR_GLOBAL_VARIABLE_NOT_FOUND;

		case ERROR_FUNC_NOT_ALLOWED_IN_TESTING:
			return FRAMEWORK_MSG_ERROR_FUNC_NOT_ALLOWED_IN_TESTING;

		case ERROR_FUNCTION_NOT_CONFIRMED:
			return FRAMEWORK_MSG_ERROR_FUNCTION_NOT_CONFIRMED;

		case ERROR_SEND_MAIL_ERROR:
			return FRAMEWORK_MSG_ERROR_SEND_MAIL_ERROR;

		case ERROR_STRING_PARAMETER_EXPECTED:
			return FRAMEWORK_MSG_ERROR_STRING_PARAMETER_EXPECTED;

		case ERROR_INTEGER_PARAMETER_EXPECTED:
			return FRAMEWORK_MSG_ERROR_INTEGER_PARAMETER_EXPECTED;

		case ERROR_DOUBLE_PARAMETER_EXPECTED:
			return FRAMEWORK_MSG_ERROR_DOUBLE_PARAMETER_EXPECTED;

		case ERROR_ARRAY_AS_PARAMETER_EXPECTED:
			return FRAMEWORK_MSG_ERROR_ARRAY_AS_PARAMETER_EXPECTED;

		case ERROR_HISTORY_WILL_UPDATED:
			return FRAMEWORK_MSG_ERROR_HISTORY_WILL_UPDATED;

		case ERROR_TRADE_ERROR:
			return FRAMEWORK_MSG_ERROR_TRADE_ERROR;

		case ERROR_RESOURCE_NOT_FOUND:
			return FRAMEWORK_MSG_ERROR_RESOURCE_NOT_FOUND;

		case ERROR_RESOURCE_NOT_SUPPORTED:
			return FRAMEWORK_MSG_ERROR_RESOURCE_NOT_SUPPORTED;

		case ERROR_RESOURCE_DUPLICATED:
			return FRAMEWORK_MSG_ERROR_RESOURCE_DUPLICATED;

		case ERROR_INDICATOR_CANNOT_INIT:
			return FRAMEWORK_MSG_ERROR_INDICATOR_CANNOT_INIT;

		case ERROR_INDICATOR_CANNOT_LOAD:
			return FRAMEWORK_MSG_ERROR_INDICATOR_CANNOT_LOAD;

		case ERROR_NO_HISTORY_DATA:
			return FRAMEWORK_MSG_ERROR_NO_HISTORY_DATA;

		case ERROR_NO_MEMORY_FOR_HISTORY:
			return FRAMEWORK_MSG_ERROR_NO_MEMORY_FOR_HISTORY;

		case ERROR_END_OF_FILE:
			return FRAMEWORK_MSG_ERROR_END_OF_FILE;

		case ERROR_SOME_FILE_ERROR:
			return FRAMEWORK_MSG_ERROR_SOME_FILE_ERROR;

		case ERROR_WRONG_FILE_NAME:
			return FRAMEWORK_MSG_ERROR_WRONG_FILE_NAME;

		case ERROR_TOO_MANY_OPENED_FILES:
			return FRAMEWORK_MSG_ERROR_TOO_MANY_OPENED_FILES;

		case ERROR_CANNOT_OPEN_FILE:
			return FRAMEWORK_MSG_ERROR_CANNOT_OPEN_FILE;

		case ERROR_INCOMPATIBLE_FILEACCESS:
			return FRAMEWORK_MSG_ERROR_INCOMPATIBLE_FILEACCESS;

		case ERROR_NO_ORDER_SELECTED:
			return FRAMEWORK_MSG_ERROR_NO_ORDER_SELECTED;

		case ERROR_UNKNOWN_SYMBOL:
			return FRAMEWORK_MSG_ERROR_UNKNOWN_SYMBOL;

		case ERROR_INVALID_PRICE_PARAM:
			return FRAMEWORK_MSG_ERROR_INVALID_PRICE_PARAM;

		case ERROR_INVALID_TICKET:
			return FRAMEWORK_MSG_ERROR_INVALID_TICKET;

		case ERROR_TRADE_NOT_ALLOWED:
			return FRAMEWORK_MSG_ERROR_TRADE_NOT_ALLOWED;

		case ERROR_LONGS_NOT_ALLOWED:
			return FRAMEWORK_MSG_ERROR_LONGS_NOT_ALLOWED;

		case ERROR_SHORTS_NOT_ALLOWED:
			return FRAMEWORK_MSG_ERROR_SHORTS_NOT_ALLOWED;

		case ERROR_TRADE_EXPERT_DISABLED_BY_SERVER:
			return FRAMEWORK_MSG_ERROR_TRADE_EXPERT_DISABLED_BY_SERVER;

		case ERROR_OBJECT_ALREADY_EXISTS:
			return FRAMEWORK_MSG_ERROR_OBJECT_ALREADY_EXISTS;

		case ERROR_UNKNOWN_OBJECT_PROPERTY:
			return FRAMEWORK_MSG_ERROR_UNKNOWN_OBJECT_PROPERTY;

		case ERROR_OBJECT_DOES_NOT_EXIST:
			return FRAMEWORK_MSG_ERROR_OBJECT_DOES_NOT_EXIST;

		case ERROR_UNKNOWN_OBJECT_TYPE:
			return FRAMEWORK_MSG_ERROR_UNKNOWN_OBJECT_TYPE;

		case ERROR_NO_OBJECT_NAME:
			return FRAMEWORK_MSG_ERROR_NO_OBJECT_NAME;

		case ERROR_OBJECT_COORDINATES_ERROR:
			return FRAMEWORK_MSG_ERROR_OBJECT_COORDINATES_ERROR;

		case ERROR_NO_SPECIFIED_SUBWINDOW:
			return FRAMEWORK_MSG_ERROR_NO_SPECIFIED_SUBWINDOW;

		case ERROR_SOME_OBJECT_ERROR:
			return FRAMEWORK_MSG_ERROR_SOME_OBJECT_ERROR;

		case ERROR_CHART_PROP_INVALID:
			return FRAMEWORK_MSG_ERROR_CHART_PROP_INVALID;

		case ERROR_CHART_NOT_FOUND:
			return FRAMEWORK_MSG_ERROR_CHART_NOT_FOUND;

		case ERROR_CHARTWINDOW_NOT_FOUND:
			return FRAMEWORK_MSG_ERROR_CHARTWINDOW_NOT_FOUND;

		case ERROR_CHARTINDICATOR_NOT_FOUND:
			return FRAMEWORK_MSG_ERROR_CHARTINDICATOR_NOT_FOUND;

		case ERROR_SYMBOL_SELECT:
			return FRAMEWORK_MSG_ERROR_SYMBOL_SELECT;

		case ERROR_NOTIFICATION_ERROR:
			return FRAMEWORK_MSG_ERROR_NOTIFICATION_ERROR;

		case ERROR_NOTIFICATION_PARAMETER:
			return FRAMEWORK_MSG_ERROR_NOTIFICATION_PARAMETER;

		case ERROR_NOTIFICATION_SETTINGS:
			return FRAMEWORK_MSG_ERROR_NOTIFICATION_SETTINGS;

		case ERROR_NOTIFICATION_TOO_FREQUENT:
			return FRAMEWORK_MSG_ERROR_NOTIFICATION_TOO_FREQUENT;

		case ERROR_FILE_TOO_MANY_OPENED:
			return FRAMEWORK_MSG_ERROR_FILE_TOO_MANY_OPENED;

		case ERROR_FILE_WRONG_FILENAME:
			return FRAMEWORK_MSG_ERROR_FILE_WRONG_FILENAME;

		case ERROR_FILE_TOO_LONG_FILENAME:
			return FRAMEWORK_MSG_ERROR_FILE_TOO_LONG_FILENAME;

		case ERROR_FILE_CANNOT_OPEN:
			return FRAMEWORK_MSG_ERROR_FILE_CANNOT_OPEN;

		case ERROR_FILE_BUFFER_ALLOCATION_ERROR:
			return FRAMEWORK_MSG_ERROR_FILE_BUFFER_ALLOCATION_ERROR;

		case ERROR_FILE_CANNOT_DELETE:
			return FRAMEWORK_MSG_ERROR_FILE_CANNOT_DELETE;

		case ERROR_FILE_INVALID_HANDLE:
			return FRAMEWORK_MSG_ERROR_FILE_INVALID_HANDLE;

		case ERROR_FILE_WRONG_HANDLE:
			return FRAMEWORK_MSG_ERROR_FILE_WRONG_HANDLE;

		case ERROR_FILE_NOT_TOWRITE:
			return FRAMEWORK_MSG_ERROR_FILE_NOT_TOWRITE;

		case ERROR_FILE_NOT_TOREAD:
			return FRAMEWORK_MSG_ERROR_FILE_NOT_TOREAD;

		case ERROR_FILE_NOT_BIN:
			return FRAMEWORK_MSG_ERROR_FILE_NOT_BIN;

		case ERROR_FILE_NOT_TXT:
			return FRAMEWORK_MSG_ERROR_FILE_NOT_TXT;

		case ERROR_FILE_NOT_TXTORCSV:
			return FRAMEWORK_MSG_ERROR_FILE_NOT_TXTORCSV;

		case ERROR_FILE_NOT_CSV:
			return FRAMEWORK_MSG_ERROR_FILE_NOT_CSV;

		case ERROR_FILE_READ_ERROR:
			return FRAMEWORK_MSG_ERROR_FILE_READ_ERROR;

		case ERROR_FILE_WRITE_ERROR:
			return FRAMEWORK_MSG_ERROR_FILE_WRITE_ERROR;

		case ERROR_FILE_BIN_STRINGSIZE:
			return FRAMEWORK_MSG_ERROR_FILE_BIN_STRINGSIZE;

		case ERROR_FILE_INCOMPATIBLE:
			return FRAMEWORK_MSG_ERROR_FILE_INCOMPATIBLE;

		case ERROR_FILE_IS_DIRECTORY:
			return FRAMEWORK_MSG_ERROR_FILE_IS_DIRECTORY;

		case ERROR_FILE_NOT_EXIST:
			return FRAMEWORK_MSG_ERROR_FILE_NOT_EXIST;

		case ERROR_FILE_CANNOT_REWRITE:
			return FRAMEWORK_MSG_ERROR_FILE_CANNOT_REWRITE;

		case ERROR_FILE_WRONG_DIRECTORYNAME:
			return FRAMEWORK_MSG_ERROR_FILE_WRONG_DIRECTORYNAME;

		case ERROR_FILE_DIRECTORY_NOT_EXIST:
			return FRAMEWORK_MSG_ERROR_FILE_DIRECTORY_NOT_EXIST;

		case ERROR_FILE_NOT_DIRECTORY:
			return FRAMEWORK_MSG_ERROR_FILE_NOT_DIRECTORY;

		case ERROR_FILE_CANNOT_DELETE_DIRECTORY:
			return FRAMEWORK_MSG_ERROR_FILE_CANNOT_DELETE_DIRECTORY;

		case ERROR_FILE_CANNOT_CLEAN_DIRECTORY:
			return FRAMEWORK_MSG_ERROR_FILE_CANNOT_CLEAN_DIRECTORY;

		case ERROR_FILE_STRINGRESIZE_ERROR:
			return FRAMEWORK_MSG_ERROR_FILE_STRINGRESIZE_ERROR;

		case ERROR_FILE_STRUCT_WITH_OBJECTS:
			return FRAMEWORK_MSG_ERROR_FILE_STRUCT_WITH_OBJECTS;

		case ERROR_WEBREQUEST_INVALID_ADDRESS:
			return FRAMEWORK_MSG_ERROR_WEBREQUEST_INVALID_ADDRESS;

		case ERROR_WEBREQUEST_CONNECT_FAILED:
			return FRAMEWORK_MSG_ERROR_WEBREQUEST_CONNECT_FAILED;

		case ERROR_WEBREQUEST_TIMEOUT:
			return FRAMEWORK_MSG_ERROR_WEBREQUEST_TIMEOUT;

		case ERROR_WEBREQUEST_REQUEST_FAILED:
			return FRAMEWORK_MSG_ERROR_WEBREQUEST_REQUEST_FAILED;

		default:
			return FRAMEWORK_MSG_ERROR_NOT_FOUND;
	}
}

#endif

#endif
#ifndef SETKA_MQH
#define SETKA_MQH

#ifndef LOGIC_ENUM_MQH
#define LOGIC_ENUM_MQH

#ifndef LOGIC_ENUM_CALC_LOT_TYPE_MQH
#define LOGIC_ENUM_CALC_LOT_TYPE_MQH

enum enum_calc_lot_type {
	calc_lot_type_last_order = 0,
	calc_lot_type_min_order = 1
};

#endif
#ifndef LOGIC_ENUM_GAP_CONTROL_TYPE_MQH
#define LOGIC_ENUM_GAP_CONTROL_TYPE_MQH

enum enum_gap_control_type {
	no_gap = 0,
	inc_lot = 1,
	op_stop = 2
};

#endif
#ifndef LOGIC_ENUM_TAKE_PROFIT_CALC_TYPE_MQH
#define LOGIC_ENUM_TAKE_PROFIT_CALC_TYPE_MQH

enum enum_take_profit_calc_type {
	tp_avg,
	tp_level_without_loss
};

#endif
#ifndef LOGIC_ENUM_POSITION_SIGNAL_MQH
#define LOGIC_ENUM_POSITION_SIGNAL_MQH

enum enum_position_signal {
	enum_position_signal_simple = 0,
	enum_position_signal_fxht = 1
};

#endif

#endif
#ifndef DEFINES_MQH
#define DEFINES_MQH

#define VER "1.54.22"
#define BUILD "1065"

#ifndef SETTING_MQH
#define SETTING_MQH

#ifndef SCHEDULER_MQH
#define SCHEDULER_MQH

#define MIN_DATE D'1970.01.01 00:00:00'

enum day_of_week_t {
	day_of_week_t_sunday = 0,
	day_of_week_t_monday = 1,
	day_of_week_t_tuesday = 2,
	day_of_week_t_wednesday = 3,
	day_of_week_t_thursday = 4,
	day_of_week_t_friday = 5,
	day_of_week_t_saturday = 6
};

//TODO: почему-то нельзя сделать внутри класса ... блядский mql
bool scheduler_is_trade_enabled;
day_of_week_t scheduler_trade_start_day;
int scheduler_start_hour;
int scheduler_start_minutes;
int scheduler_start_total_minutes;
day_of_week_t scheduler_trade_end_day;
int scheduler_end_hour;
int scheduler_end_minutes;
int scheduler_end_total_minutes;

bool scheduler_new_position_pause_enabled;
datetime scheduler_new_position_pause_start[];
datetime scheduler_new_position_pause_end[];

bool scheduler_is_trade_pause_enabled;
datetime scheduler_start_pause[];
datetime scheduler_end_pause[];

bool scheduler_is_intraday_enabled;
int scheduler_start_intraday_hour[];
int scheduler_start_intraday_minutes[];
int scheduler_start_intraday_total_minutes[];
int scheduler_end_intraday_hour[];
int scheduler_end_intraday_minutes[];
int scheduler_end_intraday_total_minutes[];

bool scheduler_is_intraday_stop_trade_enabled;
int scheduler_start_intraday_stop_trade_hour[];
int scheduler_start_intraday_stop_trade_minutes[];
int scheduler_start_intraday_stop_trade_total_minutes[];
int scheduler_end_intraday_stop_trade_hour[];
int scheduler_end_intraday_stop_trade_minutes[];
int scheduler_end_intraday_stop_trade_total_minutes[];

bool scheduler_close_all_orders_enabled;
int scheduler_close_all_orders_hour;
int scheduler_close_all_orders_minute;
int scheduler_close_all_orders_total_minute;
int scheduler_close_all_orders_total_minute_with_wait;

class scheduler_close_all_orders_locker {
public:
	layer_order_setting *settings;
	bool lock;
};

list<scheduler_close_all_orders_locker *> *scheduler_close_all_orders_lockers;
class scheduler {
private:
	static int get_current_total_minutes() {
		TOOL_CACHED_TICK ( int,
						   _current_total_minutes,
						   _current_total_minutes = 60 * kernel_time::get_hour ( layer::time_current() ) + kernel_time::get_minute ( layer::time_current() ) );
	}

public:
	static void set_trade ( day_of_week_t start_day,
							int start_hour,
							int start_minute,
							day_of_week_t end_day,
							int end_hour,
							int end_minute ) {
		scheduler_trade_start_day = start_day;
		scheduler_start_hour = start_hour;
		scheduler_start_minutes = start_minute;
		scheduler_start_total_minutes = ( 60 * start_hour ) + start_minute;

		scheduler_trade_end_day = end_day;
		scheduler_end_hour = end_hour;
		scheduler_end_minutes = end_minute;
		scheduler_end_total_minutes = ( 60 * end_hour ) + end_minute;

		scheduler_is_trade_enabled = true;
	}

	static void reset_trade () {
		scheduler_is_trade_enabled = false;
	}


#define declare_new_position_pause( number ) \
	datetime start##number, datetime end##number
#define declare_set_new_position_pause( number ) \
	scheduler_new_position_pause_start[number] = start##number; \
	scheduler_new_position_pause_end[number] = end##number;

	static void set_new_position_pause ( declare_new_position_pause ( 0 ),
										 declare_new_position_pause ( 1 ),
										 declare_new_position_pause ( 2 ),
										 declare_new_position_pause ( 3 ),
										 declare_new_position_pause ( 4 ),
										 declare_new_position_pause ( 5 ),
										 declare_new_position_pause ( 6 ),
										 declare_new_position_pause ( 7 ),
										 declare_new_position_pause ( 8 ),
										 declare_new_position_pause ( 9 ) ) {
		ArrayResize ( scheduler_new_position_pause_start, 10 );
		ArrayInitialize ( scheduler_new_position_pause_start, MIN_DATE );
		ArrayResize ( scheduler_new_position_pause_end, 10 );
		ArrayInitialize ( scheduler_new_position_pause_end, MIN_DATE );

		declare_set_new_position_pause ( 0 );
		declare_set_new_position_pause ( 1 );
		declare_set_new_position_pause ( 2 );
		declare_set_new_position_pause ( 3 );
		declare_set_new_position_pause ( 4 );
		declare_set_new_position_pause ( 5 );
		declare_set_new_position_pause ( 6 );
		declare_set_new_position_pause ( 7 );
		declare_set_new_position_pause ( 8 );
		declare_set_new_position_pause ( 9 );

		scheduler_new_position_pause_enabled = true;
	}

	static void reset_new_position_pause () {
		scheduler_new_position_pause_enabled = false;
	}

#define declare_intraday_range( number ) \
	int start_hour_##number, \
	int start_minute_##number, \
	int end_hour_##number, \
	int end_minute_##number
#define set_intraday_range( number ) \
	scheduler_start_intraday_hour[number] = start_hour_##number; \
	scheduler_start_intraday_minutes[number] = start_minute_##number; \
	scheduler_start_intraday_total_minutes[number] = ( 60 * start_hour_##number ) + start_minute_##number; \
	scheduler_end_intraday_hour[number] = end_hour_##number; \
	scheduler_end_intraday_minutes[number] = end_minute_##number; \
	scheduler_end_intraday_total_minutes[number] = ( 60 * end_hour_##number ) + end_minute_##number;

	static void set_intraday ( declare_intraday_range ( 0 ),
							   declare_intraday_range ( 1 ),
							   declare_intraday_range ( 2 ),
							   declare_intraday_range ( 3 ),
							   declare_intraday_range ( 4 ),
							   declare_intraday_range ( 5 ),
							   declare_intraday_range ( 6 ),
							   declare_intraday_range ( 7 ),
							   declare_intraday_range ( 8 ),
							   declare_intraday_range ( 9 ) ) {
		ArrayResize ( scheduler_start_intraday_hour, 10 );
		ArrayInitialize ( scheduler_start_intraday_hour, 0 );
		ArrayResize ( scheduler_start_intraday_minutes, 10 );
		ArrayInitialize ( scheduler_start_intraday_minutes, 0 );
		ArrayResize ( scheduler_start_intraday_total_minutes, 10 );
		ArrayInitialize ( scheduler_start_intraday_total_minutes, 0 );

		ArrayResize ( scheduler_end_intraday_hour, 10 );
		ArrayInitialize ( scheduler_end_intraday_hour, 0 );
		ArrayResize ( scheduler_end_intraday_minutes, 10 );
		ArrayInitialize ( scheduler_end_intraday_minutes, 0 );
		ArrayResize ( scheduler_end_intraday_total_minutes, 10 );
		ArrayInitialize ( scheduler_end_intraday_total_minutes, 0 );

		set_intraday_range ( 0 );
		set_intraday_range ( 1 );
		set_intraday_range ( 2 );
		set_intraday_range ( 3 );
		set_intraday_range ( 4 );
		set_intraday_range ( 5 );
		set_intraday_range ( 6 );
		set_intraday_range ( 7 );
		set_intraday_range ( 8 );
		set_intraday_range ( 9 );

		scheduler_is_intraday_enabled = true;
	}

	static void reset_intraday_stop_trade() {
		scheduler_is_intraday_stop_trade_enabled = false;
	}

#define declare_trade_pause( number ) \
	datetime start##number, datetime end##number
#define set_pause( number ) \
	scheduler_start_pause[number] = start##number; \
	scheduler_end_pause[number] = end##number;

	static void set_trade_pause ( declare_trade_pause ( 0 ),
								  declare_trade_pause ( 1 ),
								  declare_trade_pause ( 2 ),
								  declare_trade_pause ( 3 ),
								  declare_trade_pause ( 4 ),
								  declare_trade_pause ( 5 ),
								  declare_trade_pause ( 6 ),
								  declare_trade_pause ( 7 ),
								  declare_trade_pause ( 8 ),
								  declare_trade_pause ( 9 ) ) {
		ArrayResize ( scheduler_start_pause, 10 );
		ArrayInitialize ( scheduler_start_pause, MIN_DATE );
		ArrayResize ( scheduler_end_pause, 10 );
		ArrayInitialize ( scheduler_end_pause, MIN_DATE );

		set_pause ( 0 );
		set_pause ( 1 );
		set_pause ( 2 );
		set_pause ( 3 );
		set_pause ( 4 );
		set_pause ( 5 );
		set_pause ( 6 );
		set_pause ( 7 );
		set_pause ( 8 );
		set_pause ( 9 );

		scheduler_is_trade_pause_enabled = true;
	}

	static void reset_trade_pause () {
		scheduler_is_trade_pause_enabled = false;
	}

#define declare_intraday_stop_trade_range( number ) \
	int start_hour_##number, \
	int start_minute_##number, \
	int end_hour_##number, \
	int end_minute_##number
#define set_intraday_stop_trade_range( number ) \
	scheduler_start_intraday_stop_trade_hour[number] = start_hour_##number; \
	scheduler_start_intraday_stop_trade_minutes[number] = start_minute_##number; \
	scheduler_start_intraday_stop_trade_total_minutes[number] = ( 60 * start_hour_##number ) + start_minute_##number; \
	scheduler_end_intraday_stop_trade_hour[number] = end_hour_##number; \
	scheduler_end_intraday_stop_trade_minutes[number] = end_minute_##number; \
	scheduler_end_intraday_stop_trade_total_minutes[number] = ( 60 * end_hour_##number ) + end_minute_##number;

	static void set_intraday_stop_trade ( declare_intraday_stop_trade_range ( 0 ),
										  declare_intraday_stop_trade_range ( 1 ),
										  declare_intraday_stop_trade_range ( 2 ),
										  declare_intraday_stop_trade_range ( 3 ),
										  declare_intraday_stop_trade_range ( 4 ),
										  declare_intraday_stop_trade_range ( 5 ),
										  declare_intraday_stop_trade_range ( 6 ),
										  declare_intraday_stop_trade_range ( 7 ),
										  declare_intraday_stop_trade_range ( 8 ),
										  declare_intraday_stop_trade_range ( 9 ) ) {
		ArrayResize ( scheduler_start_intraday_stop_trade_hour, 10 );
		ArrayInitialize ( scheduler_start_intraday_stop_trade_hour, 0 );
		ArrayResize ( scheduler_start_intraday_stop_trade_minutes, 10 );
		ArrayInitialize ( scheduler_start_intraday_stop_trade_minutes, 0 );
		ArrayResize ( scheduler_start_intraday_stop_trade_total_minutes, 10 );
		ArrayInitialize ( scheduler_start_intraday_stop_trade_total_minutes, 0 );

		ArrayResize ( scheduler_end_intraday_stop_trade_hour, 10 );
		ArrayInitialize ( scheduler_end_intraday_stop_trade_hour, 0 );
		ArrayResize ( scheduler_end_intraday_stop_trade_minutes, 10 );
		ArrayInitialize ( scheduler_end_intraday_stop_trade_minutes, 0 );
		ArrayResize ( scheduler_end_intraday_stop_trade_total_minutes, 10 );
		ArrayInitialize ( scheduler_end_intraday_stop_trade_total_minutes, 0 );

		set_intraday_stop_trade_range ( 0 );
		set_intraday_stop_trade_range ( 1 );
		set_intraday_stop_trade_range ( 2 );
		set_intraday_stop_trade_range ( 3 );
		set_intraday_stop_trade_range ( 4 );
		set_intraday_stop_trade_range ( 5 );
		set_intraday_stop_trade_range ( 6 );
		set_intraday_stop_trade_range ( 7 );
		set_intraday_stop_trade_range ( 8 );
		set_intraday_stop_trade_range ( 9 );

		scheduler_is_intraday_stop_trade_enabled = true;
	}

	static void reset_intraday () {
		scheduler_is_intraday_enabled = false;
	}

	static void set_close_all_orders ( int hour,
									   int minute ) {
		scheduler_close_all_orders_hour = hour;
		scheduler_close_all_orders_minute = minute;
		scheduler_close_all_orders_total_minute = ( 60 * hour ) + minute;
		scheduler_close_all_orders_total_minute_with_wait = scheduler_close_all_orders_total_minute + 3;

		scheduler_close_all_orders_enabled = true;

		scheduler_close_all_orders_lockers = new list<scheduler_close_all_orders_locker *>();
		gc::push ( gc_dispose_type_on_end_deinit, scheduler_close_all_orders_lockers );
	}

	static void reset_close_all_orders() {
		scheduler_close_all_orders_enabled = false;
	}

	static bool is_trade_time() {
		return pre_check_trade_pause();
	}

	static bool is_trade_time_for_first_order() {
		return pre_check_new_position_pause()
			   && pre_check_trade_on_week()
			   && pre_check_intraday();
	}

	static bool is_stop_trade_time() {
		return pre_check_intraday_stop_trade();
	}

	static bool is_close_all_orders ( layer_order_setting *settings_ptr ) {
		return pre_check_close_all_orders ( settings_ptr );
	}

private:
	static bool pre_check_trade_on_week() {
		if ( check_trade_on_week() ) {
			return true;
		}

		log_info ( StringFormat ( SRC_SCHEDULER_IS_NOT_TRADE_TIME_ON_WEEK,
								  get_day_of_week_str ( scheduler_trade_start_day ),
								  scheduler_start_hour,
								  scheduler_start_minutes,
								  get_day_of_week_str ( scheduler_trade_end_day ),
								  scheduler_end_hour,
								  scheduler_end_minutes ) );
		return false;
	}

	static bool check_trade_on_week() {
		if ( !scheduler_is_trade_enabled ) {
			return true;
		}

		int day = kernel_time::get_day_of_week();

		if ( scheduler_trade_start_day > day
				|| scheduler_trade_end_day < day ) {
			return false;
		}

		int total_minutes = get_current_total_minutes();

		if ( ( scheduler_trade_start_day == day && scheduler_start_total_minutes >= total_minutes )
				|| ( scheduler_trade_end_day == day && scheduler_end_total_minutes < total_minutes ) ) {
			return false;
		}

		return true;
	}

	static bool pre_check_new_position_pause() {
		int new_position_pause_index = get_new_position_pause_index();

		if ( new_position_pause_index == -1 ) {
			return true;
		}

		string from_time = TimeToString ( scheduler_new_position_pause_start[new_position_pause_index], TIME_DATE | TIME_MINUTES );
		string to_time = TimeToString ( scheduler_new_position_pause_end[new_position_pause_index], TIME_DATE | TIME_MINUTES );
		log_info ( StringFormat ( SRC_SCHEDULER_NEW_POSITION_PAUSE,
								  from_time,
								  to_time ) );
		return false;
	}

	static int get_new_position_pause_index() {
		if ( !scheduler_new_position_pause_enabled ) {
			return -1;
		}

		datetime current_time = layer::time_current();
		int size = ArraySize ( scheduler_new_position_pause_start );

		for ( int i = 0; i < size; i++ ) {
			if ( scheduler_new_position_pause_start[i] != MIN_DATE
					&& scheduler_new_position_pause_end[i] != MIN_DATE
					&& current_time >= scheduler_new_position_pause_start[i]
					&& current_time < scheduler_new_position_pause_end[i] ) {
				return i;
			}
		}

		return -1;
	}

	static bool pre_check_trade_pause() {
		int trade_pause_index = get_trade_pause_index();

		if ( trade_pause_index == -1 ) {
			return true;
		}

		string from_time = TimeToString ( scheduler_start_pause[trade_pause_index], TIME_DATE | TIME_MINUTES );
		string to_time = TimeToString ( scheduler_end_pause[trade_pause_index], TIME_DATE | TIME_MINUTES );
		log_info ( StringFormat ( SRC_SCHEDULER_IS_TRADE_PAUSE,
								  from_time,
								  to_time ) );
		return false;
	}

	static int get_trade_pause_index() {
		if ( !scheduler_is_trade_pause_enabled ) {
			return -1;
		}

		datetime current_time = layer::time_current();
		int size = ArraySize ( scheduler_start_pause );

		for ( int i = 0; i < size; i++ ) {
			if ( scheduler_start_pause[i] != MIN_DATE
					&& scheduler_end_pause[i] != MIN_DATE
					&& current_time >= scheduler_start_pause[i]
					&& current_time < scheduler_end_pause[i] ) {
				return i;
			}
		}

		return -1;
	}

	static bool pre_check_intraday() {
		if ( check_intraday() ) {
			return true;
		}

		int near_intraday_index = get_near_intraday_index();
		log_info ( StringFormat ( SRC_SCHEDULER_IS_NOR_INTRADAY,
								  scheduler_start_intraday_hour[near_intraday_index],
								  scheduler_start_intraday_minutes[near_intraday_index],
								  scheduler_end_intraday_hour[near_intraday_index],
								  scheduler_end_intraday_minutes[near_intraday_index] ) );
		return false;
	}

	static bool check_intraday() {
		if ( !scheduler_is_intraday_enabled ) {
			return true;
		}

		int total_minutes = get_current_total_minutes();
		bool is_all_same = true;

		int size = ArraySize ( scheduler_start_intraday_total_minutes );

		for ( int i = 0; i < size; i++ ) {
			if ( scheduler_start_intraday_total_minutes[i] == scheduler_end_intraday_total_minutes[i] ) {
				continue;
			}

			is_all_same = false;

			if ( check_total_minutes_range ( scheduler_start_intraday_total_minutes[i],
											 total_minutes,
											 scheduler_end_intraday_total_minutes[i] ) ) {
				return true;
			}
		}

		return is_all_same;
	}

	static int get_near_intraday_index() {
		int result = -1;
		int distance = 1440;
		int total_minutes = get_current_total_minutes();

		// Ищем ближайшее время внутри дня текущего дня
		int size = ArraySize ( scheduler_start_intraday_total_minutes );

		for ( int i = 0; i < size; i++ ) {
			if ( scheduler_start_intraday_total_minutes[i] == scheduler_end_intraday_total_minutes[i] ) {
				continue;
			}

			int tmp_distance = scheduler_start_intraday_total_minutes[i] - total_minutes;

			if ( tmp_distance < 0
					|| tmp_distance < distance ) {
				continue;
			}

			distance = tmp_distance;
			result = i;
		}

		if ( result != -1 ) {
			return result;
		}

		// Ищем ближайшее время внутри дня следующего дня
		for ( int i = 0; i < size; i++ ) {
			if ( scheduler_start_intraday_total_minutes[i] == scheduler_end_intraday_total_minutes[i] ) {
				continue;
			}

			if ( distance > scheduler_start_intraday_total_minutes[i] ) {
				distance = scheduler_start_intraday_total_minutes[i];
				result = i;
			}
		}

		return result;
	}

	static bool pre_check_intraday_stop_trade() {
		if ( !check_intraday_stop_trade() ) {
			return false;
		}

		int near_intraday_index = get_near_intraday_stop_trade_index();
		log_info ( StringFormat ( SRC_SCHEDULER_IS_NOR_INTRADAY_STOP_TRADE,
								  scheduler_start_intraday_stop_trade_hour[near_intraday_index],
								  scheduler_start_intraday_stop_trade_minutes[near_intraday_index],
								  scheduler_end_intraday_stop_trade_hour[near_intraday_index],
								  scheduler_end_intraday_stop_trade_minutes[near_intraday_index] ) );
		return true;
	}

	static bool check_intraday_stop_trade() {
		if ( !scheduler_is_intraday_stop_trade_enabled ) {
			return false;
		}

		int total_minutes = get_current_total_minutes();
		int size = ArraySize ( scheduler_start_intraday_stop_trade_total_minutes );

		for ( int i = 0; i < size; i++ ) {
			if ( scheduler_start_intraday_stop_trade_total_minutes[i] != scheduler_end_intraday_stop_trade_total_minutes[i]
					&& check_total_minutes_range ( scheduler_start_intraday_stop_trade_total_minutes[i],
												   total_minutes,
												   scheduler_end_intraday_stop_trade_total_minutes[i] ) ) {
				return true;
			}
		}

		return false;
	}

	static int get_near_intraday_stop_trade_index() {
		int result = -1;
		int distance = 1440;
		int total_minutes = get_current_total_minutes();

		// Ищем ближайшее время внутри дня текущего дня
		int size = ArraySize ( scheduler_start_intraday_stop_trade_total_minutes );

		for ( int i = 0; i < size; i++ ) {
			if ( scheduler_start_intraday_stop_trade_total_minutes[i] == scheduler_end_intraday_stop_trade_total_minutes[i] ) {
				continue;
			}

			int tmp_distance = scheduler_start_intraday_stop_trade_total_minutes[i] - total_minutes;

			if ( tmp_distance < 0
					|| tmp_distance < distance ) {
				continue;
			}

			distance = tmp_distance;
			result = i;
		}

		if ( result != -1 ) {
			return result;
		}

		// Ищем ближайшее время внутри дня следующего дня
		for ( int i = 0; i < size; i++ ) {
			if ( scheduler_start_intraday_stop_trade_total_minutes[i] == scheduler_end_intraday_stop_trade_total_minutes[i] ) {
				continue;
			}

			if ( distance > scheduler_start_intraday_stop_trade_total_minutes[i] ) {
				distance = scheduler_start_intraday_stop_trade_total_minutes[i];
				result = i;
			}
		}

		return result;
	}

	static bool pre_check_close_all_orders ( layer_order_setting *settings_ptr ) {
		if ( !check_close_all_orders ( settings_ptr ) ) {
			return false;
		}

		log_info_k ( StringFormat ( SRC_SCHEDULER_CLOSE_ALLORDERS_EVERYDAY,
									scheduler_close_all_orders_hour,
									scheduler_close_all_orders_minute ) );
		return true;
	}

	static bool check_close_all_orders ( layer_order_setting *settings_ptr ) {
		if ( !scheduler_close_all_orders_enabled ) {
			return false;
		}

		LIST_FIRST_OR_DEFAULT ( scheduler_close_all_orders_lockers, locker, scheduler_close_all_orders_locker *, item, item.settings == settings_ptr );
		ACTION_ON_NONVALUE_OR_DEFAULT ( locker, {
			locker = new scheduler_close_all_orders_locker();
			locker.settings = settings_ptr;
			locker.lock = false;
			scheduler_close_all_orders_lockers.add ( locker );
		} );

		bool result = check_total_minutes_range ( scheduler_close_all_orders_total_minute,
					  get_current_total_minutes(),
					  scheduler_close_all_orders_total_minute_with_wait );

		if ( !result ) {
			locker.lock = false;
			return false;
		}

		if ( locker.lock ) {
			return false;
		}

		locker.lock = true;
		return true;
	}

	static bool check_total_minutes_range ( int start_range, int value, int end_range ) {
		return start_range <= value && value < end_range;
	}

	static string get_day_of_week_str ( int day_of_week ) {
		switch ( day_of_week ) {
			case 0:
				return SRC_SCHEDULER_SUNDAY;

			case 1:
				return SRC_SCHEDULER_MONDAY;

			case 2:
				return SRC_SCHEDULER_TUESDAY;

			case 3:
				return SRC_SCHEDULER_WEDNESDAY;

			case 4:
				return SRC_SCHEDULER_THURSDAY;

			case 5:
				return SRC_SCHEDULER_FRIDAY;

			case 6:
				return SRC_SCHEDULER_SATURDAY;

			default:
				return "";
		}
	}
};

#endif

class setting_t : public disposable_obj  {
public:
	bool is_testing;
	double testing_balance;
	double testing_layer_market_lot_min;

	int magic_number;
	int max_spread;

	bool close_all_orders;
	bool open_positions;
	bool open_first_order;
	int max_open_orders;

	int pause_on_close_in_sec;


	enum_position_signal position_signal;

	ENUM_TIMEFRAMES time_frame;
	int candles_for_open_first_order;
	bool candles_for_open_first_order_open_close;
	int candles_for_open_first_order_min_pips;
	int candles_for_open_first_order_max_pips;
	bool revers_signal_to_open_first_order;

	enum_take_profit_calc_type tp_type;
	int take_proffit;
	int take_proffit_level1;
	int take_proffit_level1_corr;
	int take_proffit_level2;
	int take_proffit_level2_corr;
	int take_proffit_level3;
	int take_proffit_level3_fix_pips;
	int take_profit_control_timing;
	int take_profit_control_noloss_fixpips;
	int max_spread_stop_drading_timing;

	int grid_step;
	int grid_level;
	int grid_value;
	int grid_level2;
	int grid_level2_add_pips;
	int grid_level3;
	int grid_level3_add_pips;
	int grid_stop;

	enum_calc_lot_type mult_type;
	int currency_for_min_lot;
	double lots;
	int lot_exp;
	int multi_lots_level1;
	double multi_lots_factor;
	int multi_lots_level2;
	double multi_lots_level2_corr;
	int multi_lots_level3;
	double multi_lots_level3_corr;
	int mult4;
	double mult4_add;

	int mult_stop;
	double max_lot;

	enum_gap_control_type gap_control;
	int gap_max_order_stop;
	int gap_min_pips_from_market;
	int gap_min_pips;
	int gap_min_percent;
	double gap_lot_koef;
	double gap_last_order_koef;

	ENUM_TIMEFRAMES vol_candle_tf;
	int vol_candle_max_size;
	int vol_stop_trade_timing;
	int vol_from_level;
	bool vol_block_both_direction;

	day_of_week_t trade_start_day;
	int trade_start_minute;
	day_of_week_t trade_end_day;
	int trade_stop_minute;

	datetime final_stop_trading;
	int max_trade_pairs;
	int currency_block;
	int no1Order_by_drawdown_percent;
	int no1Order_by_drawdown_percent_off;
	bool close_all_orders_by_drawdown_stop_trade;
	string add_comment;
	int min_leverage;
	int min_time_step;

	string currency_block_label;
	string max_trade_pairs_label;
};

#endif

#property strict
#property version VER

#ifdef NODE
#define INPUT
#define SINPUT
#else
#define INPUT input
#define SINPUT sinput
#endif

input string set_info_MAJOR_VER_MINOR_VER = "Информация о сете и авторе"; // ===== Информация о сете

input string set_name = "Setka v1.54-RSI-AUDCAD-H1_(5,3-633)_tp_avg_17-26.05.1"; // Название сета
input string set_pair = "AUDCAD"; // Валютная пара
input string set_author = ""; // Автор сета
input string set_version = ""; // Версия сета
//--- main_settings
input string main_settings_MAJOR_VER_MINOR_VER = "Общие настройки и управление торгами"; // ===== Общие настройки

input bool TradeSell = true;
input bool TradeBuy = true;
input bool S_OpenFirstOrder = true;
input bool B_OpenFirstOrder = true;
input double LevelNoFirstOrderSell = 0.0;
input double LevelNoFirstOrderBuy = 0.0;
input bool S_CloseAllOrders = false;
input bool B_CloseAllOrders = false;
input int S_PauseOnClose = 0;
input int B_PauseOnClose = 0;
input ulong MagicNumber = 11111;
input string AddComment = "AUDCAD H1";
input bool ReflectSellSettingsToBuy = false;
//--- filters_part
input string filters_part_MAJOR_VER_MINOR_VER = "Фильтры спрэда и одновременно торгуемых пар и валют"; // ===== Фильтры, часть 1

input double MaxSpread = 8.0;
input int MaxSpreadStopTradingTimining = 45;
input int MinLeverage = 400;
input int MinTimeStep = 0;
input int MaxTradePairs = 3;
input int CurrencyBlock = 1;
//--- levels_settings
input string levels_settings_MAJOR_VER_MINOR_VER = "Настройки параметров полуавтоматической работы от уровней"; // ===== Работа в полуавтоматическом режиме

input double LevelForSell = 0.0;
input double LevelForSell_MoveKoafInPercentByTP = 0.0;
input double LevelForBuy = 0.0;
input double LevelForBuy_MoveKoafInPercentByTP = 0.0;
//--- trade_control_by_drawdown
input string trade_control_by_drawdown_MAJOR_VER_MINOR_VER = "Управление торгами в зависимости от просадки"; // ===== Контроль просадки

input double No1Order_ByDrawdownPercent = 0.0;
input double No1Order_ByDrawdownPercent_Off = 0.0;
input double StopTrade_ByDrawdownPercent = 0.0;
input double StopTrade_ByDrawdownPercent_Off = 0.0;
input double StopTrade_ByDrawdownMoney = 0.0;
input double StopTrade_ByDrawdownMoney_Off = 0.0;
input double CloseAllOrders_ByProfitPercent = 0.0;
input double CloseAllOrders_ByProfitMoney = 0.0;
input double CloseAllOrders_ByDrawdownPercent = 0.0;
input double CloseAllOrders_ByDrawdownMoney = 0.0;
input double S_CloseOrders_ByDrawdown_For001Lot = 0.0;
input double B_CloseOrders_ByDrawdown_For001Lot = 0.0;
input bool CloseAllOrders_ByDrawdown_StopTrade = true;
//--- money_management
input string money_management_MAJOR_VER_MINOR_VER = ""; // ===== Управление лотностью

input bool UseBalanceForMM = false;
input double NotUsedCurrency = 0.0;
input double UsedCurrencyPercent = 100.0;
//--- sell_step_settings
input string sell_step_settings_MAJOR_VER_MINOR_VER = "SELL сетки - настройки шагов, количества колен и длины"; // ===== SELL сетки - шаг и поправки в 4-хзначных пипсах

input int S_MaxOpenOrders = 10;
input double S_GridStep = 25.0;
input int S_GridLevel = 0;
input double S_GridStep_AddPips = 0.0;
input int S_GridStep_Level2 = 0;
input double S_GridStep_Level2_AddPips = 0.0;
input int S_Grid3 = 0;
input double S_Grid3Add = 0.0;
input int S_GridStop = 0;
//--- sell_lot_settings
input string sell_lot_settings_MAJOR_VER_MINOR_VER = "SELL сетки - min ордер и множители лота всех колен"; // ===== SELL сетки - настройки лотов ордеров всех колен

input enum_calc_lot_type S_CalcLotType = calc_lot_type_last_order;
input double S_CurrencyFor001Lot = 0.0;
input double S_MinLot = 0.01;
input double S_Mult = 1.55;
input int S_MultStart = 2;
input int S_MultLevel2 = 0;
input double S_MultCorr = 0.0;
input int S_MultLevel3 = 0;
input double S_MultСorrLevel3 = 0.0;
input int S_Mult3 = 0;
input double S_Mult3Add = 0.0;
input int S_MultStop = 0;
input double S_MaxLotCoef = 26.0;
input double S_TestMinLot = 0.0;
//--- sell_tp_settings
input string sell_tp_settings_MAJOR_VER_MINOR_VER = "SELL сетки: настройки TP (чистая прибыль) ==> [уровень_БУ]+ТР"; // ===== SELL сетки - TP и поправка в 4-хзначных пипсах

input enum_take_profit_calc_type S_TakeProffitType = tp_avg;
input double S_TakeProffit = 23.0;
input int S_TakeProffit_Level1 = 0;
input double S_TakeProffit_Level1Corr = 0.0;
input int S_TakeProffit_Level1_5 = 0;
input double S_TakeProffit_Level1_5Corr = 0.0;
input int S_TakeProffit_Level2 = 0;
input double S_TakeProffit_Level2FixPips = 0.0;
//--- buy_step_settings
input string buy_step_settings_MAJOR_VER_MINOR_VER = "BUY сетки - настройки шагов, количества колен и длины"; // ===== BUY сетки - шаг и поправки в 4-хзначных пипсах

input int B_MaxOpenOrders = 10;
input double B_GridStep = 40.0;
input int B_GridLevel = 0;
input double B_GridStep_AddPips = 0.0;
input int B_GridStep_Level2 = 0;
input double B_GridStep_Level2_AddPips = 0.0;
input int B_Grid3 = 0;
input double B_Grid3Add = 0.0;
input int B_GridStop = 0;
//--- buy_lot_settings
input string buy_lot_settings_MAJOR_VER_MINOR_VER = "BUY сетки - min ордер и множители лота всех колен"; // ===== BUY сетки - настройки лотов ордеров всех колен

input enum_calc_lot_type B_CalcLotType = calc_lot_type_last_order;
input double B_CurrencyFor001Lot = 0.0;
input double B_MinLot = 0.01;
input double B_Mult = 1.55;
input int B_MultStart = 2;
input int B_MultLevel2 = 0;
input double B_MultCorr = 0.0;
input int B_MultLevel3 = 0;
input double B_MultСorrLevel3 = 0.0;
input int B_Mult3 = 0;
input double B_Mult3Add = 0.0;
input int B_MultStop = 0;
input double B_MaxLotCoef = 26.0;
input double B_TestMinLot = 0.0;
//--- buy_tp_settings
input string buy_tp_settings_MAJOR_VER_MINOR_VER = "BUY сетки: настройки TP (прибыль) ==> [уровень_БУ]+ТР"; // ===== BUY сетки - TP и поправка в 4-хзначных пипсах

input enum_take_profit_calc_type B_TakeProffitType = tp_avg;
input double B_TakeProffit = 26.0;
input int B_TakeProffit_Level1 = 0;
input double B_TakeProffit_Level1Corr = 0.0;
input int B_TakeProffit_Level1_5 = 0;
input double B_TakeProffit_Level1_5Corr = 0.0;
input int B_TakeProffit_Level2 = 0;
input double B_TakeProffit_Level2FixPips = 0.0;
//--- rsi_cci_filter_settings
input string rsi_cci_filter_settings_MAJOR_VER_MINOR_VER = "Фильтр - RSI-CCI"; // ===== Фильтры, ИНДИКАТОРНЫЙ RSI-CCI фильтр

input ENUM_TIMEFRAMES CandleTimeframe = PERIOD_H1;
input ENUM_TIMEFRAMES CandleTimeframeNext = PERIOD_H1;
input ENUM_TIMEFRAMES RsiTimeframe = PERIOD_H1;
input int RsiPeriod = 9;
input double RsiLevel = 20.0;
input ENUM_TIMEFRAMES RsiTimeframeNext = PERIOD_M5;
input int RsiPeriodNext = 14;
input double RsiLevelNext = 20.0;
input ENUM_TIMEFRAMES CciTimeframe = PERIOD_H1;
input int CciPeriod = 16;
input double CciLevel = 100.0;
input ENUM_TIMEFRAMES CciTimeframeNext = PERIOD_M5;
input int CciPeriodNext = 30;
input double CciLevelNext = 50.0;
input bool use_for1Order = true;
input int use_for_next_Order = 0;
//--- without_indicator_settings
input string without_indicator_settings_MAJOR_VER_MINOR_VER = "Настройки параметров и фильтров безиндикаторного входа"; // ===== Фильтры, часть 2 - безиндикаторный вход 1-м ордером

input ENUM_TIMEFRAMES OpenFirstOrderTF = PERIOD_M1;
input int CandlesToOpen1Order = 0;
input bool CandlesToOpen1Order_OpenClose = false;
input double CandlesToOpen1Order_MinPips = 0.0;
input double CandlesToOpen1Order_MaxPips = 0.0;
input bool ReversSignalToOpen1Order = true;
input bool CandlesToOpen1Order_OneWay = true;
//--- gap_settings
input string gap_settings_MAJOR_VER_MINOR_VER = "Настройки блока выявления и обработки гэпов"; // ===== Фильтры, часть 3 - обработка мартин-гэпов

input int GapControl = 2;
input int GapMaxStopOrders = 4;
input double GapMinDistanceFromMarket = 2.0;
input double S_GapMinPips = 5.0;
input double S_GapMinPercent = 0.0;
input double S_GapLotKoef = 0.5;
input double S_GapLastOrderKoef = 2.0;
input double B_GapMinPips = 5.0;
input double B_GapMinPercent = 0.0;
input double B_GapLotKoef = 0.5;
input double B_GapLastOrderKoef = 2.0;
input int FarPendingOrdersDelete = 0;
//--- vol_filter1_settings
input string vol_filter1_settings_MAJOR_VER_MINOR_VER = "Фильтр - Запрет открывать ордера, если импульс"; // ===== Фильтры, часть 4 - фильтр волатильности №1

input int VolFromLevel = 1;
input ENUM_TIMEFRAMES VolCandleTF = PERIOD_M1;
input double VolCandleMaxSize = 40.0;
input int VolStopTradeTimining = 60;
input bool VolBlockBothDirection = true;
//--- sheduler_settings
input string sheduler_settings_MAJOR_VER_MINOR_VER = "Настройки планировщиков торговли - их 5 разных"; // ===== Фильтры, часть 6 - фильтры времени торговли

//--- sheduler_trade_week_settings
input string sheduler_trade_week_settings_MAJOR_VER_MINOR_VER = "№1 Еженедельно: можно открывать 1-е ордера со Start_дня|время по End_день|время"; // ===№1 Еженедельно: можно открывать 1-е ордера - начало/конец

input int TradeStartDay = 1;
input int TradeStartHour = 1;
input int TradeStartMinute = 0;
input int TradeEndDay = 5;
input int TradeEndHour = 16;
input int TradeEndMinute = 0;
//--- sheduler_new_positio_pause_settings
input string sheduler_new_positio_pause_settings_MAJOR_VER_MINOR_VER = "№2 Однократно: от и до - запрещено открывать любые новые позиции"; // ===№2 Однократно: запрещено открывать 1-е ордера

input datetime NewPositionPause1Start = 0;
input datetime NewPositionPause1End = 0;
input datetime NewPositionPause2Start = 0;
input datetime NewPositionPause2End = 0;
input datetime NewPositionPause3Start = 0;
input datetime NewPositionPause3End = 0;
input datetime NewPositionPause4Start = 0;
input datetime NewPositionPause4End = 0;
input datetime NewPositionPause5Start = 0;
input datetime NewPositionPause5End = 0;
input datetime NewPositionPause6Start = 0;
input datetime NewPositionPause6End = 0;
input datetime NewPositionPause7Start = 0;
input datetime NewPositionPause7End = 0;
input datetime NewPositionPause8Start = 0;
input datetime NewPositionPause8End = 0;
input datetime NewPositionPause9Start = 0;
input datetime NewPositionPause9End = 0;
input datetime NewPositionPause10Start = 0;
input datetime NewPositionPause10End = 0;
input datetime NewPositionPauseNewYearDayStart = 0;
input datetime NewPositionPauseNewYearDayEnd = 0;
//--- sheduler_trade_day_settings
input string sheduler_trade_day_settings_MAJOR_VER_MINOR_VER = "№3 Ежедневно: можно открывать 1-е ордера сеток - 10 интервалов"; // ===№3 Ежедневно: до 10 интервалов открытия 1-х ордеров

input int IntraDay1StartHour = 0;
input int IntraDay1StartMinute = 0;
input int IntraDay1EndHour = 0;
input int IntraDay1EndMinute = 0;
input int IntraDay2StartHour = 0;
input int IntraDay2StartMinute = 0;
input int IntraDay2EndHour = 0;
input int IntraDay2EndMinute = 0;
input int IntraDay3StartHour = 0;
input int IntraDay3StartMinute = 0;
input int IntraDay3EndHour = 0;
input int IntraDay3EndMinute = 0;
input int IntraDay4StartHour = 0;
input int IntraDay4StartMinute = 0;
input int IntraDay4EndHour = 0;
input int IntraDay4EndMinute = 0;
input int IntraDay5StartHour = 0;
input int IntraDay5StartMinute = 0;
input int IntraDay5EndHour = 0;
input int IntraDay5EndMinute = 0;
input int IntraDay6StartHour = 0;
input int IntraDay6StartMinute = 0;
input int IntraDay6EndHour = 0;
input int IntraDay6EndMinute = 0;
input int IntraDay7StartHour = 0;
input int IntraDay7StartMinute = 0;
input int IntraDay7EndHour = 0;
input int IntraDay7EndMinute = 0;
input int IntraDay8StartHour = 0;
input int IntraDay8StartMinute = 0;
input int IntraDay8EndHour = 0;
input int IntraDay8EndMinute = 0;
input int IntraDay9StartHour = 0;
input int IntraDay9StartMinute = 0;
input int IntraDay9EndHour = 0;
input int IntraDay9EndMinute = 0;
input int IntraDay10StartHour = 0;
input int IntraDay10StartMinute = 0;
input int IntraDay10EndHour = 0;
input int IntraDay10EndMinute = 0;
//--- sheduler_trade_pause_settings
input string sheduler_trade_pause_settings_MAJOR_VER_MINOR_VER = "№4 Однократно: от и до - запрещено открывать любые ордера"; // ===№4 Однократно: от и до - запрещено открывать любые ордера

input datetime TradePause1Start = 0;
input datetime TradePause1End = 0;
input datetime TradePause2Start = 0;
input datetime TradePause2End = 0;
input datetime TradePause3Start = 0;
input datetime TradePause3End = 0;
input datetime TradePause4Start = 0;
input datetime TradePause4End = 0;
input datetime TradePause5Start = 0;
input datetime TradePause5End = 0;
input datetime TradePause6Start = 0;
input datetime TradePause6End = 0;
input datetime TradePause7Start = 0;
input datetime TradePause7End = 0;
input datetime TradePause8Start = 0;
input datetime TradePause8End = 0;
input datetime TradePause9Start = 0;
input datetime TradePause9End = 0;
input datetime TradePause10Start = 0;
input datetime TradePause10End = 0;
//--- sheduler_trade_stop_settings
input string sheduler_trade_stop_settings_MAJOR_VER_MINOR_VER = "№5 Ежедневно - до 10 интервалов запрета открывать любые ордера"; // ===№5 Ежедневно - до 10 интервалов запрета открывать любые ордера

input int IntraDayStopTrade1StartHour = 0;
input int IntraDayStopTrade1StartMinute = 0;
input int IntraDayStopTrade1EndHour = 0;
input int IntraDayStopTrade1EndMinute = 0;
input int IntraDayStopTrade2StartHour = 0;
input int IntraDayStopTrade2StartMinute = 0;
input int IntraDayStopTrade2EndHour = 0;
input int IntraDayStopTrade2EndMinute = 0;
input int IntraDayStopTrade3StartHour = 0;
input int IntraDayStopTrade3StartMinute = 0;
input int IntraDayStopTrade3EndHour = 0;
input int IntraDayStopTrade3EndMinute = 0;
input int IntraDayStopTrade4StartHour = 0;
input int IntraDayStopTrade4StartMinute = 0;
input int IntraDayStopTrade4EndHour = 0;
input int IntraDayStopTrade4EndMinute = 0;
input int IntraDayStopTrade5StartHour = 0;
input int IntraDayStopTrade5StartMinute = 0;
input int IntraDayStopTrade5EndHour = 0;
input int IntraDayStopTrade5EndMinute = 0;
input int IntraDayStopTrade6StartHour = 0;
input int IntraDayStopTrade6StartMinute = 0;
input int IntraDayStopTrade6EndHour = 0;
input int IntraDayStopTrade6EndMinute = 0;
input int IntraDayStopTrade7StartHour = 0;
input int IntraDayStopTrade7StartMinute = 0;
input int IntraDayStopTrade7EndHour = 0;
input int IntraDayStopTrade7EndMinute = 0;
input int IntraDayStopTrade8StartHour = 0;
input int IntraDayStopTrade8StartMinute = 0;
input int IntraDayStopTrade8EndHour = 0;
input int IntraDayStopTrade8EndMinute = 0;
input int IntraDayStopTrade9StartHour = 0;
input int IntraDayStopTrade9StartMinute = 0;
input int IntraDayStopTrade9EndHour = 0;
input int IntraDayStopTrade9EndMinute = 0;
input int IntraDayStopTrade10StartHour = 0;
input int IntraDayStopTrade10StartMinute = 0;
input int IntraDayStopTrade10EndHour = 0;
input int IntraDayStopTrade10EndMinute = 0;
//--- sheduler_close_all_order_settings
input string sheduler_close_all_order_settings_MAJOR_VER_MINOR_VER = "№6 Ежедневно - закрытие обеих сеток в одно время"; // ===№6 Ежедневно - закрытие обеих сеток в одно время

input int CloseAllOrders_EveryDay_Hour = 0;
input int CloseAllOrders_EveryDay_Minute = 0;
//--- other_settings
input string other_settings_MAJOR_VER_MINOR_VER = "Прочие общие настройки"; // ===== Прочие общие настройки

input int TakeProffitControlTiming = 90;
input double TakeProffitControlNoLossFixPips = 0.0;
input datetime FinalGridDate = 1924819200;
input int GlobalParamsUpdateTiming = 60;

//--- prototype_settings

// ===== Internal compatibility variables for preserved Setka 1.43 trading code =====
int Iterator = 0;
int S_CurrencyForMinLot = (int)S_CurrencyFor001Lot;
int B_CurrencyForMinLot = (int)B_CurrencyFor001Lot;
int LogVerbose = 2;
bool UseRsiCciFilter = false;
bool UseWithoutIndicatorFilter = true;
bool UseGapControlBlock = true;
bool UseVolatilityBlock = true;
enum_position_signal PositionSignal = enum_position_signal_simple;
// ===== End internal compatibility variables =====

#define conv_expression(exp) \
	ext_string::replace( ext_string::replace( ext_string::replace( ext_string::replace( exp, "!=", SRC_DEFINES_NOT_EQUALLY ), "==", SRC_DEFINES_EQUALLY ), "||", SRC_DEFINES_OR ), "&&", SRC_DEFINES_AND )

#ifdef FOR_OPTIMIZATION

#define def_to_str_from_int( value ) EXT_STRING_EMPTY

#define valid_tboo(field) ( true )
#define valid_tint(field) ( true )
#define valid_tdou(field) ( true )
#define valid_tenu(field) ( true )
#define valid_tstr(field) ( true )
#define valid_bool(field, expression) ( expression )
#define valid_inte(field, expression) ( expression )
#define valid_doub(field, expression) ( expression )
#define valid_enum(field, expression) ( expression )

#else

#define def_to_str_from_int( value ) StringFormat("%s = %s", #value, IntegerToString( value ) )

#define valid_tboo(field) \
	defines_validate( true,\
					  EXT_STRING_EMPTY,\
					  StringFormat ( SRC_DEFINES_VALID_MSG, #field, ( field ? "true" : "false" ) ) )

#define valid_tint(field) \
	defines_validate( true,\
					  EXT_STRING_EMPTY,\
					  StringFormat ( SRC_DEFINES_VALID_MSG, #field, IntegerToString ( field ) ) )

#define valid_tdou(field) \
	defines_validate( true,\
					  EXT_STRING_EMPTY,\
					  StringFormat ( SRC_DEFINES_VALID_MSG, #field, DoubleToString ( field ) ) )

#define valid_tenu(field) \
	defines_validate( true,\
					  EXT_STRING_EMPTY,\
					  StringFormat ( SRC_DEFINES_VALID_MSG, #field, EnumToString ( field ) ) )

#define valid_tstr(field) \
	defines_validate( true,\
					  EXT_STRING_EMPTY,\
					  StringFormat ( SRC_DEFINES_VALID_MSG, #field, field ) )

#define valid_bool(field, expression) \
	defines_validate( expression,\
					  StringFormat ( SRC_DEFINES_ERROR_MSG, #field, conv_expression(#expression) ),\
					  StringFormat ( SRC_DEFINES_VALID_MSG, #field, ( field ? "true" : "false" ) ) )

#define valid_inte(field, expression) \
	defines_validate( expression,\
					  StringFormat ( SRC_DEFINES_ERROR_MSG, #field, conv_expression(#expression) ),\
					  StringFormat ( SRC_DEFINES_VALID_MSG, #field, IntegerToString ( field ) ) )

#define valid_doub(field, expression) \
	defines_validate( expression,\
					  StringFormat ( SRC_DEFINES_ERROR_MSG, #field, conv_expression(#expression) ),\
					  StringFormat ( SRC_DEFINES_VALID_MSG, #field, DoubleToString ( field ) ) )

#define valid_enum(field, expression) \
	defines_validate( expression,\
					  StringFormat ( SRC_DEFINES_ERROR_MSG, #field, conv_expression(#expression) ),\
					  StringFormat ( SRC_DEFINES_VALID_MSG, #field, EnumToString ( field ) ) )

bool defines_validate ( bool value, string not_valid_msg, string valid_msg )
{
	log_info ( valid_msg );

	if ( value ) {
		return true;
	}

	log_error ( not_valid_msg );
	MessageBox ( not_valid_msg, SRC_DEFINES_ERROR_INPUT, MB_OK );
	return false;
}

#endif

#define check_new_position_pause(number) \
	(valid_tint ( NewPositionPause##number##Start ) \
	 && valid_inte ( NewPositionPause##number##End, \
					 NewPositionPause##number##Start == MIN_DATE \
					 || NewPositionPause##number##End > NewPositionPause##number##Start ))

#define check_trade_pause(number) \
	(valid_tint ( TradePause##number##Start ) \
	 && valid_inte ( TradePause##number##End, \
					 TradePause##number##Start == MIN_DATE \
					 || TradePause##number##End > TradePause##number##Start ))

#define check_intrade(number) \
	(valid_inte ( IntraDay##number##StartHour, \
				  IntraDay##number##StartHour >= 0 \
				  && IntraDay##number##StartHour <= 23 ) \
	 && valid_inte ( IntraDay##number##StartMinute, \
					 IntraDay##number##StartMinute >= 0 \
					 && IntraDay##number##StartMinute <= 59 ) \
	 && valid_inte ( IntraDay##number##EndHour, \
					 IntraDay##number##EndHour >= 0 \
					 && IntraDay##number##EndHour <= 23 \
					 && IntraDay##number##EndHour >= IntraDay##number##StartHour ) \
	 && valid_inte ( IntraDay##number##EndMinute, \
					 IntraDay##number##EndMinute >= 0 \
					 && IntraDay##number##EndMinute <= 59 \
					 && ( IntraDay##number##StartHour != IntraDay##number##EndHour \
						  || ( IntraDay##number##StartHour == IntraDay##number##EndHour \
							   &&  IntraDay##number##StartMinute <= IntraDay##number##EndMinute ) ) ))

#define check_intraday_stop_trade(number) \
	(valid_inte ( IntraDayStopTrade##number##StartHour, \
				  IntraDayStopTrade##number##StartHour >= 0 \
				  && IntraDayStopTrade##number##StartHour <= 23 ) \
	 && valid_inte ( IntraDayStopTrade##number##StartMinute, \
					 IntraDayStopTrade##number##StartMinute >= 0 \
					 && IntraDayStopTrade##number##StartMinute <= 59 ) \
	 && valid_inte ( IntraDayStopTrade##number##EndHour, \
					 IntraDayStopTrade##number##EndHour >= 0 \
					 && IntraDayStopTrade##number##EndHour <= 23 \
					 && IntraDayStopTrade##number##EndHour >= IntraDayStopTrade##number##StartHour ) \
	 && valid_inte ( IntraDayStopTrade##number##EndMinute, \
					 IntraDayStopTrade##number##EndMinute >= 0 \
					 && IntraDayStopTrade##number##EndMinute <= 59 \
					 && ( IntraDayStopTrade##number##StartHour != IntraDayStopTrade##number##EndHour \
						  || ( IntraDayStopTrade##number##StartHour == IntraDayStopTrade##number##EndHour \
							   &&  IntraDayStopTrade##number##StartMinute <= IntraDayStopTrade##number##EndMinute ) ) ))

bool defines_validate()
{
	return valid_tboo ( TradeSell )
		   && valid_tboo ( TradeBuy )
		   && valid_tboo ( S_OpenFirstOrder )
		   && valid_tboo ( B_OpenFirstOrder )
		   && valid_tboo ( S_CloseAllOrders )
		   && valid_tboo ( B_CloseAllOrders )
		   && valid_inte ( No1Order_ByDrawdownPercent,
						   No1Order_ByDrawdownPercent >= 0
						   && No1Order_ByDrawdownPercent <= 100 )
		   && valid_inte ( StopTrade_ByDrawdownPercent,
						   StopTrade_ByDrawdownPercent >= 0
						   && StopTrade_ByDrawdownPercent <= 100 )
		   && valid_inte ( StopTrade_ByDrawdownPercent_Off,
						   StopTrade_ByDrawdownPercent_Off == 0
						   || ( StopTrade_ByDrawdownPercent_Off >= 0
								&& StopTrade_ByDrawdownPercent_Off <= StopTrade_ByDrawdownPercent ) )
		   && valid_inte ( StopTrade_ByDrawdownMoney,
						   StopTrade_ByDrawdownMoney >= 0 )
		   && valid_inte ( StopTrade_ByDrawdownMoney_Off,
						   StopTrade_ByDrawdownMoney_Off == 0
						   || ( StopTrade_ByDrawdownMoney_Off >= 0
								&& StopTrade_ByDrawdownMoney_Off <= StopTrade_ByDrawdownMoney ) )
		   && valid_doub ( CloseAllOrders_ByProfitPercent,
						   CloseAllOrders_ByProfitPercent >= 0.0
						   && CloseAllOrders_ByProfitPercent <= 100.0 )
		   && valid_doub ( CloseAllOrders_ByProfitMoney,
						   CloseAllOrders_ByProfitMoney >= 0.0 )
		   && valid_doub ( CloseAllOrders_ByDrawdownPercent,
						   CloseAllOrders_ByDrawdownPercent >= 0.0
						   && CloseAllOrders_ByDrawdownPercent <= 100.0 )
		   && valid_doub ( CloseAllOrders_ByDrawdownMoney,
						   CloseAllOrders_ByDrawdownMoney >= 0 )
		   && valid_inte ( S_PauseOnClose, S_PauseOnClose >= 0 )
		   && valid_inte ( B_PauseOnClose, B_PauseOnClose >= 0 )
		   && valid_inte ( MaxSpread,
						   MaxSpread == 0
						   || ( MaxSpread > 0 && MaxSpreadStopTradingTimining >= 30 ) )
		   && valid_inte ( MaxSpreadStopTradingTimining,
						   MaxSpread == 0
						   || ( MaxSpread > 0 && MaxSpreadStopTradingTimining >= 30 ) )
		   && valid_inte ( MinLeverage,
						   MinLeverage >= 0 )
		   && valid_inte ( MinTimeStep,
						   MinTimeStep >= 0 )
		   && valid_inte ( MaxTradePairs,
						   MaxTradePairs >= 0 )
		   && valid_inte ( CurrencyBlock,
						   CurrencyBlock >= 0 && CurrencyBlock < 100 )
		   && valid_tint ( MagicNumber )
		   && valid_tstr ( AddComment )
		   && valid_tboo ( ReflectSellSettingsToBuy )
		   // Найстройки шага сетки для коротких позиций
		   && valid_inte ( S_MaxOpenOrders,
						   S_MaxOpenOrders > 0 )
		   && valid_inte ( S_GridStep, S_GridStep > 0 )
		   && valid_inte ( S_GridLevel,
						   S_GridLevel == 0
						   || ( S_GridLevel > 1
								&& S_GridLevel <= S_MaxOpenOrders ) )
		   && valid_tint ( S_GridStep_AddPips )
		   && valid_inte ( S_GridStep_Level2,
						   S_GridStep_Level2 == 0
						   || ( S_GridLevel > 0
								&& S_GridStep_Level2 > S_GridLevel
								&& S_GridStep_Level2 <= S_MaxOpenOrders ) )
		   && valid_tint ( S_GridStep_Level2_AddPips )
		   && valid_inte ( S_Grid3,
						   S_Grid3 == 0
						   || ( S_GridStep_Level2 > 0
								&& S_Grid3 > S_GridStep_Level2
								&& S_Grid3 <= S_MaxOpenOrders ) )
		   && valid_tint ( S_Grid3Add )
		   && valid_inte ( S_GridStop,
						   S_GridStop >= 0
						   && S_GridStop <= S_MaxOpenOrders )
		   // Настройки лота для коротких позиций
		   && valid_tint ( S_CalcLotType )
		   && valid_inte ( S_CurrencyForMinLot,
						   S_CurrencyForMinLot >= 0 )
		   && valid_tdou ( S_MinLot )
		   && valid_doub ( S_Mult,
						   S_Mult > 0.00 )
		   && valid_inte ( S_MultStart,
						   S_MultStart > 1
						   && S_MultStart <= S_MaxOpenOrders )
		   && valid_inte ( S_MultLevel2,
						   S_MultLevel2 == 0
						   || ( S_MultStart > 0
								&& S_MultLevel2 > S_MultStart
								&& S_MultLevel2 <= S_MaxOpenOrders ) )
		   && valid_tdou ( S_MultCorr )
		   && valid_inte ( S_MultLevel3,
						   S_MultLevel3 == 0
						   || ( S_MultLevel2 > 0
								&& S_MultLevel3 > S_MultLevel2
								&& S_MultLevel3 <= S_MaxOpenOrders ) )
		   && valid_tdou ( S_MultСorrLevel3 )
		   && valid_inte ( S_Mult3,
						   S_Mult3 == 0
						   || ( S_MultLevel3 > 0
								&& S_Mult3 > S_MultLevel3
								&& S_Mult3 <= S_MaxOpenOrders ) )
		   && valid_tdou ( S_Mult3Add )
		   && valid_inte ( S_MultStop,
						   S_MultStop >= 0
						   && S_MultStop <= S_MaxOpenOrders )
		   && valid_doub ( S_MaxLotCoef,
						   S_MaxLotCoef == 0
						   || S_MaxLotCoef >= S_MaxLotCoef )
		   // Настройки ТР для коротких позиций
		   && valid_tint ( S_TakeProffitType )
		   && valid_doub ( S_TakeProffit,
						   S_TakeProffit > 0.0 )
		   && valid_inte ( S_TakeProffit_Level1,
						   S_TakeProffit_Level1 == 0
						   || ( S_TakeProffit_Level1 > 1
								&& S_TakeProffit_Level1 <= S_MaxOpenOrders ) )
		   && valid_tint ( S_TakeProffit_Level1Corr )
		   && valid_inte ( S_TakeProffit_Level1_5,
						   S_TakeProffit_Level1_5 == 0
						   || ( S_TakeProffit_Level1_5 > S_TakeProffit_Level1
								&& S_TakeProffit_Level1_5 <= S_MaxOpenOrders ) )
		   && valid_tint ( S_TakeProffit_Level1_5Corr )
		   && valid_inte ( S_TakeProffit_Level2,
						   S_TakeProffit_Level2 == 0
						   || ( S_TakeProffit_Level2 > S_TakeProffit_Level1
								&& S_TakeProffit_Level2 <= S_MaxOpenOrders ) )
		   && valid_inte ( S_TakeProffit_Level2FixPips,
						   S_TakeProffit_Level2 == 0
						   || S_TakeProffit_Level2FixPips >= TakeProffitControlNoLossFixPips )
		   // Найстройки шага сетки для длинных позиций
		   && ( ReflectSellSettingsToBuy
				|| ( valid_inte ( B_MaxOpenOrders,
								  B_MaxOpenOrders > 0 )
					 && valid_inte ( B_GridStep, B_GridStep > 0 )
					 && valid_inte ( B_GridLevel,
									 B_GridLevel == 0
									 || ( B_GridLevel > 1
										  && B_GridLevel <= B_MaxOpenOrders ) )
					 && valid_tint ( B_GridStep_AddPips )
					 && valid_inte ( B_GridStep_Level2,
									 B_GridStep_Level2 == 0
									 || ( B_GridLevel > 0
										  && B_GridStep_Level2 > B_GridLevel
										  && B_GridStep_Level2 <= B_MaxOpenOrders ) )
					 && valid_tint ( B_GridStep_Level2_AddPips )
					 && valid_inte ( B_Grid3,
									 B_Grid3 == 0
									 || ( B_GridStep_Level2 > 0
										  && B_Grid3 > B_GridStep_Level2
										  && B_Grid3 <= B_MaxOpenOrders ) )
					 && valid_tint ( S_Grid3Add )
					 && valid_inte ( B_GridStop,
									 B_GridStop >= 0
									 && B_GridStop <= B_MaxOpenOrders ) ) )
		   // Настройки лота для длинных позиций
		   && ( ReflectSellSettingsToBuy
				|| ( valid_tint ( B_CalcLotType )
					 && valid_inte ( B_CurrencyForMinLot,
									 B_CurrencyForMinLot >= 0 )
					 && valid_tdou ( B_MinLot )
					 && valid_doub ( B_Mult,
									 B_Mult > 0.00 )
					 && valid_inte ( B_MultStart,
									 B_MultStart > 1
									 && B_MultStart <= B_MaxOpenOrders )
					 && valid_inte ( B_MultLevel2,
									 B_MultLevel2 == 0
									 || ( B_MultStart > 0
										  && B_MultLevel2 > B_MultStart
										  && B_MultLevel2 <= B_MaxOpenOrders ) )
					 && valid_tdou ( B_MultCorr )
					 && valid_inte ( B_MultLevel3,
									 B_MultLevel3 == 0
									 || ( B_MultLevel2 > 0
										  && B_MultLevel3 > B_MultLevel2
										  && B_MultLevel3 <= B_MaxOpenOrders ) )
					 && valid_tdou ( B_MultСorrLevel3 )
					 && valid_inte ( B_Mult3,
									 B_Mult3 == 0
									 || ( B_MultLevel3 > 0
										  && B_Mult3 > B_MultLevel3
										  && B_Mult3 <= B_MaxOpenOrders ) )
					 && valid_tdou ( B_Mult3Add )
					 && valid_inte ( B_MultStop,
									 B_MultStop >= 0
									 && B_MultStop <= B_MaxOpenOrders )
					 && valid_doub ( B_MaxLotCoef,
									 B_MaxLotCoef == 0
									 || B_MaxLotCoef >= B_MinLot  ) ) )
		   // Настройки ТР для длинных позиций
		   && ( ReflectSellSettingsToBuy
				|| ( valid_tint ( B_TakeProffitType )
					 && valid_doub ( B_TakeProffit,
									 B_TakeProffit > 0.0 )
					 && valid_inte ( B_TakeProffit_Level1,
									 B_TakeProffit_Level1 == 0
									 || ( B_TakeProffit_Level1 > 1
										  && B_TakeProffit_Level1 <= B_MaxOpenOrders ) )
					 && valid_tint ( B_TakeProffit_Level1Corr )
					 && valid_inte ( B_TakeProffit_Level1_5,
									 B_TakeProffit_Level1_5 == 0
									 || ( B_TakeProffit_Level1_5 > B_TakeProffit_Level1
										  && B_TakeProffit_Level1_5 <= B_MaxOpenOrders ) )
					 && valid_tint ( S_TakeProffit_Level1_5Corr )
					 && valid_inte ( B_TakeProffit_Level2,
									 B_TakeProffit_Level2 == 0
									 || ( B_TakeProffit_Level2 > B_TakeProffit_Level1
										  && B_TakeProffit_Level2 <= B_MaxOpenOrders ) )
					 && valid_inte ( B_TakeProffit_Level2FixPips,
									 B_TakeProffit_Level2 == 0
									 || B_TakeProffit_Level2FixPips >= TakeProffitControlNoLossFixPips ) ) )
		   // Настройки безиндикаторного входа
		   && valid_tint ( OpenFirstOrderTF )
		   && valid_inte ( CandlesToOpen1Order,
						   CandlesToOpen1Order >= 0 )
		   && valid_tboo ( CandlesToOpen1Order_OpenClose )
		   && valid_inte ( CandlesToOpen1Order_MinPips,
						   CandlesToOpen1Order_MinPips == 0
						   || CandlesToOpen1Order_MinPips > 0 )
		   && valid_inte ( CandlesToOpen1Order_MaxPips,
						   CandlesToOpen1Order_MaxPips == 0
						   || ( CandlesToOpen1Order_MinPips == 0 && CandlesToOpen1Order_MaxPips > 0 )
						   || ( CandlesToOpen1Order_MinPips > 0 && CandlesToOpen1Order_MaxPips > CandlesToOpen1Order_MinPips ) )
		   && valid_tboo ( ReversSignalToOpen1Order )
		   // Настройки гэп контроля
		   && valid_tint ( GapControl )
		   && valid_inte ( GapMaxStopOrders,
						   GapMaxStopOrders >= 0 )
		   && valid_tint ( GapMinDistanceFromMarket )
		   && valid_inte ( S_GapMinPips,
						   S_GapMinPips == 0
						   || ( S_GapMinPips > 0 && S_GapMinPercent == 0 ) )
		   && valid_inte ( S_GapMinPercent,
						   S_GapMinPercent == 0
						   || ( S_GapMinPercent > 0 && S_GapMinPips == 0 ) )
		   && valid_doub ( S_GapLotKoef,
						   S_GapLotKoef <= 1 )
		   && valid_doub ( S_GapLastOrderKoef,
						   S_GapLastOrderKoef >= 0.00 )
		   && ( ReflectSellSettingsToBuy
				|| ( valid_inte ( B_GapMinPips,
								  B_GapMinPips == 0
								  || ( B_GapMinPips > 0 && B_GapMinPercent == 0 ) )
					 && valid_inte ( B_GapMinPercent,
									 B_GapMinPercent == 0
									 || ( B_GapMinPercent > 0 && B_GapMinPips == 0 ) )

					 && valid_doub ( B_GapLotKoef,
									 B_GapLotKoef <= 1 )
					 && valid_doub ( B_GapLastOrderKoef,
									 B_GapLastOrderKoef >= 0.00 ) ) )
		   // Настройки фильтра волатильности
		   && valid_tint ( VolCandleTF )
		   && valid_inte ( VolCandleMaxSize,
						   VolCandleMaxSize >= 0 )
		   && valid_inte ( VolStopTradeTimining,
						   VolStopTradeTimining == 0 || VolStopTradeTimining >= 30 )
		   // Настройки планировщика
		   && valid_bool ( CloseAllOrders_ByDrawdown_StopTrade, true )
		   && valid_inte ( TradeStartDay,
						   TradeStartDay <= TradeEndDay
						   && TradeStartDay >= day_of_week_t_sunday )
		   && valid_inte ( TradeStartHour,
						   TradeStartHour >= 0
						   && TradeStartHour <= 23
						   && ( TradeStartDay != TradeEndDay
								|| ( TradeStartDay == TradeEndDay
									 && TradeStartHour <= TradeEndHour  ) ) )
		   && valid_inte ( TradeStartMinute,
						   TradeStartMinute >= 0
						   && TradeStartMinute <= 59
						   && ( TradeStartDay != TradeEndDay
								|| ( TradeStartDay == TradeEndDay
									 && ( TradeStartHour < TradeEndHour
										  || ( TradeStartHour == TradeEndHour
												  && TradeStartMinute < TradeEndMinute )  ) ) ) )
		   && valid_inte ( TradeEndDay,
						   TradeEndDay >= TradeStartDay
						   && TradeEndDay <= day_of_week_t_saturday )
		   && valid_inte ( TradeEndHour,
						   TradeEndHour >= 0
						   && TradeEndHour <= 23 )
		   && valid_inte ( TradeEndMinute,
						   TradeEndMinute >= 0
						   && TradeEndMinute <= 59 )
		   && check_new_position_pause ( 1 )
		   && check_new_position_pause ( 2 )
		   && check_new_position_pause ( 3 )
		   && check_new_position_pause ( 4 )
		   && check_new_position_pause ( 5 )
		   && check_new_position_pause ( 6 )
		   && check_new_position_pause ( 7 )
		   && check_new_position_pause ( 8 )
		   && check_new_position_pause ( 9 )
		   && check_new_position_pause ( 10 )
		   && check_trade_pause ( 1 )
		   && check_trade_pause ( 2 )
		   && check_trade_pause ( 3 )
		   && check_trade_pause ( 4 )
		   && check_trade_pause ( 5 )
		   && check_trade_pause ( 6 )
		   && check_trade_pause ( 7 )
		   && check_trade_pause ( 8 )
		   && check_trade_pause ( 9 )
		   && check_trade_pause ( 10 )
		   && check_intrade ( 1 )
		   && check_intrade ( 2 )
		   && check_intrade ( 3 )
		   && check_intrade ( 4 )
		   && check_intrade ( 5 )
		   && check_intrade ( 6 )
		   && check_intrade ( 7 )
		   && check_intrade ( 8 )
		   && check_intrade ( 9 )
		   && check_intrade ( 10 )
		   && check_intraday_stop_trade ( 1 )
		   && check_intraday_stop_trade ( 2 )
		   && check_intraday_stop_trade ( 3 )
		   && check_intraday_stop_trade ( 4 )
		   && check_intraday_stop_trade ( 5 )
		   && check_intraday_stop_trade ( 6 )
		   && check_intraday_stop_trade ( 7 )
		   && check_intraday_stop_trade ( 8 )
		   && check_intraday_stop_trade ( 9 )
		   && check_intraday_stop_trade ( 10 )
		   && valid_inte ( CloseAllOrders_EveryDay_Hour,
						   CloseAllOrders_EveryDay_Hour >= 0
						   && CloseAllOrders_EveryDay_Hour <= 23 )
		   && valid_inte ( CloseAllOrders_EveryDay_Minute,
						   CloseAllOrders_EveryDay_Minute >= 0
						   && CloseAllOrders_EveryDay_Minute <= 57 )
		   // Прочие настройки
		   && valid_inte ( TakeProffitControlTiming,
						   TakeProffitControlTiming == 0
						   || TakeProffitControlTiming >= 30 )
		   && valid_tint ( TakeProffitControlNoLossFixPips )
		   && valid_inte ( GlobalParamsUpdateTiming,
						   GlobalParamsUpdateTiming == 0
						   || GlobalParamsUpdateTiming >= 30 )
		   && valid_inte ( LogVerbose,
						   LogVerbose >= 0
						   && LogVerbose <= 4 );
}

setting_t *defines_create ( bool is_buy, int lot_exp )
{
#ifndef FOR_OPTIMIZATION

	//TODO: нужно перенести вниз и сделать все это через reflect
	if ( is_buy && ReflectSellSettingsToBuy ) {
		log_info ( SRC_DEFINES_REFLECT_SELL_SETTINGS_TO_BUY );

		valid_tint ( S_MaxOpenOrders );
		valid_tint ( S_GridStep );
		valid_tint ( S_GridLevel );
		valid_tint ( S_GridStep_AddPips );
		valid_tint ( S_GridStep_Level2 );
		valid_tint ( S_GridStep_Level2_AddPips );
		valid_tint ( S_Grid3 );
		valid_tint ( S_Grid3Add );
		valid_tint ( S_GridStop );

		valid_tint ( S_CalcLotType );
		valid_tint ( S_CurrencyForMinLot );
		valid_tdou ( S_MinLot );
		valid_tdou ( S_Mult );
		valid_tint ( S_MultStart );
		valid_tint ( S_MultLevel2 );
		valid_tdou ( S_MultCorr );
		valid_tint ( S_MultLevel3 );
		valid_tdou ( S_MultСorrLevel3 );
		valid_tint ( S_Mult3 );
		valid_tdou ( S_Mult3Add );
		valid_tint ( S_MultStop );
		valid_tdou ( S_MaxLotCoef );

		valid_tint ( S_TakeProffitType );
		valid_tdou ( S_TakeProffit );
		valid_tint ( S_TakeProffit_Level1 );
		valid_tint ( S_TakeProffit_Level1Corr );
		valid_tint ( S_TakeProffit_Level1_5 );
		valid_tint ( S_TakeProffit_Level1_5Corr );
		valid_tint ( S_TakeProffit_Level2 );
		valid_tint ( S_TakeProffit_Level2FixPips );

		valid_tint ( S_GapMinPips );
		valid_tint ( S_GapMinPercent );
		valid_tdou ( S_GapLotKoef );
		valid_tdou ( S_GapLastOrderKoef );
	}

#endif

#define bs( name ) ( is_buy ? B_##name : S_##name )
#define bs_reflect( name ) ( is_buy && !ReflectSellSettingsToBuy ? B_##name : S_##name )

	int bit_multiplier = layer_account::bit_multiplier();
	setting_t *result = new setting_t();
	result.magic_number = MagicNumber;
	result.max_spread =	MaxSpread * bit_multiplier;
	result.close_all_orders = bs ( CloseAllOrders );
	result.open_positions = is_buy ? TradeBuy : TradeSell;
	result.open_first_order = bs ( OpenFirstOrder );
	result.max_open_orders = bs_reflect ( MaxOpenOrders );
	result.pause_on_close_in_sec = 60 *	bs ( PauseOnClose );
	result.position_signal = PositionSignal;
	result.time_frame =	OpenFirstOrderTF;
	result.candles_for_open_first_order = CandlesToOpen1Order;
	result.candles_for_open_first_order_open_close = CandlesToOpen1Order_OpenClose;
	result.candles_for_open_first_order_min_pips = CandlesToOpen1Order_MinPips * bit_multiplier;
	result.candles_for_open_first_order_max_pips = CandlesToOpen1Order_MaxPips * bit_multiplier;
	result.revers_signal_to_open_first_order = ReversSignalToOpen1Order;;
	result.grid_step = bs_reflect ( GridStep ) * bit_multiplier;
	result.grid_level = bs_reflect ( GridLevel );
	result.grid_value =	bs_reflect ( GridStep_AddPips ) * bit_multiplier;
	result.grid_level2 = bs_reflect ( GridStep_Level2 );
	result.grid_level2_add_pips = bs_reflect ( GridStep_Level2_AddPips ) * bit_multiplier;
	result.grid_level3 = bs_reflect ( Grid3 );
	result.grid_level3_add_pips = bs_reflect ( Grid3Add ) * bit_multiplier;
	result.grid_stop = bs_reflect ( GridStop );
	result.lot_exp = lot_exp;
	result.tp_type = bs_reflect ( TakeProffitType );
	result.take_profit_control_timing =	TakeProffitControlTiming;
	result.take_profit_control_noloss_fixpips =	TakeProffitControlNoLossFixPips * bit_multiplier;
	result.take_proffit = bs_reflect ( TakeProffit ) * bit_multiplier;
	result.take_proffit_level1 = bs_reflect ( TakeProffit_Level1 );
	result.take_proffit_level1_corr = bs_reflect ( TakeProffit_Level1Corr ) * bit_multiplier;
	result.take_proffit_level2 = bs_reflect ( TakeProffit_Level1_5 );
	result.take_proffit_level2_corr = bs_reflect ( TakeProffit_Level1_5Corr ) * bit_multiplier;
	result.take_proffit_level3 = bs_reflect ( TakeProffit_Level2 );
	result.take_proffit_level3_fix_pips = bs_reflect ( TakeProffit_Level2FixPips ) * bit_multiplier;
	result.max_spread_stop_drading_timing =	MaxSpreadStopTradingTimining;
	result.mult_type = bs_reflect ( CalcLotType );
	result.currency_for_min_lot = bs_reflect ( CurrencyForMinLot );
	result.lots = bs_reflect ( MinLot );
	result.multi_lots_factor = bs_reflect ( Mult );
	result.multi_lots_level1 = bs_reflect ( MultStart );
	result.multi_lots_level2 = bs_reflect ( MultLevel2 );
	result.multi_lots_level2_corr = bs_reflect ( MultCorr );
	result.multi_lots_level3 = bs_reflect ( MultLevel3 );
	result.multi_lots_level3_corr = bs_reflect ( MultСorrLevel3 );
	result.mult4 = bs_reflect ( Mult3 );
	result.mult4_add = bs_reflect ( Mult3Add );
	result.mult_stop = bs_reflect ( MultStop );
	result.gap_control = GapControl;
	result.gap_max_order_stop = GapMaxStopOrders;
	result.gap_min_pips_from_market = GapMinDistanceFromMarket * bit_multiplier;
	result.gap_min_pips = bs_reflect ( GapMinPips ) * bit_multiplier;
	result.gap_min_percent = bs_reflect ( GapMinPercent );
	result.gap_lot_koef = bs_reflect ( GapLotKoef );
	result.gap_last_order_koef = bs_reflect ( GapLastOrderKoef );
	result.vol_candle_tf = VolCandleTF;
	result.vol_candle_max_size = VolCandleMaxSize * bit_multiplier;
	result.vol_stop_trade_timing = VolStopTradeTimining;
	result.vol_from_level = VolFromLevel;
	result.vol_block_both_direction = VolBlockBothDirection;
	result.trade_start_day = TradeStartDay;
	result.trade_start_minute =	60 * TradeStartHour + TradeStartMinute;
	result.trade_end_day = TradeEndDay;
	result.trade_stop_minute = 60 * TradeEndHour + TradeEndMinute;
	result.final_stop_trading =	FinalGridDate;
	result.max_trade_pairs = MaxTradePairs;
	result.currency_block =	CurrencyBlock;
	result.no1Order_by_drawdown_percent = No1Order_ByDrawdownPercent;
	result.no1Order_by_drawdown_percent_off = No1Order_ByDrawdownPercent_Off;
	result.close_all_orders_by_drawdown_stop_trade = CloseAllOrders_ByDrawdown_StopTrade;
	result.add_comment = AddComment;
	result.min_leverage = MinLeverage;
	result.min_time_step = MinTimeStep;
	result.max_lot = bs_reflect ( MaxLotCoef );

	result.currency_block_label = def_to_str_from_int ( CurrencyBlock );
	result.max_trade_pairs_label = def_to_str_from_int ( MaxTradePairs );

	return result;
}

#define define_check_new_position_pause( number ) \
	( NewPositionPause##number##Start != MIN_DATE \
	  || NewPositionPause##number##End != MIN_DATE )
#define define_check_intraday( number ) \
	( IntraDay##number##StartHour != IntraDay##number##EndHour \
	  || IntraDay##number##StartMinute != IntraDay##number##EndMinute )
#define define_check_trade_pause( number ) \
	( TradePause##number##Start != MIN_DATE \
	  && TradePause##number##End != MIN_DATE )
#define define_check_intraday_stop_trade( number ) \
	( IntraDayStopTrade##number##StartHour != IntraDayStopTrade##number##EndHour \
	  || IntraDayStopTrade##number##StartMinute != IntraDayStopTrade##number##EndMinute )

#define defines_put_new_position_pause( number ) \
	NewPositionPause##number##Start, \
	NewPositionPause##number##End
#define defines_put_trade_pause( number ) \
	TradePause##number##Start, \
	TradePause##number##End
#define define_put_intraday( number ) \
	IntraDay##number##StartHour, \
	IntraDay##number##StartMinute, \
	IntraDay##number##EndHour, \
	IntraDay##number##EndMinute
#define define_put_intraday_stop_trade( number ) \
	IntraDayStopTrade##number##StartHour, \
	IntraDayStopTrade##number##StartMinute, \
	IntraDayStopTrade##number##EndHour, \
	IntraDayStopTrade##number##EndMinute

void defines_init_scheduler()
{
	if ( TradeStartDay != TradeEndDay
			|| TradeStartHour != TradeEndHour
			|| TradeStartMinute != TradeEndMinute ) {
		scheduler::set_trade ( (day_of_week_t)TradeStartDay,
							   TradeStartHour,
							   TradeStartMinute,
							   (day_of_week_t)TradeEndDay,
							   TradeEndHour,
							   TradeEndMinute );
	} else {
		scheduler::reset_trade ();
	}

	if ( define_check_new_position_pause ( 1 )
			|| define_check_new_position_pause ( 2 )
			|| define_check_new_position_pause ( 3 )
			|| define_check_new_position_pause ( 4 )
			|| define_check_new_position_pause ( 5 )
			|| define_check_new_position_pause ( 6 )
			|| define_check_new_position_pause ( 7 )
			|| define_check_new_position_pause ( 8 )
			|| define_check_new_position_pause ( 9 )
			|| define_check_new_position_pause ( 10 ) ) {
		scheduler::set_new_position_pause ( defines_put_new_position_pause ( 1 ),
											defines_put_new_position_pause ( 2 ),
											defines_put_new_position_pause ( 3 ),
											defines_put_new_position_pause ( 4 ),
											defines_put_new_position_pause ( 5 ),
											defines_put_new_position_pause ( 6 ),
											defines_put_new_position_pause ( 7 ),
											defines_put_new_position_pause ( 8 ),
											defines_put_new_position_pause ( 9 ),
											defines_put_new_position_pause ( 10 )  );
	} else {
		scheduler::reset_new_position_pause();
	}

	if ( define_check_trade_pause ( 1 )
			|| define_check_trade_pause ( 2 )
			|| define_check_trade_pause ( 3 )
			|| define_check_trade_pause ( 4 )
			|| define_check_trade_pause ( 5 )
			|| define_check_trade_pause ( 6 )
			|| define_check_trade_pause ( 7 )
			|| define_check_trade_pause ( 8 )
			|| define_check_trade_pause ( 9 )
			|| define_check_trade_pause ( 10 ) ) {
		scheduler::set_trade_pause ( defines_put_trade_pause ( 1 ),
									 defines_put_trade_pause ( 2 ),
									 defines_put_trade_pause ( 3 ),
									 defines_put_trade_pause ( 4 ),
									 defines_put_trade_pause ( 5 ),
									 defines_put_trade_pause ( 6 ),
									 defines_put_trade_pause ( 7 ),
									 defines_put_trade_pause ( 8 ),
									 defines_put_trade_pause ( 9 ),
									 defines_put_trade_pause ( 10 )  );
	} else {
		scheduler::reset_trade_pause();
	}

	if ( define_check_intraday ( 1 )
			|| define_check_intraday ( 2 )
			|| define_check_intraday ( 3 )
			|| define_check_intraday ( 4 )
			|| define_check_intraday ( 5 )
			|| define_check_intraday ( 6 )
			|| define_check_intraday ( 7 )
			|| define_check_intraday ( 8 )
			|| define_check_intraday ( 9 )
			|| define_check_intraday ( 10 ) ) {
		scheduler::set_intraday ( define_put_intraday ( 1 ),
								  define_put_intraday ( 2 ),
								  define_put_intraday ( 3 ),
								  define_put_intraday ( 4 ),
								  define_put_intraday ( 5 ),
								  define_put_intraday ( 6 ),
								  define_put_intraday ( 7 ),
								  define_put_intraday ( 8 ),
								  define_put_intraday ( 9 ),
								  define_put_intraday ( 10 ) );
	} else {
		scheduler::reset_intraday();
	}

	if ( define_check_intraday_stop_trade ( 1 )
			|| define_check_intraday_stop_trade ( 2 )
			|| define_check_intraday_stop_trade ( 3 )
			|| define_check_intraday_stop_trade ( 4 )
			|| define_check_intraday_stop_trade ( 5 )
			|| define_check_intraday_stop_trade ( 6 )
			|| define_check_intraday_stop_trade ( 7 )
			|| define_check_intraday_stop_trade ( 8 )
			|| define_check_intraday_stop_trade ( 9 )
			|| define_check_intraday_stop_trade ( 10 ) ) {
		scheduler::set_intraday_stop_trade ( define_put_intraday_stop_trade ( 1 ),
											 define_put_intraday_stop_trade ( 2 ),
											 define_put_intraday_stop_trade ( 3 ),
											 define_put_intraday_stop_trade ( 4 ),
											 define_put_intraday_stop_trade ( 5 ),
											 define_put_intraday_stop_trade ( 6 ),
											 define_put_intraday_stop_trade ( 7 ),
											 define_put_intraday_stop_trade ( 8 ),
											 define_put_intraday_stop_trade ( 9 ),
											 define_put_intraday_stop_trade ( 10 ) );
	} else {
		scheduler::reset_intraday_stop_trade();
	}

	if ( CloseAllOrders_EveryDay_Hour != 0
			|| CloseAllOrders_EveryDay_Minute != 0 ) {
		scheduler::set_close_all_orders ( CloseAllOrders_EveryDay_Hour,
										  CloseAllOrders_EveryDay_Minute );
	} else {
		scheduler::reset_close_all_orders();
	}
}

#endif
#ifndef LOGIC_HANDLER_MQH
#define LOGIC_HANDLER_MQH

#ifndef LOGICS_CALC_MQH
#define LOGICS_CALC_MQH

#ifndef GAP_CALC_MQH
#define GAP_CALC_MQH


class calc_gap {
public:
	static bool is_gap ( setting_t *settings,
						 double distance,
						 double step_p ) {
		return settings.gap_min_pips != 0 ?
			   distance - step_p >= layer_market::to_points ( settings.gap_min_pips ) :
			   distance - step_p >= ( ( step_p / 100.0f ) * settings.gap_min_percent );
	}

	static bool is_gap ( setting_t *settings,
						 enum_order_operation_type order_type,
						 double last_price,
						 double price,
						 double step_p ) {
		return is_gap ( settings, tool_order::get_distance ( order_type, price, last_price ), step_p );
	}
};

#endif
#ifndef GRID_STEP_CALC_MQH
#define GRID_STEP_CALC_MQH


class calc_grid_step {
private:
	static bool is_lvl1 ( setting_t *settings, int order_count ) {
		return settings.grid_level != 0
			   && order_count >= settings.grid_level;
	}

	static bool is_lvl2 ( setting_t *settings, int order_count ) {
		return settings.grid_level2 != 0
			   && is_lvl1 ( settings, order_count )
			   && order_count >= settings.grid_level2;
	}

	static bool is_lvl3 ( setting_t *settings, int order_count ) {
		return settings.grid_level3 != 0
			   && is_lvl2 ( settings, order_count )
			   && order_count >= settings.grid_level3;
	}

public:
	static int get ( setting_t *settings, int lvl ) {
		int result = settings.grid_step;

		if ( settings.grid_stop != 0 && settings.grid_stop < lvl ) {
			lvl = settings.grid_stop;
		}

		// РћС‡РµРЅСЊ РІР°Р¶РµРЅ РїРѕСЂСЏРґРѕРє РїСЂРѕРІРµСЂРєРё СѓСЃР»РѕРІРёР№ РѕРЅ СЃРѕРєСЂР°С‰Р°РµС‚СЃСЏ РєРѕР»-РІРѕ СѓСЃР»РѕРІРёР№
		if ( is_lvl3 ( settings, lvl ) ) {
			result = get ( settings, lvl - ( lvl - settings.grid_level3 + 1 )  );

			int count =  lvl + 1 - settings.grid_level3;

			for ( int i = 0; i < count; i++ ) {
				result += settings.grid_level3_add_pips;
			}
		} else if ( is_lvl2 ( settings, lvl ) ) {
			result = get ( settings, lvl - ( lvl - settings.grid_level2 + 1 )  );

			int count =  lvl + 1 - settings.grid_level2;

			for ( int i = 0; i < count; i++ ) {
				result += settings.grid_level2_add_pips;
			}
		} else if ( is_lvl1 ( settings, lvl ) ) {
			result = settings.grid_step + ( settings.grid_value * ( lvl + 1 - settings.grid_level ) );
		}

		return result;
	}
};

#endif
#ifndef LOT_CALC_MQH
#define LOT_CALC_MQH


class calc_lot {
private:
	static bool is_lvl1 ( setting_t *settings, int order_count ) {
		return settings.multi_lots_level1 != 0
			   && order_count >= settings.multi_lots_level1;
	}

	static bool is_lvl2 ( setting_t *settings, int order_count ) {
		return settings.multi_lots_level2 != 0
			   && is_lvl1 ( settings, order_count )
			   && order_count >= settings.multi_lots_level2;
	}

	static bool is_lvl3 ( setting_t *settings, int order_count ) {
		return settings.multi_lots_level3 != 0
			   && is_lvl2 ( settings, order_count )
			   && order_count >= settings.multi_lots_level3;
	}

	static bool is_lvl4 ( setting_t *settings, int order_count ) {
		return settings.mult4 != 0
			   && is_lvl3 ( settings, order_count )
			   && order_count >= settings.mult4;
	}

	static double get_factor ( setting_t *settings,
							   int lvl ) {
		double result = 1.0;

		if ( settings.mult_stop != 0
				&& settings.mult_stop < lvl ) {
			lvl = settings.mult_stop;
		}

		if ( is_lvl4 ( settings, lvl ) ) {
			result = get_factor ( settings, lvl - ( lvl - settings.mult4 + 1 ) );

			int count = lvl + 1 - settings.mult4;

			for ( int i = 0; i < count; i++ ) {
				result += settings.mult4_add;
			}
		} else if ( is_lvl3 ( settings, lvl ) ) {
			result = get_factor ( settings, lvl - ( lvl - settings.multi_lots_level3 + 1 ) );

			int count = lvl + 1 - settings.multi_lots_level3;

			for ( int i = 0; i < count; i++ ) {
				result += settings.multi_lots_level3_corr;
			}
		} else if ( is_lvl2 ( settings, lvl ) ) {
			result = get_factor ( settings, lvl - ( lvl - settings.multi_lots_level2 + 1 ) );

			int count = lvl + 1 - settings.multi_lots_level2;

			for ( int i = 0; i < count; i++ ) {
				result += settings.multi_lots_level2_corr;
			}
		} else if ( is_lvl1 ( settings, lvl ) ) {
			result = settings.multi_lots_factor;
		}

		return result;
	}

	static double get_for_gap_control ( setting_t *settings,
										enum_order_operation_type order_type,
										int lvl,
										double last_lot,
										double last_price,
										double price ) {
		double step_p = layer_market::to_points ( calc_grid_step::get ( settings, lvl ) );
		double distance_p = tool_order::get_distance ( order_type, price, last_price );
		double lot_factor = get_factor ( settings, lvl );

		if ( !calc_gap::is_gap ( settings, order_type, order_type, distance_p, step_p ) ) {
			return last_lot * lot_factor;
		}

		// TODO: print on every calc lot
		//log_info_k ( _msg_key, StringFormat ( SRC_HANDLER_BASE_DETECT_GAP, dtos ( last_price ), dtos ( price ), dtos ( order::get_distance ( _order_type, price, last_price ) ) ) );
		double gap_factor = lot_factor * ( ( distance_p - step_p ) / step_p ) * settings.gap_lot_koef;
		double tripple_last_lot = last_lot * settings.gap_last_order_koef;
		double result = last_lot * ( lot_factor + gap_factor );
		return tripple_last_lot < result ? tripple_last_lot : result;
	}

	static double calc_lot_by_balance ( double min_lot,
										double balance_by_min_lot,
										double balance,
										int truncate_count,
										double market_lot_min ) {
		double coff = balance / balance_by_min_lot;
		double result = ext_string::truncate_real_part ( min_lot * coff, truncate_count );
		return result < market_lot_min ? market_lot_min : result;
	}

	static double get_base_lot ( setting_t *settings,
								 layer_order_setting *settings_ptr,
								 int lvl ) {
		if ( !settings.is_testing && lvl != 1 ) {
			return layer_order::get_min ( settings_ptr ).lot;
		}

		return settings.currency_for_min_lot == 0 ?
			   settings.lots :
			   calc_lot_by_balance ( settings.lots,
									 settings.currency_for_min_lot,
									 settings.is_testing ? settings.testing_balance : kernel_account::balance(),
									 settings.lot_exp,
									 settings.is_testing ? settings.testing_layer_market_lot_min : layer_market::lot_min() );
	}

	static double get_by_min_order ( setting_t *settings,
									 layer_order_setting *order_layer_settings_ptr,
									 int lvl,
									 enum_gap_control_type control_type,
									 double price,
									 double first_lot ) {
		double result = first_lot;

		switch ( control_type ) {
			case no_gap:
			case op_stop:
				result *= get_factor ( settings, lvl );
				break;

			case inc_lot:
				//result = get_for_gap_control ( settings, settings_ptr.order_type, count + 1, result, open_prices[count - 1], price );
				break;
		}

		return result;
	}

	static double get_by_last_order ( setting_t *settings,
									  layer_order_setting *settings_ptr,
									  int lvl,
									  enum_gap_control_type control_type,
									  double price,
									  double first_lot ) {
		double result = first_lot;

		switch ( control_type ) {
			case no_gap:
			case op_stop:
				for ( int i = 1; i < lvl; i++ ) {
					result *= get_factor ( settings, i + 1 );
				}

				break;

			case inc_lot: {
				int count = 0;
				double open_prices[];

				list<order *> *orders = layer_order::get ( settings_ptr );
				ArrayResize ( open_prices, orders.count );
				LIST_FOREACH ( orders, order *, item, {
					count += 1;
					open_prices[count - 1] = item.open_price;
				} );

				if ( count == 0 ) {
					break;
				}

				for ( int i = 1; i < count; i++ ) {
					result = get_for_gap_control ( settings, settings_ptr.order_type, i + 1, result, open_prices[i - 1], open_prices[i] );
				}

				result = get_for_gap_control ( settings, settings_ptr.order_type, count + 1, result, open_prices[count - 1], price );
				break;
			}
		}

		return result;
	}

public:
	static double get ( setting_t *settings,
						layer_order_setting *settings_ptr,
						int lvl,
						enum_gap_control_type control_type,
						double price ) {
		double base_lot = get_base_lot ( settings,
										 settings_ptr,
										 lvl );
		double result = base_lot;

		if ( lvl != 1 ) {
			result = settings.mult_type == calc_lot_type_last_order ?
					 get_by_last_order ( settings,
										 settings_ptr,
										 lvl,
										 control_type,
										 price,
										 result ) :
					 get_by_min_order ( settings,
										settings_ptr,
										lvl,
										control_type,
										price,
										result );
		}

		if ( settings.max_lot != 0.00 ) {
			double max_lot = settings.max_lot * base_lot;

			if ( max_lot < result ) {
				result = max_lot;
			}
		}

		return result;
	};
};

#endif
#ifndef TAKE_PROFIT_CALC_MQH
#define TAKE_PROFIT_CALC_MQH

class calc_take_profit {
private:
	static bool is_lvl1 ( setting_t *settings,
						  int order_count ) {
		return settings.take_proffit_level1 != 0
			   && order_count >= settings.take_proffit_level1;
	}

	static bool is_lvl2 ( setting_t *settings,
						  int order_count ) {
		return settings.take_proffit_level2 != 0
			   && order_count >= settings.take_proffit_level2;
	}

	static enum_take_profit_calc_type get_type ( setting_t *settings,
			int order_count ) {
		return is_lvl3 ( settings, order_count ) ?
			   tp_level_without_loss :
			   settings.tp_type;
	}

	static int get_pips ( setting_t *settings,
						  int order_count ) {
		int result = settings.take_proffit;

		if ( is_lvl3 ( settings, order_count ) ) {
			result = settings.take_proffit_level3_fix_pips;
		} else if ( is_lvl2 ( settings, order_count ) ) {
			int lvl1_count = settings.take_proffit_level2 - 1;
			int lvl2_count = order_count - lvl1_count;

			result = get_pips ( settings, lvl1_count );

			for ( int i = 0; i < lvl2_count; i++ ) {
				result += settings.take_proffit_level2_corr;
			}
		} else if ( is_lvl1 ( settings, order_count ) ) {
			int take_profit_factor = settings.take_proffit_level1_corr * ( order_count + 1 - settings.take_proffit_level1 );
			result = settings.take_proffit + take_profit_factor;
		}

		return result;
	}

public:
	static bool is_lvl3 ( setting_t *settings,
						  int order_count ) {
		return settings.take_proffit_level3 != 0
			   && order_count >= settings.take_proffit_level3;
	}

	static double get ( setting_t *settings,
						layer_order_setting *order_settings,
						enum_take_profit_calc_type type,
						int tp_pips,
						bool with_virtual_order = false,
						double virtual_price = 0.0,
						double virtual_lot = 0.0 ) {
		list<order *> *orders = layer_order::get ( order_settings );
		int stop_count = layer_order::get_count ( order_settings ).stop();

		double last_result = 0,
			   result = 0,
			   tp_in_points = tp_pips == 0 ? 0.0 : layer_market::to_points ( tp_pips );
		int last_stop_count_before_line = 0,
			stop_count_before_line = 0,
			skip_stop_order = stop_count;

		while ( true ) {
			last_result = result;

			switch ( type ) {
				case tp_avg:
					result = tool_take_profit::get_avg_price_by_lot_factor ( orders,
							 skip_stop_order,
							 with_virtual_order,
							 virtual_price,
							 virtual_lot );
					break;

				case tp_level_without_loss:
					result = tool_take_profit::get_level_without_loss ( orders,
							 skip_stop_order,
							 with_virtual_order,
							 virtual_price,
							 virtual_lot );
					break;

				default:
					return 0.0;
			}

			result = tool_order::add_point ( order_settings.order_type, result, tp_in_points );

			// РЎСЂР°Р·Сѓ Р¶Рµ РІС‹С…РѕРґРёРј, РµСЃР»Рё РЅРµ СѓС‡РёС‚С‹РІР°СЋС‚СЃСЏ РѕС‚Р»РѕР¶РµРЅРЅС‹Рµ РѕСЂРґРµСЂР°
			// Р»РёР±Рѕ РѕС‚Р»РѕР¶РµРЅРЅС‹С… РѕСЂРґРµСЂРѕРІ РЅРµС‚Сѓ
			// Р»РёР±Рѕ РІСЃРµ РѕС‚Р»РѕР¶РєРё СѓС‡РёС‚С‹РІР°СЋС‚СЃСЏ РІ РўР 
			if ( order_settings.order_stop_type == -1
					|| stop_count == 0
					|| skip_stop_order <= 0 ) {
				break;
			}

			last_stop_count_before_line = stop_count_before_line;

			LIST_COUNT ( orders, stop_count_before_line_by_result, order *, item, item.is_order_stop() && tool_order::is_price_before_line ( item.order_type, item.open_price, result ) );
			stop_count_before_line = stop_count_before_line_by_result;

			// Р•СЃР»Рё РєРѕР»-РІРѕ РѕС‚Р»РѕР¶РµРЅРЅС‹С… РѕСЂРґРµСЂРѕРІ РїРѕРїР°РґР°СЋС‰РёС… РІ РўР  РЅРµ СѓРІРµР»РёС‡РёР»РѕСЃСЊ,
			// С‚Рѕ РІС‹С…РѕРґРёРј РёР· С†РёРєР»Р° Рё Р±РµСЂРµРј РїСЂРѕС€Р»С‹Р№ РўР 
			if ( last_stop_count_before_line == stop_count_before_line ) {
				if ( skip_stop_order > 0 ) {
					// TODO: РІС‹РІРѕРґ РїСЂРѕРёСЃС…РѕРґРёС‚ РєР°Р¶РґС‹Р№ СЂР°Р· РїСЂРё СЂР°СЃС‡РµС‚Рµ РўР , РЅСѓР¶РЅРѕ СЌС‚Рѕ РїРµСЂРµРЅРµСЃС‚Рё РІ Р±Р»РѕРє, РєРѕРіРґР° СЏРІРЅРѕ Р·Р°РґР°РµС‚СЃСЏ РўР 
					// РёР»Рё РїСЂРёРґСѓРјР°С‚СЊ РІРѕР·РјРѕР¶РЅРѕСЃС‚СЊ РѕС‚Р»РѕР¶РµРЅРЅРѕРіРѕ РІС‹РІРѕРґР° СЃРѕРѕР±С‰РµРЅРёСЏ РІ Р»РѕРі
					//log_info_k ( StringFormat ( SRC_HANDLER_BASE_TP_SKIP_ORDER_STOP, skip_stop_order ) );
				}

				break;
			}

			skip_stop_order -= 1;
		}

		return result;
	}

	static double get ( setting_t *settings,
						layer_order_setting *order_settings,
						int order_count,
						bool with_virtual_order = false,
						double virtual_price = 0.0,
						double virtual_lot = 0.0 ) {
		double result = get ( settings,
							  order_settings,
							  get_type ( settings, order_count ),
							  get_pips ( settings, order_count ),
							  with_virtual_order,
							  virtual_price,
							  virtual_lot );
		return layer::correct_price ( result );
	}

#define ADD_IN_NULL(collection_item_type, collection, collection_capacity, for_add) \
	if(collection == NULL){ \
		collection = new list<collection_item_type>(collection_capacity); \
	} \
	collection.add(for_add);

	static list<order_operation *> *get_set_tp_if ( setting_t *settings,
			layer_order_setting *order_settings,
			double norm_tp ) {
		list<order_operation *> *result = NULL;

		bool min_distance_inited = false;
		double min_distance_from_open_price_p = 0.0;

		list<order *> *orders = layer_order::get ( order_settings );
		LIST_FOREACH ( orders, order *, item, {
			if ( item.take_profit == norm_tp ) {
				continue;
			}

			if ( item.is_order_stop() && !item.is_before_line ( norm_tp ) ) {
				if ( !min_distance_inited ) {
					min_distance_inited = true;
					min_distance_from_open_price_p = layer_market::min_distance_from_open_price_p ( CURRENT_SYMBOL,
							settings.max_spread );
					// TODO: РІСЂРµРјРµРЅРЅР°СЏ РјРµСЂР° layer_market?Рё СЃ РїСЂРѕР±Р»РµРјР°РјРё РЅР° EURJPY
					min_distance_from_open_price_p += layer_market::to_points ( layer_account::bit_multiplier() );
				}

				// РўР°Рє РєР°Рє СЌС‚Рѕ РѕС‚Р»РѕР¶РєР° Рё РѕРЅР° РЅР°С…РѕРґРёС‚СЊСЃСЏ Р·Р° Р»РёРЅРёРµР№ РЅСѓР¶РЅРѕРіРѕ РЅР°Рј РўР ,
				// С‚Рѕ С‚СЂРµР±СѓРµС‚СЃСЏ РІС‹СЃС‚Р°РІРёС‚СЊ РјРёРЅРёРјР°Р»СЊРЅРѕРµ Р·РЅР°С‡РµРЅРёРµ РўР  Рё SL
				double sl = item.is_buy_direction() ?
							item.open_price - min_distance_from_open_price_p :
							item.open_price + min_distance_from_open_price_p;
				sl = layer::correct_price ( sl );
				double tp = item.is_buy_direction() ?
							item.open_price + min_distance_from_open_price_p :
							item.open_price - min_distance_from_open_price_p ;
				tp = layer::correct_price ( tp );

				if ( tp == item.take_profit && sl == item.stop_loss ) {
					continue;
				}


				order_operation *for_add = factory_order_operation::get();
				for_add.is_completed = false;
				for_add.ticket = item.ticket;
				for_add.operation_type = order_operation_type_set_sl_tp;
				for_add.take_profit = tp;
				for_add.stop_loss = sl;
				ADD_IN_NULL ( order_operation *, result, order_settings.max_orders, for_add );
				continue;
			}

			order_operation *for_add = factory_order_operation::get();
			for_add.is_completed = false;
			for_add.ticket = item.ticket;
			for_add.operation_type = order_operation_type_set_tp;
			for_add.take_profit = norm_tp;
			ADD_IN_NULL ( order_operation *, result, order_settings.max_orders, for_add );
		} );

		return result;
	}
};

#endif

#endif

timer_t *handler_base_spread_block_trading_timer;
timer_t *handler_base_shared_vol_block_trading_timer = NULL;

class logic_handler {
public:
	setting_t *_settings;
	layer_order_setting *_order_settings;
	color _order_color;
	string _msg_key;
	timer_t *_ct_timer;
	timer_t *_close_orders;
	timer_t *_strong_sleep_timer;
	timer_t *handler_base_vol_block_trading_timer;
	order *_last_order;
	order_operation *_last_not_open_order_stop;
	bool _is_first_tick;
	bool _is_block_work;
	bool _is_block_work_by_stop_trade;
	int _last_order_stop_count;
	bool _drawdown_percent_block;

	double _last_tp;
	double _log_last_tp;

	logic_handler ( bool is_buy, setting_t *settings ) {
		_msg_key = StringFormat ( "[%s]", is_buy ? SRC_HANDLER_BASE_LONG : SRC_HANDLER_BASE_SHORT );
		_order_color = is_buy ? Green : Red;
		_settings = settings;
		_ct_timer = timer_t::create ( _settings.take_profit_control_timing );
		gc::push ( gc_dispose_type_on_end_deinit, _ct_timer );

		handler_base_spread_block_trading_timer = NULL;
		// VolBlockBothDirection shares volatility pause between BUY and SELL.
		handler_base_vol_block_trading_timer = NULL;
		_strong_sleep_timer = NULL;
		_close_orders = NULL;
		_last_not_open_order_stop = NULL;
		_is_first_tick = true;
		_is_block_work = false;

		_order_settings = layer_order_setting::create ( _settings.max_open_orders,
						  _settings.magic_number,
						  is_buy ?
						  order_operation_buy :
						  order_operation_sell,
						  settings.gap_control != op_stop ?
						  order_operation_none :
						  is_buy ?
						  order_operation_buy_stop :
						  order_operation_sell_stop,
						  _settings.max_trade_pairs,
						  _settings.currency_block );
		gc::push ( gc_dispose_type_on_end_deinit, _order_settings );

		layer_order::push_settings ( _order_settings );
		reset_vars();
	}

	double get_profit() {
		return layer_order::get_by_setting ( _order_settings ).profit_clear_currency();
	}

	bool is_close_module_activated() {
		return GC_CHECK_PTR ( _close_orders );
	}

	~logic_handler() {
		GC_DISPOSE_IF ( handler_base_spread_block_trading_timer );
		GC_DISPOSE_IF ( handler_base_shared_vol_block_trading_timer );
		GC_DISPOSE_IF ( handler_base_vol_block_trading_timer );
		GC_DISPOSE_IF ( _last_not_open_order_stop );
		GC_DISPOSE_IF ( _strong_sleep_timer );
	}

	void drawdown_changed_handler ( double drawdown_percent ) {
		log_set_msg_key ( _msg_key );

		if ( _drawdown_percent_block
				&& drawdown_percent <= _settings.no1Order_by_drawdown_percent_off ) {
			_drawdown_percent_block = false;

			log_info_k ( StringFormat ( SRC_HANDLER_BASE_DRAWDOWN_BLOCK_OFF, DoubleToString ( drawdown_percent, 0 ), _settings.no1Order_by_drawdown_percent_off ) );
		}
	}

	void tick_handler() {
		log_set_msg_key ( _msg_key );

		if ( _settings.close_all_orders ) {
			close_all_lvls ( );
			return;
		}

		if ( is_close_module_activated() ) {
			if ( !_close_orders.is_elapsed() ) {
				return;
			}

			log_info_k ( SRC_HANDLER_BASE_MODULE_CLOSE_START );

			if ( !close_all_lvls ( ) ) {
				log_info_k ( SRC_HANDLER_BASE_MODULE_CLOSE_ERROR );
				_close_orders.reset();
				return;
			}

			log_info_k ( SRC_HANDLER_BASE_MODULE_CLOSE_COMPLETE );
			gc::push ( gc_dispose_type_on_end_tick, _close_orders );
			return;
		}

		order_count_t *orders_count = layer_order::get_count ( _order_settings );

		if ( orders_count.all() == 0 ) {
			//РЎР±СЂР°СЃС‹РІР°РµРј РІСЃРµ РїРµСЂРµРјРµРЅРЅС‹Рµ РёСЃРїРѕР»СЊР·СѓРµРјС‹Рµ РІ С‚РµС‡РµРЅРёРµ СЃСѓС‰. СЃРµС‚РєРё
			reset_vars();
		} else {
			if ( orders_count.order() > 0 && _last_tp == 0.0f ) {
				_last_tp = calc_take_profit::get ( _settings, _order_settings, orders_count.all() );
			}

			_last_order = layer_order::get_max ( _order_settings );
		}

		double price_open = layer_market::price_open ( _order_settings.order_type );
		double step_in_point = layer_market::to_points ( calc_grid_step::get ( _settings, orders_count.all() + 1 ) );

		if ( is_need_close_orders ( orders_count ) ) {
			_close_orders = timer_t::create ( 0 );
			return;
		}

		if ( GC_CHECK_PTR ( _last_not_open_order_stop ) ) {
			if ( _last_not_open_order_stop.price == price_open
					|| !is_price_better ( _last_not_open_order_stop.price, price_open ) ) {
				log_info_k ( StringFormat ( SRC_HANDLER_BASE_STOP_ORDER_CLEAR,
											dtos ( price_open ),
											itos ( _last_not_open_order_stop.lvl ),
											dtos ( _last_not_open_order_stop.price ),
											dtos ( _last_not_open_order_stop.lot ),
											dtos ( _last_not_open_order_stop.step_p ) ) );
				gc::push ( gc_dispose_type_on_end_tick, _last_not_open_order_stop );
			} else {
				if ( order_operation_process ( orders_count, _last_not_open_order_stop ) ) {
					orders_count.inc_by_type ( _order_settings.order_stop_type );
					gc::push ( gc_dispose_type_on_end_tick, _last_not_open_order_stop );

					double take_profit = calc_take_profit::get ( _settings, _order_settings, orders_count.all() );
					set_tp ( take_profit, SRC_HANDLER_BASE_UPDATE_TP );
					_ct_timer.reset();
				} else {
					log_info_k ( layer_error::get_last_saved_string() );
					log_info_k (  StringFormat ( SRC_HANDLER_BASE_NOT_COMPLETE_STOP_ORDER,
												 itos ( _last_not_open_order_stop.lvl ),
												 dtos ( _last_not_open_order_stop.price ),
												 dtos ( _last_not_open_order_stop.lot ),
												 dtos ( _last_not_open_order_stop.step_p ) ) );
				}

				return;
			}
		}

		if ( is_can_open_order ( orders_count,
								 !GC_CHECK_PTR ( _last_order ) ? -1.0 : _last_order.open_price,
								 price_open,
								 step_in_point ) ) {
			//set_last_candle();
			bool need_aligment = _settings.gap_control == op_stop
								 && orders_count.stop() > 0
								 && layer_order::get_max ( _order_settings ).is_order_stop();

			if ( open_lvl_handler ( _settings.gap_control,
									orders_count,
									!GC_CHECK_PTR ( _last_order ) ? -1.0 : _last_order.open_price,
									price_open,
									step_in_point ) ) {
				if ( need_aligment
						&& layer_order::get_max ( _order_settings ).is_order() ) {
					_last_order_stop_count = process_order_stop_aligment ( orders_count ) ? orders_count.stop() : 0;
				}

				double take_profit = calc_take_profit::get ( _settings, _order_settings, orders_count.all() );
				set_tp ( take_profit, SRC_HANDLER_BASE_UPDATE_TP );
				_ct_timer.reset();
			}
		} else if ( is_ct_elapsed ( orders_count ) ) {
			//set_last_candle();
			_ct_timer.reset();
			double take_profit = layer::correct_price ( calc_take_profit::get ( _settings, _order_settings, orders_count.all() ) );

			if ( !calc_take_profit:: is_lvl3 ( _settings, orders_count.all( ) ) ) {
				double profit_on_tp = 0.0;

				list<order *> *orders = layer_order::get ( _order_settings );
				LIST_FOREACH ( orders, order *, item, {
					if ( item.is_order() ) {
						profit_on_tp += item.commission + item.swap;
						profit_on_tp += item.get_profit_in_currency ( take_profit );
						continue;
					}

					if ( item.is_before_line ( take_profit ) ) {
						profit_on_tp += item.get_profit_in_currency ( take_profit );
					}
				} );

				if ( profit_on_tp < 0.00 ) {
					take_profit = calc_take_profit::get ( _settings,
														  _order_settings,
														  tp_level_without_loss,
														  _settings.take_profit_control_noloss_fixpips );
				}
			}

			set_tp ( take_profit, SRC_HANDLER_BASE_TIMER_UPDATE_TP );
		} else {
			//set_last_candle();

			if ( _settings.gap_control == op_stop
					&& orders_count.stop() > 0
					&& _last_order_stop_count != orders_count.stop()
					&& layer_order::get_max ( _order_settings ).is_order()
					&& layer_symbol::trade_mode ( CURRENT_SYMBOL ) == trade_mode_type_full
					&& process_order_stop_aligment ( orders_count ) ) {
				_last_order_stop_count = orders_count.stop();

				double take_profit = calc_take_profit::get ( _settings, _order_settings, orders_count.all() );
				set_tp ( take_profit, SRC_HANDLER_BASE_UPDATE_TP );
				_ct_timer.reset();
			}
		}
	}

	void mark_close_all_orders ( int time_to_start, bool timer_on_start, bool is_close_by_drawdown ) {
		if ( is_close_by_drawdown ) {
			_is_block_work = _settings.close_all_orders_by_drawdown_stop_trade;
		}

		_close_orders = timer_t::create ( time_to_start );

		if ( timer_on_start ) {
			_close_orders.set_zero();
		}
	}

	void mark_block_work_by_stop_trade ( bool block ) {
		_is_block_work_by_stop_trade = block;
	}

	bool close_all_lvls () {
		order_count_t *orders_count = layer_order::get_count ( _order_settings );

		int lvl = orders_count.all();

		if ( lvl == 0 ) {
			return true;
		}

		double step_p = layer_market::to_points ( calc_grid_step::get ( _settings, lvl ) );
		int slippage = calc_slippage ( lvl, step_p );

		if ( !layer_order::close_all ( _settings.magic_number, _order_settings.order_type, _order_settings.order_stop_type, slippage ) ) {
			int error = layer_error::get_last();

			if ( error == ERROR_MARKET_CLOSED ) {
				log_info_k ( SRC_SETKA_MARKET_CLOSE );
				return false;
			} else if ( error != ERROR_REQUOTE ) {
				log_info_k ( StringFormat ( SRC_HANDLER_BASE_ERROR_CLOSE_ORDERS, error_get_last ( error ) ) );
				return false;
			}
		}

		layer_order::refresh ( _order_settings );
		order_count_t *orders_count_before = layer_order::get_count ( _order_settings );
		return orders_count_before.all() == 0;
	}

	bool set_tp ( double tp, string msg ) {
		_last_tp = tp;
		list<order_operation *> *operations = calc_take_profit::get_set_tp_if ( _settings, _order_settings, tp );

		if ( !GC_CHECK_PTR ( operations ) ) {
			return true;
		}

		log_info_k ( StringFormat ( msg, dtos ( _log_last_tp ), dtos ( tp ) ) );

		gc::push ( gc_dispose_type_on_end_tick, operations );
		bool all_complete;

		for ( int i = 0; i < 3; i++ ) {
			all_complete = true;
			LIST_FOREACH_REVERSE ( operations,
								   order_operation *,
			item, {
				if ( item.is_completed ) {
					continue;
				}

				if ( !order_operation_process ( NULL, item ) ) {
					log_info_k ( layer_error::get_last_saved_string() );

					all_complete = false;
					continue;
				}

				item.is_completed = true;
			} );

			if ( all_complete ) {
				_log_last_tp = tp;
				operations.clear_without_dispoce();
				return true;
			}
		}

		operations.clear_without_dispoce();
		return false;
	}

	bool open_lvl_handler ( enum_gap_control_type control_type, order_count_t *orders_count, double last_price, double price, double step_in_point ) {
		if ( orders_count.all() + 1 == 1 ) {
			control_type = no_gap;
		}

		switch ( control_type ) {
			case no_gap: {
				orders_count.inc_by_type ( _order_settings.order_type );
				double lot = calc_lot::get ( _settings, _order_settings,  orders_count.all(), control_type, price );
				double normalized_lot = NormalizeDouble ( lot, _settings.lot_exp );

				if ( free_check ( orders_count, price, normalized_lot ) <= 0.0 ) {
					log_info_k (  StringFormat ( SRC_HANDLER_BASE_NOT_GOOD_LOT, normalized_lot ) );
					orders_count.deinc_by_type ( _order_settings.order_type );
					return false;
				}

				if ( !open_lvl ( orders_count, control_type, price, normalized_lot, step_in_point ) ) {
					orders_count.deinc_by_type ( _order_settings.order_type );
					return false;
				}

				return true;
			}

			case inc_lot: {
				orders_count.inc_by_type ( _order_settings.order_type );
				double lot = calc_lot::get ( _settings, _order_settings,  orders_count.all(), control_type, price );
				double normalized_lot = NormalizeDouble ( lot, _settings.lot_exp );

				if ( free_check ( orders_count, price, normalized_lot ) <= 0.0 ) {
					log_info_k ( StringFormat ( SRC_HANDLER_BASE_NO_MONEY_ON_INC_LOT, NormalizeDouble ( lot, _settings.lot_exp ) ) );
					orders_count.deinc_by_type ( _order_settings.order_type );
					return open_lvl_handler ( no_gap, orders_count, 0.0, price, step_in_point );
				}

				if ( !open_lvl ( orders_count, control_type, price, normalized_lot, step_in_point ) ) {
					orders_count.deinc_by_type ( _order_settings.order_type );
					return false;
				}

				return true;
			}

			case op_stop: {
				if ( !calc_gap::is_gap ( _settings, _order_settings.order_type, last_price, price, step_in_point ) ) {
					return open_lvl_handler ( no_gap, orders_count, 0.0, price, step_in_point );
				}

				double stop_level = layer_market::min_distance_from_open_price_p ( CURRENT_SYMBOL, _settings.max_spread );
				double stop_level_offset = layer_market::to_points ( _settings.gap_min_pips_from_market );
				double adjusted_price = tool_price::deduct_by_order_type_direction ( _order_settings.order_type, price, stop_level + stop_level_offset );

				if ( !calc_gap::is_gap ( _settings, _order_settings.order_type, last_price, adjusted_price, step_in_point ) ) {
					return open_lvl_handler ( no_gap, orders_count, 0.0, price, step_in_point );
				}

				double gap_size = tool_order::get_distance ( _order_settings.order_type, price, last_price );
				log_alert_k ( StringFormat ( SRC_HANDLER_BASE_DETECT_GAP,
											 dtos ( last_price ),
											 dtos ( price ),
											 dtos ( gap_size ),
											 dtos ( step_in_point ),
											 DoubleToString ( ( gap_size / ( step_in_point / 100.00f ) ) - 100.00, 2 ),
											 dtos ( stop_level + stop_level_offset ) ) );

				list<order *> *opened_orders = layer_order::get ( _order_settings );
				LIST_LAST_INDEX_OF ( opened_orders, last_order_index, order *, item, item.is_order() );

				//РџРѕР»СѓС‡Р°РµРј РєРѕР»-РІРѕ РѕСЂРґРµСЂРѕРІ Рё РЅР°С‡Р°Р»СЊРЅСѓСЋ С†РµРЅСѓ РѕС‚РЅРѕСЃРёС‚РµР»СЊРЅРѕ РїРѕСЃР»РµРґРЅРµРіРѕ РѕС‚РєСЂС‹С‚РѕРіРѕ РѕСЂРґРµСЂР°
				if ( last_order_index != opened_orders.count - 1 ) {
					list<order *> *orders_before_gap = opened_orders.take ( last_order_index + 1 );
					gc::push ( gc_dispose_type_on_end_tick, orders_before_gap );

					orders_count = new order_count_t();
					LIST_FOREACH ( orders_before_gap, order *, item, orders_count.inc_by_type ( item.order_type ) );
					gc::push ( gc_dispose_type_on_end_tick, orders_count );

					orders_before_gap.clear_without_dispoce();

					order *item = opened_orders.items[last_order_index];
					last_price = item.open_price;
				}

				//Р“РµРЅРµСЂРёСЂСѓРµРј СЃРїРёСЃРѕРє РѕСЂРґРµСЂРѕРІ, РєРѕС‚РѕСЂС‹Рµ С‚СЂРµР±СѓРµС‚СЃСЏ РѕС‚РєСЂС‹С‚СЊ
				list<order_operation *> *list_order_open = generate_list_order_for_open ( orders_count.all() + 1,
						last_price,
						adjusted_price );
				gc::push ( gc_dispose_type_on_end_tick, list_order_open );

				//РќР°РєР»Р°РґС‹РІР°РµРј СѓР¶Рµ РѕС‚РєСЂС‹С‚С‹Рµ РѕС‚Р»РѕР¶РєРё РЅР° С‚Рµ РєРѕС‚РѕСЂС‹Рµ С‚СЂРµР±СѓРµС‚СЃСЏ РѕС‚РєСЂС‹С‚СЊ
				if ( last_order_index != opened_orders.count - 1 ) {
					LIST_JOIN ( opened_orders,
								list_order_open,
								order *,
								left,
								order_operation *,
								right,
					left.lvl == right.lvl, {
						right.ticket = left.ticket;
						right.operation_type = order_operation_type_update;
					} );
				}

				LIST_FOREACH ( list_order_open,
							   order_operation *,
				item, {
					if ( item.ticket != 0 ) {
						log_info_k ( StringFormat ( SRC_HANDLER_BASE_SHOW_CALC_STOP_ORDER_WITH_TIKET, itos ( item.lvl ), itos ( item.ticket ), dtos ( item.price ), dtos ( item.lot ), dtos ( item.step_p ) ) );
					} else {
						log_info_k ( StringFormat ( SRC_HANDLER_BASE_SHOW_CALC_STOP_ORDER, itos ( item.lvl ), dtos ( item.price ), dtos ( item.lot ), dtos ( item.step_p ) ) );
					}
				} );

				LIST_FOREACH ( list_order_open, order_operation *, item, {
					if ( !order_operation_process ( orders_count, item ) ) {
						log_info_k ( layer_error::get_last_saved_string() );
						//TODO: Р’РѕРѕР±С‰Рµ РЅСѓР¶РЅРѕ РїСЂРѕРІРµСЂСЏС‚СЊ РїРѕСЃР»РµРґРЅРёР№ Р»Рё СЌС‚Рѕ РѕСЂРґРµСЂ
						_last_not_open_order_stop = item.clone();
						list_order_open.clear_without_dispoce();
						return false;
					}

					item.is_completed = true;
				} );

				list_order_open.clear_without_dispoce();
				return true;
			}

			default:
				return false;
		}
	}

	// Р“РµРЅРµСЂРёСЂСѓРµРј СЃРїРёСЃРѕРє РѕСЂРґРµСЂРѕРІ, РєРѕС‚РѕСЂС‹Рµ С‚СЂРµР±СѓРµС‚СЃСЏ РѕС‚РєСЂС‹С‚СЊ
	list<order_operation *> *generate_list_order_for_open ( int start_lvl, double start_price, double end_price ) {
		int end_lvl = _settings.max_open_orders;

		if ( _settings.gap_max_order_stop != 0
				&&  end_lvl - start_lvl + 1 > _settings.gap_max_order_stop ) {
			end_lvl = start_lvl + _settings.gap_max_order_stop - 1;
		}

		list<order_operation *> *result = new list<order_operation *>();
		double current_price = start_price;

		for ( int i = start_lvl; i <= end_lvl; i++ ) {
			double step_p = layer_market::to_points ( calc_grid_step::get ( _settings, i ) );

			// РќСѓР¶РЅРѕ РїСЂРѕРІРµСЂСЏС‚СЊ РїРѕ РєРѕР»-РІСѓ Р±РµР· РѕС‚РєСЂС‹С‚РѕРіРѕ РѕСЂРґРµСЂР°
			if ( !is_can_add_order ( i - 1, current_price, end_price, step_p, 100.0 ) ) {
				break;
			}

			current_price = tool_price::add_by_direction ( current_price, step_p, end_price );

			order_operation *for_add = factory_order_operation::get();
			for_add.is_completed = false;
			for_add.operation_type = order_operation_type_open;
			for_add.magic_number = _settings.magic_number;
			for_add.order_type = _order_settings.order_stop_type;
			for_add.lvl = i;
			for_add.lot = NormalizeDouble (  calc_lot::get ( _settings, _order_settings, i, no_gap, 0.0 ), _settings.lot_exp );
			for_add.price = current_price;
			for_add.step_p = step_p;
			for_add.comment = create_order_comment ( i );
			result.add ( for_add );
		}

		//РЎРґРІРёРіР°РµРј РѕС‚Р»РѕР¶РµРЅРЅС‹Рµ РѕСЂРґРµСЂР° Рє РїРѕСЃР»РµРґРЅРµР№ РїРѕР»СѓС‡РµРЅРЅРѕР№ С†РµРЅРµ, С‚Р°Рє РєР°Рє РјС‹ РЅРµ СЃРјРѕРіР»Рё РїРѕРєСЂС‹С‚СЊ РІРµСЃСЊ РіСЌРї.
		double shift_offset = tool_price::distance_by_type ( _order_settings.order_type,
							  result.last_or_default().price,
							  end_price );
		LIST_FOREACH ( result,
					   order_operation *,
					   item,
					   item.price = tool_price::add_by_order_type_direction ( _order_settings.order_type, item.price, shift_offset ) );
		return result;
	}

	bool process_order_stop_aligment ( order_count_t *orders_count ) {
		list<order_operation *> *need_aligment = generate_list_order_stop_for_aligment();

		if ( !GC_CHECK_PTR ( need_aligment ) ) {
			return true;
		}

		gc::push ( gc_dispose_type_on_end_tick, need_aligment );

		bool is_completed = true;
		LIST_FOREACH ( need_aligment, order_operation *, item, {
			if ( !order_operation_process ( orders_count, item ) ) {
				log_info_k ( layer_error::get_last_saved_string() );
				is_completed = false;
			}
		} );

		need_aligment.clear_without_dispoce();
		return is_completed;
	}

	list<order_operation *> *generate_list_order_stop_for_aligment() {
		list<order_operation *> *result = NULL;
		list<order *> *opened_orders = layer_order::get ( _order_settings );

		for ( int i = opened_orders.count - 1; i > 0; i-- ) {
			order *first = opened_orders.items[i];
			order *for_aligment = opened_orders.items[i - 1];

			if ( !first.is_order() || !for_aligment.is_order_stop() ) {
				continue;
			}

			double distance = tool_order::get_distance ( _order_settings.order_type, first.open_price, for_aligment.open_price );
			double step = layer_market::to_points ( calc_grid_step::get ( _settings, first.lvl ) );
			double shift_offset = layer::correct_price ( distance - step );

			if ( shift_offset == 0.00 ) {
				i--;
				continue;
			}

			for ( ; i > 0; i-- ) {
				for_aligment = opened_orders.items[i - 1];

				if ( for_aligment.is_order() ) {
					break;
				}

				order_operation *for_add = factory_order_operation::get();
				for_add.is_completed = false;
				for_add.ticket = for_aligment.ticket;
				for_add.operation_type = order_operation_type_set_sl_tp_price;
				for_add.take_profit = 0.0f;
				for_add.stop_loss = 0.0f;
				for_add.lvl = for_aligment.lvl;
				for_add.price = tool_price::add_by_order_type_direction ( for_aligment.order_type,
								for_aligment.open_price,
								shift_offset );

				if ( !GC_CHECK_PTR ( result ) ) {
					result = new list<order_operation *>();
					log_info_k ( SRC_HANDLER_BASE_ALIGMENT );
				}

				result.add ( for_add );

				log_info_k ( StringFormat ( SRC_HANDLER_BASE_SHOW_ALIGMENT_STOP_ORDER,
											itos ( for_add.lvl ),
											itos ( for_add.ticket ),
											dtos ( for_aligment.open_price ),
											dtos ( for_add.price ) ) );
			}
		}

		return result;
	}

	bool order_operation_process ( order_count_t *orders_count,
								   order_operation *order_oper ) {
		switch ( order_oper.operation_type ) {
			case order_operation_type_none:
				return true;

			case order_operation_type_set_tp: {
				if ( kernel_order::set_tp ( order_oper.magic_number,
											order_oper.ticket,
											order_oper.take_profit ) ) {
					//layer_order::refresh ( _order_settings, order_operation.ticket );
					order_oper.is_completed = true;
					return true;
				}

				return false;
			}

			case order_operation_type_set_sl_tp: {
				if ( kernel_order::set_sl_tp ( order_oper.ticket,
											   order_oper.stop_loss,
											   order_oper.take_profit ) ) {
					//layer_order::refresh ( _order_settings, order_operation.ticket );
					order_oper.is_completed = true;
					return true;
				}

				return false;
			}

			case order_operation_type_update: {
				if ( kernel_order::set_price ( order_oper.ticket,
											   order_oper.price,
											   _order_color ) ) {
					layer_order::refresh ( _order_settings, order_oper.ticket );
					order_oper.is_completed = true;
					return true;
				}

				return false;
			}

			case order_operation_type_set_sl_tp_price: {
				if ( kernel_order::set_sl_tp_price ( order_oper.ticket,
													 order_oper.stop_loss,
													 order_oper.take_profit,
													 order_oper.price ) ) {
					layer_order::refresh ( _order_settings, order_oper.ticket );
					order_oper.is_completed = true;
					return true;
				}

				return false;
			}

			case order_operation_type_open: {
				orders_count.inc_by_type ( _order_settings.order_stop_type );

				if ( free_check ( orders_count, order_oper.price, order_oper.lot ) <= 0.0 ) {
					log_info_k (  StringFormat ( SRC_HANDLER_BASE_NOT_GOOD_STOP_LOT, order_oper.lot ) );
					return false;
				}

				string comment = create_order_comment ( order_oper.lvl );
				log_info_k (  StringFormat ( SRC_HANDLER_BASE_TRY_OPEN_STOP_LVL, IntegerToString ( order_oper.lvl, 0 ), dtos ( order_oper.step_p ), dtos ( order_oper.lot ), comment ) );

				int ticket = kernel_order::send_stop ( _settings.magic_number, order_oper.order_type, order_oper.price, order_oper.lot, comment, _order_color );

				if ( ticket != -1 ) {
					layer_order::push ( _order_settings, ticket );

					order_oper.is_completed = true;
					return true;
				}

				orders_count.deinc_by_type ( _order_settings.order_type );
				return false;
			}

			default:
				return false;
		}

		return false;
	}

	bool open_lvl ( order_count_t *orders_count, enum_gap_control_type control_type, double price, double lot, double step ) {
		string comment = create_order_comment ( orders_count.all() );
		log_info_k (  StringFormat ( SRC_HANDLER_BASE_TRY_OPEN_LVL, IntegerToString ( orders_count.all(), 0 ), DoubleToString ( step, kernel_account::digits() ), comment ) );

		for ( int i = 0; i < 5; i++ ) {
			int slippage = calc_slippage ( orders_count.all(), step );

			int ticket = kernel_order::send ( _settings.magic_number, _order_settings.order_type, price, lot, slippage, comment, _order_color );

			if ( ticket != -1 ) {
				layer_order::push ( _order_settings, ticket );
				return true;
			}

			int error = layer_error::get_last();

			if ( error == ERROR_MARKET_CLOSED ) {
				log_info_k (  SRC_SETKA_MARKET_CLOSE );
				break;
			} else if ( error != ERROR_REQUOTE ) {
				log_info_k (  StringFormat ( SRC_HANDLER_BASE_ERROR_OPEN_LVL, error_get_last ( error ) ) );
				break;
			}

			log_info_k ( SRC_HANDLER_BASE_FAIL_SLIPPAGE_OPEN_LVL );

			tool_cache::update_tick_state();
			double new_price =  layer_market::price_open ( _order_settings.order_type );
			double distance = tool_order::get_distance ( _order_settings.order_type, new_price, price );
			lot = calc_lot::get ( _settings, _order_settings, orders_count.all(), control_type, new_price );

			if ( orders_count.all() == 1 ) {
				if ( distance >= step ) {
					double spread_in_point = layer_market::to_points ( layer_market::spread () );
					log_info_k (  StringFormat ( SRC_HANDLER_BASE_VERY_STRONG_MOTION, distance, step, spread_in_point ) );
					break;
				}

				if ( !is_can_open_first_order ( orders_count.all() ) ) {
					log_info_k ( SRC_HANDLER_BASE_OPENED_NEW_CANDLE_NO_SIGNAL );
					break;
				}

				if ( !is_price_better ( price, new_price ) ) {
					log_info_k (  StringFormat ( SRC_HANDLER_BASE_BAD_PRICE, new_price, price ) );
					break;
				}
			} else {
				if ( distance >= step
						&& _settings.gap_control != no_gap ) {
					break;
				}

				// РўР°Рє РєР°Рє РјС‹ СѓР¶Рµ РїСЂРёР±Р°Р»Рё РѕСЂРґРµСЂ, С‚Рѕ РјРѕР¶РµС‚ Р±С‹С‚СЊ РѕС€РёР±РєР° РµСЃР»Рё РѕС‚РєСЂС‹РІР°РµРј РїРѕСЃР»РµРґРЅРёР№ РѕСЂРґРµСЂ
				if ( !is_can_add_order ( orders_count.all() - 1, price, new_price, step, 75 ) ) {
					log_info_k (  StringFormat ( SRC_HANDLER_BASE_PRICE_GOTO_START, dtos ( new_price ), dtos ( price ) ) );
					break;
				}
			}

			if ( !is_spred_valid()
					|| !is_vol_valid ( orders_count.all() ) ) {
				break;
			}

			price = new_price;
		}

		log_info_k ( SRC_HANDLER_BASE_FAIL_EXIT_OPEN_LVL );
		return false;
	}

	int calc_slippage ( int order_count, double step_in_point ) {
		double double_spread = layer_market::to_points ( layer_market::spread () ) * 2.0;
		double step = ( step_in_point / 100.0 ) * 25.0; // 25% Г®ГІ ГІГҐГЄГіГ№ГҐГЈГ® ГёГ ГЈГ  Г±ГҐГІГЄГЁ
		double result = double_spread > step ? double_spread : step;
		return layer_market::to_pips ( result );
	}

	bool is_can_close() {
		enum_trade_mode_type trade_mode = layer_symbol::trade_mode ( CURRENT_SYMBOL );
		return trade_mode == trade_mode_type_full
			   || trade_mode == trade_mode_type_close_only;
	}

	bool is_need_close_orders ( order_count_t *orders_count ) {
		if ( !is_can_close() ) {
			return false;
		}

		if ( scheduler::is_close_all_orders ( _order_settings ) ) {
			return true;
		}

		if ( _settings.gap_control == op_stop
				&& orders_count.order() == 0
				&& orders_count.stop() > 0 ) {
			log_info_k (  StringFormat ( SRC_HANDLER_BASE_NOT_CLOSE_ORDER_STOP, itos ( orders_count.stop() ) ) );
			return true;
		}

		double price_close = layer_market::price_close ( _order_settings.order_type );

		if ( orders_count.all() > 0
				&& is_price_worse ( _last_tp, price_close ) ) {
			log_info_k (  StringFormat ( SRC_HANDLER_BASE_PRICE_REACED_TP, dtos ( price_close ), dtos ( _last_tp ) ) );
			return true;
		}

		return false;
	}

	bool is_can_open() {
		enum_trade_mode_type trade_mode = layer_symbol::trade_mode ( CURRENT_SYMBOL );

		return trade_mode == trade_mode_type_full
			   || ( trade_mode == trade_mode_type_long_only && _order_settings.is_buy_direction )
			   || ( trade_mode == trade_mode_type_short_only && !_order_settings.is_buy_direction );
	}

	bool is_can_open_order ( order_count_t *orders_count, double last_price, double price, double step ) {
		return _settings.open_positions
			   && !_is_block_work
			   && !_is_block_work_by_stop_trade
			   && is_can_open()
			   && ( is_can_open_first_order ( orders_count.all() )
					|| is_can_add_order ( orders_count, last_price, price, step, 100.0 ) )
			   && !scheduler::is_stop_trade_time()
			   && is_spred_valid()
			   && is_vol_valid ( orders_count.all() + 1 );
	}

	bool is_can_open_first_order ( int lvl ) {
		return lvl == 0
			   && _settings.open_first_order
			   && !is_strong_sleep()
			   && scheduler::is_trade_time()
			   && scheduler::is_trade_time_for_first_order()
			   && can_open_first_order()
			   && !is_wait_stop_on_close()
			   && !is_drawdown_percent_block()
			   && !is_max_pair_block()
			   && !is_currency_block()
			   && is_leverage_valid()
			   && _settings.final_stop_trading > layer::time_current()
			   && true;
	}

	bool is_can_add_order ( order_count_t *orders_count, double last_price, double price, double grid_step, double percent_of_price ) {
		return is_can_add_order ( orders_count.all(), last_price, price, grid_step, percent_of_price );
	}

	bool is_can_add_order ( int orders_count, double last_price, double price, double grid_step, double percent_of_price ) {
		return orders_count > 0
			   && orders_count < _settings.max_open_orders
			   && ( percent_of_price == 100 ? grid_step : ( grid_step / 100 ) * percent_of_price ) <= tool_order::get_distance ( _order_settings.order_type, price, last_price )
			   && scheduler::is_trade_time()
			   && is_min_time_step_valid()
			   && true;
	}

	bool is_max_pair_block() {
		if ( _settings.max_trade_pairs == 0
				|| layer_order::get_pair_count() < _settings.max_trade_pairs ) {
			return false;
		}

		log_info_k2 ( _settings.max_trade_pairs_label,
					  StringFormat ( SRC_HANDLER_BASE_MAX_PAIR_BLOCK, _settings.max_trade_pairs ) );
		return true;
	}

	bool is_currency_block() {
		if ( _settings.currency_block == 0 ) {
			return false;
		}

		int base_count = layer_order::get_base_count ( _order_settings.is_buy_direction );
		int profit_count = layer_order::get_profit_count ( _order_settings.is_buy_direction );

		if ( base_count < _order_settings.currency_block
				&& profit_count < _order_settings.currency_block ) {
			return false;
		}

		log_info_k2 ( _settings.currency_block_label,
					  StringFormat ( _order_settings.is_buy_direction ?
									 SRC_HANDLER_BASE_CURRENCY_BLOCK_LONG :
									 SRC_HANDLER_BASE_CURRENCY_BLOCK_SHORT,
									 layer_order::get_order_layer_symbol_current_symbol().base(),
									 base_count,
									 layer_order::get_order_layer_symbol_current_symbol().profit(),
									 profit_count,
									 _settings.currency_block ) );
		return true;
	}

	bool is_drawdown_percent_block() {
		if ( _settings.no1Order_by_drawdown_percent == 0 ) {
			return false;
		}

		double drawdown_percent = ( 1 - ( kernel_account::equity() / kernel_account::balance() ) ) * 100;

		if ( drawdown_percent <= _settings.no1Order_by_drawdown_percent ) {
			return false;
		}

		if ( _settings.no1Order_by_drawdown_percent_off != 0 ) {
			_drawdown_percent_block = true;
		}

		log_info_k ( StringFormat ( SRC_HANDLER_BASE_DRAWDOWN_BLOCK, DoubleToString ( drawdown_percent, 0 ), _settings.no1Order_by_drawdown_percent ) );
		return true;
	}

	bool is_ct_elapsed ( order_count_t *counts ) {
		if ( _settings.take_profit_control_timing == 0
				|| counts.order() == 0 ) {
			return false;
		}

		if ( _is_first_tick ) {
			_is_first_tick = false;
			return true;
		}

		return _ct_timer.is_elapsed();
	}

	bool is_min_time_step_valid() {
		if ( _settings.min_time_step == 0 ) {
			return true;
		}

		order *last_order = layer_order::get_max ( _order_settings );
		int diff_in_seconds = ( int ) ( layer::time_current() - last_order.open_time );

		if ( _settings.min_time_step < diff_in_seconds ) {
			return true;
		}

		log_info_k ( StringFormat ( SRC_HANDLER_BASE_CANCEL_MIN_TIME_STEP, TimeToString ( last_order.open_time + _settings.min_time_step + 1, TIME_DATE | TIME_MINUTES | TIME_SECONDS ) ) );
		return false;
	}

	bool is_leverage_valid() {
		if ( _settings.min_leverage == 0 ) {
			return true;
		}

		int leverage = layer::account_leverage();

		if ( _settings.min_leverage <= leverage ) {
			return true;
		}

		log_info_k ( StringFormat ( SRC_HANDLER_BASE_CANCEL_LEVERAGE, itos ( leverage ), itos ( _settings.min_leverage ) ) );
		return false;
	}

	bool is_spred_valid() {
		if ( _settings.max_spread == 0 ) {
			return true;
		}

		if ( handler_base_spread_block_trading_timer != NULL ) {
			if ( !handler_base_spread_block_trading_timer.is_elapsed() ) {
				return false;
			}

			GC_DISPOSE_IF ( handler_base_spread_block_trading_timer );
		}

		int spread = layer_market::spread ();

		if ( spread <= _settings.max_spread ) {
			return true;
		}

		if ( _settings.max_spread_stop_drading_timing != 0 ) {
			handler_base_spread_block_trading_timer = timer_t::create ( _settings.max_spread_stop_drading_timing );
			log_info ( StringFormat ( SRC_HANDLER_BASE_SPREAD_NOT_GOOD, spread, _settings.max_spread, _settings.max_spread_stop_drading_timing, ttos ( handler_base_spread_block_trading_timer.ent_time() ) ) );
		}

		return false;
	}

	bool is_vol_valid ( int next_level ) {
		if ( _settings.vol_candle_max_size == 0 ) {
			return true;
		}

		// VolFromLevel starts volatility filter from selected grid level.
		if ( _settings.vol_from_level > 0 && next_level < _settings.vol_from_level ) {
			return true;
		}

		timer_t *vol_timer = _settings.vol_block_both_direction ? handler_base_shared_vol_block_trading_timer : handler_base_vol_block_trading_timer;

		if ( vol_timer != NULL ) {
			if ( !vol_timer.is_elapsed() ) {
				return false;
			}

			if ( _settings.vol_block_both_direction ) {
				GC_DISPOSE_IF ( handler_base_shared_vol_block_trading_timer );
			} else {
				GC_DISPOSE_IF ( handler_base_vol_block_trading_timer );
			}
		}

		double candle_pips_size = tool_candle::get_candle_size_by_high_low_p ( CURRENT_SYMBOL, _settings.vol_candle_tf, 0 );

		if ( candle_pips_size <= _settings.vol_candle_max_size ) {
			return true;
		}

		if ( _settings.vol_stop_trade_timing != 0 ) {
			if ( _settings.vol_block_both_direction ) {
				handler_base_shared_vol_block_trading_timer = timer_t::create ( _settings.vol_stop_trade_timing );
				log_info ( StringFormat ( SRC_HANDLER_BASE_VOL_NOT_GOOD, candle_pips_size, _settings.vol_candle_max_size, _settings.vol_stop_trade_timing, ttos ( handler_base_shared_vol_block_trading_timer.ent_time() ) ) );
			} else {
				handler_base_vol_block_trading_timer = timer_t::create ( _settings.vol_stop_trade_timing );
				log_info ( StringFormat ( SRC_HANDLER_BASE_VOL_NOT_GOOD, candle_pips_size, _settings.vol_candle_max_size, _settings.vol_stop_trade_timing, ttos ( handler_base_vol_block_trading_timer.ent_time() ) ) );
			}
		}

		return false;
	}

	bool is_wait_stop_on_close() {
		if ( _settings.pause_on_close_in_sec == 0 ) {
			return false;
		}

		order *last_order = layer_order::get_history_last_order ( _order_settings );

		if ( !GC_CHECK_PTR ( last_order ) ) {
			return false;
		}

		datetime last_close_time = last_order.close_time;
		int distance = time_get_distance_in_sec ( layer::time_current(), last_close_time );

		if ( _settings.pause_on_close_in_sec <= distance ) {
			return false;
		}

		int need_sleep = _settings.pause_on_close_in_sec - distance;
		log_info_k (  StringFormat ( SRC_HANDLER_BASE_TIMER_STOP_ON_CLOSE, need_sleep / 60 ) );
		_strong_sleep_timer = timer_t::create ( need_sleep );
		return true;
	}

	TOOL_CACHED_INSTANCE_TICK ( bool,
	is_strong_sleep, {
		if ( !_settings.open_positions )
			_is_strong_sleep = true;
		else if ( !GC_CHECK_PTR ( _strong_sleep_timer ) )
			_is_strong_sleep = false;
		else if ( !_strong_sleep_timer.is_elapsed() )
			_is_strong_sleep = true;
		else {
			gc::push ( gc_dispose_type_on_end_tick, _strong_sleep_timer );
			_strong_sleep_timer = NULL;
			_is_strong_sleep = false;
		}
	} )

	void skip_candles ( int count ) {
		int current_candle_time_open = ( int ) tool_candle::get_time ( CURRENT_SYMBOL, _settings.time_frame, 0 );
		int need_candle_time_open = current_candle_time_open + ( time::get_seconds_from_time_frame ( _settings.time_frame ) * count );
		_strong_sleep_timer = timer_t::create ( need_candle_time_open - ( int ) layer::time_current() );
	}

	bool can_open_first_order () {
		if ( _settings.candles_for_open_first_order == 0 ) {
			return true;
		}

		   for ( int i = 0; i < _settings.candles_for_open_first_order; i++ ) {
			candle_type candle_t = tool_candle::get_candle_type ( CURRENT_SYMBOL,
								   _settings.time_frame,
								   i + 1 );

			if ( candle_t == candle_type_zero ) {
				if ( i + 1 == _settings.candles_for_open_first_order ) {
					return false;
				}

				continue;
			}

			bool signal = _order_settings.is_buy_direction ?
						  candle_t == candle_type_bull :
						  candle_t == candle_type_bear;

			if ( _settings.revers_signal_to_open_first_order ) {
				signal = !signal;
			}

			if ( !signal ) {
				skip_candles ( _settings.candles_for_open_first_order - i );
				return false;
			}
		}   

		   if ( _settings.candles_for_open_first_order_min_pips > 0
				|| _settings.candles_for_open_first_order_max_pips > 0 ) {
			int candle_pips_size = _settings.candles_for_open_first_order_open_close ?
								   tool_candle::get_merged_candle_size_by_open_close_p ( CURRENT_SYMBOL, _settings.time_frame, _settings.candles_for_open_first_order, 1 ) :
								   tool_candle::get_merged_candle_size_by_high_low_p ( CURRENT_SYMBOL, _settings.time_frame, _settings.candles_for_open_first_order, 1 );

			if ( _settings.candles_for_open_first_order_min_pips > 0
					&& candle_pips_size < _settings.candles_for_open_first_order_min_pips ) {
				log_info_k ( StringFormat ( SRC_HANDLER_BASE_CANCEL_CANDLE_SIZE_MIN, candle_pips_size, _settings.candles_for_open_first_order_min_pips ) );
				skip_candles ( 1 );
				return false;
			}

			if ( _settings.candles_for_open_first_order_max_pips > 0
					&& candle_pips_size > _settings.candles_for_open_first_order_max_pips ) {
				log_info_k ( StringFormat ( SRC_HANDLER_BASE_CANCEL_CANDLE_SIZE_MAX, candle_pips_size, _settings.candles_for_open_first_order_max_pips ) );
				skip_candles ( 1 );
				return false;
			}
		}  

		return true;
	}
   
//+------------------------------------------------------------------+
//| Chrck  indincator signal                                         |
//+------------------------------------------------------------------+
   bool is_indicator_signal () {
		return false;
		double PrevCl = iClose(Symbol(), CandleTimeframe, 2);
      double CurrCl = iClose(Symbol(), CandleTimeframe, 1);
      bool sigbuy=false,sigsell=false;
      if(PrevCl>CurrCl){
         //Print("Г»аЇ«о¦­оЎіс«®ўйҐ SELL");
         if(iRSI(Symbol(),RsiTimeframe,RsiPeriod,PRICE_CLOSE,1)>50+RsiLevel && iCCI(Symbol(),CciTimeframe,CciPeriod,PRICE_CLOSE,1)>CciLevel) sigsell=true;

      }
      if(PrevCl<CurrCl){
         //Print("Г»аЇ«о¦­оЎіс«®ўйҐ BUY");
         if(iRSI(Symbol(),RsiTimeframe,RsiPeriod,PRICE_CLOSE,1)<50-RsiLevel && iCCI(Symbol(),CciTimeframe,CciPeriod,PRICE_CLOSE,1)<-1*CciLevel) sigbuy=true;
      }
      
		bool signal = order::is_buy_direction ( _order_settings.order_type ) ? sigbuy : sigsell;

		if ( !signal ) {
			return false;
		}
		return true;
	}
   
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

   
   
	double free_check ( order_count_t *order_count,
						double price,
						double lot ) {
		double free_margin_before_open = kernel_account::free_margin_check ( CURRENT_SYMBOL,
										 _order_settings.order_type,
										 lot );

		if ( order_count.stop() > 0 ) {
			double tp_with_new_order = calc_take_profit::get ( _settings, _order_settings, order_count.all(),
									   true,
									   price,
									   lot );
			double margin_stop_orders = tool_margin::calc_margin ( _order_settings, tp_with_new_order );
			free_margin_before_open -= margin_stop_orders;
		}

		log_info_k ( StringFormat ( SRC_HANDLER_BASE_FREE_MAGIN_CHECK_NEW_ORDER, itos ( order_count.all() ), dtos ( price ), dtos ( lot ), dtos ( free_margin_before_open ) ) );
		return free_margin_before_open;
	}

	string create_order_comment ( int lvl ) {
		int last_order_tiket = 0;

		if ( lvl > 1 ) {
			last_order_tiket = layer_order::get_min ( _order_settings ).ticket;
		}

		return !ext_string_equals ( _settings.add_comment, EXT_STRING_EMPTY, false ) ?
			   StringFormat ( "%s-%s<%s>%d-%s", _settings.add_comment, IntegerToString ( last_order_tiket, 8, '0' ), IntegerToString ( lvl, 2, '0' ), _settings.gap_control, VER ) :
			   StringFormat ( "%s<%s>%d-%s", IntegerToString ( last_order_tiket, 8, '0' ), IntegerToString ( lvl, 2, '0' ), _settings.gap_control, VER );
	}

	void reset_vars() {
		_last_tp = 0;
		_log_last_tp = 0;
		_drawdown_percent_block = false;
		_last_order = NULL;
		GC_DISPOSE_IF ( _last_not_open_order_stop );
	}

	bool is_price_better ( double last_price, double price ) {
		return _order_settings.is_buy_direction ?
			   price <= last_price :
			   price >= last_price;
	}

	bool is_price_worse ( double last_price, double price ) {
		return _order_settings.is_buy_direction ?
			   price >= last_price :
			   price <= last_price;
	}

	void reset_states() {
		if ( GC_CHECK_PTR ( _close_orders ) ) {
			log_info_k ( SRC_HANDLER_BASE_RESET_STATE_CLOSE_ORDER );
			gc::push ( gc_dispose_type_on_end_tick, _close_orders );
		}
	}

	// API
	bool can_update_params() {
		return !GC_CHECK_PTR ( _close_orders )
			   && !GC_CHECK_PTR ( _last_not_open_order_stop );
	}

	string get_global_prefix ( string base_prefix ) {
		string side_prefix = order::is_buy_direction ( _order_settings.order_type ) ? "Buy" : "Sell";
		return StringFormat ( "%s_%d_%s_%s", base_prefix, _settings.magic_number, CURRENT_SYMBOL, side_prefix  );
	}

	double get_order_position ( double last_price, int lvl ) {
		return tool_order::deduct_points ( _order_settings.order_type,
										   last_price,
										   layer_market::to_points ( calc_grid_step::get ( _settings, lvl ) ) );
	}
};

#endif
#ifndef API_MQH
#define API_MQH

#define PREFIX_MAIN "IG"
#define PREFIX_ORDER_STEP "OrderStep"
#define PREFIX_NEXT_ORDER_POSITION "NextOrderPosition"
#define PREFIX_LEVEL_WITHOUT_LOSS "NoLossLevel"
#define PREFIX_TAKE_PROFIT "TakeProfit"
#define PREFIX_PROFIT_IN_CURRENCY "ProfitInCurrency"
#define PREFIX_FUTURE_PROFIT_IN_CURRENCY "FutureProfitInCurrency"
#define PREFIX_LOT_SUM "LotSum"

string _prefix_long = "";
logic_handler *_api_long_handler;

string _prefix_short = "";
logic_handler *_api_short_handler;

timer_t *_api_update_time;
// РќСѓР¶РЅРѕ РєР°Рє С‚Рѕ РІ С‚Р°Р№РјРµСЂРµ СЌС‚Рѕ СЃРґРµР»Р°С‚СЊ
bool _api_first_tick;

class api {
public:
#ifdef FOR_OPTIMIZATION
	static void init() {}
	static void deinit() {}
	static void process() {}
	static void set_times ( int seconds ) {}
	static void set_short_handler ( logic_handler *value ) {}
	static void set_long_handler ( logic_handler *value ) {}
#else
	static void init() {
		_api_first_tick = true;
		GlobalVariablesDeleteAll ( _prefix_long );
		GlobalVariablesDeleteAll ( _prefix_short );
	}

	static void deinit() {
		GC_DISPOSE_IF ( _api_update_time );
	}

	static void process() {
		if ( _api_update_time == NULL
				|| ( !_api_first_tick && !_api_update_time.is_elapsed() ) ) {
			return;
		}

		_api_first_tick = false;
		handler_process ( _prefix_long, _api_long_handler );
		handler_process ( _prefix_short, _api_short_handler );
		_api_update_time.reset();
	}

	static void set_times ( int seconds ) {
		_api_update_time = seconds == 0 ? NULL : timer_t::create ( seconds );
	}

	static void set_short_handler ( logic_handler *value ) {
		_api_short_handler = value;
		_prefix_short = value.get_global_prefix ( PREFIX_MAIN );
	}

	static void set_long_handler ( logic_handler *value ) {
		_api_long_handler = value;
		_prefix_long = value.get_global_prefix ( PREFIX_MAIN );
	}

private:
#define GLOB_SET(name, value) \
	GlobalVariableSet ( StringFormat ( "%s_%s", base_prefix, name ), value )
	static void handler_process ( string base_prefix, logic_handler *handler ) {
		list<order *> *orders = layer_order::get ( handler._order_settings );

		if ( orders.count == 0 ) {
			GlobalVariablesDeleteAll ( base_prefix );
			return;
		}

		if ( !handler.can_update_params() ) {
			return;
		}

		double grid_step = layer::correct_price (  calc_grid_step::get ( handler._settings,  orders.count + 1 ) );
		double next_lvl = layer::correct_price ( handler.get_order_position ( orders.last_or_default().open_price, orders.count + 1 ) );
		double level_without_loss = layer::correct_price ( calc_take_profit::get ( handler._settings, handler._order_settings, tp_level_without_loss, 0 ) );
		double take_profit = layer::correct_price ( calc_take_profit::get ( handler._settings, handler._order_settings, orders.count ) );
		double current_price = layer_market::price_close ( handler._order_settings.order_type );

		double lot_sum = 0.0,
			   current_profit_in_currency = handler.get_profit(),
			   future_profit_in_currency = 0;
		LIST_FOREACH ( orders, order *, item, {
			lot_sum += item.lot;

			if ( item.is_order() ) {
				future_profit_in_currency += item.commission + item.swap;
				future_profit_in_currency += item.get_profit_in_currency ( take_profit );
				continue;
			}

			if ( item.is_before_line ( take_profit ) ) {
				future_profit_in_currency += item.get_profit_in_currency ( take_profit );
			}
		} );

		GLOB_SET ( PREFIX_ORDER_STEP, grid_step );
		GLOB_SET ( PREFIX_NEXT_ORDER_POSITION, next_lvl );
		GLOB_SET ( PREFIX_LEVEL_WITHOUT_LOSS, level_without_loss );
		GLOB_SET ( PREFIX_TAKE_PROFIT, take_profit );
		GLOB_SET ( PREFIX_PROFIT_IN_CURRENCY, current_profit_in_currency );
		GLOB_SET ( PREFIX_FUTURE_PROFIT_IN_CURRENCY, future_profit_in_currency );
		GLOB_SET ( PREFIX_LOT_SUM, lot_sum );
	}
#endif
};

#endif

#property version VER

logic_handler *short_hd;
logic_handler *long_hd;
timer_t *life_timer;
bool _init_failed = false;


// ===== BEGIN Setka 1.54.11 MT4 tester equity curve logger =====
#define EQUITY_LOGGER_VERSION "Setka_v1.54.22"
#define EQUITY_LOG_LOAD_STEP 0.005
#define EQUITY_LOG_WORST_EQUITY_STEP_MONEY 1.0
#define EQUITY_LOG_USE_PENDING_WORST_EQUITY true
#define EQUITY_LOG_SUPPRESS_LOAD_ONLY_SAME_MINUTE true


int equity_log_file_handle = INVALID_HANDLE;
bool equity_log_has_last_values = false;
double equity_log_last_balance = 0.0;
double equity_log_last_equity = 0.0;
double equity_log_last_deposit_load = 0.0;
double equity_log_last_recorded_max_floating_dd = 0.0;
bool equity_log_has_pending_worst = false;
datetime equity_log_pending_worst_minute = 0;
double equity_log_pending_worst_balance = 0.0;
double equity_log_pending_worst_equity = 0.0;
double equity_log_pending_worst_dd = 0.0;
double equity_log_pending_worst_deposit_load = 0.0;
datetime equity_log_last_written_minute = 0;
datetime g_equityLogFirstTestTime = 0;
datetime g_equityLogLastTestTime = 0;
string g_equityLogFileName = "";


string equity_log_timeframe_to_string()
{
	switch ( Period() ) {
		case PERIOD_M1: return "M1";
		case PERIOD_M5: return "M5";
		case PERIOD_M15: return "M15";
		case PERIOD_M30: return "M30";
		case PERIOD_H1: return "H1";
		case PERIOD_H4: return "H4";
		case PERIOD_D1: return "D1";
		case PERIOD_W1: return "W1";
		case PERIOD_MN1: return "MN1";
	}

	return IntegerToString ( Period() );
}

string equity_log_sanitize_file_part ( string value )
{
	StringReplace ( value, "\\", "_" );
	StringReplace ( value, "/", "_" );
	StringReplace ( value, ":", "-" );
	StringReplace ( value, "*", "_" );
	StringReplace ( value, "?", "_" );
	StringReplace ( value, "\"", "_" );
	StringReplace ( value, "<", "_" );
	StringReplace ( value, ">", "_" );
	StringReplace ( value, "|", "_" );
	StringReplace ( value, " ", "_" );
	return value;
}

string equity_log_numbered_file_name ( string base_name )
{
	for ( int i = 1; i < 10000; i++ ) {
		string candidate = base_name + " (" + IntegerToString ( i ) + ").csv";
		if ( !FileIsExist ( candidate, 0 ) ) {
			return candidate;
		}
	}

	return base_name + " (9999).csv";
}

string equity_log_build_file_name()
{
	string symbol = equity_log_sanitize_file_part ( Symbol() );
	string base_name = EQUITY_LOGGER_VERSION + "_" + symbol + "_" + equity_log_timeframe_to_string();

	return equity_log_numbered_file_name ( base_name );
}

string equity_log_build_final_file_name()
{
	if ( g_equityLogFirstTestTime == 0 || g_equityLogLastTestTime == 0 ) {
		return g_equityLogFileName;
	}

	string symbol = equity_log_sanitize_file_part ( Symbol() );
	string test_period = TimeToString ( g_equityLogFirstTestTime, TIME_DATE ) + "-" + TimeToString ( g_equityLogLastTestTime, TIME_DATE );
	test_period = equity_log_sanitize_file_part ( test_period );
	string base_name = EQUITY_LOGGER_VERSION + "_" + symbol + "_" + equity_log_timeframe_to_string() + "_" + test_period;

	return equity_log_numbered_file_name ( base_name );
}

datetime equity_log_current_minute()
{
	return ( datetime ) ( ( int ) TimeCurrent() - ( ( int ) TimeCurrent() % 60 ) );
}

bool equity_log_values_changed ( double balance, double deposit_load )
{
	if ( !equity_log_has_last_values ) {
		return true;
	}

	double load_rounded = NormalizeDouble ( deposit_load, 4 );
	double last_load_rounded = NormalizeDouble ( equity_log_last_deposit_load, 4 );
	bool balance_changed = MathAbs ( balance - equity_log_last_balance ) >= 0.005;
	bool deposit_load_opened = ( last_load_rounded == 0.0 && load_rounded > 0.0 );
	bool deposit_load_closed = ( last_load_rounded > 0.0 && load_rounded == 0.0 );
	bool deposit_load_changed = MathAbs ( load_rounded - last_load_rounded ) >= EQUITY_LOG_LOAD_STEP;

	return balance_changed || deposit_load_opened || deposit_load_closed || deposit_load_changed;
}

bool equity_log_important_same_minute_event ( double balance, double deposit_load )
{
	if ( !equity_log_has_last_values ) {
		return true;
	}

	double load_rounded = NormalizeDouble ( deposit_load, 4 );
	double last_load_rounded = NormalizeDouble ( equity_log_last_deposit_load, 4 );
	bool balance_changed = MathAbs ( balance - equity_log_last_balance ) >= 0.005;
	bool deposit_load_opened = ( last_load_rounded == 0.0 && load_rounded > 0.0 );
	bool deposit_load_closed = ( last_load_rounded > 0.0 && load_rounded == 0.0 );

	return balance_changed || deposit_load_opened || deposit_load_closed;
}

void equity_log_write_snapshot ( datetime snapshot_minute, double balance, double equity, double deposit_load )
{
	string row = TimeToString ( snapshot_minute, TIME_DATE | TIME_MINUTES )
		+ "\t" + DoubleToString ( balance, 2 )
		+ "\t" + DoubleToString ( equity, 2 )
		+ "\t" + DoubleToString ( deposit_load, 4 )
		+ "\r\n";

	FileWriteString ( equity_log_file_handle, row );
	if ( g_equityLogFirstTestTime == 0 ) {
		g_equityLogFirstTestTime = snapshot_minute;
	}

	g_equityLogLastTestTime = snapshot_minute;
	equity_log_last_balance = balance;
	equity_log_last_equity = equity;
	equity_log_last_deposit_load = deposit_load;
	equity_log_last_written_minute = snapshot_minute;
	equity_log_has_last_values = true;
}


void equity_log_capture_current_state()
{
	if ( equity_log_file_handle == INVALID_HANDLE || !EQUITY_LOG_USE_PENDING_WORST_EQUITY ) {
		return;
	}

	double balance = AccountBalance();
	double equity = AccountEquity();
	double deposit_load = 0.0;

	if ( equity != 0.0 ) {
		deposit_load = AccountMargin() / equity * 100.0;
	}

	double floating_dd = NormalizeDouble ( balance - equity, 2 );

	if ( deposit_load <= 0.0 ) {
		return;
	}

	if ( floating_dd <= equity_log_last_recorded_max_floating_dd + EQUITY_LOG_WORST_EQUITY_STEP_MONEY ) {
		return;
	}

	if ( !equity_log_has_pending_worst || floating_dd > equity_log_pending_worst_dd ) {
		equity_log_has_pending_worst = true;
		equity_log_pending_worst_minute = equity_log_current_minute();
		equity_log_pending_worst_balance = balance;
		equity_log_pending_worst_equity = equity;
		equity_log_pending_worst_deposit_load = deposit_load;
		equity_log_pending_worst_dd = floating_dd;
	}
}

void equity_log_write_current_state ( bool force_write )
{
	if ( force_write ) {
		Print ( "EQUITY_LOG_FORCE_WRITE called" );
	}

	if ( equity_log_file_handle == INVALID_HANDLE ) {
		return;
	}

	double balance = AccountBalance();
	double equity = AccountEquity();
	double deposit_load = 0.0;
	datetime current_minute = equity_log_current_minute();

	if ( equity != 0.0 ) {
		deposit_load = AccountMargin() / equity * 100.0;
	}

	double floating_dd = NormalizeDouble ( balance - equity, 2 );

	if ( EQUITY_LOG_USE_PENDING_WORST_EQUITY && deposit_load > 0.0 ) {
		if ( !equity_log_has_pending_worst || floating_dd > equity_log_pending_worst_dd ) {
			equity_log_has_pending_worst = true;
			equity_log_pending_worst_minute = current_minute;
			equity_log_pending_worst_balance = balance;
			equity_log_pending_worst_equity = equity;
			equity_log_pending_worst_deposit_load = deposit_load;
			equity_log_pending_worst_dd = floating_dd;
		}
	}

	bool values_changed = equity_log_values_changed ( balance, deposit_load );
	bool important_same_minute_event = equity_log_important_same_minute_event ( balance, deposit_load );
	bool pending_worst_changed = EQUITY_LOG_USE_PENDING_WORST_EQUITY
		&& equity_log_has_pending_worst
		&& ( equity_log_pending_worst_dd > equity_log_last_recorded_max_floating_dd + EQUITY_LOG_WORST_EQUITY_STEP_MONEY );

	if ( !force_write && !values_changed && !pending_worst_changed ) {
		return;
	}

	if ( pending_worst_changed ) {
		equity_log_write_snapshot ( equity_log_pending_worst_minute, equity_log_pending_worst_balance, equity_log_pending_worst_equity, equity_log_pending_worst_deposit_load );
		equity_log_last_recorded_max_floating_dd = equity_log_pending_worst_dd;
		equity_log_has_pending_worst = false;
	}

	if ( force_write || values_changed ) {
		if ( force_write || !EQUITY_LOG_SUPPRESS_LOAD_ONLY_SAME_MINUTE || current_minute != equity_log_last_written_minute || important_same_minute_event ) {
			equity_log_write_snapshot ( current_minute, balance, equity, deposit_load );
			if ( floating_dd > equity_log_last_recorded_max_floating_dd ) {
				equity_log_last_recorded_max_floating_dd = floating_dd;
			}
		}
	}
}

void equity_log_init()
{
	Print ( "EQUITY_LOG_INIT called" );

	if ( !IsTesting() || IsOptimization() ) {
		return;
	}

	g_equityLogFileName = equity_log_build_file_name();
	Print ( "EQUITY_LOG_FILE_NAME=", g_equityLogFileName );
	equity_log_file_handle = FileOpen ( g_equityLogFileName, FILE_WRITE | FILE_TXT | FILE_UNICODE );

	if ( equity_log_file_handle == INVALID_HANDLE ) {
		Print ( "EQUITY_LOG_FILE_OPEN_FAILED error=", GetLastError() );
		return;
	}

	Print ( "EQUITY_LOG_FILE_OPEN_OK handle=", equity_log_file_handle );
	FileWriteString ( equity_log_file_handle, "<DATE>\t<BALANCE>\t<EQUITY>\t<DEPOSIT LOAD>\r\n" );
	Print ( "EQUITY_LOG_HEADER_WRITTEN" );
	equity_log_write_current_state ( true );
}

void equity_log_deinit()
{
	Print ( "EQUITY_LOG_DEINIT called" );

	if ( equity_log_file_handle == INVALID_HANDLE ) {
		return;
	}

	equity_log_write_current_state ( true );
	FileClose ( equity_log_file_handle );
	equity_log_file_handle = INVALID_HANDLE;

	string final_file_name = equity_log_build_final_file_name();
	if ( final_file_name != g_equityLogFileName ) {
		if ( !FileMove ( g_equityLogFileName, 0, final_file_name, 0 ) ) {
			Print ( "EquityLog: cannot rename file, error=", GetLastError(), ", file=", g_equityLogFileName );
		}
	}
}
// ===== END Setka 1.54.11 MT4 tester equity curve logger =====

#ifndef FOR_OPTIMIZATION

#ifndef LOGICS_TEST_MQH
#define LOGICS_TEST_MQH

#ifndef SETKA_TEST_MQH
#define SETKA_TEST_MQH


class test_entry_point {
public:
	bool test_all() {
		return test_get_drawdown_in_percent()
			   && test_get_drawdown();
	}

private:
	bool test_get_drawdown_in_percent() {
		double for_check[] = {
			50.0, 10000, 6000,
			40.0, 10000, 7000,
			30.0, 10000, 8000,
			20.0, 10000, 9000,
			10.0, 10000, 9500,
		};
		double for_check2[] = {
			50.0, 10000, 9500,
			40.0, 10000, 9000,
			30.0, 10000, 8000,
			20.0, 10000, 7000,
			10.0, 10000, 6000,
		};
		/*
		    for ( int i = 0; i < 15; i += 3 ) {
				if ( !get_drawdown_in_percent ( ( int ) for_check[i], for_check[i + 1], for_check[i + 2] )
						&& get_drawdown_in_percent ( ( int ) for_check2[i], for_check2[i + 1], for_check2[i + 2] ) ) {
					return false;
				}
			}

			return !get_drawdown_in_percent ( 0.0, 0.0, 0.0 );
		*/
		return true;
	}

	bool test_get_drawdown() {
		double for_check[] = {
			3000, 10000, 8000,
			4000, 10000, 7000,
			5000, 10000, 6000,
			6000, 10000, 5000,
			7000, 10000, 4000,
		};
		double for_check2[] = {
			3000, 10000, 4000,
			4000, 10000, 5000,
			5000, 10000, 6000,
			6000, 10000, 7000,
			7000, 10000, 8000,
		};
		/*
		    for ( int i = 0; i < 15; i += 3 ) {
				if ( !get_drawdown ( ( int ) for_check[i], for_check[i + 1], for_check[i + 2] )
						&& get_drawdown ( ( int ) for_check2[i], for_check2[i + 1], for_check2[i + 2] ) ) {
					return false;
				}
			}

			return !get_drawdown ( 0.0, 0.0, 0.0 );
		*/
		return true;
	}
};

#endif
#ifndef TEST_GRID_STEP_CALC_MQH
#define TEST_GRID_STEP_CALC_MQH

class test_grid_step_calc {
public:
	static bool test_all() {
		return test_grid_stop();
	}

private:
	static bool test_grid_stop() {
		int for_check[] = {
			0, //1
			19, //2
			19, //3
			19, //4
			22, //5
			25, //6
			29, //7
			33, //8
			38, //9
			43, //10
			48, //11
			48  //12
		};

		setting_t *test_settings = new setting_t();
		test_settings.is_testing = true;
		test_settings.testing_balance = 1000;

		test_settings.grid_step = 19;

		test_settings.grid_level = 5;
		test_settings.grid_value = 3;

		test_settings.grid_level2 = 7;
		test_settings.grid_level2_add_pips = 4;

		test_settings.grid_level3 = 9;
		test_settings.grid_level3_add_pips = 5;

		test_settings.grid_stop = 11;

		int count = ArraySize ( for_check );

		for ( int i = 1; i < count; i++ ) {
			int check = for_check[ i ];
			int result = calc_grid_step::get ( test_settings, i + 1 );

			if ( check != result ) {
				delete test_settings;
				return false;
			}
		}

		delete test_settings;
		return true;
	}
};

#endif
#ifndef HANDLER_BASE_TEST_MQH
#define HANDLER_BASE_TEST_MQH

class test_handler_base {
public:
	bool test_all() {
		return test_calc_lot()
			   && test_grid_step();
	}

private:
	bool test_calc_lot() {
		return true;

		/*

		    setting_t *setting = new setting_t();
		    setting.lots = 0.01;
		    setting.lot_exp = 2.0;
		    setting.multi_lots_level1 = 3;
		    setting.multi_lots_factor = 1.65;
		    setting.multi_lots_level2 = 11;
		    setting.multi_lots_level2_corr = -0.05;
		    _instance._settings = setting;
		    double for_check[] = {
			0.01, 0.01, 0.02,
			0.03, 0.04, 0.07,
			0.12, 0.20, 0.33,
			0.55, 0.88, 1.36,
			2.04, 2.96, 4.15
		    };

		    for ( int i = 0; i < 15; i++ ) {
			if ( NormalizeDouble ( _instance.calc_lot ( i + 1, no_gap, 0.0 ), setting.lot_exp ) != for_check[i] ) {
				return false;
			}
		    }

		    setting.multi_lots_level2 = 0;
		    double for_check2[] = {
			0.01, 0.01, 0.02,
			0.03, 0.04, 0.07,
			0.12, 0.20, 0.33,
			0.55, 0.91, 1.50,
			2.47, 4.07, 6.72
		    };

		    for ( int i = 0; i < 15; i++ ) {
			if ( NormalizeDouble ( _instance.calc_lot ( i + 1, no_gap, 0.0 ), setting.lot_exp ) != for_check2[i] ) {
				return false;
			}
		    }

		    setting.multi_lots_level1 = 0;

		    for ( int i = 0; i < 15; i++ ) {
			if ( NormalizeDouble ( _instance.calc_lot ( i + 1, no_gap, 0.0 ), setting.lot_exp ) != setting.lots ) {
				return false;
			}
		    }

		    setting.lots = 0.01;
		    setting.lot_exp = 2.0;
		    setting.multi_lots_level1 = 3;
		    setting.multi_lots_factor = 1.4;
		    setting.multi_lots_level2 = 5;
		    setting.multi_lots_level2_corr = 0.02;
		    setting.multi_lots_level3 = 10;
		    setting.multi_lots_level3_corr = -0.05;

		    double for_check3[] = {
			1.00, 1.00, 1.40,
			1.40, 1.42, 1.44,
			1.46, 1.48, 1.50,
			1.45, 1.40, 1.35,
			1.30, 1.25, 1.20
		    };

		    for ( int i = 0; i < 15; i++ ) {
			if ( NormalizeDouble ( _instance.calc_lot_factor ( i + 1 ), 2 ) != for_check3[i] ) {
				return false;
			}
		    }

		    delete setting;
		    return true;

		*/
	}

	bool test_grid_step() {
		return true;
		/*

		    setting_t *setting = new setting_t();
		    setting.grid_step = 10.0;
		    setting.grid_level = 9;
		    setting.grid_value = 16;
		    setting.grid_level2 = 16;
		    setting.grid_level2_add_pips = 0;
		    _instance._settings = setting;
		    double for_check[] = { 10, 10, 10, 10, 10, 10, 10, 10, 26, 42, 58, 74, 90, 106, 122 };

		    for ( int i = 0; i < 15; i++ ) {
			if ( _instance.calc_grid_step ( i + 1 ) != for_check[i] ) {
				return false;
			}
		    }

		    for ( int i = 15; i < 21; i++ ) {
			if ( _instance.calc_grid_step ( i + 1 ) != 122 ) {
				return false;
			}
		    }

		    setting.grid_level = 0;

		    for ( int i = 0; i < 21; i++ ) {
			if ( _instance.calc_grid_step ( i + 1 ) != 10 ) {
				return false;
			}
		    }

		    delete setting;
		    return true;
		*/
	}
};

#endif
#ifndef LOT_CALC_TEST_MQH
#define LOT_CALC_TEST_MQH

class test_lot_calc {
public:
	static bool test_all() {
		return test_calc_lot_by_balance()
			   && test_calc_lot_by_last_order()
			   && test_calc_lot_by_min_order()
			   && test_mult_stop()
			   && test_max_lot();
	}

private:
	static bool test_calc_lot_by_balance() {
		double for_check[] = {
			1000, 3, 1000, 0.01, 0.010,
			1050, 3, 1000, 0.01, 0.010,
			1100, 3, 1000, 0.01, 0.011,
			1150, 3, 1000, 0.01, 0.011,
			1200, 3, 1000, 0.01, 0.012,
			1250, 3, 1000, 0.01, 0.012,
			1300, 3, 1000, 0.01, 0.013,
			1350, 3, 1000, 0.01, 0.013,
			1400, 3, 1000, 0.01, 0.014,
			1450, 3, 1000, 0.01, 0.014,
			1500, 3, 1000, 0.01, 0.015,
			1550, 3, 1000, 0.01, 0.015,
			1600, 3, 1000, 0.01, 0.016,
			1650, 3, 1000, 0.01, 0.016,
			1700, 3, 1000, 0.01, 0.017,
			1750, 3, 1000, 0.01, 0.017,
			1850, 3, 1000, 0.01, 0.018,
			1900, 3, 1000, 0.01, 0.019,
			1950, 3, 1000, 0.01, 0.019,
			2000, 3, 1000, 0.01, 0.020
		};

		int columns = 5;
		int rows = 20;
		int count = rows * columns;

		setting_t *test_settings = new setting_t();
		test_settings.is_testing = true;

		bool result = true;

		for ( int i = 0; i < count; ) {
			test_settings.testing_balance = for_check[ i++ ];
			test_settings.lot_exp = ( int ) for_check[ i++ ];
			test_settings.currency_for_min_lot = ( int ) for_check[ i++ ];
			test_settings.lots = for_check[ i++ ];

			double check_lot = for_check[ i++ ];
			double result_lot = calc_lot::get ( test_settings,  NULL, 1, no_gap, 0.00000f );

			if ( check_lot != result_lot ) {
				result = false;
				break;
			}
		}

		delete test_settings;
		return result;
	}

	static bool test_calc_lot_by_last_order() {
		double for_check[] = {
			0.01f,
			0.02f,
			0.02f,
			0.04f,
			0.07f,
			0.14f,
			0.28f,
			0.59f,
			1.29f,
			2.97f
		};

		setting_t *test_settings = new setting_t();
		test_settings.is_testing = true;
		test_settings.testing_balance = 1000;
		test_settings.mult_type = calc_lot_type_last_order;
		test_settings.lot_exp = 2;
		test_settings.currency_for_min_lot = 1000;
		test_settings.lots = 0.01f;
		test_settings.multi_lots_level1 = 2;
		test_settings.multi_lots_factor = 1.5f;
		test_settings.multi_lots_level2 = 3;
		test_settings.multi_lots_level2_corr = 0.1f;

		bool result = true;
		int count = ArraySize ( for_check );

		for ( int i = 0; i < count; i++ ) {
			double check_lot = NormalizeDouble ( for_check[ i ], test_settings.lot_exp );
			double result_lot = NormalizeDouble ( calc_lot::get ( test_settings,  NULL, i + 1, no_gap, 0.00000f ), test_settings.lot_exp );

			if ( check_lot != result_lot ) {
				result = false;
				break;
			}
		}

		delete test_settings;
		return result;
	}

	static bool test_calc_lot_by_min_order() {
		double for_check[] = {
			0.0100f,
			0.0150f,
			0.0160f,
			0.0170f,
			0.0180f,
			0.0190f,
			0.0200f,
			0.0210f,
			0.0220f,
			0.0230f
		};

		setting_t *test_settings = new setting_t();
		test_settings.is_testing = true;
		test_settings.testing_balance = 1000;
		test_settings.mult_type = calc_lot_type_min_order;
		test_settings.lot_exp = 2;
		test_settings.currency_for_min_lot = 1000;
		test_settings.lots = 0.01f;
		test_settings.multi_lots_level1 = 2;
		test_settings.multi_lots_factor = 1.5f;
		test_settings.multi_lots_level2 = 3;
		test_settings.multi_lots_level2_corr = 0.1f;

		bool result = true;
		int count = ArraySize ( for_check );

		for ( int i = 0; i < count; i++ ) {
			double check_lot = NormalizeDouble ( for_check[ i ], test_settings.lot_exp );
			double result_lot = NormalizeDouble ( calc_lot::get ( test_settings,  NULL, i + 1, no_gap, 0.00000f ), test_settings.lot_exp );

			if ( check_lot != result_lot ) {
				result = false;
				break;
			}
		}

		delete test_settings;
		return result;
	}

	static bool test_mult_stop() {
		double for_check[] = {
			0.0100f,
			0.0150f,
			0.0240f,
			0.0408f,
			0.0694f,
			0.1179f,
			0.2005f,
			0.3408f,
			0.5793f,
			0.9848f
		};

		setting_t *test_settings = new setting_t();
		test_settings.is_testing = true;
		test_settings.testing_balance = 1000;
		test_settings.mult_type = calc_lot_type_last_order;
		test_settings.lot_exp = 4;
		test_settings.currency_for_min_lot = 1000;
		test_settings.lots = 0.01f;
		test_settings.multi_lots_level1 = 2;
		test_settings.multi_lots_factor = 1.5f;
		test_settings.multi_lots_level2 = 3;
		test_settings.multi_lots_level2_corr = 0.1f;
		test_settings.mult_stop = 4;

		int count = ArraySize ( for_check );

		for ( int i = 0; i < count; i++ ) {
			double check_lot = NormalizeDouble ( for_check[ i ], test_settings.lot_exp );
			double result_lot = NormalizeDouble ( calc_lot::get ( test_settings,  NULL, i + 1, no_gap, 0.00000f ), test_settings.lot_exp );

			if ( check_lot != result_lot ) {
				delete test_settings;
				return false;
			}
		}

		delete test_settings;
		return true;
	}

	static bool test_max_lot() {
		double for_check[] = {
			0.0100f,
			0.0150f,
			0.0200f,
			0.0200f,
			0.0200f,
			0.0200f,
			0.0200f,
			0.0200f,
			0.0200f,
			0.0200f
		};

		setting_t *test_settings = new setting_t();
		test_settings.is_testing = true;
		test_settings.testing_balance = 1000;
		test_settings.mult_type = calc_lot_type_last_order;
		test_settings.lot_exp = 4;
		test_settings.currency_for_min_lot = 1000;
		test_settings.lots = 0.01f;
		test_settings.multi_lots_level1 = 2;
		test_settings.multi_lots_factor = 1.5f;
		test_settings.multi_lots_level2 = 3;
		test_settings.multi_lots_level2_corr = 0.1f;
		test_settings.mult_stop = 4;
		test_settings.max_lot = 2;

		int count = ArraySize ( for_check );

		for ( int i = 0; i < count; i++ ) {
			double check_lot = NormalizeDouble ( for_check[ i ], test_settings.lot_exp );
			double result_lot = NormalizeDouble ( calc_lot::get ( test_settings,  NULL, i + 1, no_gap, 0.00000f ), test_settings.lot_exp );

			if ( check_lot != result_lot ) {
				delete test_settings;
				return false;
			}
		}

		delete test_settings;
		return true;
	}
};

#endif

class test {
public:
	static bool all() {
		/*
		    test_handler_base *hb_test = new test_handler_base();

		    if ( !hb_test.test_all() ) {
			return false;
		    }


		    delete hb_test;
		    test_entry_point *s_test = new test_entry_point();

		    if ( !s_test.test_all() ) {
			return false;
		    }

		    delete s_test;
		*/

		if ( !test_lot_calc::test_all() ) {
			return false;
		}

		if ( !test_grid_step_calc::test_all() ) {
			return false;
		}

		return true;
	}
};

#endif

void show_market_info()
{
	log_info ( StringFormat ( SRC_SETKA_MODE_LOW, dtos ( kernel_market::price_day_min (  ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_HIGH, dtos ( kernel_market::price_day_max (  ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_TIME, TimeToString ( kernel_market::tick_last_time (  ), TIME_DATE | TIME_MINUTES | TIME_SECONDS ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_BID, dtos ( layer_market::price_buy (  ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_ASK, dtos ( layer_market::price_sell (  ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_POINT, dtos ( layer_market::point (  ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_DIGITS, itos ( kernel_market::digits (  ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_SPREAD, itos ( layer_market::spread (  ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_STOPLEVEL, dtos ( layer_market::stop_level (  ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_LOTSIZE, dtos ( layer_market::lot_size ( ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_TICKVALUE, dtos ( layer_market::tick_value ( ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_TICKSIZE, dtos ( layer_market::tick_size ( ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_SWAPLONG, dtos ( kernel_market::swap_long ( ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_SWAPSHORT, dtos ( kernel_market::swap_short ( ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_STARTING, TimeToString ( kernel_market::starting ( ), TIME_DATE | TIME_MINUTES | TIME_SECONDS ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_EXPIRATION, TimeToString ( kernel_market::expiration ( ), TIME_DATE | TIME_MINUTES | TIME_SECONDS ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_TRADEALLOWED, kernel_market::trade_allowed ( ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_MINLOT, dtos ( layer_market::lot_min ( ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_LOTSTEP, dtos ( layer_market::lot_step ( ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_MAXLOT, dtos ( kernel_market::lot_max ( ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_SWAPTYPE, EnumToString ( kernel_market::swap_type ( ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_PROFITCALCMODE, EnumToString ( kernel_market::profit_calc_type ( ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_MARGINCALCMODE, EnumToString ( kernel_market::margin_calc_type ( ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_MARGININIT, dtos ( kernel_market::margin_init ( ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_MARGINMAINTENANCE, dtos ( kernel_market::margin_maintenance ( ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_MARGINHEDGED, dtos ( kernel_market::margin_hedged (  ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_MARGINREQUIRED, dtos ( layer_market::margin_required (  ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_MODE_FREEZELEVEL, dtos ( kernel_market::freeze_level (  ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_TERMINAL_VERSION_MSG, itos ( TerminalInfoInteger ( TERMINAL_BUILD ) ) ) );
	log_info ( StringFormat ( SRC_SETKA_VERSION_MSG, VER, BUILD, TimeToString ( __DATETIME__, TIME_DATE | TIME_MINUTES | TIME_SECONDS ) ) );
	log_info ( StringFormat ( SRC_SETKA_ACCOUNT_COMPANY, kernel_account::company() ) );
	log_info ( StringFormat ( SRC_SETKA_ACCOUNT_CURRENCY, layer_account::currency() ) );
	log_info ( StringFormat ( SRC_SETKA_ACCOUNT_LEVERAGE, itos ( layer::account_leverage() ) ) );
	log_info ( ext_string::get_sha256 ( itos ( kernel_account::number() ) ) );
	log_info ( StringFormat ( SRC_SETKA_ACCOUNT_SERVER, kernel_account::server() ) );
	log_info ( StringFormat ( SRC_SETKA_ACCOUNT_STOPOUT, itos ( kernel_account::stopout_level() ) ) );
	log_info ( StringFormat ( SRC_SETKA_ACCOUNT_STOPOUT_MODE, itos ( kernel_account::stopout_mode() ) ) );
}

int OnInit()
{
	_init_failed = false;
	equity_log_init();

	tool_cache::update_instance_state();

	if ( layer_account::is_optimization() ) {
		_init_failed = true;
		return INIT_SUCCEEDED;
	}

	gc::init();

	if ( !layer_account::is_testing() ) {
		life_timer = timer_t::create ( 60 );
		gc::push ( gc_dispose_type_on_end_deinit, life_timer );

		update_time_on_chart();
	}

	show_market_info();

	double lot_step = layer_market::lot_step ();
	int lot_exp = get_lot_exp_by_minlot ( lot_step );
	log_info (  StringFormat ( SRC_SETKA_COUNT_SYMBOL_FOR_AVG, ( int ) lot_exp ) );

	if ( lot_exp == -1 ) {
		log_error ( StringFormat ( SRC_SETKA_NOT_GOOD_LOTSTEP, lot_step ) );
		_init_failed = true;
		return INIT_SUCCEEDED;
	}

	if ( !defines_validate() ) {
		log_error ( SRC_SETKA_VALID_NOT_GOOD );
		_init_failed = true;
		return INIT_SUCCEEDED;
	}

	if ( !test::all() ) {
		log_error ( SRC_SETKA_TEST_NOT_GOOD );
		_init_failed = true;
		return INIT_SUCCEEDED;
	}

	log_info ( SRC_SETKA_TEST_GOOD );

	setting_t *short_settings = defines_create ( false, lot_exp );
	gc::push ( gc_dispose_type_on_end_deinit, short_settings );
	setting_t *long_settings = defines_create ( true, lot_exp );
	gc::push ( gc_dispose_type_on_end_deinit, long_settings );

	layer_order::init();
	short_hd = new logic_handler ( false, short_settings );
	long_hd = new logic_handler ( true, long_settings );

	int max_order_count = short_settings.max_open_orders + long_settings.max_open_orders;
	factory_order::init ( max_order_count );
	factory_order_operation::init ( max_order_count );

	if ( !layer_account::is_testing() ) {
		api::set_short_handler ( short_hd );
		api::set_long_handler ( long_hd );
		api::set_times ( GlobalParamsUpdateTiming );
		api::init();
	}

	defines_init_scheduler();

	log_info ( SRC_SETKA_INIT_COMPLETED );

	return INIT_SUCCEEDED;
}

#else

int OnInit()
{
	_init_failed = false;
	equity_log_init();

	tool_cache::update_instance_state();

	if ( !layer_account::is_optimization()
			&& !layer_account::is_testing() ) {
		_init_failed = true;
		return INIT_SUCCEEDED;
	}

	gc::init();

	double lot_step = layer_market::lot_step ();
	int lot_exp = get_lot_exp_by_minlot ( lot_step );

	log_info (  StringFormat ( SRC_SETKA_COUNT_SYMBOL_FOR_AVG, ( int ) lot_exp ) );

	if ( lot_exp == -1 ) {
		log_error ( StringFormat ( SRC_SETKA_NOT_GOOD_LOTSTEP, lot_step ) );
		_init_failed = true;
		return INIT_SUCCEEDED;
	}

	if ( !defines_validate() ) {
		log_error ( SRC_SETKA_VALID_NOT_GOOD );
		_init_failed = true;
		return INIT_PARAMETERS_INCORRECT;
	}

	setting_t *short_settings = defines_create ( false, lot_exp );
	gc::push ( gc_dispose_type_on_end_deinit, short_settings );
	setting_t *long_settings = defines_create ( true, lot_exp );
	gc::push ( gc_dispose_type_on_end_deinit, long_settings );

	layer_order::init();
	short_hd = new logic_handler ( false, short_settings );
	long_hd = new logic_handler ( true, long_settings );

	int max_order_count = short_settings.max_open_orders + long_settings.max_open_orders;
	factory_order::init ( max_order_count );
	factory_order_operation::init ( max_order_count );

	defines_init_scheduler();

	return INIT_SUCCEEDED;
}

#endif

void OnDeinit ( const int reason )
{
	string reason_str = error_deinit_reason ( reason );

	if ( reason_str != NULL ) {
		log_info ( StringFormat ( SRC_SETKA_DEINIT_REASON, reason_str ) );
	}

	if ( short_hd != NULL ) {
		delete short_hd;
	}

	if ( short_hd != NULL ) {
		delete long_hd;
	}

	api::deinit();
	gc::deinit();
	equity_log_write_current_state ( true );
	equity_log_deinit();
}

double get_recovery_factor()
{
	double dd = TesterStatistics ( STAT_EQUITY_DD );
	return dd != 0.0 ? ( TesterStatistics ( STAT_PROFIT ) / dd ) : 0;
}

double OnTester( )
{
	return get_recovery_factor();
}

void OnTick()
{
	if ( _init_failed ) {
		return;
	}

	equity_log_capture_current_state();
	pre_tick_handler();
	tick_handler();
	post_tick_handler();
	equity_log_write_current_state ( false );
}

void pre_tick_handler()
{
	layer_error::reset();
	tool_cache::update_tick_state();
	factory_order::reset();
	factory_order_operation::reset();

	if ( short_hd.is_strong_sleep() && long_hd.is_strong_sleep() ) {
		return;
	}

	layer_order::refresh_all();
}

void tick_handler()
{
	if ( short_hd.is_strong_sleep() && long_hd.is_strong_sleep() ) {
		return;
	}

	if ( !layer_account::is_trade_allowed() ) {
		log_info ( SRC_SETKA_TRADE_NOT_ALLOWED  );
		return;
	}

	enum_trade_mode_type trade_mode = layer_symbol::trade_mode ( CURRENT_SYMBOL );

	if ( trade_mode != trade_mode_type_full ) {
		switch ( trade_mode ) {
			case trade_mode_type_disabled:
				log_info ( SRC_SETKA_SYMBOL_TRADE_MODE_DISABLED );
				return;

			case trade_mode_type_long_only:
				log_info ( SRC_SETKA_SYMBOL_TRADE_MODE_LONGONLY );
				break;

			case trade_mode_type_short_only:
				log_info ( SRC_SETKA_SYMBOL_TRADE_MODE_SHORTONLY );
				break;

			case trade_mode_type_close_only:
				log_info ( SRC_SETKA_SYMBOL_TRADE_MODE_CLOSEONLY );
				break;
		}
	}

	double account_balance = kernel_account::balance();

	if ( account_balance == 0.00 ) {
		log_info ( SRC_SETKA_NO_MONEY  );
		return;
	}

	double account_drawdown_percent = ( 1 - ( kernel_account::equity() / account_balance ) ) * 100;

	short_hd.drawdown_changed_handler ( account_drawdown_percent );
	long_hd.drawdown_changed_handler ( account_drawdown_percent );
	short_hd.mark_block_work_by_stop_trade ( false );
	long_hd.mark_block_work_by_stop_trade ( false );

	bool is_close_by_profit_percent = is_close_orders_profit_in_percent ( layer_account::profit_clear_percent() );
	bool is_close_by_profit_currency = is_close_orders_profit_in_money ( layer_account::profit_clear_currency() );
	bool is_close_by_drawdown_percent = is_close_orders_drawdown_in_percent ( layer_account::drawdown_percent() );
	bool is_close_by_drawdown_currency = is_close_orders_drawdown_in_money ( layer_account::drawdown_currency() );

	bool is_close_by_profit = is_close_by_profit_currency
							  || is_close_by_profit_percent;
	bool is_close_by_drawdown = is_close_by_drawdown_currency
								|| is_close_by_drawdown_percent;
	bool is_need_close = is_close_by_profit
						 || is_close_by_drawdown;
	bool is_close_by_percent = is_close_by_profit_percent
							   || is_close_by_drawdown_percent;

	if (  !short_hd.is_close_module_activated()
			&& !long_hd.is_close_module_activated()
			&& short_hd.is_can_close()
			&& long_hd.is_can_close()
			&& is_need_close ) {

		if ( is_close_by_drawdown ) {
			log_alert ( StringFormat ( SRC_SETKA_DRAWDOWN_CLOSE_ALL_BY_DRAWDOWN_MSG,
									   is_close_by_percent ?
									   DoubleToString ( layer_account::drawdown_percent(), 2 ) + "%" :
									   DoubleToString ( layer_account::drawdown_currency(), 2 ),
									   is_close_by_percent ?
									   DoubleToString ( CloseAllOrders_ByDrawdownPercent, 2 ) + "%" :
									   DoubleToString ( CloseAllOrders_ByDrawdownMoney, 2 ) ) );
		} else {
			log_alert ( StringFormat ( SRC_SETKA_DRAWDOWN_CLOSE_ALL_BY_PROFIT_MSG,
									   is_close_by_percent ?
									   DoubleToString ( layer_account::profit_clear_percent(), 2 ) + "%" :
									   DoubleToString ( layer_account::profit_clear_currency(), 2 ),
									   is_close_by_percent ?
									   DoubleToString ( CloseAllOrders_ByProfitPercent, 2 ) + "%" :
									   DoubleToString ( CloseAllOrders_ByProfitMoney, 2 ) ) );
		}

		short_hd.mark_close_all_orders ( 0, true, is_close_by_drawdown );
		long_hd.mark_close_all_orders ( 0, true, is_close_by_drawdown  );

		if ( short_hd._is_block_work ) {
			log_alert ( SRC_SETKA_DRAWDOWN_CLOSE_ALL_STOP_TRADE_MSG );
		}
	} else if ( is_stop_trade_drawdown_in_percent ( layer_account::drawdown_percent() )
				|| is_stop_trade_drawdown_in_money ( layer_account::drawdown_currency() ) ) {
		log_info (  StringFormat ( SRC_SETKA_DRAWDOWN_MSG,
								   DoubleToString ( layer_account::drawdown_percent(), 0 ) + "%" ) );

		if ( short_hd.get_profit() > long_hd.get_profit() ) {
			long_hd.mark_block_work_by_stop_trade ( true );
		} else {
			short_hd.mark_block_work_by_stop_trade ( true );
		}
	}

	short_hd.tick_handler();

	if ( layer_market::is_closed() ) {
		return;
	}

	long_hd.tick_handler();
}

void post_tick_handler()
{
	if ( layer_market::is_closed() ) {
		log_info ( SRC_SETKA_MARKET_CLOSE_ERROR );
		short_hd.reset_states();
		long_hd.reset_states();
	}

	api::process();
	gc::dispose();

	if ( life_timer != NULL && life_timer.is_elapsed() ) {
		life_timer.reset();
		update_time_on_chart();
	}
}

void update_time_on_chart()
{
	Comment ( StringFormat ( SRC_SETKA_VERSION_MSG, VER, BUILD, TimeToString ( __DATETIME__, TIME_DATE | TIME_MINUTES ), TimeToString ( layer::time_current(), TIME_DATE | TIME_MINUTES ) ) );
}

bool is_close_orders_drawdown_in_percent ( double drawdown_percent )
{
	return CloseAllOrders_ByDrawdownPercent > 0
		   && drawdown_percent >= CloseAllOrders_ByDrawdownPercent;
}

bool is_close_orders_drawdown_in_money ( double drawdown_currency )
{
	return CloseAllOrders_ByDrawdownMoney > 0
		   && drawdown_currency >= CloseAllOrders_ByDrawdownMoney;
}

bool is_close_orders_profit_in_percent ( double profit_percent )
{
	return CloseAllOrders_ByProfitPercent > 0
		   && profit_percent >= CloseAllOrders_ByProfitPercent;
}

bool is_close_orders_profit_in_money ( double profit_currency )
{
	return CloseAllOrders_ByProfitMoney > 0
		   && profit_currency >= CloseAllOrders_ByProfitMoney;
}

bool _stop_trade_by_drawdown_in_percent_enabled = false;
bool is_stop_trade_drawdown_in_percent ( double drawdown_percent )
{
	if ( StopTrade_ByDrawdownPercent == 0 ) {
		return false;
	}

	if ( _stop_trade_by_drawdown_in_percent_enabled ) {
		if ( drawdown_percent >= StopTrade_ByDrawdownPercent_Off ) {
			return true;
		}

		log_alert ( StringFormat ( SRC_SETKA_STOP_DRAWDOWN_OFF,
								   DoubleToString ( drawdown_percent, 2 ) + "%",
								   DoubleToString ( StopTrade_ByDrawdownPercent_Off, 2 ) + "%" ) );
		_stop_trade_by_drawdown_in_percent_enabled = false;
		return false;
	}

	bool result = drawdown_percent >= StopTrade_ByDrawdownPercent;

	if ( result
			&& StopTrade_ByDrawdownPercent_Off != 0 ) {
		log_alert ( StringFormat ( SRC_SETKA_STOP_DRAWDOWN_ON,
								   DoubleToString ( drawdown_percent, 2 ) + "%",
								   DoubleToString ( StopTrade_ByDrawdownPercent_Off, 2 ) + "%" ) );
		_stop_trade_by_drawdown_in_percent_enabled = true;
	}

	return result;
}

bool _stop_trade_by_drawdown_in_money_enabled = false;
bool is_stop_trade_drawdown_in_money ( double drawdown_currency )
{
	if ( StopTrade_ByDrawdownMoney == 0 ) {
		return false;
	}

	if ( _stop_trade_by_drawdown_in_money_enabled ) {
		if ( drawdown_currency >= StopTrade_ByDrawdownMoney_Off ) {
			return true;
		}

		log_alert ( StringFormat ( SRC_SETKA_STOP_DRAWDOWN_OFF,
								   DoubleToString ( drawdown_currency, 2 ),
								   DoubleToString ( StopTrade_ByDrawdownMoney_Off, 2 ) ) );
		_stop_trade_by_drawdown_in_money_enabled = false;
		return false;
	}

	bool result = drawdown_currency >= StopTrade_ByDrawdownMoney;

	if ( result
			&& StopTrade_ByDrawdownMoney_Off != 0 ) {
		log_alert ( StringFormat ( SRC_SETKA_STOP_DRAWDOWN_ON,
								   DoubleToString ( drawdown_currency, 2 ),
								   DoubleToString ( StopTrade_ByDrawdownMoney_Off, 2 ) ) );
		_stop_trade_by_drawdown_in_money_enabled = true;
	}

	return result;
}

int get_lot_exp_by_minlot ( double minlot )
{
	int result = -1;

	if ( minlot >= 1.0 ) {
		return result;
	}

	do {
		result++;
	} while ( ( minlot *= 10 ) <= 1.0 );

	return result;
}

#endif
