функция автоматического расчета размера партии?

 

Привет всем, снова вернулся к вам :-) Есть ли у кого-нибудь удобная маленькая функция на MQL4, которая автоматически рассчитывает размер лота (для любого инструмента) на основе % риска от имеющегося капитала и желаемого размера стоплосса в пунктах?


Спасибо!

Shawn

 
 


Спасибо, Филипп! Похоже, что у кода были некоторые проблемы с парами JPY. Это было решено?


Спасибо

Шон

 
shawnh:


Спасибо, Филипп! Похоже, что у кода были некоторые проблемы с парами JPY. Это было решено?


Спасибо

Шон




Я понятия не имею, что вы имеете в виду? Он отлично работает с парами JPY. Как и с любым другим кодом, которому вы можете доверить свои деньги, вы должны исследовать код и подтвердить его правильность с помощью некоторых ручных расчетов. Код корректен, но он не защищает от дурака :)

 

1. Образец: Вычисление размера лота https://www.mql5.com/en/code/8583

2. Торговый робот AIS1 https://www.mql5.com/en/code/8700

//< 7.7.2. Risk Management > //<192>
//< 7.7.3. Operation Size Control > //<202>

 
shawnh:

Есть ли у кого-нибудь удобная маленькая функция MQL4, которая автоматически рассчитывает размер лота (для любого символа) на основе % риска от имеющегося капитала и желаемого размера стоплосса в пунктах?

