604 lines
53 KiB
MQL5
604 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.05"
|
|
|
|
#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; // Множитель используемой части общего баланса по общему убытку
|
|
|
|
// Защищённые методы
|
|
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 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();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Сохранение состояния |
|
|
//+------------------------------------------------------------------+
|
|
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();
|
|
|
|
// Раз в час выводим значения в лог
|
|
if(IsNewBar(Symbol(), PERIOD_H1)) {
|
|
PrintFormat(__FUNCTION__" | Virtual = %.2f | Profit = %.2f | Daily = %.2f | Overall = %.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);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Обновление дневных базовых уровней |
|
|
//+------------------------------------------------------------------+
|
|
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);
|
|
}
|
|
//+------------------------------------------------------------------+
|