Skip to content

MT5Service - Symbol Methods (Mid-Level API)ΒΆ

13 methods for working with symbols and their parameters with clean Go types

🧩 API Layer: MID-LEVEL - wrappers over MT5Account with convenient DTO structures

Implementation:

These methods are implemented in examples/mt5/MT5Service.go, which wraps package/Helpers/MT5Account.go low-level API with convenient helpers for ease of use.

Demo files:

  • examples/demos/service/04_service_demo.go - comprehensive examples of all service wrapper methods
  • examples/demos/service/05_service_streaming.go - streaming methods examples

🎯 Why These Methods Exist¢

Problem: In MT5Account, to get symbol parameters you need to make multiple calls:

// Low-level (MT5Account) - 3 calls for 3 parameters:
bidData, _ := account.SymbolInfoDouble(ctx, &pb.SymbolInfoDoubleRequest{
    Symbol: "EURUSD",
    Type:   pb.SymbolInfoDoubleProperty_SYMBOL_BID,
})
bid := bidData.Value  // ← unpacking

askData, _ := account.SymbolInfoDouble(ctx, &pb.SymbolInfoDoubleRequest{
    Symbol: "EURUSD",
    Type:   pb.SymbolInfoDoubleProperty_SYMBOL_ASK,
})
ask := askData.Value  // ← unpacking

digitsData, _ := account.SymbolInfoInteger(ctx, &pb.SymbolInfoIntegerRequest{
    Symbol: "EURUSD",
    Type:   pb.SymbolInfoIntegerProperty_SYMBOL_DIGITS,
})
digits := digitsData.Value  // ← unpacking

Solution: MT5Service provides direct methods and batch operations:

// Mid-level (MT5Service) - 1 call for all parameters:
symbols, _, _ := service.GetSymbolParamsMany(ctx, nil, nil, nil, nil)
for _, s := range symbols {
    fmt.Printf("%s: Bid=%.5f, Ask=%.5f, Digits=%d\n",
        s.Name, s.Bid, s.Ask, s.Digits)
}

Advantages:

  • βœ… One GetSymbolParamsMany call instead of 10+ SymbolInfo* calls
  • βœ… Returns clean Go types (float64, int64, string)
  • βœ… SymbolTick with time.Time (not Unix timestamp)
  • βœ… SessionTime with time.Time (not protobuf Timestamp)
  • βœ… Automatic timestamp conversion

πŸ“‹ All 13 MethodsΒΆ

Method Returns Low-Level Equivalent
GetSymbolsTotal(ctx, selectedOnly) int32 SymbolsTotal(ctx, req) + .Total
SymbolExist(ctx, symbol) (bool, bool) SymbolExist(ctx, req) + .Exists, .IsCustom
GetSymbolName(ctx, index, selectedOnly) string SymbolName(ctx, req) + .Name
SymbolSelect(ctx, symbol, select_) bool SymbolSelect(ctx, req) + .Success
IsSymbolSynchronized(ctx, symbol) bool SymbolIsSynchronized(ctx, req) + .Synchronized
GetSymbolDouble(ctx, symbol, property) float64 SymbolInfoDouble(ctx, req) + .Value
GetSymbolInteger(ctx, symbol, property) int64 SymbolInfoInteger(ctx, req) + .Value
GetSymbolString(ctx, symbol, property) string SymbolInfoString(ctx, req) + .Value
GetSymbolMarginRate(ctx, symbol, orderType) *SymbolMarginRate SymbolInfoMarginRate(ctx, req) + unpacking
GetSymbolTick(ctx, symbol) *SymbolTick SymbolInfoTick(ctx, req) + time.Time conversion
GetSymbolSessionQuote(ctx, symbol, day, idx) *SessionTime SymbolInfoSessionQuote(ctx, req) + .AsTime()
GetSymbolSessionTrade(ctx, symbol, day, idx) *SessionTime SymbolInfoSessionTrade(ctx, req) + .AsTime()
GetSymbolParamsMany(ctx, name, sort, page, perPage) []SymbolParams SymbolParamsMany(ctx, req) + unpacking

