StopFirst 1.00, the read-only core
Fourteen headers, a header-only MQL5 library: lot size from risk, pips on
forex, gold and indices, broker checks, bars and candle patterns, cached ATR,
sessions in GMT, account risk, symbol suffixes, a calendar filter. Sends no
trade requests. Plus the LotByRisk example script.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-16 21:40:34 +03:00 | | | //+------------------------------------------------------------------+
|
| | | //| Risk.mqh|
|
| | | //| Copyright 2026, bandersoft |
|
| | | //| https://www.mql5.com/en/users/fats |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //| Position sizing and value at risk. |
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | #ifndef STOPFIRST_RISK_MQH
|
| | | #define STOPFIRST_RISK_MQH
|
| | |
|
| | | #include <Trade\SymbolInfo.mqh>
|
| | | #include <Trade\AccountInfo.mqh>
|
| | | #include "Defs.mqh"
|
| | | #include "Symbol.mqh" // GetPipSize - single definition of a pip
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Value of one unit of currency `from` in currency `to` |
|
| | | //| |
|
| | | //| Looks for a symbol quoting the pair either way round, first with |
|
| | | //| the same suffix as `likeSymbol` ("EURUSD.m" -> ".m"), then bare. |
|
| | | //| A symbol that exists but is not in Market Watch is selected, as |
|
| | | //| the terminal's own OrderCalcProfit would have to. |
|
| | | //| |
|
| | | //| Returns: the rate, 1 when the currencies are the same, 0 when no |
|
| | | //| symbol quotes the pair. |
|
| | | //+------------------------------------------------------------------+
|
| | | double CurrencyRate(const string from, const string to, const string likeSymbol = "")
|
| | | {
|
| | | if(from == "" || to == "") return 0;
|
| | | if(from == to) return 1.0;
|
| | |
|
| | | //--- the suffix of the symbol being priced, if it has one
|
| | | string suffix = "";
|
| | | if(likeSymbol != "")
|
| | | {
|
| | | string base = SymbolInfoString(likeSymbol, SYMBOL_CURRENCY_BASE) +
|
| | | SymbolInfoString(likeSymbol, SYMBOL_CURRENCY_PROFIT);
|
| | | if(StringLen(base) == 6 && StringFind(likeSymbol, base) == 0)
|
| | | suffix = StringSubstr(likeSymbol, 6);
|
| | | }
|
| | |
|
| | | string tails[2];
|
| | | tails[0] = suffix;
|
| | | tails[1] = "";
|
| | |
|
| | | for(int t = 0; t < 2; t++)
|
| | | {
|
| | | if(t == 1 && suffix == "") break;
|
| | |
|
| | | for(int inverse = 0; inverse < 2; inverse++)
|
| | | {
|
| | | string name = (inverse == 0 ? from + to : to + from) + tails[t];
|
| | |
|
| | | bool custom = false;
|
| | | if(!SymbolExist(name, custom)) continue;
|
| | | if(!SymbolInfoInteger(name, SYMBOL_SELECT)) SymbolSelect(name, true);
|
| | |
|
| | | double quote = (inverse == 0) ? SymbolInfoDouble(name, SYMBOL_BID)
|
| | | : SymbolInfoDouble(name, SYMBOL_ASK);
|
| | | if(quote <= 0) continue;
|
| | |
|
| | | return (inverse == 0) ? quote : 1.0 / quote;
|
| | | }
|
| | | }
|
| | |
|
| | | return 0;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Pip value from the contract specification |
|
| | | //| |
|
| | | //| The profit formulas MQL5 documents per ENUM_SYMBOL_CALC_MODE: for |
|
| | | //| forex, CFD, CFD index, CFD leverage and exchange stocks a price |
|
| | | //| move of d earns d * ContractSize per lot, in the symbol's profit |
|
| | | //| currency. Converted to the account currency with CurrencyRate. |
|
| | | //| |
|
| | | //| Exists because OrderCalcProfit is not always available: inside |
|
| | | //| an INDICATOR it fails with 4014 ERR_FUNCTION_NOT_ALLOWED |
|
| | | //| (measured 2026-10-14). Without this, an indicator fell through |
|
| | | //| to TICK_VALUE - the figure that is ten times wrong on gold. |
|
| | | //| |
|
| | | //| Returns: value of one pip per lot in account currency, or 0 for |
|
| | | //| other calculation modes or when no conversion rate is |
|
| | | //| available. |
|
| | | //+------------------------------------------------------------------+
|
| | | double PipValueByContract(string symbol = "")
|
| | | {
|
| | | if(symbol == "") symbol = _Symbol;
|
| | |
|
| | | double pipSize = GetPipSize(symbol);
|
| | | double contract = SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE);
|
| | | if(pipSize <= 0 || contract <= 0) return 0;
|
| | |
|
| | | ENUM_SYMBOL_CALC_MODE mode =
|
| | | (ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);
|
| | |
|
| | | switch(mode)
|
| | | {
|
| | | case SYMBOL_CALC_MODE_FOREX:
|
| | | case SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE:
|
| | | case SYMBOL_CALC_MODE_CFD:
|
| | | case SYMBOL_CALC_MODE_CFDINDEX:
|
| | | case SYMBOL_CALC_MODE_CFDLEVERAGE:
|
| | | case SYMBOL_CALC_MODE_EXCH_STOCKS:
|
| | | break;
|
| | | default:
|
| | | return 0; // futures and bonds price through tick value
|
| | | }
|
| | |
|
| | | double rate = CurrencyRate(SymbolInfoString(symbol, SYMBOL_CURRENCY_PROFIT),
|
| | | AccountInfoString(ACCOUNT_CURRENCY), symbol);
|
| | | if(rate <= 0) return 0;
|
| | |
|
| | | return pipSize * contract * rate;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Money one pip is worth, per lot, in account currency |
|
| | | //| |
|
2026-10-16 21:48:01 +03:00 | | | //| In order: |
|
StopFirst 1.00, the read-only core
Fourteen headers, a header-only MQL5 library: lot size from risk, pips on
forex, gold and indices, broker checks, bars and candle patterns, cached ATR,
sessions in GMT, account risk, symbol suffixes, a calendar filter. Sends no
trade requests. Plus the LotByRisk example script.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-16 21:40:34 +03:00 | | | //| 1. OrderCalcProfit - the terminal's own settlement maths |
|
| | | //| 2. the contract specification - PipValueByContract() |
|
| | | //| 3. tick value over tick size |
|
| | | //| A broker CAN report tick fields that disagree with how it |
|
| | | //| actually settles - see below - so tick value is the last resort. |
|
| | | //| |
|
| | | //| Returns: value of one pip per lot, or 0 if the symbol does not |
|
| | | //| report usable data by any route. |
|
| | | //+------------------------------------------------------------------+
|
| | | double PipValuePerLot(string symbol = "")
|
| | | {
|
| | | if(symbol == "") symbol = _Symbol;
|
| | |
|
| | | CSymbolInfo symbolInfo;
|
| | | if(!symbolInfo.Name(symbol)) return 0.0;
|
| | |
|
| | | double pipSize = GetPipSize(symbol);
|
| | | if(pipSize <= 0) return 0.0;
|
| | |
|
| | | //--- Preferred source: ask the terminal to price one pip of
|
| | | //--- movement on one lot. OrderCalcProfit runs the same calculation
|
| | | //--- a real trade settles with, so it is right by construction.
|
| | | //---
|
| | | //--- This is not theoretical. Measured on a live account
|
| | | //--- 2026-09-24: XAUUSD reported TICK_VALUE 0.1 against TICK_SIZE
|
| | | //--- 0.01 and CONTRACT_SIZE 100. The tick formula below therefore
|
| | | //--- returned 0.10 per pip where OrderCalcProfit - and the actual
|
| | | //--- profit and loss - said 1.00. A tenth of the true value makes
|
| | | //--- CalcLotSizeByRisk size TEN TIMES too large. EURUSD agreed to
|
| | | //--- the cent on the same broker, so the tick fields are reliable
|
| | | //--- for forex and not for this CFD.
|
| | | //---
|
| | | //--- Measured over 1000 pips and divided, not over one. The terminal
|
| | | //--- rounds OrderCalcProfit to the cent: on DE40, with a 0.01 pip,
|
| | | //--- one pip came back as 0.01 where the true value is 0.0112 - 11%
|
| | | //--- low, so 11% too many lots (measured 2026-10-14). Profit is
|
| | | //--- linear in the move, so the larger move loses nothing.
|
| | | const double MEASURE_PIPS = 1000.0;
|
| | |
|
| | | symbolInfo.RefreshRates();
|
| | | double price = symbolInfo.Ask();
|
| | | double profit = 0;
|
| | |
|
| | | if(price > 0 &&
|
| | | OrderCalcProfit(ORDER_TYPE_BUY, symbol, 1.0, price,
|
| | | price + MEASURE_PIPS * pipSize, profit) &&
|
| | | profit > 0)
|
| | | return profit / MEASURE_PIPS;
|
| | |
|
| | | //--- Second: the contract specification. This is the route an
|
| | | //--- indicator takes, since OrderCalcProfit is refused there (4014).
|
| | | double byContract = PipValueByContract(symbol);
|
| | | if(byContract > 0) return byContract;
|
| | |
|
| | | //--- Last resort: the tick-value route. Correct for forex, and the
|
| | | //--- best available guess otherwise.
|
| | | double tickValue = symbolInfo.TickValueLoss();
|
| | | if(tickValue <= 0) tickValue = symbolInfo.TickValue();
|
| | |
|
| | | double tickSize = symbolInfo.TickSize();
|
| | |
|
2026-10-16 21:48:01 +03:00 | | | //--- every divisor guarded
|
StopFirst 1.00, the read-only core
Fourteen headers, a header-only MQL5 library: lot size from risk, pips on
forex, gold and indices, broker checks, bars and candle patterns, cached ATR,
sessions in GMT, account risk, symbol suffixes, a calendar filter. Sends no
trade requests. Plus the LotByRisk example script.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-16 21:40:34 +03:00 | | | if(tickValue <= 0 || tickSize <= 0) return 0.0;
|
| | |
|
| | | return tickValue * (pipSize / tickSize);
|
| | | }
|
| | |
|
| | | //--- CalcLotSizeByRisk caps itself against this, which is defined below
|
| | | double CalcMaxLotSize(string symbol, double marginPercent);
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Calculate lot size based on risk percentage and stop loss |
|
| | | //| Parameters: |
|
| | | //| riskPercent - Risk as percentage of account balance (e.g., 1.0)|
|
| | | //| stopLossPips - Stop loss distance in pips |
|
| | | //| symbol - Trading symbol (empty = current symbol) |
|
| | | //| |
|
| | | //| marginCapPercent - share of free margin the result may need, |
|
| | | //| 1..100. Lower it to leave headroom. |
|
| | | //| |
|
| | | //| Returns: the lot size whose stop costs riskPercent of balance, |
|
| | | //| floored to the volume step. |
|
| | | //| 0 on failure, and 0 - not the broker minimum - when the |
|
| | | //| risk budget will not cover one minimum lot. Rounding up |
|
| | | //| there would silently risk more than was asked for. |
|
| | | //| |
|
| | | //| The result is capped THREE ways, all downwards, because reducing |
|
| | | //| a position can only reduce risk: |
|
| | | //| - the broker's maximum volume |
|
| | | //| - what free margin supports (measured 2026-09-24: it returned |
|
| | | //| 100 lots of XAUUSD on an account whose free margin |
|
| | | //| covered 23.44 - the broker maximum was the only ceiling) |
|
| | | //| - marginCapPercent of that |
|
| | | //| A capped result risks LESS than requested, never more. |
|
| | | //+------------------------------------------------------------------+
|
| | | double CalcLotSizeByRisk(double riskPercent, double stopLossPips, string symbol = "",
|
| | | double marginCapPercent = 100.0)
|
| | | {
|
| | | if(symbol == "") symbol = _Symbol;
|
| | |
|
2026-10-16 21:48:01 +03:00 | | | //--- guard before dividing: a zero stop would make the size infinite,
|
| | | //--- and MathMin(maxLot, inf) would return the MAXIMUM lot size
|
StopFirst 1.00, the read-only core
Fourteen headers, a header-only MQL5 library: lot size from risk, pips on
forex, gold and indices, broker checks, bars and candle patterns, cached ATR,
sessions in GMT, account risk, symbol suffixes, a calendar filter. Sends no
trade requests. Plus the LotByRisk example script.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-16 21:40:34 +03:00 | | | if(riskPercent <= 0 || stopLossPips <= 0) return 0.0;
|
| | |
|
| | | CSymbolInfo symbolInfo;
|
| | | if(!symbolInfo.Name(symbol)) return 0.0;
|
| | |
|
| | | CAccountInfo accountInfo;
|
| | | double riskAmount = accountInfo.Balance() * (riskPercent / 100.0);
|
| | | if(riskAmount <= 0) return 0.0;
|
| | |
|
| | | double pipValue = PipValuePerLot(symbol);
|
| | | if(pipValue <= 0) return 0.0;
|
| | |
|
| | | double minLot = symbolInfo.LotsMin();
|
| | | double maxLot = symbolInfo.LotsMax();
|
| | | double lotStep = symbolInfo.LotsStep();
|
| | | if(lotStep <= 0) return 0.0;
|
| | |
|
| | | double lotSize = FloorToVolumeStep(riskAmount / (stopLossPips * pipValue), lotStep);
|
| | |
|
| | | //--- capping down is safe, it can only reduce exposure
|
| | | if(lotSize > maxLot) lotSize = FloorToVolumeStep(maxLot, lotStep);
|
| | |
|
| | | //--- and the broker maximum is NOT the real ceiling: free margin
|
| | | //--- usually runs out first. Without this a 1% risk on gold asked
|
| | | //--- for 100 lots against margin that covered 23.
|
| | | //---
|
| | | //--- CalcMaxLotSize returns 0 both when margin is unknown and when it
|
| | | //--- will not fund one minimum lot. Only the first may skip the cap:
|
| | | //--- the second used to, and returned an unfundable size.
|
| | | if(MarginPerLot(symbol, ORDER_TYPE_BUY) > 0)
|
| | | {
|
| | | double affordable = CalcMaxLotSize(symbol, marginCapPercent);
|
| | | if(affordable <= 0) return 0.0;
|
| | | if(lotSize > affordable) lotSize = FloorToVolumeStep(affordable, lotStep);
|
| | | }
|
| | |
|
| | | //--- capping up is not: refuse instead
|
| | | if(lotSize < minLot - 1e-9) return 0.0;
|
| | |
|
| | | return lotSize;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Margin one lot needs, in account currency |
|
| | | //| |
|
2026-10-16 21:48:01 +03:00 | | | //| OrderCalcMargin first, which honours the symbol's |
|
StopFirst 1.00, the read-only core
Fourteen headers, a header-only MQL5 library: lot size from risk, pips on
forex, gold and indices, broker checks, bars and candle patterns, cached ATR,
sessions in GMT, account risk, symbol suffixes, a calendar filter. Sends no
trade requests. Plus the LotByRisk example script.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-16 21:40:34 +03:00 | | | //| margin rate, calculation mode and hedged margin settings. |
|
| | | //| |
|
| | | //| Inside an indicator OrderCalcMargin fails with 4014 |
|
| | | //| ERR_FUNCTION_NOT_ALLOWED (measured 2026-10-14), and so does |
|
| | | //| CAccountInfo::MaxLotCheck, which is built on it - it also prints |
|
| | | //| "margin calculation failed" on every call. The fallback is the |
|
| | | //| margin formula MQL5 documents per ENUM_SYMBOL_CALC_MODE, with the |
|
| | | //| symbol's initial margin rate, converted from the margin currency. |
|
| | | //| It ignores hedged-margin reductions, so it can only overstate. |
|
| | | //| |
|
| | | //| Returns: margin for 1.0 lot, or 0 when it cannot be determined. |
|
| | | //+------------------------------------------------------------------+
|
| | | double MarginPerLotByFormula(string symbol = "", const ENUM_ORDER_TYPE type = ORDER_TYPE_BUY);
|
| | |
|
| | | double MarginPerLot(string symbol = "", const ENUM_ORDER_TYPE type = ORDER_TYPE_BUY)
|
| | | {
|
| | | if(symbol == "") symbol = _Symbol;
|
| | |
|
| | | bool isBuy = (type == ORDER_TYPE_BUY);
|
| | | double price = SymbolInfoDouble(symbol, isBuy ? SYMBOL_ASK : SYMBOL_BID);
|
| | | if(price <= 0) return 0;
|
| | |
|
| | | double margin = 0;
|
| | | if(OrderCalcMargin(type, symbol, 1.0, price, margin) && margin > 0)
|
| | | return margin;
|
| | |
|
| | | return MarginPerLotByFormula(symbol, type);
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Margin for one lot from the documented formula alone |
|
| | | //| |
|
| | | //| The fallback inside MarginPerLot, public so a test can compare it |
|
| | | //| with OrderCalcMargin where both are available. |
|
| | | //| |
|
| | | //| Returns: margin for 1.0 lot in account currency, or 0 for other |
|
| | | //| calculation modes or without a conversion rate. |
|
| | | //+------------------------------------------------------------------+
|
| | | double MarginPerLotByFormula(string symbol, const ENUM_ORDER_TYPE type)
|
| | | {
|
| | | if(symbol == "") symbol = _Symbol;
|
| | |
|
| | | bool isBuy = (type == ORDER_TYPE_BUY);
|
| | | double price = SymbolInfoDouble(symbol, isBuy ? SYMBOL_ASK : SYMBOL_BID);
|
| | | if(price <= 0) return 0;
|
| | |
|
| | | //--- the documented formulas, in the margin currency
|
| | | double contract = SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE);
|
| | | double leverage = (double)AccountInfoInteger(ACCOUNT_LEVERAGE);
|
| | | double initialRate = 0, maintenanceRate = 0;
|
| | | if(!SymbolInfoMarginRate(symbol, type, initialRate, maintenanceRate) || initialRate <= 0)
|
| | | initialRate = 1.0;
|
| | | if(contract <= 0) return 0;
|
| | |
|
| | | ENUM_SYMBOL_CALC_MODE mode =
|
| | | (ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);
|
| | | double perLot = 0;
|
| | |
|
| | | switch(mode)
|
| | | {
|
| | | case SYMBOL_CALC_MODE_FOREX:
|
| | | if(leverage <= 0) return 0;
|
| | | perLot = contract / leverage;
|
| | | break;
|
| | | case SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE:
|
| | | perLot = contract;
|
| | | break;
|
| | | case SYMBOL_CALC_MODE_CFD:
|
| | | perLot = contract * price;
|
| | | break;
|
| | | case SYMBOL_CALC_MODE_CFDLEVERAGE:
|
| | | if(leverage <= 0) return 0;
|
| | | perLot = contract * price / leverage;
|
| | | break;
|
| | | case SYMBOL_CALC_MODE_CFDINDEX:
|
| | | {
|
| | | double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
|
| | | double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
|
| | | if(tickValue <= 0 || tickSize <= 0) return 0;
|
| | | perLot = contract * price * tickValue / tickSize;
|
| | | break;
|
| | | }
|
| | | default:
|
| | | return 0;
|
| | | }
|
| | |
|
| | | double rate = CurrencyRate(SymbolInfoString(symbol, SYMBOL_CURRENCY_MARGIN),
|
| | | AccountInfoString(ACCOUNT_CURRENCY), symbol);
|
| | | if(rate <= 0) return 0;
|
| | |
|
| | | return perLot * initialRate * rate;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Calculate maximum lot size based on free margin |
|
| | | //| Parameters: |
|
| | | //| symbol - Trading symbol (empty = current symbol) |
|
| | | //| marginPercent - share of free margin to commit, 1..100 |
|
| | | //| |
|
| | | //| Free margin times the share, over MarginPerLot(). That is what |
|
| | | //| CAccountInfo::MaxLotCheck computes, without its dependency on |
|
| | | //| OrderCalcMargin alone - so it also works inside an indicator. |
|
| | | //| |
|
| | | //| Returns: the largest lot size free margin supports, floored to |
|
| | | //| the volume step. 0 if margin cannot be calculated or |
|
| | | //| will not cover one minimum lot - MarginPerLot() tells |
|
| | | //| the two apart. |
|
| | | //+------------------------------------------------------------------+
|
| | | double CalcMaxLotSize(string symbol = "", double marginPercent = 100.0)
|
| | | {
|
| | | if(symbol == "") symbol = _Symbol;
|
| | |
|
| | | if(marginPercent < 1.0 || marginPercent > 100.0) return 0.0;
|
| | |
|
| | | CSymbolInfo symbolInfo;
|
| | | if(!symbolInfo.Name(symbol)) return 0.0;
|
| | |
|
| | | double perLot = MarginPerLot(symbol, ORDER_TYPE_BUY);
|
| | | if(perLot <= 0) return 0.0;
|
| | |
|
| | | double freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
|
| | | if(freeMargin <= 0) return 0.0;
|
| | |
|
| | | double maxLot = freeMargin * (marginPercent / 100.0) / perLot;
|
| | |
|
| | | double minLot = symbolInfo.LotsMin();
|
| | | double maxAllowed = symbolInfo.LotsMax();
|
| | | double lotStep = symbolInfo.LotsStep();
|
| | | if(lotStep <= 0) return 0.0;
|
| | |
|
| | | maxLot = FloorToVolumeStep(maxLot, lotStep);
|
| | | if(maxLot > maxAllowed) maxLot = FloorToVolumeStep(maxAllowed, lotStep);
|
| | |
|
| | | //--- do not claim a tradable size when margin will not cover one
|
| | | if(maxLot < minLot - 1e-9) return 0.0;
|
| | |
|
| | | return maxLot;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Calculate risk-reward ratio |
|
| | | //| |
|
| | | //| Returns: reward distance divided by risk distance, 2 decimals. |
|
| | | //| 0 when the stop equals the entry, which leaves the ratio |
|
| | | //| undefined. |
|
| | | //+------------------------------------------------------------------+
|
| | | double CalcRiskRewardRatio(double entryPrice, double stopLoss, double takeProfit)
|
| | | {
|
| | | double risk = MathAbs(entryPrice - stopLoss);
|
| | | double reward = MathAbs(takeProfit - entryPrice);
|
| | |
|
| | | if(risk == 0) return 0;
|
| | | return NormalizeDouble(reward / risk, 2);
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Calculate position value at risk in account currency |
|
| | | //| Parameters: |
|
| | | //| lotSize - position size |
|
| | | //| stopLossPips - stop distance in pips |
|
| | | //| symbol - Trading symbol (empty = current symbol) |
|
| | | //| |
|
| | | //| Returns: the money lost if the stop is hit, to 2 decimals. |
|
| | | //| 0 if either argument is not positive, or the symbol |
|
| | | //| reports no usable tick data. |
|
| | | //+------------------------------------------------------------------+
|
| | | double CalcValueAtRisk(double lotSize, double stopLossPips, string symbol = "")
|
| | | {
|
| | | if(symbol == "") symbol = _Symbol;
|
| | |
|
| | | if(lotSize <= 0 || stopLossPips <= 0) return 0.0;
|
| | |
|
| | | double pipValue = PipValuePerLot(symbol);
|
| | | if(pipValue <= 0) return 0.0;
|
| | |
|
| | | return NormalizeDouble(lotSize * stopLossPips * pipValue, 2);
|
| | | }
|
| | |
|
| | | #endif // STOPFIRST_RISK_MQH
|
| | | //+------------------------------------------------------------------+
|