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>
149 lines
6.1 KiB
Markdown
149 lines
6.1 KiB
Markdown
# StopFirst
|
|
|
|
A header-only MQL5 library of the calculations an Expert Advisor keeps
|
|
re-implementing: position sizing from a risk percentage, pip and price
|
|
conversion, broker constraint checks, bar queries and candle patterns, trading
|
|
sessions in GMT, total risk across open positions, broker symbol suffixes, an
|
|
economic-calendar filter, and account metrics.
|
|
|
|
No DLLs, no `WebRequest`, no external dependencies beyond the standard
|
|
`Include\Trade\` classes that ship with MetaTrader 5.
|
|
|
|
---
|
|
|
|
## Install
|
|
|
|
**From the CodeBase archive:** unpack it into the terminal's data folder
|
|
(File > Open Data Folder). It adds `MQL5\Include\StopFirst\*.mqh` and the
|
|
example `MQL5\Scripts\StopFirst\LotByRisk.mq5`, and touches nothing else.
|
|
|
|
**From Algo Forge:** clone the repository, then copy its `Include\StopFirst\`
|
|
folder into `MQL5\Include\`, so the headers sit at
|
|
`MQL5\Include\StopFirst\*.mqh`. The example is in `Examples\`.
|
|
|
|
Then:
|
|
|
|
```mql5
|
|
#include <StopFirst\StopFirst.mqh>
|
|
```
|
|
|
|
Nothing to compile or link — it is header-only.
|
|
|
|
## Example
|
|
|
|
```mql5
|
|
#include <StopFirst\StopFirst.mqh>
|
|
|
|
void OnStart()
|
|
{
|
|
// Lot size whose 30-pip stop costs 1% of the balance
|
|
double lots = CalcLotSizeByRisk(1.0, 30);
|
|
|
|
if(lots <= 0)
|
|
{
|
|
Print("Risk budget does not cover one minimum lot.");
|
|
return;
|
|
}
|
|
|
|
PrintFormat("%.2f lots risks %.2f %s over 30 pips",
|
|
lots, CalcValueAtRisk(lots, 30), AccountInfoString(ACCOUNT_CURRENCY));
|
|
}
|
|
```
|
|
|
|
`LotByRisk.mq5` is the same idea with the output filled in. It places no
|
|
orders.
|
|
|
|
## Two things to know before using it
|
|
|
|
**Sizing fails to zero, never upward.** `CalcLotSizeByRisk` returns `0` when the
|
|
risk budget will not cover one minimum lot, rather than rounding up to the
|
|
minimum. Rounding up would silently risk more than you asked for. Check the
|
|
return value.
|
|
|
|
**Pip size is a forex convention.** The default rule — `point * 10` on a 3- or
|
|
5-digit symbol, `point` otherwise — is right for currency pairs and wrong
|
|
anywhere a "pip" means something else. It is out by 10× on gold quoted to two
|
|
decimals and 100× on most crypto. No symbol property distinguishes these cases,
|
|
so declare it once at startup:
|
|
|
|
```mql5
|
|
SetPipSize("XAUUSD", 0.1);
|
|
```
|
|
|
|
or take the conventional value for metals, indices, oil and crypto from the
|
|
built-in table with `ApplyBuiltInPipSize("XAUUSD")`. Everything downstream —
|
|
lot sizing, value at risk, stop distances — reads from that one definition.
|
|
|
|
## In the Strategy Tester
|
|
|
|
Everything works in the tester except two things the tester does not have:
|
|
|
|
- **The broker's GMT offset cannot be measured** (`TimeGMT()` there is not
|
|
model time). `DetectGmtOffset()` reports `reliable = false`; call
|
|
`SetGmtOffset(hours)` in `OnInit`, or sessions and `IsWithinTradingHours`
|
|
assume GMT+0.
|
|
- **There is no economic calendar.** `IsCalendarAvailable()` returns false and
|
|
`IsNewsNear()` returns false, so a news filter neither blocks nor allows on
|
|
invented data.
|
|
|
|
## Files
|
|
|
|
| Header | Contents |
|
|
|---|---|
|
|
| `StopFirst.mqh` | Umbrella. Include this. |
|
|
| `Defs.mqh` | Constants, sentinels, `ENUM_SF_PATTERN`, `ENUM_SF_SIGNAL` |
|
|
| `Symbol.mqh` | Pip size and overrides, price/pip conversion, lot normalisation, broker constraint checks, whether the market is open |
|
|
| `PipTable.mqh` | `BuiltInPipSize`, `ApplyBuiltInPipSize` — opt-in conventional pips for metals, indices, oil, crypto |
|
|
| `Risk.mqh` | `CalcLotSizeByRisk`, `CalcMaxLotSize`, `CalcValueAtRisk`, `CalcRiskRewardRatio`, pip value and margin per lot |
|
|
| `Bars.mqh` | `CNewBarDetector`, bar extremes, candle patterns |
|
|
| `Atr.mqh` | `CAtr` with a cached indicator handle, plus `GetATRPips` |
|
|
| `Sessions.mqh` | Broker GMT offset, Sydney/Tokyo/London/New York sessions, server/GMT conversion |
|
|
| `Time.mqh` | Timeframe and weekday names, trading-hour windows in GMT |
|
|
| `Positions.mqh` | Read-only position queries |
|
|
| `Account.mqh` | Floating loss, peak drawdown, compounding, summary string |
|
|
| `AccountRisk.mqh` | Money at risk across open positions and pending orders, positions without a stop, risk budget check |
|
|
| `Symbols.mqh` | Resolve `EURUSD` to the broker's `EURUSD.m`, `EURUSDpro` and similar |
|
|
| `News.mqh` | Economic-calendar filter: news near, upcoming events, minutes to the next one |
|
|
|
|
## Conventions
|
|
|
|
- `symbol = ""` means the current chart symbol — **except** on the position
|
|
filter functions (`GetPositionCount`, `GetTotalProfit`, `GetTotalVolume`,
|
|
and the totals in `AccountRisk.mqh`), where it means *every* symbol. Widening a filter and defaulting a subject are
|
|
different operations; they happen to share a spelling.
|
|
- `magic = STOPFIRST_ANY_MAGIC` matches any magic number. Magic is `ulong`, so
|
|
there is no negative value to borrow as a sentinel.
|
|
- Functions returning a price or a count return `0` on failure. Where `0` is
|
|
also a plausible real answer, the doc comment on the function says so.
|
|
- Every public function documents what it returns **and what it returns on
|
|
failure**.
|
|
|
|
## Tests
|
|
|
|
The library is exercised by read-only harnesses that can be attached to any
|
|
chart, and by demo-only ones that place and close real positions, on a live
|
|
demo account and in the Strategy Tester, on forex, gold, indices and stocks.
|
|
The test programs are not part of this archive.
|
|
|
|
Compiling proves the types line up. It proves nothing about a broker: tick
|
|
values, minimum stop distances and close-time races all behave differently on
|
|
different servers, and every defect found on 2026-09-24 compiled cleanly.
|
|
|
|
## Requirements
|
|
|
|
MetaTrader 5, any recent build. Uses `Include\Trade\` (`CSymbolInfo`,
|
|
`CAccountInfo`, `CPositionInfo`), which ships with the terminal.
|
|
|
|
No DLL imports. No `WebRequest`. Nothing in this package sends a trade request —
|
|
it reads and calculates. Order execution lives in a separate, unpublished part
|
|
of the project.
|
|
|
|
The one change it makes to the terminal is adding symbols to Market Watch, so
|
|
that they have quotes: `ResolveSymbol` adds the symbol it finds (pass `false`
|
|
to stop it), `EnsureSymbolSelected` exists to do exactly that, and the
|
|
currency conversion behind pip value and margin adds the conversion pair it
|
|
needs, such as `USDJPY` for a JPY-quoted symbol on a USD account.
|
|
|
|
## License
|
|
|
|
MIT. See [LICENSE](LICENSE).
|