//+------------------------------------------------------------------+
//| Lot size computation.                                            |
//+------------------------------------------------------------------+
double  LotSize(double risk){
/*double    TEF.value,                          // Import from ComputeTEF
//double    at.risk;                            // Export to init/start
//bool      need2refresh;                       // Import from RelTradeContext
//int       op.code; // -1/OP_BUY/OP_SELL       // Import from setDIR */
    /* This function computes the lot size for a trade.
     * Explicit inputs are SL relative to bid/ask (E.G. SL=30*points,)
     * Implicit inputs are the MM mode, the MM multiplier, count currently
     * filled orders by all EA's vs this EA/pair/period count and history.
     * Implicit inputs are all used to reduce available balance the maximum
     * dollar risk allowed. StopLoss determines the maximum dollar risk possible
     * per lot. Lots=maxRisk/maxRiskPerLot
     **************************************************************************/
    if (need2refresh)   Refresh();
    /*++++ Compute lot size based on account balance and MM mode*/{
    double  ab  = AccountBalance();
    switch(Money.Management.F0M1G2){
    case MMMODE_FIXED:
        at.risk = Money.Management.Multiplier;
        break;
    case MMMODE_MODERATE:
        // See https://www.mql5.com/en/articles/1526 Fallacies, Part 1: Money
        // Management is Secondary and Not Very Important.       // %used/trade=
        at.risk = MathSqrt(Money.Management.Multiplier * ab)/ab; // ~const rate.
        at.risk = MathSqrt(Money.Management.Multiplier * ab
                            * MathPow( 1 - at.risk, OrdersTotal() ));
        break;
    case MMMODE_GEOMETRICAL:
        at.risk = Money.Management.Multiplier * ab *
                MathPow(1 - Money.Management.Multiplier, OrdersTotal());
        break;
    }
    double  maxLossPerLot   = risk * PointValuePerLot(),
    /* Number of lots wanted = at.risk / maxLossPerLot rounded/truncated to
     * nearest lotStep size.
     *
     * However, the broker doesn't care about the at.risk/account balance. They
     * care about margin. Margin used=lots used*marginPerLot and that must be
     * less than free margin available. */
            marginFree      = AccountFreeMargin(),
            marginPerLot    = MarketInfo( Symbol(), MODE_MARGINREQUIRED ),
    // So I use, the lesser of either.
            size = MathMin(marginFree / marginPerLot, at.risk / maxLossPerLot),
            minLot  = MarketInfo(Symbol(), MODE_MINLOT),
            LotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
    /*---- Compute lot size based on account balance and MM mode*/}
    double  adjFact = IfD(MathMin(1, TEF.value), 1, TEF.Enable01);
    while (true){   // Adjust for broker, test for margin, combine with TEF
        size =  MathFloor(size/LotStep)*LotStep;
        if (size < minLot){ // Insufficient margin.
            Print(
            "LotSize(SL=", DoubleToStr(risk/pips2dbl, Digits.pips), ")=",
            size, " [risk=", at.risk, AccountCurrency(),    "/", maxLossPerLot,
                    ", margin=",    marginFree,             "/", marginPerLot,
                    ", MMM=",       Money.Management.F0M1G2,"x",
                    Money.Management.Multiplier,    ", OO=",   OrdersTotal(),
                "]" );
            size=0; break;  }
        /* size<minLot should be sufficient, but the tester was generating error
         * 134 even when marginFree should have been OK. So I also use
         * AccountFreeMarginCheck which aggrees with the tester.
         * https://forum.mql4.com/35056 */
        double AFMC = AccountFreeMarginCheck(Symbol(), op.code, size);
        /**/ if (AFMC < 0)      size *= 0.95;
        else if (adjFact < 1){  size  = MathMax(minLot,size*adjFact);adjFact=1;}
        else break; // We're good to go.
    }
    at.risk = size * maxLossPerLot;                     // Export for Comment
    return(size);
}   // LotSize
double PointValuePerLot() { // Value in account currency of a Point of Symbol.
    /* In tester I had a sale: open=1.35883 close=1.35736 (0.00147)
     * gain$=97.32/6.62 lots/147 points=$0.10/point or $1.00/pip.
     * IBFX demo/mini       EURUSD TICKVALUE=0.1 MAXLOT=50 LOTSIZE=10,000
     * IBFX demo/standard   EURUSD TICKVALUE=1.0 MAXLOT=50 LOTSIZE=100,000
     *                                  $1.00/point or $10.00/pip.
     *
     * https://forum.mql4.com/33975 CB: MODE_TICKSIZE will usually return the
     * same value as MODE_POINT (or Point for the current symbol), however, an
     * example of where to use MODE_TICKSIZE would be as part of a ratio with
     * MODE_TICKVALUE when performing money management calculations which need
     * to take account of the pair and the account currency. The reason I use
     * this ratio is that although TV and TS may constantly be returned as
     * something like 7.00 and 0.00001 respectively, I've seen this
     * (intermittently) change to 14.00 and 0.00002 respectively (just example
     * tick values to illustrate). */
    return(  MarketInfo(Symbol(), MODE_TICKVALUE)
           / MarketInfo(Symbol(), MODE_TICKSIZE) ); // Not Point.
}
 

Филипп, я вставил ваш код в мой советник, и он прекрасно работает - большое вам спасибо. Спасибо также AIS и WHRoeder за их ответы!


Будь здоров

Шон

 

Рад это слышать, Шон!

Я постоянно дорабатываю коды, если вам нужна более свежая версия (в той, что у вас есть, нет ошибок), я с удовольствием ею поделюсь.

Изменения в основном направлены на то, чтобы сделать включаемый файл более легким для интеграции и использования с вашим существующим советником. Поскольку вы уже успели внедрить другой советник, это может не иметь для вас никакого значения.

 

Филипп, я бы хотел получить этот новый "более простой в использовании" включаемый файл, не могли бы вы опубликовать его или отправить мне, я пытаюсь сделать это сегодня.

Спасибо!

 

Конечно, я опубликую его, когда вернусь к компьютеру, на котором хранятся мои коды.

Наверное, мне стоит загрузить его и в банк кодов, раз уж я об этом подумал.

 

Шаг 1: Поместите все прикрепленные файлы из этого поста в путь include (...\experts\include\*.mqh).

