StopFirst-Core/Include/StopFirst/PipTable.mqh
RUSLAN SLOBODIANIUK 6ba79702fd Make the header comments self-contained
They referred to project documents that are not part of this repository.
Comments only; PriceToPips is now documented as not rounding, which is what
it does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-16 21:48:01 +03:00

162 lines
7.9 KiB
MQL5

//+------------------------------------------------------------------+
//| PipTable.mqh |
//| Copyright 2026, bandersoft |
//| https://www.mql5.com/en/users/fats |
//+------------------------------------------------------------------+
//| |
//| Conventional pip sizes for common non-FX symbols. Read-only. |
//| |
//| A pip on a CFD is a CONVENTION, not a property the broker |
//| reports. GetPipSize()'s automatic rule (point * 10 on 3- and |
//| 5-digit symbols, point otherwise) is the forex convention, and |
//| makes a gold pip 0.01 - while most traders mean 0.10. Someone |
//| typing "30 pips" on gold then gets a stop ten times tighter than |
//| they meant. The table encodes the usual retail convention. |
//| |
//| OPT-IN. GetPipSize() does not consult the table; a program |
//| calls ApplyBuiltInPipSize() for a symbol to adopt it, after any |
//| explicit override, and should show users the pip in force. |
//| Both products do; keeping one table keeps them in agreement. |
//| |
//| Matching is by PREFIX of the symbol name with leading non-letter |
//| characters stripped, case-insensitive: "XAUUSD.m", "#XAUUSD" and |
//| "GOLDmicro" match; "MYGOLD" does not. Prefix rather than |
//| substring, because a substring match on "DOW" or "CAC" would |
//| catch unrelated names. |
//| |
//| A prefix alone is not enough. MetaQuotes-Demo lists exchange |
//| stocks and ETFs named BTCO, BTCW, ETHE, ETHU, DJIA (observed |
//| 2026-10-14); a prefix rule gave each of them a 1.0 pip. So the |
//| table applies only to forex and CFD calculation modes, and |
//| crypto needs the quote currency in the name (BTCUSD, ETHEUR). |
//| |
//+------------------------------------------------------------------+
#ifndef STOPFIRST_PIPTABLE_MQH
#define STOPFIRST_PIPTABLE_MQH
#include "Symbol.mqh" // SetPipSize - the table only feeds the override
//+------------------------------------------------------------------+
//| Upper-case a symbol and drop leading characters that are not |
//| letters or digits ("#US30" -> "US30") |
//| Returns: the cleaned name. |
//+------------------------------------------------------------------+
string PipTableKey(const string symbol)
{
string name = symbol;
StringToUpper(name);
int start = 0;
int length = StringLen(name);
while(start < length)
{
ushort c = StringGetCharacter(name, start);
bool alnum = (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
if(alnum) break;
start++;
}
return StringSubstr(name, start);
}
bool PipTableStartsWith(const string text, const string head)
{
return StringFind(text, head) == 0;
}
//+------------------------------------------------------------------+
//| Conventional pip size for a symbol the table knows |
//| |
//| Returns: the pip size in price units, or 0 when the symbol is not |
//| in the table, or when the table value is finer than the |
//| symbol's own point (a quote too coarse for the |
//| convention - the automatic rule is then the honest one). |
//+------------------------------------------------------------------+
double BuiltInPipSize(const string symbol)
{
//--- exchange-traded instruments (stocks, ETFs, futures, bonds) are
//--- quoted in plain currency units; the CFD conventions below would
//--- be wrong for every one of them
ENUM_SYMBOL_CALC_MODE mode =
(ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);
if(mode != SYMBOL_CALC_MODE_FOREX && mode != SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE &&
mode != SYMBOL_CALC_MODE_CFD && mode != SYMBOL_CALC_MODE_CFDINDEX &&
mode != SYMBOL_CALC_MODE_CFDLEVERAGE)
return 0;
string key = PipTableKey(symbol);
double pip = 0;
//--- precious metals
if(PipTableStartsWith(key, "XAU") || PipTableStartsWith(key, "GOLD"))
pip = 0.1;
else if(PipTableStartsWith(key, "XAG") || PipTableStartsWith(key, "SILVER"))
pip = 0.01;
else if(PipTableStartsWith(key, "XPT") || PipTableStartsWith(key, "XPD"))
pip = 0.1;
//--- energy
else if(PipTableStartsWith(key, "USOIL") || PipTableStartsWith(key, "UKOIL") ||
PipTableStartsWith(key, "WTI") || PipTableStartsWith(key, "BRENT") ||
PipTableStartsWith(key, "XTI") || PipTableStartsWith(key, "XBR"))
pip = 0.01;
else if(PipTableStartsWith(key, "XNG") || PipTableStartsWith(key, "NGAS") ||
PipTableStartsWith(key, "NATGAS"))
pip = 0.001;
//--- equity indices: one index point
else if(PipTableStartsWith(key, "US30") || PipTableStartsWith(key, "DJ30") ||
PipTableStartsWith(key, "WS30") || PipTableStartsWith(key, "DJI") ||
PipTableStartsWith(key, "US100") || PipTableStartsWith(key, "NAS100") ||
PipTableStartsWith(key, "USTEC") || PipTableStartsWith(key, "NDX") ||
PipTableStartsWith(key, "US500") || PipTableStartsWith(key, "SPX500") ||
PipTableStartsWith(key, "SP500") || PipTableStartsWith(key, "US2000") ||
PipTableStartsWith(key, "GER40") || PipTableStartsWith(key, "GER30") ||
PipTableStartsWith(key, "DE40") || PipTableStartsWith(key, "DE30") ||
PipTableStartsWith(key, "UK100") || PipTableStartsWith(key, "FTSE") ||
PipTableStartsWith(key, "JP225") || PipTableStartsWith(key, "JPN225") ||
PipTableStartsWith(key, "NIKKEI") || PipTableStartsWith(key, "FRA40") ||
PipTableStartsWith(key, "F40") || PipTableStartsWith(key, "EU50") ||
PipTableStartsWith(key, "STOXX50")|| PipTableStartsWith(key, "AUS200") ||
PipTableStartsWith(key, "HK50") || PipTableStartsWith(key, "ESP35") ||
PipTableStartsWith(key, "SPA35"))
pip = 1.0;
//--- crypto: one unit of the quote currency. The quote currency must
//--- be in the name - a bare "BTC..." prefix also matches ETF tickers
else if(PipTableStartsWith(key, "BTCUSD") || PipTableStartsWith(key, "BTCEUR") ||
PipTableStartsWith(key, "BTCUSDT") || PipTableStartsWith(key, "ETHUSD") ||
PipTableStartsWith(key, "ETHEUR"))
pip = 1.0;
if(pip <= 0) return 0;
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
if(point <= 0 || pip < point - 1e-12) return 0;
return pip;
}
//+------------------------------------------------------------------+
//| Adopt the conventional pip size for a symbol, if the table has one|
//| |
//| Parameters: |
//| symbol - "" for the chart symbol |
//| |
//| Returns: true if the table set the pip size through SetPipSize(). |
//| false, leaving GetPipSize() unchanged, when the symbol is |
//| not in the table. |
//+------------------------------------------------------------------+
bool ApplyBuiltInPipSize(string symbol = "")
{
if(symbol == "") symbol = _Symbol;
double pip = BuiltInPipSize(symbol);
if(pip <= 0) return false;
SetPipSize(symbol, pip);
return true;
}
#endif // STOPFIRST_PIPTABLE_MQH
//+------------------------------------------------------------------+