Adwizard/Virtual/VirtualRiskManager.mqh
2025-04-11 13:28:40 +03:00

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);
}
//+------------------------------------------------------------------+