β
Get Symbol Digits (GetDigitsAsync)ΒΆ
Sugar method: Gets number of decimal places for symbol prices. Simple wrapper for
SymbolInfoIntegerAsync(SymbolDigits)with int conversion.
API Information:
- Extension method:
MT5Service.GetDigitsAsync(...)(fromMT5ServiceExtensions) - Package: Part of
mt5_term_apilibrary - Underlying calls:
SymbolInfoIntegerAsync(SymbolDigits)
Method SignatureΒΆ
public static class MT5ServiceExtensions
{
public static async Task<int> GetDigitsAsync(
this MT5Service svc,
string symbol,
int timeoutSec = 10,
CancellationToken ct = default);
}
π½ InputΒΆ
| Parameter | Type | Description |
|---|---|---|
svc |
MT5Service |
MT5Service instance (extension method) |
symbol |
string |
Symbol name (e.g., "EURUSD") |
timeoutSec |
int |
Timeout in seconds (default: 10) |
ct |
CancellationToken |
Cancellation token |
β¬οΈ Output β intΒΆ
Returns the number of decimal places (digits) for symbol prices.
Examples:
- EURUSD:
5(prices like 1.10000) - USDJPY:
3(prices like 149.123) - GOLD:
2(prices like 2050.12)
Exception: Throws OverflowException if value doesn't fit in int (extremely rare).
π¬ Just the essentialsΒΆ
- What it is. One-liner to get symbol decimal precision - how many digits after decimal point for prices.
- Why you need it. Essential for formatting prices correctly, rounding calculations, and displaying prices to users.
- Sanity check. Returns small integer like 5 (for EURUSD) or 3 (for USDJPY). Use for FORMATTING only, NOT for calculations.
π― PurposeΒΆ
Use it for price formatting:
- Format prices for display.
- Round prices to correct precision.
- Validate price strings.
- Format order parameters.
- Build price display templates.
π§© Notes & TipsΒΆ
- Digits vs Point: Digits is for FORMATTING (display), Point is for CALCULATIONS. Never use digits for calculating SL/TP.
- Format strings: Use
price.ToString($"F{digits}")to format prices correctly. - Rounding: Use
Math.Round(price, digits)to round to correct precision. - Not for calculations: Don't use
Math.Pow(10, -digits)for calculations. UseGetPointAsync()instead. - Caching: Digits don't change during session. Cache if calling frequently.
- 5-digit vs 4-digit brokers: Modern brokers use 5 digits (EURUSD), old brokers used 4 digits.
π§ Under the HoodΒΆ
This sugar method wraps a low-level call with type conversion:
var deadline = DateTime.UtcNow.AddSeconds(timeoutSec);
// Get SYMBOL_DIGITS property (returns int64)
var result = await svc.SymbolInfoIntegerAsync(symbol,
SymbolInfoIntegerProperty.SymbolDigits, deadline, ct);
// Convert int64 to int with overflow check
long value = result.Value;
if (value > int.MaxValue || value < int.MinValue)
throw new OverflowException($"SymbolDigits={value} does not fit into int.");
return (int)value;
What it improves:
- Simpler call - no need to specify property enum
- Automatic deadline - just pass timeout in seconds
- Safe int conversion - handles overflow gracefully
- Returns int directly - not int64, easier to use
π Low-Level AlternativeΒΆ
WITHOUT sugar:
var deadline = DateTime.UtcNow.AddSeconds(10);
var result = await svc.SymbolInfoIntegerAsync("EURUSD",
SymbolInfoIntegerProperty.SymbolDigits, deadline, ct);
long digitsLong = result.Value;
int digits = (int)digitsLong; // Unsafe cast!
WITH sugar:
Benefits:
- β 3 lines β 1 line
- β No enum lookup needed
- β Safe int64βint conversion
- β Auto deadline management
π Usage ExamplesΒΆ
1) Basic digits retrievalΒΆ
// svc β MT5Service instance
var digits = await svc.GetDigitsAsync("EURUSD");
Console.WriteLine($"EURUSD digits: {digits}");
// Output: EURUSD digits: 5
2) Format price for displayΒΆ
var digits = await svc.GetDigitsAsync("EURUSD");
double price = 1.100005;
string formatted = price.ToString($"F{digits}");
Console.WriteLine($"Raw price: {price}");
Console.WriteLine($"Formatted price: {formatted}");
// Output:
// Raw price: 1.100005
// Formatted price: 1.10001
3) Round price to correct precisionΒΆ
var digits = await svc.GetDigitsAsync("GBPUSD");
double rawPrice = 1.250000123456;
double rounded = Math.Round(rawPrice, digits);
Console.WriteLine($"Raw: {rawPrice}");
Console.WriteLine($"Rounded: {rounded}");
Console.WriteLine($"Display: {rounded.ToString($"F{digits}")}");
4) Compare digits across symbolsΒΆ
string[] symbols = { "EURUSD", "GBPUSD", "USDJPY", "GOLD", "BTCUSD" };
Console.WriteLine("Symbol Digits:");
Console.WriteLine("βββββββββββββββββββββββββββββββββ");
foreach (var symbol in symbols)
{
var digits = await svc.GetDigitsAsync(symbol);
var samplePrice = digits == 5 ? "1.10000" :
digits == 3 ? "149.123" :
digits == 2 ? "2050.12" : "0.00";
Console.WriteLine($"{symbol,-10} {digits} digits (e.g., {samplePrice})");
}
5) Validate price stringΒΆ
var digits = await svc.GetDigitsAsync("EURUSD");
string priceStr = "1.10005";
bool isValid = false;
if (double.TryParse(priceStr, out double price))
{
// Check if price has correct number of decimal places
string[] parts = priceStr.Split('.');
if (parts.Length == 2 && parts[1].Length == digits)
{
isValid = true;
}
}
Console.WriteLine($"Price: {priceStr}");
Console.WriteLine($"Valid: {isValid}");
6) Create price format templateΒΆ
var digits = await svc.GetDigitsAsync("EURUSD");
// Create reusable format string
string formatTemplate = $"F{digits}";
// Use for multiple prices
double[] prices = { 1.10000, 1.10050, 1.10100 };
Console.WriteLine("Formatted Prices:");
foreach (var price in prices)
{
Console.WriteLine($" {price.ToString(formatTemplate)}");
}
7) Determine pip positionΒΆ
var digits = await svc.GetDigitsAsync("EURUSD");
// For 5-digit pairs, pip is 4th digit (index 3 from right)
// For 3-digit pairs, pip is 2nd digit (index 1 from right)
int pipPosition = digits - 1;
Console.WriteLine($"Symbol: EURUSD");
Console.WriteLine($"Digits: {digits}");
Console.WriteLine($"Pip position: {pipPosition}th digit from right");
if (digits == 5)
{
Console.WriteLine("Example: 1.10[0]05 - pip digit in brackets");
}
8) Format prices in tableΒΆ
var symbols = new[] { "EURUSD", "USDJPY", "GOLD" };
var prices = new[] { 1.10000, 149.123, 2050.12 };
Console.WriteLine("Symbol Price");
Console.WriteLine("βββββββββββββββββββββ");
for (int i = 0; i < symbols.Length; i++)
{
var digits = await svc.GetDigitsAsync(symbols[i]);
var formatted = prices[i].ToString($"F{digits}");
Console.WriteLine($"{symbols[i],-10} {formatted,10}");
}
9) Calculate decimal multiplier (for display)ΒΆ
var digits = await svc.GetDigitsAsync("EURUSD");
// Calculate multiplier for decimal conversions (display only!)
double multiplier = Math.Pow(10, digits);
double price = 1.10005;
long priceAsInt = (long)(price * multiplier);
Console.WriteLine($"Digits: {digits}");
Console.WriteLine($"Multiplier: {multiplier}");
Console.WriteLine($"Price: {price}");
Console.WriteLine($"As integer: {priceAsInt}");
// WARNING: Don't use this for trading calculations!
10) Smart price rounding utilityΒΆ
async Task<double> SmartRound(string symbol, double price)
{
var digits = await svc.GetDigitsAsync(symbol);
return Math.Round(price, digits);
}
// Usage
double rawPrice1 = 1.100005123;
double rawPrice2 = 149.123456789;
double rounded1 = await SmartRound("EURUSD", rawPrice1);
double rounded2 = await SmartRound("USDJPY", rawPrice2);
Console.WriteLine($"EURUSD: {rawPrice1} β {rounded1}");
Console.WriteLine($"USDJPY: {rawPrice2} β {rounded2}");
π Related MethodsΒΆ
π¦ Low-level method used internally:
SymbolInfoIntegerAsync(SymbolDigits)- Direct digits query (this is what GetDigitsAsync wraps)
π¬ Other sugar methods:
GetPointAsync()- Get symbol point size (use this for calculations, not digits!)GetSymbolSnapshot()- Get point, digits, tick, and margin in one callNormalizePriceAsync()- Normalize price to tick sizePointsToPipsAsync()- Convert points to pips (uses digits internally for conversion factor)
β οΈ Common PitfallsΒΆ
-
Using digits for price calculations
// β WRONG - using digits to calculate point var digits = await svc.GetDigitsAsync("EURUSD"); double point = Math.Pow(10, -digits); // DON'T DO THIS! double slPrice = entry - (100 * point); // β CORRECT - use point directly var point = await svc.GetPointAsync("EURUSD"); double slPrice = entry - (100 * point); -
Assuming all FX pairs have 5 digits
-
Using digits for volume formatting
-
Confusing digits with point
-
Not rounding after calculations
// β WRONG - calculated price has wrong precision var point = await svc.GetPointAsync("EURUSD"); double slPrice = entry - (100 * point); // Might have rounding errors // β CORRECT - round to digits after calculation var point = await svc.GetPointAsync("EURUSD"); var digits = await svc.GetDigitsAsync("EURUSD"); double slPrice = Math.Round(entry - (100 * point), digits); -
Using digits to normalize prices