πŸ“¦ DTO StructuresΒΆ

SymbolParamsΒΆ

type SymbolParams struct {
    Name                 string  // Symbol name (EURUSD, GBPUSD, etc.)
    Bid                  float64 // Current Bid price
    Ask                  float64 // Current Ask price
    Last                 float64 // Last deal price
    Point                float64 // Point size (minimal price change)
    Digits               int32   // Number of decimal places
    Spread               int32   // Current spread in points
    VolumeMin            float64 // Minimum volume for trading
    VolumeMax            float64 // Maximum volume for trading
    VolumeStep           float64 // Volume step
    TradeTickSize        float64 // Trade tick size
    TradeTickValue       float64 // Trade tick value
    TradeContractSize    float64 // Contract size
    SwapLong             float64 // Swap for long positions
    SwapShort            float64 // Swap for short positions
    MarginInitial        float64 // Initial margin requirement
    MarginMaintenance    float64 // Maintenance margin requirement
}

Advantage: All important symbol parameters in one structure.

SymbolTickΒΆ

type SymbolTick struct {
    Time       time.Time // Tick time (already converted from Unix)
    Bid        float64   // Current Bid price
    Ask        float64   // Current Ask price
    Last       float64   // Last deal price
    Volume     uint64    // Tick volume
    TimeMS     int64     // Tick time in milliseconds
    Flags      uint32    // Tick flags
    VolumeReal float64   // Tick volume with decimal precision
}

Advantage: Time is already time.Time, no manual conversion from Unix timestamp needed.

SymbolMarginRateΒΆ

type SymbolMarginRate struct {
    InitialMarginRate     float64 // Initial margin rate
    MaintenanceMarginRate float64 // Maintenance margin rate
}

SessionTimeΒΆ

type SessionTime struct {
    From time.Time // Session start time (already converted)
    To   time.Time // Session end time (already converted)
}

Advantage: From/To are already time.Time, no .AsTime() calls needed.


πŸ“– Method SignaturesΒΆ

1) GetSymbolsTotalΒΆ

func (s *MT5Service) GetSymbolsTotal(
    ctx context.Context,
    selectedOnly bool,
) (int32, error)

Returns the number of available symbols.

  • selectedOnly=true - only symbols in Market Watch
  • selectedOnly=false - all symbols

2) SymbolExistΒΆ

func (s *MT5Service) SymbolExist(
    ctx context.Context,
    symbol string,
) (bool, bool, error)

Checks if a symbol exists in the terminal.

Returns: (exists, isCustom, error)


3) GetSymbolNameΒΆ

func (s *MT5Service) GetSymbolName(
    ctx context.Context,
    index int32,
    selectedOnly bool,
) (string, error)

Gets symbol name by index.


4) SymbolSelectΒΆ

func (s *MT5Service) SymbolSelect(
    ctx context.Context,
    symbol string,
    select_ bool,
) (bool, error)

Adds/removes a symbol to/from Market Watch.

  • select_=true - add
  • select_=false - remove

5) IsSymbolSynchronizedΒΆ

func (s *MT5Service) IsSymbolSynchronized(
    ctx context.Context,
    symbol string,
) (bool, error)

Checks if symbol data is synchronized with the server.


6-8) GetSymbolDouble / GetSymbolInteger / GetSymbolStringΒΆ

func (s *MT5Service) GetSymbolDouble(
    ctx context.Context,
    symbol string,
    property pb.SymbolInfoDoubleProperty,
) (float64, error)

func (s *MT5Service) GetSymbolInteger(
    ctx context.Context,
    symbol string,
    property pb.SymbolInfoIntegerProperty,
) (int64, error)

func (s *MT5Service) GetSymbolString(
    ctx context.Context,
    symbol string,
    property pb.SymbolInfoStringProperty,
) (string, error)

Get a single symbol property by ID.

Available Double properties:

  • SYMBOL_BID - Bid price
  • SYMBOL_ASK - Ask price
  • SYMBOL_POINT - point size
  • SYMBOL_VOLUME_MIN - minimum volume
  • SYMBOL_VOLUME_MAX - maximum volume

