Przejdź do treści
MQL5 · MetaTrader 5 · po polsku
kod odczarowany

MQL5 / Przepisy

Wielkość pozycji wyliczona z ryzyka

Przeliczenie procentu kapitału i odległości stopa na wolumen, poprawnie dla dowolnego instrumentu — nie tylko dla par walutowych.

2 fragmenty kodu z tej strony przeszły przez kompilator MetaEditor build 6090, 2026-08-05.

Zdecydowana większość kodu krążącego po forach liczy wolumen wzorem, który działa wyłącznie na parach walutowych z rachunkiem w dolarze. Na złocie, indeksie albo akcji daje wynik kilkakrotnie zawyżony lub zaniżony — bez żadnego komunikatu.

Skąd biorą się właściwe liczby

Instrument sam podaje wszystko, czego potrzeba:

WłaściwośćCo znaczy
SYMBOL_TRADE_TICK_SIZEnajmniejsza możliwa zmiana ceny
SYMBOL_TRADE_TICK_VALUEile pieniędzy zmienia się przy tej zmianie, na 1 lot
SYMBOL_VOLUME_MIN / MAX / STEPgranice i krok wolumenu

Uwaga na różnicę między SYMBOL_TRADE_TICK_SIZE a SYMBOL_POINT. Na większości instrumentów są równe, ale nie na wszystkich — i wtedy wzór oparty na punkcie zamiast na ticku się rozjeżdża.

Wzór

strata na 1 lot = (dystans stopa w punktach × punkt ÷ tick size) × tick value
wolumen         = kwota ryzyka ÷ strata na 1 lot

Kod

Wolumen z procentu kapitału i odległości stopa
double WolumenZRyzyka(const string symbol,
                      const double procentRyzyka,
                      const int dystansPunktow)
  {
   if(dystansPunktow <= 0 || procentRyzyka <= 0.0)
      return 0.0;

   double punkt      = SymbolInfoDouble(symbol, SYMBOL_POINT);
   double rozmiarTicku = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
   double wartoscTicku = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);

   if(rozmiarTicku <= 0.0 || wartoscTicku <= 0.0)
     {
      Print("Instrument nie podaje rozmiaru albo wartości ticku.");
      return 0.0;
     }

   double kapital = AccountInfoDouble(ACCOUNT_BALANCE);
   double kwotaRyzyka = kapital * procentRyzyka / 100.0;

   //--- ile stracimy na jednym locie, jeśli stop zostanie trafiony
   double strataNaLot = (dystansPunktow * punkt / rozmiarTicku) * wartoscTicku;
   if(strataNaLot <= 0.0)
      return 0.0;

   double wolumen = kwotaRyzyka / strataNaLot;

   //--- dopasowanie do kroku instrumentu, zawsze w dół
   double minimum  = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
   double maksimum = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
   double krok     = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
   if(krok <= 0.0)
      krok = minimum;

   wolumen = MathFloor(wolumen / krok) * krok;

   if(wolumen < minimum)
     {
      PrintFormat("Ryzyko %.2f%% daje wolumen poniżej minimum %.2f — "
                  "nie otwieram pozycji.", procentRyzyka, minimum);
      return 0.0;
     }

   if(wolumen > maksimum)
      wolumen = maksimum;

   int cyfry = (int)MathMax(0, MathRound(-MathLog(krok) / MathLog(10.0)));
   return NormalizeDouble(wolumen, cyfry);
  }

Zanim wyślesz zlecenie

Wolumen mieszczący się w ryzyku nie znaczy, że rachunek ma na niego depozyt. To dwie różne kontrole:

Sprawdzenie wymaganego depozytu
double wymagany = 0.0;
if(!OrderCalcMargin(ORDER_TYPE_BUY, symbol, wolumen, cena, wymagany))
   return 0.0;

if(wymagany > AccountInfoDouble(ACCOUNT_MARGIN_FREE) * 0.9)
  {
   Print("Za mało wolnego depozytu na tę pozycję.");
   return 0.0;
  }

Pominięcie tego kroku kończy się kodem 10019.

Powiązane