В оценке размера лота надо оценивать не только AccountFreeMargin, но и явно учитывать появляющийся убыток на открытой позиции. Да и торговать на все доступные деньги очень опасно из-за чрезмерного риска.
Обычно в формулах расчета лотов используется важный компонент "процент риска/использования средств", который принимает достаточно малые значения 3-5-10%. В этом случае можно не учитывать появляющийся убыток, так как им можно пренебречь. Если же процент риска доходит до 100% доступных средств, то очень важно точно расчитать лоты.
Я как раз и пытаюсь точно рассчитать лоты при максимальном риске.
Например, при ручной продаже в примере выше все прекрасно работает:
PrevBalance: 10000.00 PrevPL: 7489.70 PrevEquity: 17489.70 PrevMargin: 5630.00 PrevFreeMargin = PrevEquity - PrevMargin = 17489.70 - 5630.00 = 11859.70 Lots = PrevFreeMargin / (LotSize / Leverage) = 11859.70 / (100000 / 100) = 11.85 (с округлением вниз до LotStep) NewMargin = PrevMargin + Lots * LotSize / Leverage = 5630.00 + 11.85 * 100000 / 100 = 17480.00 (никак не 23110, как в трассировке) NewEquity = PrevEquity - Lots * LotSize * Spread * Point = 17489.70 - 11.85 * 4 * 0.0001 * 100000 = 17489.70 - 474 = 17015.70 FreeMargin = NewEquity - NewMargin = 17015.70 - 17480.00 = -464.30 (в трассировке -5620.30)
Похоже, при расчете NewFreeMargin тестер к добавляемой аллокируемой марже ошибочно прибавляет существующую маржу еще раз, т.е. NewFreeMargin = FreeMargin + FreeMargin + Lots * LotSize / Leverage, и не дает открыть ордер.Если максимальный лот рассчитывать исходя из AccountFreeMargin() - AccountMargin(), ордер открывается. После этого AccountFreeMargin() дает корректное новое значение, не то, которое тестер выводит в журнал.
В данном случае совершенно не важно, какие компоненты используются "обычно" в формулах расчета лотов. Даже если тестер учитывает зачем-то спред в расчете свободной маржи и посчитал все правильно, значения, которые он выдал, на порядок отличаются от приведенного Вами. Кто тогда считает неправильно? Совсем плохо, если и терминал при торговле экспертом будет спотыкаться об этот же баг.
Я призываю Вас обратиться к конкретике. Опасность торговли на все доступные деньги и "процент риска/использования средств" не имеют никакого отношения к реализации торговой арифметики в тестере и терминале.
Уточните, пожалуйста, какие позиции и по каким ценам были открыты, какие цены EURUSD в момент попытки открытия, в какой валюте депозит. Происходили несколько сделок подряд (несколько OrderSend) или они разнесены по разным тикам.
Ни цены, ни последовательность действий большой роли не играют.
Важно, что, во-первых, невозможно открыть инстант ордер на всю свободную маржу, если использованная маржа больше 0, т.е. уже есть по крайней мере один открытый ордер.
И, во-вторых, после 134 ошибки AccountFreeMargin() выдает неправильное значение. До ошибки - корректное.
В торговле не проверял, только в тестере.
Удачи в ловле.
//+------------------------------------------------------------------+ //| FreeMarginBug.mq4 | //| No Copyright | //| http://www.metaquotes.ru | //+------------------------------------------------------------------+ #property copyright "No Copyright" #property link "http://www.metaquotes.ru" #include <stderror.mqh> extern double FirstOrderPercentage = 0.3; extern int SameTick = 1; int exitflag = 4; int start() { int ticket, i; double lots; while (AccountFreeMargin() >= MarketInfo(Symbol(), MODE_LOTSIZE) * MarketInfo(Symbol(), MODE_MINLOT) / AccountLeverage()) { if (exitflag == 0) return (0); exitflag--; if (AccountFreeMargin() != AccountEquity() - AccountMargin()) { /* Free margin bug entry */ Print(""); Print("AccountFreeMargin bug. Balance ", AccountBalance(), ", Equity ", AccountEquity(), ", FreeMargin (INCORRECT!) ", AccountFreeMargin(), ", FreeMargin (correct) ", AccountEquity() - AccountMargin(), ", Margin() ", AccountMargin()); Print(""); } ticket = (AccountEquity() - AccountMargin()) / (MarketInfo(Symbol(), MODE_LOTSIZE) / AccountLeverage()) / MarketInfo(Symbol(), MODE_LOTSTEP); lots = ticket * MarketInfo(Symbol(), MODE_LOTSTEP); if (FirstOrderPercentage > 0.) { lots *= FirstOrderPercentage; FirstOrderPercentage = 0.; } for (i = 0; i < 3 && lots >= MarketInfo(Symbol(), MODE_MINLOT); i++) { string incorrect; string correct; if (AccountFreeMargin() != AccountEquity() - AccountMargin()) { incorrect = "IN"; correct = StringConcatenate(", FreeMargin (correct) ", AccountEquity() - AccountMargin()); } else { incorrect = ""; correct = ""; } Print("Iter ", i, ", ", Bid, "/", Ask, ", Balance ", AccountBalance(), ", Equity ", AccountEquity(), ", FreeMargin (", incorrect, "CORRECT!) ", AccountFreeMargin(), correct, ", Margin() ", AccountMargin(), ", lots ", lots); ticket = OrderSend(Symbol(), OP_BUY, lots, Ask, 5, 0., 0.); if (ticket >= 0) break; ticket = GetLastError(); if (ticket == ERR_NOT_ENOUGH_MONEY) { /* Max lots bug entry */ if (AccountFreeMargin() != AccountEquity() - AccountMargin()) { incorrect = "IN"; correct = StringConcatenate(", FreeMargin (correct) ", AccountEquity() - AccountMargin()); } else { incorrect = ""; correct = ""; } Print("Max lots bug. FreeMargin (", incorrect, "CORRECT!) ", AccountFreeMargin(), correct, ", lots ", lots, ", spread ", Ask - Bid); if (i == 0) { ticket = (Ask - Bid) * MarketInfo(Symbol(), MODE_LOTSIZE) / AccountLeverage() / MarketInfo(Symbol(), MODE_LOTSTEP); Print("Allocate spread cost in free margin (nonsense): lots -= ", ticket * MarketInfo(Symbol(), MODE_LOTSTEP)); lots -= ticket * MarketInfo(Symbol(), MODE_LOTSTEP); } else { ticket = (AccountEquity() - AccountMargin() /* Correct free margin */ - AccountMargin() /* minus yet another margin!*/) / (MarketInfo(Symbol(), MODE_LOTSIZE) / AccountLeverage()) / MarketInfo(Symbol(), MODE_LOTSTEP); lots = ticket * MarketInfo(Symbol(), MODE_LOTSTEP); Print("Workaround: lots = ", lots); } } } if (SameTick == 0) break; } return(0); }
Большое спасибо за помощь.
Небольшая специфическая проблема с Account[Equity|Margin|FreeMargin] в торговле все же осталась.
После успешного OrderSend() на инстант ордер OrderTotal() немедленно возвращает значение, увеличившееся на единицу, что очень даже правильно.
А вот параметры счета, возвращаемые тремя функциями выше, остаются неизменными в течение какого-то времени.
Почему они не обновляются мгновенно наряду с информацией об открытых ордерах?
RefreshRates() после OrderSend() не помогает.
Помогает конструкция вида
if (TimeOut > 0) Sleep(TimeOut); RefreshRates();
Вопрос.
Как обеспечить обновление параметров счета после успешной покупки/продажи (по аналогии с RefreshRates() после неудавшегося открытия ордера)?
Если только таймаутом, то какой таймаут гарантирует обновление данных?
Спасибо.
Спасибо за помощь
2006.06.21 11:11:17 2005.11.03 13:00 EURUSD,M1: OrderSend error 134 not enough money, op 0, 1.204/1.2042, price 1.2042, sl/tp 1.2014/1.2051, lots 1.1 2006.06.21 11:11:17 2005.11.03 13:00 Tester: PrevBalance: 3610.70, PrevPL: -160.70, PrevEquity 3450.00, PrevMargin: 2350.00, NewMargin: 3450, FreeMargin: -0.00
Строка
lots = NormalizeDouble(lots, 2);
перед OrderSend() есть.
Сборка 194.16.06.06.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Казалось бы,
должно хватить на продажу 11.85 лот
Тестер почему-то пытается увеличить маржу на значение Equity вместо Lots * LotSize / Leverage:
Понятное дело, денег в этом случае не хватит.
В трассировке AccountFreeMargin() выдает корректные 11859.7.
Баг выползает только при попытке открыть ордер на маржу, большую чем AccountFreeMargin() - AccountMargin().
При ручной торговле в терминале таких проблем не возникает.
Билд 193.04.05.06
Тема была озвучена в "Что обозначают эти наднписи в Логе?", но, к сожалению, должного осмысления и развития не получила.