ππ Get Symbol Info (GetSymbolInfo)ΒΆ
Sugar method: Returns comprehensive symbol information in one convenient structure.
API Information:
- Method:
sugar.GetSymbolInfo(symbol) - Timeout: 10 seconds
- Returns: SymbolInfo structure with all parameters
π Method SignatureΒΆ
π½ Input / β¬οΈ OutputΒΆ
| Input | Type | Description |
|---|---|---|
symbol |
string |
Trading symbol (e.g., "EURUSD", "XAUUSD") |
| Output | Type | Description |
|---|---|---|
*SymbolInfo |
struct | Complete symbol information |
error |
error |
"symbol <name> not found", "GetSymbolInfo failed: ..." or "GetSymbolInfo failed: stop level: ..." |
π SymbolInfo StructureΒΆ
type SymbolInfo struct {
Name string // Symbol name (e.g., "EURUSD")
Bid float64 // Current BID price
Ask float64 // Current ASK price
Digits int32 // Number of decimal places
Point float64 // Point size (minimal price change)
VolumeMin float64 // Minimum volume for trading
VolumeMax float64 // Maximum volume for trading
VolumeStep float64 // Volume step
Spread int32 // Current spread in points
StopLevel int32 // Minimum stop level in points
ContractSize float64 // Contract size (for 1 lot)
}
π¬ Just the EssentialsΒΆ
- What it is: Get all important symbol parameters in one call.
- Why you need it: Validation before trading, position sizing, SL/TP calculations.
- Sanity check: More efficient than calling individual methods for each property.
- How it works: One
SymbolParamsManyquery filtered by the symbol name; the entry whoseNameequalssymbolexactly is used (the name filter may return similar names too; no exact match β errorsymbol <name> not found). Then oneSYMBOL_TRADE_STOPS_LEVELquery; if it fails, the error is returned (GetSymbolInfo failed: stop level: ...) -StopLevelis never a silent 0. Both share one 10-second timeout.
func (s *MT5Sugar) GetSymbolInfo(symbol string) (*SymbolInfo, error) {
ctx, cancel := context.WithTimeout(s.ctx, 10*time.Second)
defer cancel()
// Get symbol parameters using Service layer
symbolName := symbol
params, _, err := s.service.GetSymbolParamsMany(ctx, &symbolName, nil, nil, nil)
if err != nil {
return nil, fmt.Errorf("GetSymbolInfo failed: %w", err)
}
// Take the entry with exactly this name (the name filter may return similar names too).
var p *SymbolParams
for i := range params {
if params[i].Name == symbol {
p = ¶ms[i]
break
}
}
if p == nil {
return nil, fmt.Errorf("symbol %s not found", symbol)
}
// Get stop level (0 = no minimum distance; a failed request is an error, not a 0)
stopLevel, err := s.service.GetSymbolInteger(ctx, symbol, pb.SymbolInfoIntegerProperty_SYMBOL_TRADE_STOPS_LEVEL)
if err != nil {
return nil, fmt.Errorf("GetSymbolInfo failed: stop level: %w", err)
}
return &SymbolInfo{
Name: p.Name,
// ... Bid, Ask, Digits, Point, VolumeMin, VolumeMax, VolumeStep, Spread from p
StopLevel: int32(stopLevel),
ContractSize: p.TradeContractSize,
}, nil
}
π― When to UseΒΆ
β Before trading - Validate symbol parameters
β Position sizing - Calculate lot sizes with constraints
β SL/TP validation - Check stop level requirements
β Symbol comparison - Compare trading conditions
π Usage ExamplesΒΆ
1) Basic usage - get symbol infoΒΆ
info, err := sugar.GetSymbolInfo("EURUSD")
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Symbol: %s\n", info.Name)
fmt.Printf("Bid: %.5f\n", info.Bid)
fmt.Printf("Ask: %.5f\n", info.Ask)
fmt.Printf("Spread: %d points\n", info.Spread)
fmt.Printf("Digits: %d\n", info.Digits)
2) Validate symbol before tradingΒΆ
func ValidateSymbol(sugar *mt5.MT5Sugar, symbol string, volume float64) (bool, string) {
info, err := sugar.GetSymbolInfo(symbol)
if err != nil {
return false, fmt.Sprintf("symbol not found: %v", err)
}
// Check volume limits
if volume < info.VolumeMin {
return false, fmt.Sprintf("volume %.2f below minimum %.2f",
volume, info.VolumeMin)
}
if volume > info.VolumeMax {
return false, fmt.Sprintf("volume %.2f exceeds maximum %.2f",
volume, info.VolumeMax)
}
// Check volume step (with a tolerance: 0.1 / 0.01 = 10.000000000000002)
steps := volume / info.VolumeStep
if math.Abs(steps-math.Round(steps)) > 1e-6 {
return false, fmt.Sprintf("volume %.2f not multiple of step %.2f",
volume, info.VolumeStep)
}
return true, "validated"
}
// Usage:
valid, message := ValidateSymbol(sugar, "EURUSD", 0.1)
if valid {
fmt.Println("β
Symbol validated")
} else {
fmt.Printf("β Validation failed: %s\n", message)
}
3) Calculate SL/TP distancesΒΆ
info, _ := sugar.GetSymbolInfo("EURUSD")
// Calculate SL distance in price
stopLossPips := 20.0
slDistancePoints := stopLossPips * 10 // For 5-digit broker
// Check against stop level
if slDistancePoints < float64(info.StopLevel) {
fmt.Printf("β οΈ SL too close! Minimum: %d points\n", info.StopLevel)
slDistancePoints = float64(info.StopLevel)
}
slDistancePrice := slDistancePoints * info.Point
fmt.Printf("Symbol: %s\n", info.Name)
fmt.Printf("Point size: %.5f\n", info.Point)
fmt.Printf("Min stop level: %d points\n", info.StopLevel)
fmt.Printf("SL distance: %.5f price units\n", slDistancePrice)
4) Display trading conditionsΒΆ
info, _ := sugar.GetSymbolInfo("EURUSD")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Println("β TRADING CONDITIONS β")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Printf("Symbol: %s\n\n", info.Name)
fmt.Printf("Current Prices:\n")
fmt.Printf(" Bid: %.5f\n", info.Bid)
fmt.Printf(" Ask: %.5f\n", info.Ask)
fmt.Printf(" Spread: %d points\n\n", info.Spread)
fmt.Printf("Volume Limits:\n")
fmt.Printf(" Min: %.2f lots\n", info.VolumeMin)
fmt.Printf(" Max: %.2f lots\n", info.VolumeMax)
fmt.Printf(" Step: %.2f lots\n\n", info.VolumeStep)
fmt.Printf("Trading Info:\n")
fmt.Printf(" Digits: %d\n", info.Digits)
fmt.Printf(" Point: %.5f\n", info.Point)
fmt.Printf(" Stop level: %d points\n", info.StopLevel)
fmt.Printf(" Contract: %.0f\n", info.ContractSize)
5) Compare multiple symbolsΒΆ
symbols := []string{"EURUSD", "GBPUSD", "USDJPY"}
fmt.Println("Symbol Comparison:")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
for _, symbol := range symbols {
info, err := sugar.GetSymbolInfo(symbol)
if err != nil {
fmt.Printf("%s: Error - %v\n", symbol, err)
continue
}
spreadCost := float64(info.Spread) * info.Point
fmt.Printf("%-8s: Spread %d pts (%.5f), Min lot %.2f\n",
symbol, info.Spread, spreadCost, info.VolumeMin)
}
6) Calculate position valueΒΆ
info, _ := sugar.GetSymbolInfo("EURUSD")
volume := 1.0 // 1 lot
positionValue := volume * info.ContractSize
fmt.Printf("Symbol: %s\n", info.Name)
fmt.Printf("Volume: %.2f lots\n", volume)
fmt.Printf("Contract size: %.0f\n", info.ContractSize)
fmt.Printf("Position value: %.2f units of the base currency (EUR)\n", positionValue)
// Pip value (for 1 lot) in the QUOTE currency (USD for EURUSD; 1 pip = 10 points on 5 digits).
// For the account currency use SYMBOL_TRADE_TICK_VALUE, as CalculatePositionSize does.
pipValue := info.Point * 10 * info.ContractSize
fmt.Printf("Pip value: %.2f USD per lot\n", pipValue)
7) Round volume to valid stepΒΆ
func RoundVolumeToStep(volume float64, info *mt5.SymbolInfo) float64 {
// Round to nearest valid step
steps := volume / info.VolumeStep
roundedSteps := math.Round(steps)
rounded := roundedSteps * info.VolumeStep
// Clamp to min/max
if rounded < info.VolumeMin {
return info.VolumeMin
}
if rounded > info.VolumeMax {
return info.VolumeMax
}
return rounded
}
// Usage:
info, _ := sugar.GetSymbolInfo("EURUSD")
requestedVolume := 0.15 // Want 0.15 lots
validVolume := RoundVolumeToStep(requestedVolume, info)
fmt.Printf("Requested: %.2f lots\n", requestedVolume)
fmt.Printf("Valid: %.2f lots (step: %.2f)\n",
validVolume, info.VolumeStep)
8) Spread cost calculatorΒΆ
info, _ := sugar.GetSymbolInfo("EURUSD")
volume := 1.0 // 1 lot
// Spread in price units
spreadPrice := float64(info.Spread) * info.Point
// Spread cost for position, in the quote currency (USD for EURUSD)
spreadCost := spreadPrice * info.ContractSize * volume
fmt.Printf("Symbol: %s\n", info.Name)
fmt.Printf("Spread: %d points\n", info.Spread)
fmt.Printf("Volume: %.2f lots\n", volume)
fmt.Printf("Spread cost: $%.2f\n", spreadCost)
if spreadCost > 10 {
fmt.Println("β οΈ High spread - consider waiting")
}
9) Symbol quality checkerΒΆ
func AssessSymbolQuality(info *mt5.SymbolInfo) string {
issues := []string{}
// Check spread
if info.Spread > 30 {
issues = append(issues, "High spread")
}
// Check minimum volume
if info.VolumeMin > 0.01 {
issues = append(issues, "High minimum volume")
}
// Check stop level
if info.StopLevel > 50 {
issues = append(issues, "Large stop level restriction")
}
if len(issues) == 0 {
return "β
Excellent trading conditions"
} else if len(issues) == 1 {
return fmt.Sprintf("π‘ Good (%s)", issues[0])
} else {
return fmt.Sprintf("β οΈ Fair (%s)", strings.Join(issues, ", "))
}
}
// Usage:
info, _ := sugar.GetSymbolInfo("EURUSD")
assessment := AssessSymbolQuality(info)
fmt.Printf("%s: %s\n", info.Name, assessment)
10) Advanced symbol analyzerΒΆ
type SymbolAnalyzer struct {
Info *mt5.SymbolInfo
}
func NewSymbolAnalyzer(sugar *mt5.MT5Sugar, symbol string) (*SymbolAnalyzer, error) {
info, err := sugar.GetSymbolInfo(symbol)
if err != nil {
return nil, err
}
return &SymbolAnalyzer{Info: info}, nil
}
func (sa *SymbolAnalyzer) CalculatePipValue(volume float64) float64 {
// 5-/3-digit symbols: 1 pip = 10 points. Result is in the QUOTE currency
// (USD for EURUSD), not necessarily the account currency.
return sa.Info.Point * 10 * sa.Info.ContractSize * volume
}
func (sa *SymbolAnalyzer) CalculateSpreadCost(volume float64) float64 {
// In the quote currency, like CalculatePipValue
spreadPrice := float64(sa.Info.Spread) * sa.Info.Point
return spreadPrice * sa.Info.ContractSize * volume
}
func (sa *SymbolAnalyzer) ValidateVolume(volume float64) (float64, error) {
// Check minimum
if volume < sa.Info.VolumeMin {
return 0, fmt.Errorf("volume %.2f below minimum %.2f",
volume, sa.Info.VolumeMin)
}
// Check maximum
if volume > sa.Info.VolumeMax {
return 0, fmt.Errorf("volume %.2f exceeds maximum %.2f",
volume, sa.Info.VolumeMax)
}
// Round to step
steps := volume / sa.Info.VolumeStep
rounded := math.Round(steps) * sa.Info.VolumeStep
return rounded, nil
}
func (sa *SymbolAnalyzer) CalculateMinSLDistance() float64 {
// Minimum SL distance in price units
return float64(sa.Info.StopLevel) * sa.Info.Point
}
func (sa *SymbolAnalyzer) GenerateReport() {
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Println("β SYMBOL ANALYSIS REPORT β")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Printf("Symbol: %s\n\n", sa.Info.Name)
// Current market
fmt.Println("Market Snapshot:")
fmt.Printf(" Bid: %.5f\n", sa.Info.Bid)
fmt.Printf(" Ask: %.5f\n", sa.Info.Ask)
fmt.Printf(" Spread: %d points (%.5f)\n",
sa.Info.Spread, float64(sa.Info.Spread)*sa.Info.Point)
// Trading specs
fmt.Println("\nTrading Specifications:")
fmt.Printf(" Precision: %d decimals\n", sa.Info.Digits)
fmt.Printf(" Point: %.5f\n", sa.Info.Point)
fmt.Printf(" Stop level: %d points (%.5f)\n",
sa.Info.StopLevel, sa.CalculateMinSLDistance())
// Volume constraints
fmt.Println("\nVolume Constraints:")
fmt.Printf(" Minimum: %.2f lots\n", sa.Info.VolumeMin)
fmt.Printf(" Maximum: %.2f lots\n", sa.Info.VolumeMax)
fmt.Printf(" Step: %.2f lots\n", sa.Info.VolumeStep)
// Contract
fmt.Println("\nContract Information:")
fmt.Printf(" Size: %.0f units\n", sa.Info.ContractSize)
fmt.Printf(" Pip value: $%.2f per lot\n",
sa.CalculatePipValue(1.0))
// Cost analysis (1 lot)
fmt.Println("\nCost Analysis (1 lot):")
spreadCost := sa.CalculateSpreadCost(1.0)
fmt.Printf(" Spread cost: $%.2f\n", spreadCost)
// Assessment
fmt.Println("\nAssessment:")
if sa.Info.Spread <= 20 {
fmt.Println(" β
Low spread - good for scalping")
} else if sa.Info.Spread <= 50 {
fmt.Println(" π‘ Moderate spread - suitable for day trading")
} else {
fmt.Println(" β οΈ High spread - best for swing trading")
}
if sa.Info.VolumeMin <= 0.01 {
fmt.Println(" β
Micro lots available - good for small accounts")
}
if sa.Info.StopLevel <= 30 {
fmt.Println(" β
Low stop level - flexible SL/TP placement")
} else {
fmt.Println(" β οΈ High stop level - limits tight stops")
}
}
// Usage:
analyzer, _ := NewSymbolAnalyzer(sugar, "EURUSD")
analyzer.GenerateReport()
// Calculate for specific volume
pipValue := analyzer.CalculatePipValue(0.5)
fmt.Printf("\nPip value for 0.5 lots: $%.2f\n", pipValue)
π Related MethodsΒΆ
π¬ Individual properties:
GetBid()- Just BID priceGetAsk()- Just ASK priceGetSpread()- Just spreadGetSymbolDigits()- Just digitsGetMinStopLevel()- Just stop level
π¬ Symbol availability:
IsSymbolAvailable()- Check if tradeableGetAllSymbols()- List all symbols
β οΈ Common PitfallsΒΆ
1) Symbol name case sensitivityΒΆ
// β WRONG - case matters! The name must match exactly ("symbol eurusd not found")
info, _ := sugar.GetSymbolInfo("eurusd")
// β
CORRECT - use exact broker symbol name
info, _ := sugar.GetSymbolInfo("EURUSD")
2) Not checking volume stepΒΆ
// β WRONG - ignoring volume step
volume := 0.15 // Might not be valid!
// β
CORRECT - round to step
info, _ := sugar.GetSymbolInfo("EURUSD")
steps := math.Round(volume / info.VolumeStep)
validVolume := steps * info.VolumeStep
3) Confusing points and pipsΒΆ
// β WRONG - points β pips for 5-digit brokers
spread := info.Spread // This is in POINTS
// For EURUSD with 5 digits: 10 points = 1 pip
// β
CORRECT - convert if needed
spreadPips := float64(info.Spread) / 10.0 // For 5-digit
π Pro TipsΒΆ
-
Cache info - Symbol info changes rarely, can cache for efficiency
-
All-in-one - More efficient than multiple individual calls
-
Validation - Always validate volumes against VolumeMin/Max/Step
-
Stop level - Check StopLevel before placing tight SL/TP
-
Point size - Use Point for price calculations, not hardcoded values
π Important RelationshipsΒΆ
Price calculations:
- Spread in price = Spread points Γ Point size
- Pip value = Point Γ 10 Γ ContractSize (for 5-digit; in the quote currency)
- SL distance = SL points Γ Point size = (SL pips Γ 10) Γ Point size (5-digit)
Volume validation:
- Volume must be β₯ VolumeMin
- Volume must be β€ VolumeMax
- Volume must be multiple of VolumeStep
Stop validation:
- SL/TP distance must be β₯ StopLevel points
- StopLevel distance in price = StopLevel Γ Point
See also: GetAllSymbols.md, IsSymbolAvailable.md, GetMinStopLevel.md, GetSymbolDigits.md