//+------------------------------------------------------------------+ //| 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 //+------------------------------------------------------------------+