Available Integer properties:

  • SYMBOL_DIGITS - number of decimal places
  • SYMBOL_SPREAD - spread in points
  • SYMBOL_TRADE_MODE - trading mode

Available String properties:

  • SYMBOL_DESCRIPTION - symbol description
  • SYMBOL_PATH - path in symbols tree

9) GetSymbolMarginRateΒΆ

func (s *MT5Service) GetSymbolMarginRate(
    ctx context.Context,
    symbol string,
    orderType pb.ENUM_ORDER_TYPE,
) (*SymbolMarginRate, error)

Gets margin rates for a symbol and order type.


10) GetSymbolTickΒΆ

func (s *MT5Service) GetSymbolTick(
    ctx context.Context,
    symbol string,
) (*SymbolTick, error)

Gets the last tick for a symbol.

Advantage: Time is already time.Time, no manual conversion needed.


11-12) GetSymbolSessionQuote / GetSymbolSessionTradeΒΆ

func (s *MT5Service) GetSymbolSessionQuote(
    ctx context.Context,
    symbol string,
    dayOfWeek pb.DayOfWeek,
    sessionIndex uint32,
) (*SessionTime, error)

func (s *MT5Service) GetSymbolSessionTrade(
    ctx context.Context,
    symbol string,
    dayOfWeek pb.DayOfWeek,
    sessionIndex uint32,
) (*SessionTime, error)

Get trading/quote session times.

Advantage: From/To are already time.Time, no .AsTime() calls needed.


13) GetSymbolParamsManyΒΆ

func (s *MT5Service) GetSymbolParamsMany(
    ctx context.Context,
    symbolName *string,
    sortType *pb.AH_SYMBOL_PARAMS_MANY_SORT_TYPE,
    pageNumber *int32,
    itemsPerPage *int32,
) ([]SymbolParams, int32, error)

RECOMMENDED method - gets parameters for multiple symbols in one call.

Returns: (symbols []SymbolParams, total int32, error)

Parameters (all optional):

  • symbolName - name filter (nil = all symbols)
  • sortType - sort type (nil = default)
  • pageNumber - page number (nil = 1)
  • itemsPerPage - items per page (nil = all)

πŸ’‘ Usage ExamplesΒΆ

Example 1: Getting Current Price (Bid/Ask)ΒΆ

// ❌ BEFORE (MT5Account) - 2 calls, 6 lines:
bidReq := &pb.SymbolInfoDoubleRequest{
    Symbol: "EURUSD",
    Type:   pb.SymbolInfoDoubleProperty_SYMBOL_BID,
}
bidData, _ := account.SymbolInfoDouble(ctx, bidReq)
bid := bidData.Value

askReq := &pb.SymbolInfoDoubleRequest{
    Symbol: "EURUSD",
    Type:   pb.SymbolInfoDoubleProperty_SYMBOL_ASK,
}
askData, _ := account.SymbolInfoDouble(ctx, askReq)
ask := askData.Value

fmt.Printf("EURUSD: Bid=%.5f, Ask=%.5f\n", bid, ask)

// βœ… AFTER (MT5Service) - 1 GetSymbolTick call, 3 lines:
tick, _ := service.GetSymbolTick(ctx, "EURUSD")
fmt.Printf("EURUSD: Bid=%.5f, Ask=%.5f\n", tick.Bid, tick.Ask)
fmt.Printf("Time: %s\n", tick.Time.Format("15:04:05"))

Code reduction: 60% (10 lines β†’ 4 lines)


Example 2: Getting All Symbol ParametersΒΆ

// ❌ BEFORE (MT5Account) - 10+ calls for different properties:
bidData, _ := account.SymbolInfoDouble(ctx, &pb.SymbolInfoDoubleRequest{
    Symbol: "EURUSD",
    Type:   pb.SymbolInfoDoubleProperty_SYMBOL_BID,
})
askData, _ := account.SymbolInfoDouble(ctx, &pb.SymbolInfoDoubleRequest{
    Symbol: "EURUSD",
    Type:   pb.SymbolInfoDoubleProperty_SYMBOL_ASK,
})
digitsData, _ := account.SymbolInfoInteger(ctx, &pb.SymbolInfoIntegerRequest{
    Symbol: "EURUSD",
    Type:   pb.SymbolInfoIntegerProperty_SYMBOL_DIGITS,
})
// ... 7 more calls for other properties

