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_SIZE | najmniejsza możliwa zmiana ceny |
SYMBOL_TRADE_TICK_VALUE | ile pieniędzy zmienia się przy tej zmianie, na 1 lot |
SYMBOL_VOLUME_MIN / MAX / STEP | granice 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 lotKod
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:
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.