If strategy use unknown symbol it will be set in inactive state. If CM or RM not activated in input params it will be deleted just after creating
618 lines
53 KiB
MQL5
618 lines
53 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| VirtualRiskManager.mqh |
|
|
//| Copyright 2022-2025, Yuriy Bykov |
|
|
//| https://www.mql5.com/ru/users/antekov |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2022-2025, Yuriy Bykov"
|
|
#property link "https://www.mql5.com/ru/users/antekov"
|
|
#property version "1.06"
|
|
|
|
#include "../Database/Storage.mqh"
|
|
|
|
// Возможные состояния риск-менеджера
|
|
enum ENUM_RM_STATE {
|
|
RM_STATE_OK, // Лимиты не превышены
|
|
RM_STATE_DAILY_LOSS, // Превышен дневной лимит
|
|
RM_STATE_RESTORE, // Восстановление после дневного лимита
|
|
RM_STATE_OVERALL_LOSS, // Превышен общий лимит
|
|
RM_STATE_OVERALL_PROFIT // Достигнута общая прибыль
|
|
};
|
|
|
|
// Возможные способы расчёта дневных лимитов
|
|
enum ENUM_RM_CALC_DAILY_LOSS {
|
|
RM_CALC_DAILY_LOSS_MONEY_BB, // [$] to Daily Level
|
|
RM_CALC_DAILY_LOSS_PERCENT_BB, // [%] from Base Balance to Daily Level
|
|
RM_CALC_DAILY_LOSS_PERCENT_DL // [%] from/to Daily Level
|
|
};
|
|
|
|
// Возможные способы расчёта общих лимитов
|
|
enum ENUM_RM_CALC_OVERALL_LOSS {
|
|
RM_CALC_OVERALL_LOSS_MONEY_BB, // [$] to Base Balance
|
|
RM_CALC_OVERALL_LOSS_MONEY_HW_BAL, // [$] to HW Balance
|
|
RM_CALC_OVERALL_LOSS_MONEY_HW_EQ_BAL, // [$] to HW Equity or Balance
|
|
RM_CALC_OVERALL_LOSS_PERCENT_BB, // [%] from/to Base Balance
|
|
RM_CALC_OVERALL_LOSS_PERCENT_HW_BAL, // [%] from/to HW Balance
|
|
RM_CALC_OVERALL_LOSS_PERCENT_HW_EQ_BAL // [%] from/to HW Equity or Balance
|
|
};
|
|
|
|
// Возможные способы расчёта общей прибыли
|
|
enum ENUM_RM_CALC_OVERALL_PROFIT {
|
|
RM_CALC_OVERALL_PROFIT_MONEY_BB, // [$] to Base Balance
|
|
RM_CALC_OVERALL_PROFIT_PERCENT_BB, // [%] from/to Base Balance
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Класс управления риском (риск-менеждер) |
|
|
//+------------------------------------------------------------------+
|
|
class CVirtualRiskManager : public CFactorable {
|
|
protected:
|
|
// Основные параметры конструктора
|
|
//bool m_isActive; // Риск менеджер активен?
|
|
|
|
double m_baseBalance; // Базовый баланс
|
|
|
|
ENUM_RM_CALC_DAILY_LOSS m_calcDailyLossLimit; // Способ расчёта максимального дневного убытка
|
|
double m_maxDailyLossLimit; // Параметр расчёта максимального дневного убытка
|
|
double m_closeDailyPart; // Значение пороговой части дневного убытка
|
|
|
|
ENUM_RM_CALC_OVERALL_LOSS m_calcOverallLossLimit; // Способ расчёта максимального общего убытка
|
|
double m_maxOverallLossLimit; // Параметр расчёта максимального общего убытка
|
|
double m_closeOverallPart; // Значение пороговой части общего убытка
|
|
|
|
ENUM_RM_CALC_OVERALL_PROFIT m_calcOverallProfitLimit; // Способ расчёта максимальной общей прибыли
|
|
double m_maxOverallProfitLimit; // Параметр расчёта максимальной общей прибыли
|
|
datetime m_maxOverallProfitDate; // Предельное время для достижения общей прибыли
|
|
|
|
double m_maxRestoreTime; // Время ожидания лучшего входа на просадке
|
|
double m_lastVirtualProfitFactor; // Множитель начальной лучшей просадки
|
|
|
|
|
|
// Текущее состояние
|
|
ENUM_RM_STATE m_state; // Состояние
|
|
double m_lastVirtualProfit; // Прибыль открытых виртуальных позиций на момент лимита убытка
|
|
datetime m_startRestoreTime; // Время начала восстановления размеров открытых позиций
|
|
datetime m_startTime;
|
|
|
|
// Обновляемые значения
|
|
double m_balance; // Текущий баланс
|
|
double m_equity; // Текущие средства
|
|
double m_profit; // Текущая прибыль
|
|
double m_dailyProfit; // Дневная прибыль
|
|
double m_overallProfit; // Общая прибыль
|
|
double m_baseDailyBalance; // Дневной базовый баланс
|
|
double m_baseDailyEquity; // Дневные базовые средства
|
|
double m_baseDailyLevel; // Дневной базовый уровень
|
|
double m_baseHWBalance; // High Watermark баланса
|
|
double m_baseHWEquityBalance; // High Watermark средств или баланса
|
|
double m_virtualProfit; // Прибыль открытых виртуальных позиций
|
|
|
|
// Управление размером открытых позиций
|
|
double m_baseDepoPart; // Используемая часть общего баланса (исходная)
|
|
double m_dailyDepoPart; // Множитель используемой части общего баланса по дневному убытку
|
|
double m_overallDepoPart; // Множитель используемой части общего баланса по общему убытку
|
|
|
|
string m_text;
|
|
|
|
// Защищённые методы
|
|
double DailyLoss(); // Максимальный дневной убыток
|
|
double OverallLoss(); // Максимальный общий убыток
|
|
double OverallProfit(); // Максимальная прибыль
|
|
|
|
void UpdateProfit(); // Обновление текущих значений прибыли
|
|
void UpdateBaseLevels(); // Обновление дневных базовых уровней
|
|
|
|
void CheckLimits(); // Проверка превышения допустимых убытков
|
|
bool CheckDailyLossLimit(); // Проверка превышения допустимого дневного убытка
|
|
bool CheckOverallLossLimit(); // Проверка превышения допустимого общего убытка
|
|
bool CheckOverallProfitLimit(); // Проверка достижения заданной прибыли
|
|
|
|
void CheckRestore(); // Проверка необходимости восстановления размеров открытых позиций
|
|
bool CheckDailyRestore(); // Проверка необходимости восстановления дневного множителя
|
|
bool CheckOverallRestore(); // Проверка необходимости восстановления общего множителя
|
|
|
|
double VirtualProfit(); // Определение прибыли открытых виртуальных позиций
|
|
double RestoreVirtualProfit(); // Определение прибыли открытых виртуальных позиций для восстановления
|
|
|
|
void SetDepoPart(); // Установка значения используемой части общего баланса
|
|
|
|
CVirtualRiskManager(string p_params); // Конструктор
|
|
|
|
public:
|
|
STATIC_CONSTRUCTOR(CVirtualRiskManager);
|
|
virtual void Tick(); // Обработка тика в риск-менеджере
|
|
virtual string Text(); // Вывод информации
|
|
|
|
virtual bool Save(); // Сохранение состояния
|
|
virtual bool Load(); // Загрузка состояния
|
|
|
|
virtual string operator~() override; // Преобразование объекта в строку
|
|
};
|
|
|
|
REGISTER_FACTORABLE_CLASS(CVirtualRiskManager);
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Конструктор |
|
|
//+------------------------------------------------------------------+
|
|
CVirtualRiskManager::CVirtualRiskManager(string p_params) {
|
|
// Запоминаем строку инициализации
|
|
m_params = p_params;
|
|
|
|
// Читаем строку инициализации и устанавливаем значения свойств
|
|
m_isActive = (bool) ReadLong(p_params);
|
|
m_baseBalance = ReadDouble(p_params);
|
|
m_calcDailyLossLimit = (ENUM_RM_CALC_DAILY_LOSS) ReadLong(p_params);
|
|
m_maxDailyLossLimit = ReadDouble(p_params);
|
|
m_closeDailyPart = ReadDouble(p_params);
|
|
m_calcOverallLossLimit = (ENUM_RM_CALC_OVERALL_LOSS) ReadLong(p_params);
|
|
m_maxOverallLossLimit = ReadDouble(p_params);
|
|
m_closeOverallPart = ReadDouble(p_params);
|
|
m_calcOverallProfitLimit = (ENUM_RM_CALC_OVERALL_PROFIT) ReadLong(p_params);
|
|
m_maxOverallProfitLimit = ReadDouble(p_params);
|
|
m_maxOverallProfitDate = (datetime) ReadLong(p_params);
|
|
m_maxRestoreTime = ReadDouble(p_params);
|
|
m_lastVirtualProfitFactor = ReadDouble(p_params);
|
|
|
|
|
|
// Устанавливаем состояние: Лимиты не превышены
|
|
m_state = RM_STATE_OK;
|
|
m_dailyDepoPart = 1;
|
|
m_overallDepoPart = 1;
|
|
m_lastVirtualProfit = 0;
|
|
m_startRestoreTime = 0;
|
|
|
|
// Запоминаем долю баланса счёта, выделенного на торговлю
|
|
m_baseDepoPart = CMoney::DepoPart();
|
|
|
|
// Обновляем базовые дневные уровни
|
|
UpdateBaseLevels();
|
|
|
|
// Корректируем базовый баланс, если он не задан
|
|
if(m_baseBalance == 0) {
|
|
m_baseBalance = m_balance;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Обработка тика в риск-менеджере |
|
|
//+------------------------------------------------------------------+
|
|
void CVirtualRiskManager::Tick() {
|
|
// Если риск-менеджер неактивен, то выходим
|
|
if(!m_isActive) {
|
|
return;
|
|
}
|
|
|
|
// Обновляем текущие значения прибыли
|
|
UpdateProfit();
|
|
|
|
// Если наступил новый дневной период, то обновляем базовые дневные уровни
|
|
if(IsNewBar(Symbol(), PERIOD_D1)) {
|
|
UpdateBaseLevels();
|
|
}
|
|
|
|
CheckRestore();
|
|
|
|
// Проверяем превышение пределов убытка
|
|
CheckLimits();
|
|
}
|
|
|
|
string CVirtualRiskManager::Text() {
|
|
string s = "=== Risk Manager ===\n";
|
|
|
|
s += m_text + "\n";
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Сохранение состояния |
|
|
//+------------------------------------------------------------------+
|
|
bool CVirtualRiskManager::Save() {
|
|
CStorage::Set("CVirtualRiskManager::m_state", m_state);
|
|
CStorage::Set("CVirtualRiskManager::m_lastVirtualProfit", m_lastVirtualProfit);
|
|
CStorage::Set("CVirtualRiskManager::m_startRestoreTime", m_startRestoreTime);
|
|
CStorage::Set("CVirtualRiskManager::m_startTime", m_startTime);
|
|
CStorage::Set("CVirtualRiskManager::m_dailyDepoPart", m_dailyDepoPart);
|
|
CStorage::Set("CVirtualRiskManager::m_overallDepoPart", m_overallDepoPart);
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Загрузка состояния |
|
|
//+------------------------------------------------------------------+
|
|
bool CVirtualRiskManager::Load() {
|
|
CStorage::Get("CVirtualRiskManager::m_state", m_state);
|
|
CStorage::Get("CVirtualRiskManager::m_lastVirtualProfit", m_lastVirtualProfit);
|
|
CStorage::Get("CVirtualRiskManager::m_startRestoreTime", m_startRestoreTime);
|
|
CStorage::Get("CVirtualRiskManager::m_startTime", m_startTime);
|
|
CStorage::Get("CVirtualRiskManager::m_dailyDepoPart", m_dailyDepoPart);
|
|
CStorage::Get("CVirtualRiskManager::m_overallDepoPart", m_overallDepoPart);
|
|
|
|
//m_state = (ENUM_RM_STATE) FileReadNumber(f);
|
|
//m_lastVirtualProfit = FileReadNumber(f);
|
|
//m_startRestoreTime = FileReadDatetime(f);
|
|
//m_startTime = FileReadDatetime(f);
|
|
//m_dailyDepoPart = FileReadNumber(f);
|
|
//m_overallDepoPart = FileReadNumber(f);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Проверка необходимости восстановления размеров открытых позиций |
|
|
//+------------------------------------------------------------------+
|
|
void CVirtualRiskManager::CheckRestore() {
|
|
// Если нужно восстанавливать состояние до нормального, то
|
|
if(m_state == RM_STATE_RESTORE) {
|
|
// Проверяем возможность восстановить до нормального множитель дневного убытка
|
|
bool dailyRes = CheckDailyRestore();
|
|
|
|
// Проверяем возможность восстановить до нормального множитель общего убытка
|
|
bool overallRes = CheckOverallRestore();
|
|
|
|
// Если хотя бы один из них восстановился, то
|
|
if(dailyRes || overallRes) {
|
|
PrintFormat(__FUNCTION__" | VirtualProfit = %.2f | Profit = %.2f | Daily Profit = %.2f",
|
|
m_virtualProfit, m_profit, m_dailyProfit);
|
|
PrintFormat(__FUNCTION__" | RESTORE: depoPart = %.2f = %.2f * %.2f * %.2f",
|
|
m_baseDepoPart * m_dailyDepoPart * m_overallDepoPart,
|
|
m_baseDepoPart, m_dailyDepoPart, m_overallDepoPart);
|
|
|
|
// Устанавливаем значение используемой части общего баланса
|
|
SetDepoPart();
|
|
|
|
// Оповещаем получатель об изменениях
|
|
CVirtualReceiver::Instance().Changed();
|
|
|
|
// Если оба множителя восстановлены до нормальных, то
|
|
if(dailyRes && overallRes) {
|
|
// Устанавливаем нормальное состояние
|
|
m_state = RM_STATE_OK;
|
|
}
|
|
}
|
|
//else {
|
|
// if(IsNewBar(Symbol(), PERIOD_H1)) {
|
|
// PrintFormat(__FUNCTION__" | VirtualProfit = %.2f | Profit = %.2f | Daily Profit = %.2f",
|
|
// m_virtualProfit, m_profit, m_dailyProfit);
|
|
// PrintFormat(__FUNCTION__" | WAIT RESTORE: depoPart = %.2f = %.2f * %.2f * %.2f",
|
|
// m_baseDepoPart * m_dailyDepoPart * m_overallDepoPart,
|
|
// m_baseDepoPart, m_dailyDepoPart, m_overallDepoPart);
|
|
// }
|
|
//}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Проверка необходимости восстановления дневного множителя |
|
|
//+------------------------------------------------------------------+
|
|
bool CVirtualRiskManager::CheckDailyRestore() {
|
|
// Если текущая виртуальная прибыль меньше желаемой для восстановления, то
|
|
if(m_virtualProfit <= RestoreVirtualProfit()) {
|
|
// Восстанавливаем множитель дневного убытка
|
|
m_dailyDepoPart = 1.0;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Проверка необходимости восстановления общего множителя |
|
|
//+------------------------------------------------------------------+
|
|
bool CVirtualRiskManager::CheckOverallRestore() {
|
|
// Если текущая виртуальная прибыль меньше желаемой для восстановления, то
|
|
if(m_virtualProfit <= RestoreVirtualProfit()) {
|
|
// Восстанавливаем множитель общего убытка
|
|
m_overallDepoPart = 1.0;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Максимальный дневной убыток |
|
|
//+------------------------------------------------------------------+
|
|
double CVirtualRiskManager::DailyLoss() {
|
|
if(m_calcDailyLossLimit == RM_CALC_DAILY_LOSS_PERCENT_BB) {
|
|
// Для заданного процента от базового баланса вычисляем его
|
|
return m_baseBalance * m_maxDailyLossLimit / 100;
|
|
} else if(m_calcDailyLossLimit == RM_CALC_DAILY_LOSS_PERCENT_DL) {
|
|
// Для заданного процента от дневного уровня вычисляем его
|
|
return m_baseDailyLevel * m_maxDailyLossLimit / 100;
|
|
} else {
|
|
// Для фиксированного значения просто возвращаем его
|
|
return m_maxDailyLossLimit;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Максимальный общий убыток |
|
|
//+------------------------------------------------------------------+
|
|
double CVirtualRiskManager::OverallLoss() {
|
|
if(m_calcOverallLossLimit == RM_CALC_OVERALL_LOSS_PERCENT_BB) {
|
|
// Для заданного процента от базового баланса вычисляем его
|
|
return m_baseBalance * m_maxOverallLossLimit / 100;
|
|
} else if(m_calcOverallLossLimit == RM_CALC_OVERALL_LOSS_PERCENT_HW_BAL) {
|
|
// Для заданного процента от дневного уровня вычисляем его
|
|
return m_baseHWBalance * m_maxOverallLossLimit / 100;
|
|
} else if(m_calcOverallLossLimit == RM_CALC_OVERALL_LOSS_PERCENT_HW_EQ_BAL) {
|
|
// Для заданного процента от дневного уровня вычисляем его
|
|
return m_baseHWEquityBalance * m_maxOverallLossLimit / 100;
|
|
} else {
|
|
// Для фиксированного значения просто возвращаем его
|
|
// RM_CALC_OVERALL_LOSS_MONEY_BB || RM_CALC_OVERALL_LOSS_MONEY_HW_BAL
|
|
return m_maxOverallLossLimit;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Максимальный общая прибыль |
|
|
//+------------------------------------------------------------------+
|
|
double CVirtualRiskManager::OverallProfit() {
|
|
// Текущее время
|
|
datetime tc = TimeCurrent();
|
|
|
|
// Если текущее время больше заданного максимально допустимого, то
|
|
if(m_maxOverallProfitDate && tc > m_maxOverallProfitDate) {
|
|
// Возвращаем значение, гарантирующее закрытие позиций
|
|
return m_overallProfit;
|
|
} else if(m_calcOverallProfitLimit == RM_CALC_OVERALL_PROFIT_PERCENT_BB) {
|
|
// Для заданного процента от базового баланса вычисляем его
|
|
return m_baseBalance * m_maxOverallProfitLimit / 100;
|
|
} else {
|
|
// Для фиксированного значения просто возвращаем его
|
|
// RM_CALC_OVERALL_PROFIT_MONEY_BB
|
|
return m_maxOverallProfitLimit;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Обновление текущих значений прибыли |
|
|
//+------------------------------------------------------------------+
|
|
void CVirtualRiskManager::UpdateProfit() {
|
|
// Текущие средства
|
|
m_equity = AccountInfoDouble(ACCOUNT_EQUITY);
|
|
|
|
// Текущий баланс
|
|
m_balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
|
|
// Наивысший баланс (High Watermark)
|
|
m_baseHWBalance = MathMax(m_balance, m_baseHWBalance);
|
|
|
|
// Наивысший баланс или средства (High Watermark)
|
|
m_baseHWEquityBalance = MathMax(m_equity, MathMax(m_balance, m_baseHWEquityBalance));
|
|
|
|
// Текущая прибыль
|
|
m_profit = m_equity - m_balance;
|
|
|
|
// Текущая дневная прибыль относительно дневного уровня
|
|
m_dailyProfit = m_equity - m_baseDailyLevel;
|
|
|
|
// Текущая общая прибыль относительно базового баланса
|
|
m_overallProfit = m_equity - m_baseBalance;
|
|
|
|
// Если общую прибыль берём относительно наивысшего баланса, то
|
|
if(m_calcOverallLossLimit == RM_CALC_OVERALL_LOSS_MONEY_HW_BAL
|
|
|| m_calcOverallLossLimit == RM_CALC_OVERALL_LOSS_PERCENT_HW_BAL) {
|
|
// Пересчитаем её
|
|
m_overallProfit = m_equity - m_baseHWBalance;
|
|
}
|
|
|
|
// Если общую прибыль берём относительно наивысшего баланса или средств, то
|
|
if(m_calcOverallLossLimit == RM_CALC_OVERALL_LOSS_MONEY_HW_EQ_BAL
|
|
|| m_calcOverallLossLimit == RM_CALC_OVERALL_LOSS_PERCENT_HW_EQ_BAL) {
|
|
// Пересчитаем её
|
|
m_overallProfit = m_equity - m_baseHWEquityBalance;
|
|
}
|
|
|
|
// Текущая прибыль виртуальных открытых позиций
|
|
m_virtualProfit = VirtualProfit();
|
|
|
|
m_text = StringFormat("Virtual = %10.2f | Profit = %8.2f | Daily = %8.2f | Overall = %8.2f"
|
|
" | depoPart = %.2f = %.2f * %.2f * %.2f",
|
|
m_virtualProfit, m_profit, m_dailyProfit, m_overallProfit,
|
|
m_baseDepoPart * m_dailyDepoPart * m_overallDepoPart,
|
|
m_baseDepoPart, m_dailyDepoPart, m_overallDepoPart);
|
|
|
|
// Раз в час выводим значения в лог
|
|
if(IsNewBar(Symbol(), PERIOD_H1)) {
|
|
PrintFormat(__FUNCTION__" | %s", m_text);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Обновление дневных базовых уровней |
|
|
//+------------------------------------------------------------------+
|
|
void CVirtualRiskManager::UpdateBaseLevels() {
|
|
// Обновляем баланс, средства и базовый дневной уровень
|
|
m_baseDailyBalance = m_balance;
|
|
m_baseDailyEquity = m_equity;
|
|
m_baseDailyLevel = MathMax(m_baseDailyBalance, m_baseDailyEquity);
|
|
|
|
m_dailyProfit = m_equity - m_baseDailyLevel;
|
|
|
|
PrintFormat(__FUNCTION__" | DAILY UPDATE: Balance = %.2f | Equity = %.2f | Level = %.2f"
|
|
" | depoPart = %.2f = %.2f * %.2f * %.2f",
|
|
m_baseDailyBalance, m_baseDailyEquity, m_baseDailyLevel,
|
|
m_baseDepoPart * m_dailyDepoPart * m_overallDepoPart,
|
|
m_baseDepoPart, m_dailyDepoPart, m_overallDepoPart);
|
|
|
|
// Если ранее был достигнут дневной уровень убытка, то
|
|
if(m_state == RM_STATE_DAILY_LOSS) {
|
|
// Переходим в состояние восстановления размеров открытых позиций
|
|
m_state = RM_STATE_RESTORE;
|
|
|
|
// Запоминаем время начала восстановления
|
|
m_startRestoreTime = TimeCurrent();
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Проверка лимитов убытка |
|
|
//+------------------------------------------------------------------+
|
|
void CVirtualRiskManager::CheckLimits() {
|
|
if(false
|
|
|| CheckDailyLossLimit() // Проверка дневного лимита
|
|
|| CheckOverallLossLimit() // Проверка общего лимита
|
|
|| CheckOverallProfitLimit() // Проверка общей прибыли
|
|
) {
|
|
// Запоминаем текущий уровень виртуальной прибыли
|
|
m_lastVirtualProfit = m_virtualProfit;
|
|
|
|
// Оповещаем получатель об изменениях
|
|
CVirtualReceiver::Instance().Changed();
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Проверка дневного лимита убытка |
|
|
//+------------------------------------------------------------------+
|
|
bool CVirtualRiskManager::CheckDailyLossLimit() {
|
|
// Если достигнут дневной убыток и позиции ещё открыты
|
|
if(m_dailyProfit < -DailyLoss() * (1 - m_dailyDepoPart * (1 - m_closeDailyPart))
|
|
&& CMoney::DepoPart() > 0) {
|
|
|
|
// Уменьшаем множитель используемой части общего баланса по дневному убытку
|
|
m_dailyDepoPart *= (1 - m_closeDailyPart);
|
|
|
|
// Если множитель уже слишком мал, то
|
|
if(m_dailyDepoPart < 0.05) {
|
|
// Устанавливаем его в 0
|
|
m_dailyDepoPart = 0;
|
|
}
|
|
|
|
// Устанавливаем значение используемой части общего баланса
|
|
SetDepoPart();
|
|
|
|
PrintFormat(__FUNCTION__" | VirtualProfit = %.2f | Profit = %.2f | Daily Profit = %.2f",
|
|
m_virtualProfit, m_profit, m_dailyProfit);
|
|
PrintFormat(__FUNCTION__" | RESET: depoPart = %.2f = %.2f * %.2f * %.2f",
|
|
m_baseDepoPart * m_dailyDepoPart * m_overallDepoPart,
|
|
m_baseDepoPart, m_dailyDepoPart, m_overallDepoPart);
|
|
|
|
// Устанавливаем риск-менеджер в состояние достигнутого дневного убытка
|
|
m_state = RM_STATE_DAILY_LOSS;
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Проверка общего лимита убытка |
|
|
//+------------------------------------------------------------------+
|
|
bool CVirtualRiskManager::CheckOverallLossLimit() {
|
|
// Если достигнут общий убыток и позиции ещё открыты
|
|
if(m_overallProfit < -OverallLoss() * (1 - m_overallDepoPart * (1 - m_closeOverallPart))
|
|
&& CMoney::DepoPart() > 0) {
|
|
// Уменьшаем множитель используемой части общего баланса по общему убытку
|
|
m_overallDepoPart *= (1 - m_closeOverallPart);
|
|
|
|
// Если множитель уже слишком мал, то
|
|
if(m_overallDepoPart < 0.05) {
|
|
// Устанавливаем его в 0
|
|
m_overallDepoPart = 0;
|
|
|
|
// Устанавливаем риск-менеджер в состояние достигнутого общего убытка
|
|
m_state = RM_STATE_OVERALL_LOSS;
|
|
}
|
|
|
|
// Устанавливаем значение используемой части общего баланса
|
|
SetDepoPart();
|
|
|
|
PrintFormat(__FUNCTION__" | VirtualProfit = %.2f | Profit = %.2f | Daily Profit = %.2f",
|
|
m_virtualProfit, m_profit, m_dailyProfit);
|
|
PrintFormat(__FUNCTION__" | RESET: depoPart = %.2f = %.2f * %.2f * %.2f",
|
|
m_baseDepoPart * m_dailyDepoPart * m_overallDepoPart,
|
|
m_baseDepoPart, m_dailyDepoPart, m_overallDepoPart);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Проверка достижения заданной прибыли |
|
|
//+------------------------------------------------------------------+
|
|
bool CVirtualRiskManager::CheckOverallProfitLimit() {
|
|
// Если достигнут общий убыток и позиции ещё открыты
|
|
if(m_overallProfit >= OverallProfit() && CMoney::DepoPart() > 0) {
|
|
// Уменьшаем множитель используемой части общего баланса по общему убытку
|
|
m_overallDepoPart = 0;
|
|
|
|
// Устанавливаем риск-менеджер в состояние достигнутой общей прибыли
|
|
m_state = RM_STATE_OVERALL_PROFIT;
|
|
|
|
// Устанавливаем значение используемой части общего баланса
|
|
SetDepoPart();
|
|
|
|
PrintFormat(__FUNCTION__" | VirtualProfit = %.2f | Profit = %.2f | Daily Profit = %.2f",
|
|
m_virtualProfit, m_profit, m_dailyProfit);
|
|
PrintFormat(__FUNCTION__" | RESET: depoPart = %.2f = %.2f * %.2f * %.2f",
|
|
m_baseDepoPart * m_dailyDepoPart * m_overallDepoPart,
|
|
m_baseDepoPart, m_dailyDepoPart, m_overallDepoPart);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Определение прибыли открытых виртуальных позиций |
|
|
//+------------------------------------------------------------------+
|
|
double CVirtualRiskManager::VirtualProfit() {
|
|
// Обращаемся к объекту получателя
|
|
CVirtualReceiver *m_receiver = CVirtualReceiver::Instance();
|
|
|
|
// Устанавливаем исходный множитель использования баланса
|
|
CMoney::DepoPart(m_baseDepoPart);
|
|
|
|
double profit = 0;
|
|
|
|
// Для всех виртуальных позиций находим сумму их прибыли
|
|
FOR(m_receiver.OrdersTotal()) profit += CMoney::Profit(m_receiver.Order(i));
|
|
|
|
// Восстанавливаем текущий множитель использования баланса
|
|
SetDepoPart();
|
|
|
|
return profit;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Определение прибыли виртуальных позиций для восстановления |
|
|
//+------------------------------------------------------------------+
|
|
double CVirtualRiskManager::RestoreVirtualProfit() {
|
|
// Если максимальное время восстановления не задано, то
|
|
if(m_maxRestoreTime == 0) {
|
|
// Возвращаем текущее значение виртуальной прибыли
|
|
return m_virtualProfit;
|
|
}
|
|
|
|
// Находим прошедшее время с начала восстановления в минутах
|
|
double t = (TimeCurrent() - m_startRestoreTime) / 60.0;
|
|
|
|
// Возвращаем расчётное значение желаемой виртуальной прибыли
|
|
// в зависимости от прошедшего времени с начала восстановления
|
|
return m_lastVirtualProfit * m_lastVirtualProfitFactor * (1 - t / m_maxRestoreTime);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Установка значения используемой части общего баланса |
|
|
//+------------------------------------------------------------------+
|
|
void CVirtualRiskManager::SetDepoPart() {
|
|
CMoney::DepoPart(m_baseDepoPart * m_dailyDepoPart * m_overallDepoPart);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Преобразование объекта в строку |
|
|
//+------------------------------------------------------------------+
|
|
string CVirtualRiskManager::operator~() {
|
|
return StringFormat("%s(%s)", typename(this), m_params);
|
|
}
|
|
//+------------------------------------------------------------------+
|