class COrderCalculateMargin{ public: double Result; public: void COrderCalculateMargin(string symbol,ENUM_ORDER_TYPE orderType,double openPrice,double volume){ Result=0; string currency=AccountInfoString(ACCOUNT_CURRENCY); if(StringSubstr(symbol,3,3)==currency)Result=CalcMarginFormula(symbol,openPrice,volume); else if(StringSubstr(symbol,0,3)==currency)Result=CalcMarginFormula(symbol,1,volume); else{ string pair=StringSubstr(symbol,0,3)+currency; if(orderType==ORDER_TYPE_BUY)Result=CalcMarginFormula(pair,Bid(pair),volume); if(orderType==ORDER_TYPE_SELL)Result=CalcMarginFormula(pair,Ask(pair),volume); } return; } double CalcMarginFormula(string symbol,double openPrice,double volume){ return NormalizeDouble(openPrice*volume*SymbolInfoDouble(symbol,SYMBOL_TRADE_CONTRACT_SIZE)/AccountInfoInteger(ACCOUNT_LEVERAGE),0); } };Писал сам, провел тесты, только на кроссах работает не всегда точно. Подскажите где ошибка.
Писал сам, провел тесты, только на кроссах работает не всегда точно. Подскажите где ошибка.
Скажем так, на кроссах будет не то что "не всегда", а всегда неправильно.
Сама формула расчета верна: Margin = quote * volume * contract_size / leverage.
Просто вместо quote в разных случаях нужно брать разные котировки. Если базовая валюта символа котируется через валюту счета (к примеру, EURUSD при валюте счета USD), то в качестве quote, действительно, нужно брать цену открытия трейда: Ask - для Buy и Bid - для Sell. Это единственный случай, для которого приведенный Вами метод расчета верен.
Немного по-другому происходит получение значения quote символов, у которых базовая валюта совпадает с валютой счета (USDCAD при валюте счета USD). В таких случаях quote будет равно: 1.0 / Ask - для Buy и 1.0 / Bid - для Sell.
И совсем иначе рассчитывается quote для кроссов (символов, в которых отсутствует валюта счета). Так, при валюте счета USD залог для трейда по EURJPY будет рассчитан по текущей цене EURUSD. Так как EURUSD и EURJPY имеют одинаковую базовую валюту, то и quote будет определяться как в случае с просто EURUSD: Ask (от EURUSD) - для Buy и Bid (от EURUSD) - для Sell.
В случае, если кросс попался вида CHFJPY, то quote нужно рассчитать по символу USDCHF. Здесь базовые валюты символа отличаются. Поэтому quote получаем как в случае с USDCAD: 1.0 / Ask (от USDCHF) - для Buy и 1.0 / Bid (от USDCHF) - для Sell.
Надеюсь, понятно объяснил. В свое время очень долго "въезжал" в эту схему.
Писал сам, провел тесты, только на кроссах работает не всегда точно. Подскажите где ошибка.
вот в этой формуле: return NormalizeDouble(openPrice*volume*SymbolInfoDouble(symbol,SYMBOL_TRADE_CONTRACT_SIZE)/AccountInfoInteger(ACCOUNT_LEVERAGE),0);
вот в этом месте: AccountInfoInteger(ACCOUNT_LEVERAGE)
тоже может быть не всегда верно. Сам не очень давно столкнулся с такой ситуацией. Вот подробное рассуждение и объяснение:
С начала и до 3 страницы всё обсуждение по этому вопросу.
Спасибо всем за советы.
После нескольких тестов код выглядит так:
class COrderCalculateMargin{ public: double Result; public: void COrderCalculateMargin(string symbol,ENUM_ORDER_TYPE orderType,double openPrice,double volume){ Result=0; string currency=AccountInfoString(ACCOUNT_CURRENCY); if(StringSubstr(symbol,3,3)==currency)Result=CalcMarginFormula(symbol,openPrice,volume); else if(StringSubstr(symbol,0,3)==currency)Result=CalcMarginFormula(symbol,1,volume); else{ string pair=StringSubstr(symbol,0,3)+currency; if(orderType==ORDER_TYPE_BUY)Result=CalcMarginFormula(pair,Ask(pair),volume); if(orderType==ORDER_TYPE_SELL)Result=CalcMarginFormula(pair,Bid(pair),volume); } return; } double CalcMarginFormula(string symbol,double openPrice,double volume){ return NormalizeDouble(openPrice*volume*SymbolInfoDouble(symbol,SYMBOL_TRADE_CONTRACT_SIZE)/AccountInfoInteger(ACCOUNT_LEVERAGE),0); } };
Единственная разница выделена желтым цветом. А вот код, который проводил тесты:
ENUM_ORDER_TYPE orderType=ORDER_TYPE_SELL; double price=0.5; double lots=1.3; string symbol[3]={"GBPUSD","USDCAD","EURJPY"}; for(int i=0;i<3;i++){ double mqlMargin=0; if(!OrderCalcMargin(orderType,symbol[i],lots,price,mqlMargin))Print("CompareCalcMargin Error"); COrderCalculateMargin OrderCalculateMargin(symbol[i],orderType,price,lots); Print(symbol[i]+" ORDER_TYPE_SELL, price = "+price+", lots = "+lots+"; OrderCalcMargin() = "+(string)mqlMargin+"; COrderCalculateMargin.Result = "+(string)OrderCalculateMargin.Result); }
Вот результат, оба варианта практически одинаковы:
CompareMargin (GBPUSD,H4) GBPUSD ORDER_TYPE_BUY, price = 2.5, lots = 1.3; OrderCalcMargin() = 6500; COrderCalculateMargin.Result = 6500 CompareMargin (GBPUSD,H4) USDCAD ORDER_TYPE_BUY, price = 2.5, lots = 1.3; OrderCalcMargin() = 2600; COrderCalculateMargin.Result = 2600 CompareMargin (GBPUSD,H4) EURJPY ORDER_TYPE_BUY, price = 2.5, lots = 1.3; OrderCalcMargin() = 2848.56; COrderCalculateMargin.Result = 2848 CompareMargin (GBPUSD,H4) GBPUSD ORDER_TYPE_SELL, price = 2.5, lots = 1.3; OrderCalcMargin() = 6500; COrderCalculateMargin.Result = 6500 CompareMargin (GBPUSD,H4) USDCAD ORDER_TYPE_SELL, price = 2.5, lots = 1.3; OrderCalcMargin() = 2600; COrderCalculateMargin.Result = 2600 CompareMargin (GBPUSD,H4) EURJPY ORDER_TYPE_SELL, price = 2.5, lots = 1.3; OrderCalcMargin() = 2848.51; COrderCalculateMargin.Result = 2849 CompareMargin (GBPUSD,H4) GBPUSD ORDER_TYPE_SELL, price = 0.5, lots = 1.3; OrderCalcMargin() = 1300; COrderCalculateMargin.Result = 1300 CompareMargin (GBPUSD,H4) USDCAD ORDER_TYPE_SELL, price = 0.5, lots = 1.3; OrderCalcMargin() = 2600; COrderCalculateMargin.Result = 2600 CompareMargin (GBPUSD,H4) EURJPY ORDER_TYPE_SELL, price = 0.5, lots = 1.3; OrderCalcMargin() = 2847.1; COrderCalculateMargin.Result = 2847 CompareMargin (GBPUSD,H4) GBPUSD ORDER_TYPE_SELL, price = 0.5, lots = 1.3; OrderCalcMargin() = 1300; COrderCalculateMargin.Result = 1300 CompareMargin (GBPUSD,H4) USDCAD ORDER_TYPE_SELL, price = 0.5, lots = 1.3; OrderCalcMargin() = 2600; COrderCalculateMargin.Result = 2600 CompareMargin (GBPUSD,H4) EURJPY ORDER_TYPE_SELL, price = 0.5, lots = 1.3; OrderCalcMargin() = 2847.42; COrderCalculateMargin.Result = 2847
Если в случае USDxxx поменять CalcMarginFormula(symbol,1,volume); на CalcMarginFormula(symbol,1/openprice,volume); результаты сильно расходятся
Почему?
Писал сам, провел тесты, только на кроссах работает не всегда точно. Подскажите где ошибка.
кроссы считаются по другому:
//USD/CHF Цена пункта = размер пункта * объем позиции / текущий курс //EUR/USD Цена пункта = размер пункта * объем позиции //EUR/CHF Цена пункта = объем позиции * размер пункта * текущая котировка базовой валюты по отношению к USD / текущий курс валютной пары (кросс-курс)
Допустим депозит у Вас в USD
Пары XXXUSD - будут считаться верно по этой формуле,
а вот для остальных пар необходим перевод в валюту депозита по текущему курсу в зависимости от направления BUY/SELL.
На MQL4 community был алгоритм расчета, насколько помнится мне
Ребята, может пора бы уже от MQ запросить функцию получения маржи ордера ? хотя бы открытого. бывает очень нужно.
Прошло некое время, а формула расчета OrderCalcProfit() по прежнему точно не известна. Нашел код GetOrderProfit(), результат немного расходится:
double GetOrderProfit(ENUM_ORDER_TYPE action, string symbol, double volume, double price_open, double price_close){ double tickValue=SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_VALUE); double profit = NULL; if ( action == ORDER_TYPE_BUY || action == ORDER_TYPE_BUY_LIMIT || action == ORDER_TYPE_BUY_STOP ) { profit = (price_close - price_open) * volume * tickValue / _Point; return profit; } else if ( action == ORDER_TYPE_SELL || action == ORDER_TYPE_SELL_LIMIT || action == ORDER_TYPE_SELL_STOP ) { profit = (price_open - price_close) * volume * tickValue / _Point; return profit; } return profit; }
Подскажите что добавить, чтобы результаты OrderCalcProfit() и этой функции совпадали ?
- 2018.07.16
- www.mql5.com
https://www.mql5.com/en/blogs/post/719643
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Добрый день
Подскажите пожалуйста формулы расчета данных функций. В частности интересует что произходит при кроссах - например имется счет в USD, а открывается позиция на EURGBP.
Так же по формуле OrderCalcProfit() хотелось бы подсчитать Volume имея Profit.
Спасибо