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>
162 lines
7.9 KiB
MQL5
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
|
|
//+------------------------------------------------------------------+
|