// βœ… AFTER (MT5Service) - 1 GetSymbolParamsMany call:
symbolName := "EURUSD"
symbols, _, _ := service.GetSymbolParamsMany(ctx, &symbolName, nil, nil, nil)
if len(symbols) > 0 {
    s := symbols[0]
    fmt.Printf("Symbol: %s\n", s.Name)
    fmt.Printf("Bid: %.5f, Ask: %.5f\n", s.Bid, s.Ask)
    fmt.Printf("Digits: %d, Spread: %d\n", s.Digits, s.Spread)
    fmt.Printf("Volume: %.2f - %.2f (step: %.2f)\n",
        s.VolumeMin, s.VolumeMax, s.VolumeStep)
    fmt.Printf("Swap Long: %.2f, Short: %.2f\n", s.SwapLong, s.SwapShort)
}

Code reduction: 70% (30+ lines β†’ 9 lines)


Example 3: Getting List of All SymbolsΒΆ

// βœ… MT5Service - get all symbols in one call
symbols, total, err := service.GetSymbolParamsMany(ctx, nil, nil, nil, nil)
if err != nil {
    return err
}

fmt.Printf("Total symbols: %d\n", total)
for i, s := range symbols {
    fmt.Printf("%d. %s: Bid=%.5f, Ask=%.5f, Digits=%d\n",
        i+1, s.Name, s.Bid, s.Ask, s.Digits)
}

Example 4: Filtering Symbols with High SpreadΒΆ

// βœ… MT5Service - filter symbols by spread
symbols, _, err := service.GetSymbolParamsMany(ctx, nil, nil, nil, nil)
if err != nil {
    return err
}

fmt.Println("Symbols with spread > 10 points:")
for _, s := range symbols {
    if s.Spread > 10 {
        fmt.Printf("%s: Spread=%d points (%.5f)\n",
            s.Name, s.Spread, float64(s.Spread)*s.Point)
    }
}

Example 5: Checking Symbol Availability for TradingΒΆ

// βœ… MT5Service - comprehensive symbol check
func IsSymbolTradeable(service *mt5.MT5Service, symbol string) (bool, error) {
    ctx := context.Background()

    // 1. Check existence
    exists, isCustom, err := service.SymbolExist(ctx, symbol)
    if err != nil {
        return false, err
    }
    if !exists {
        fmt.Printf("❌ Symbol %s does not exist\n", symbol)
        return false, nil
    }
    if isCustom {
        fmt.Printf("⚠️ Symbol %s is custom\n", symbol)
    }

    // 2. Add to Market Watch (if needed)
    success, err := service.SymbolSelect(ctx, symbol, true)
    if err != nil || !success {
        fmt.Printf("❌ Cannot add %s to Market Watch\n", symbol)
        return false, err
    }

    // 3. Check synchronization
    synced, err := service.IsSymbolSynchronized(ctx, symbol)
    if err != nil || !synced {
        fmt.Printf("❌ Symbol %s is not synchronized\n", symbol)
        return false, err
    }

    // 4. Check trading parameters
    symbolName := symbol
    symbols, _, err := service.GetSymbolParamsMany(ctx, &symbolName, nil, nil, nil)
    if err != nil || len(symbols) == 0 {
        return false, err
    }

    s := symbols[0]
    if s.VolumeMin <= 0 || s.VolumeMax <= 0 {
        fmt.Printf("❌ Symbol %s has invalid volume limits\n", symbol)
        return false, nil
    }

    fmt.Printf("βœ… Symbol %s is tradeable:\n", symbol)
    fmt.Printf("   Bid=%.5f, Ask=%.5f\n", s.Bid, s.Ask)
    fmt.Printf("   Volume: %.2f - %.2f (step: %.2f)\n",
        s.VolumeMin, s.VolumeMax, s.VolumeStep)
    fmt.Printf("   Spread: %d points\n", s.Spread)

    return true, nil
}

