В мире алгоритмического трейдинга одним из ключевых аспектов успешной стратегии является эффективное управление капиталом и рисками. Критерий Келли (Kelly Criterion) — это математическая формула, используемая для определения оптимального размера ставки или объема инвестиции, чтобы максимизировать долгосрочный рост капитала. В этой статье мы рассмотрим, как реализовать автоматическое выравнивание объемов ордеров (Lot Sizing) по модели Келли в MQL5, создав скрипт, который поможет вашим торговым советникам принимать обоснованные решения об объеме сделки.
Модель Келли предлагает оптимальную долю капитала, которую следует рисковать в каждой сделке, исходя из вероятности выигрыша и соотношения прибыли к убытку. Это мощный инструмент для предотвращения чрезмерного риска и обеспечения устойчивого роста счета. Понимание того, как рассчитываются маржинальные требования, является ключевым аспектом управления капиталом, особенно при работе со сложными стратегиями, такими как Straddle, о чем мы подробно писали в статье Расчет маржинальных требований для Straddle в MQL5.
Исходный код
Представленный ниже скрипт на MQL5 является экспертным советником (EA), который при запуске на графике рассчитывает и выводит в журнал оптимальный объем ордера, используя критерий Келли. Он учитывает текущий баланс счета, заданные вероятность выигрыша, соотношение прибыли к убытку и размер стоп-лосса в пунктах.
//+------------------------------------------------------------------+
//| KellyLotSizer.mq5 |
//| FinFluct.com |
//+------------------------------------------------------------------+
#property copyright "FinFluct.com"
#property version "1.00"
#property description "Автоматическое выравнивание объемов ордеров по модели Келли"
#property script_show_inputs
//--- Входные параметры
input double WinRate = 0.55; // Вероятность выигрыша (0.0 - 1.0)
input double RiskRewardRatio = 1.5; // Соотношение прибыли к убытку (например, 1.5 означает 1.5R прибыли на 1R риска)
input double StopLossPips = 50.0; // Размер стоп-лосса в пунктах (для расчета риска на лот)
input double KellyFraction = 1.0; // Доля от оптимальной Келли (1.0 = полная Келли, 0.5 = половинная Келли)
//+------------------------------------------------------------------+
//| Функция для получения стоимости одного пункта для одного лота |
//+------------------------------------------------------------------+
double GetPipValuePerLot(string symbol_name)
{
double point = SymbolInfoDouble(symbol_name, SYMBOL_POINT);
int digits = (int)SymbolInfoInteger(symbol_name, SYMBOL_DIGITS);
// Определяем размер одного пипса в единицах цены
// Для 4-значных котировок (или 2-значных для JPY), 1 пипс = 10 пунктов
// Для 5-значных котировок (или 3-значных для JPY), 1 пипс = 1 пункт
double pipSize = point;
if (digits == 2 || digits == 4) // Например, USDJPY (2), EURUSD (4)
{
pipSize = point * 10;
}
double tickValue = SymbolInfoDouble(symbol_name, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(symbol_name, SYMBOL_TICK_SIZE);
// Стоимость одного пипса для одного лота
return tickValue / tickSize * pipSize;
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- Проверка входных параметров
if (WinRate <= 0 || WinRate >= 1.0)
{
Print("Ошибка: WinRate должен быть между 0 и 1.");
return;
}
if (RiskRewardRatio <= 0)
{
Print("Ошибка: RiskRewardRatio должен быть больше 0.");
return;
}
if (StopLossPips <= 0)
{
Print("Ошибка: StopLossPips должен быть больше 0.");
return;
}
if (KellyFraction <= 0 || KellyFraction > 1.0)
{
Print("Ошибка: KellyFraction должен быть между 0 и 1.");
return;
}
//--- Получаем текущий баланс счета
double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
if (accountBalance <= 0)
{
Print("Ошибка: Не удалось получить баланс счета или он равен 0.");
return;
}
//--- Расчет оптимальной доли Келли
double optimalKellyFraction = WinRate - (1.0 - WinRate) / RiskRewardRatio;
if (optimalKellyFraction <= 0)
{
Print("Критерий Келли отрицателен или равен нулю. Стратегия не имеет положительного математического ожидания.");
Print("Оптимальный объем ордера: 0.0 лотов.");
return;
}
//--- Применяем заданную долю от Келли
double finalKellyFraction = optimalKellyFraction * KellyFraction;
//--- Рассчитываем максимальную сумму риска на сделку
double maxRiskAmount = accountBalance * finalKellyFraction;
//--- Получаем информацию о символе
string currentSymbol = Symbol();
double minLot = SymbolInfoDouble(currentSymbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(currentSymbol, SYMBOL_VOLUME_MAX);
double lotStep = SymbolInfoDouble(currentSymbol, SYMBOL_VOLUME_STEP);
//--- Получаем стоимость одного пипса для одного лота
double pipValuePerLot = GetPipValuePerLot(currentSymbol);
if (pipValuePerLot <= 0)
{
Print("Ошибка: Не удалось получить стоимость пипса для символа " + currentSymbol);
return;
}
//--- Рассчитываем риск в деньгах для одного лота
double riskPerLot = StopLossPips * pipValuePerLot;
if (riskPerLot <= 0)
{
Print("Ошибка: Расчетный риск на лот равен 0. Проверьте StopLossPips или GetPipValuePerLot.");
return;
}
//--- Рассчитываем предварительный объем ордера
double calculatedLot = maxRiskAmount / riskPerLot;
//--- Приводим объем к допустимым значениям
calculatedLot = fmax(minLot, calculatedLot); // Не меньше минимального лота
calculatedLot = fmin(maxLot, calculatedLot); // Не больше максимального лота
// Округляем до шага лота
calculatedLot = NormalizeDouble(calculatedLot / lotStep, 0) * lotStep;
//--- Выводим результаты
Print("--- Расчет объема ордера по Келли ---");
Print("Баланс счета: " + DoubleToString(accountBalance, 2));
Print("Вероятность выигрыша (WinRate): " + DoubleToString(WinRate * 100, 2) + "%");
Print("Соотношение прибыли к убытку (RiskRewardRatio): " + DoubleToString(RiskRewardRatio, 2));
Print("Стоп-лосс в пунктах (StopLossPips): " + DoubleToString(StopLossPips, 1));
Print("Оптимальная доля Келли (f): " + DoubleToString(optimalKellyFraction * 100, 2) + "%");
Print("Используемая доля Келли (KellyFraction): " + DoubleToString(KellyFraction * 100, 2) + "%");
Print("Финальная доля капитала для риска: " + DoubleToString(finalKellyFraction * 100, 2) + "%");
Print("Максимальная сумма риска на сделку: " + DoubleToString(maxRiskAmount, 2) + " " + AccountInfoString(ACCOUNT_CURRENCY));
Print("Риск на 1 лот (" + currentSymbol + "): " + DoubleToString(riskPerLot, 2) + " " + AccountInfoString(ACCOUNT_CURRENCY));
Print("Минимальный лот: " + DoubleToString(minLot, 2));
Print("Максимальный лот: " + DoubleToString(maxLot, 2));
Print("Шаг лота: " + DoubleToString(lotStep, 2));
Print("---");
Print("Оптимальный объем ордера: " + DoubleToString(calculatedLot, 2) + " лотов.");
}
Разбор параметров
Скрипт имеет несколько входных параметров, которые позволяют настроить расчет под вашу торговую стратегию и предпочтения:
WinRate: Вероятность выигрыша. Это процент ваших прибыльных сделок. Например,0.55означает 55% выигрышных сделок. Этот параметр критически важен для формулы Келли.RiskRewardRatio: Соотношение прибыли к убытку. Это среднее отношение размера прибыли к размеру убытка в ваших сделках. Например,1.5означает, что в среднем вы зарабатываете в 1.5 раза больше, чем теряете.StopLossPips: Размер стоп-лосса в пунктах. Этот параметр используется для расчета денежного риска на один лот. Укажите здесь типичный или планируемый размер стоп-лосса для ваших сделок.KellyFraction: Доля от оптимальной Келли. Критерий Келли часто дает агрессивные результаты, поэтому многие трейдеры предпочитают использовать лишь часть от рассчитанной оптимальной доли (например,0.5для половинной Келли). Значение1.0использует полную Келли.
Как запустить
Чтобы использовать скрипт для автоматического выравнивания объемов ордеров по модели Келли, выполните следующие шаги:
-
Сохраните код: Скопируйте предоставленный MQL5 код и сохраните его в файл с расширением
.mq5(например,KellyLotSizer.mq5) в папкеMQL5/Scriptsвашего терминала MetaTrader 5. -
Скомпилируйте: Откройте MetaEditor (нажмите F4 в MT5), найдите ваш файл в навигаторе проекта и нажмите кнопку «Компилировать» (или F7). Убедитесь, что нет ошибок компиляции.
-
Прикрепите к графику: Откройте терминал MetaTrader 5, перейдите в окно «Навигатор» (Ctrl+N), найдите раздел «Скрипты» и перетащите
KellyLotSizerна любой график. -
Настройте параметры: При запуске скрипта появится окно с входными параметрами. Введите свои значения для
WinRate,RiskRewardRatio,StopLossPipsиKellyFraction. Нажмите «ОК». -
Проверьте результат: Результаты расчета будут выведены во вкладку «Эксперты» в окне «Терминал» (Ctrl+T). Здесь вы увидите оптимальный объем ордера в лотах, а также промежуточные расчеты.
Этот скрипт является отличной основой для интеграции управления капиталом по Келли в ваши торговые советники. Для более продвинутого мониторинга и логирования результатов работы советника, включая расчеты лотов, вы можете использовать методы, описанные в нашей статье MQL5 Discord WebRequest: Логирование Сделок Советника на VPS. Хотя наш скрипт фокусируется на расчете объема, а не на управлении большим количеством ордеров, для тех, кто сталкивается с ограничениями брокера на количество открытых позиций, может быть полезна статья MT4 Max Orders Bypass: Скрипт для обхода ограничения через пулы заявок.