Шаг 2: Добавьте следующее в верхнюю часть вашего эксперта, чтобы он имел доступ к функциям вызова, содержащимся во вложенных файлах.

#include <OrderReliable_2010.10.12.mqh>
#include <Trade_Position_Management_2010.10.29.mqh>

Шаг 3: Чтобы рассчитать размер лота на основе бюджетной суммы капитала для риска, добавьте следующее

   // Determine position lotsize based on order direction and market prices
   double CurrentEquityAtRisk=(MaxPercentEquityAtRisk/100.)*AccountBalance();
   double CurrentLotSize=LotSize(CurrentEquityAtRisk,OpenPrice_ND,StopLossPrice_ND,CurrentOrderType); // Compute the max possible lotsize for the risk equity
   Print("Max allowed EquityAtRisk = $",DoubleToStr(CurrentEquityAtRisk,2)," and Max computed Lotsize = ",CurrentLotSize);
   CurrentLotSize=NormalizeLotSize(CurrentLotSize);   // Normalize the lotsize to conform with the Broker's specific quantized position allowances
   if(CurrentLotSize<MarketInfo(CurrentSymbol,MODE_MINLOT)) CurrentLotSize=MarketInfo(CurrentSymbol,MODE_MINLOT);
   if(CurrentLotSize> MarketInfo(CurrentSymbol,MODE_MAXLOT)) CurrentLotSize=MarketInfo(CurrentSymbol,MODE_MAXLOT);

Предполагая, что вы определили MaxPercentEquityAtRisk где-то в вашем советнике как максимально допустимый размер капитала для риска полного убытка по сделке в случае срабатывания стопов, эта часть кода сначала определит максимальный размер лота на основе openprice и stoplossprice (не пунктов, а реальной рыночной цены, той же самой, что вы отправляете в своем ордере брокеру), а затем определит максимальный размер позиции, который брокер примет, не превышая ваш бюджетный риск капитала.

Шаг 4: Если вам нравится, когда результаты расчетов печатаются в журнале или добавляются к сделке в виде комментария к ордеру, вы можете добавить следующее

   // Determine the actual equity at risk of total loss for the position's normalized lotsize
   CurrentEquityAtRisk=EquityAtRisk(CurrentLotSize,OpenPrice_ND,StopLossPrice_ND,CurrentOrderType);
   if(TakeProfitBidPrice>0.01)
      {
      CurrentProfitPotential=ProfitPotential(CurrentLotSize,OpenPrice_ND,TakeProfitPrice_ND,CurrentOrderType);
      Print("Current EquityAtRisk = $",DoubleToStr(CurrentEquityAtRisk,2)," and Current Lotsize = ",CurrentLotSize," and Profit Target = $"
            ,DoubleToStr(CurrentProfitPotential,2)," for a ",DoubleToStr(CurrentProfitPotential/CurrentEquityAtRisk,1),":1 Profit:Loss ratio");
      Order_Comment=StringConcatenate("EaR = $",DoubleToStr(CurrentEquityAtRisk,2)," & Profit = $",DoubleToStr(CurrentProfitPotential,2));
      }
   else
      {
      Print("Current EquityAtRisk = $",DoubleToStr(CurrentEquityAtRisk,2)," and Current Lotsize = ",CurrentLotSize);
      Order_Comment=StringConcatenate("EquityAtRisk = $",DoubleToStr(CurrentEquityAtRisk,2));
      }

Шаг 5: Разместите свой ордер (используя метод ordersendreliable)

   // Place the order
   ticket = OrderSendReliable(CurrentSymbol,CurrentOrderType,CurrentLotSize,OpenPrice_ND,MarketInfo(CurrentSymbol,MODE_SPREAD)
            ,StopLossPrice_ND,TakeProfitPrice_ND,Order_Comment,0,0,Aqua);

https://c.mql5.com/mql4/forum/2010/10/OrderReliable_2010.10.12.mqh