Example 6: Calculating Pip ValueΒΆ

// βœ… MT5Service - calculate pip value
symbolName := "EURUSD"
symbols, _, _ := service.GetSymbolParamsMany(ctx, &symbolName, nil, nil, nil)
if len(symbols) == 0 {
    return fmt.Errorf("symbol not found")
}

s := symbols[0]
volume := 1.0 // 1 lot

// Pip value = TradeTickValue * Volume
pipValue := s.TradeTickValue * volume
fmt.Printf("Symbol: %s\n", s.Name)
fmt.Printf("Point: %.5f\n", s.Point)
fmt.Printf("Pip value (1 lot): %.2f USD\n", pipValue)
fmt.Printf("Contract size: %.0f\n", s.TradeContractSize)

πŸ”§ When to UseΒΆ

Use when:

  • Need multiple parameters for one symbol
  • Getting a list of symbols (all or filtered)
  • Building a table/list of symbols
  • Need pagination for large lists

Example:

symbols, total, _ := service.GetSymbolParamsMany(ctx, nil, nil, nil, nil)
fmt.Printf("Found %d symbols\n", total)

βœ… GetSymbolTickΒΆ

Use when:

  • Need current price (Bid/Ask)
  • Need last tick with timestamp
  • Checking quote freshness

Example:

tick, _ := service.GetSymbolTick(ctx, "EURUSD")
fmt.Printf("Current: Bid=%.5f, Ask=%.5f\n", tick.Bid, tick.Ask)


βœ… GetSymbolDouble/Integer/StringΒΆ

Use when:

  • Need one specific property
  • Making a point check
  • GetSymbolParamsMany is overkill

Example:

spread, _ := service.GetSymbolInteger(ctx, "EURUSD",
    pb.SymbolInfoIntegerProperty_SYMBOL_SPREAD)

βœ… SymbolExist / SymbolSelect / IsSymbolSynchronizedΒΆ

Use when:

  • Checking symbol existence
  • Adding symbol to Market Watch
  • Checking data readiness for trading

πŸ“Š Performance ComparisonΒΆ

Task Low-Level (lines of code) Mid-Level (lines of code) Reduction
Get Bid/Ask 6-8 lines 2-3 lines 60-70%
Get all symbol parameters 30-40 lines 5-10 lines 70-80%
Get list of all symbols 50+ lines 5-10 lines 80-90%
Check symbol 10-15 lines 3-5 lines 60-70%

πŸ’‘ RecommendationsΒΆ

  1. For multiple properties β†’ use GetSymbolParamsMany instead of multiple GetSymbolDouble/Integer calls
  2. For current price β†’ use GetSymbolTick (Bid/Ask + timestamp in one call)
  3. Before trading β†’ check SymbolExist + IsSymbolSynchronized
  4. For batch operations β†’ use GetSymbolParamsMany with pagination
  5. For filtering β†’ get all symbols via GetSymbolParamsMany, then filter in code

"One Request Instead of Many" Pattern:

// ❌ BAD - 10 calls for 10 parameters
bid, _ := service.GetSymbolDouble(ctx, "EURUSD", SYMBOL_BID)
ask, _ := service.GetSymbolDouble(ctx, "EURUSD", SYMBOL_ASK)
// ... 8 more calls

// βœ… GOOD - 1 call for all parameters
symbolName := "EURUSD"
symbols, _, _ := service.GetSymbolParamsMany(ctx, &symbolName, nil, nil, nil)
s := symbols[0]  // Everything in one structure



🎯 Summary¢

MT5Service Symbol methods solve the main task - eliminate multiple calls:

  • ❌ No need for 10+ SymbolInfo* calls for all parameters
  • ❌ No need to call .Value for each property
  • ❌ No need to convert Unix timestamp to time.Time
  • βœ… Get all symbol parameters in one GetSymbolParamsMany call
  • βœ… SymbolTick and SessionTime with ready time.Time
  • βœ… Code reads like normal Go
  • βœ… Batch operations with pagination