Skip to content

MT5Service - Position & Orders Methods (Mid-Level API)ΒΆ

5 methods for getting information about open positions, pending orders, and history

🧩 API Layer: MID-LEVEL - wrappers over MT5Account with clean Go types

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 positions and orders you need to work with protobuf structures:

// Low-level (MT5Account)
data, err := account.PositionsTotal(ctx)
total := data.TotalPositions  // ← unpacking

ordersData, err := account.OpenedOrders(ctx, &pb.OpenedOrdersRequest{...})
// ordersData.OpenedPositions - complex protobuf structure

Solution: MT5Service simplifies access and returns clean types:

// Mid-level (MT5Service)
total, err := service.GetPositionsTotal(ctx)  // βœ… directly int32

orders, err := service.GetOpenedOrders(ctx, sortMode)  // βœ… protobuf data directly

Advantages:

  • βœ… Less code (1 line instead of 2-3)
  • βœ… Direct access to data without .TotalPositions
  • βœ… Simplified method signatures
  • βœ… Automatic request structure creation
  • βœ… Pagination support for history

πŸ“‹ All 5 MethodsΒΆ

Method Returns Low-Level Equivalent
GetPositionsTotal(ctx) int32 PositionsTotal(ctx) + .TotalPositions
GetOpenedOrders(ctx, sortMode) *OpenedOrdersData OpenedOrders(ctx, req)
GetOpenedTickets(ctx) ([]int64, []int64) OpenedOrdersTickets(ctx, req) + unpacking
GetOrderHistory(ctx, from, to, sortMode, page, perPage) *OrdersHistoryData OrderHistory(ctx, req) with time.Time conversion
GetPositionsHistory(ctx, sortType, from, to, page, perPage) *PositionsHistoryData PositionsHistory(ctx, req) with time.Time conversion

πŸ“– Method SignaturesΒΆ

1) GetPositionsTotalΒΆ

func (s *MT5Service) GetPositionsTotal(ctx context.Context) (int32, error)

Returns the number of open positions.

Low-level equivalent: PositionsTotal(ctx) with .TotalPositions extraction.

Example:

total, err := service.GetPositionsTotal(ctx)
fmt.Printf("Open positions: %d\n", total)


2) GetOpenedOrdersΒΆ

func (s *MT5Service) GetOpenedOrders(
    ctx context.Context,
    sortMode pb.BMT5_ENUM_OPENED_ORDER_SORT_TYPE,
) (*pb.OpenedOrdersData, error)

Gets all open positions and pending orders.

Parameters:

  • sortMode - sorting mode from BMT5_ENUM_OPENED_ORDER_SORT_TYPE:
  • SORT_BY_TICKET_ASC - by ticket ascending
  • SORT_BY_TICKET_DESC - by ticket descending
  • SORT_BY_SYMBOL_ASC - by symbol (Aβ†’Z)
  • SORT_BY_PROFIT_ASC - by profit (loss β†’ profit)
  • SORT_BY_PROFIT_DESC - by profit (profit β†’ loss)

Returns:

  • *pb.OpenedOrdersData with lists:
  • OpenedPositions []MqlPosition - open positions
  • OpenedOrders []MqlOrder - pending orders

Example:

data, err := service.GetOpenedOrders(ctx,
    pb.BMT5_ENUM_OPENED_ORDER_SORT_TYPE_SORT_BY_PROFIT_DESC)
if err != nil {
    return err
}

fmt.Printf("Opened positions: %d\n", len(data.OpenedPositions))
for _, pos := range data.OpenedPositions {
    fmt.Printf("  Position #%d: %s, Profit: %.2f\n",
        pos.Ticket, pos.Symbol, pos.Profit)
}

fmt.Printf("Pending orders: %d\n", len(data.OpenedOrders))
for _, order := range data.OpenedOrders {
    fmt.Printf("  Order #%d: %s, Type: %v\n",
        order.Ticket, order.Symbol, order.Type)
}

3) GetOpenedTicketsΒΆ

func (s *MT5Service) GetOpenedTickets(ctx context.Context) ([]int64, []int64, error)

Gets only ticket numbers of open positions and pending orders.

Lightweight alternative to GetOpenedOrders - returns only IDs, not full information.

Returns:

  • positionTickets []int64 - ticket numbers of open positions
  • orderTickets []int64 - ticket numbers of pending orders
  • error

Example:

posTickets, orderTickets, err := service.GetOpenedTickets(ctx)
if err != nil {
    return err
}

fmt.Printf("Open positions: %d\n", len(posTickets))
fmt.Printf("Position tickets: %v\n", posTickets)

fmt.Printf("Pending orders: %d\n", len(orderTickets))
fmt.Printf("Order tickets: %v\n", orderTickets)

When to use:

  • Need only ticket numbers (not full information)
  • Checking for open positions
  • Fast position count monitoring

4) GetOrderHistoryΒΆ

func (s *MT5Service) GetOrderHistory(
    ctx context.Context,
    from time.Time,
    to time.Time,
    sortMode pb.BMT5_ENUM_ORDER_HISTORY_SORT_TYPE,
    pageNumber int32,
    itemsPerPage int32,
) (*pb.OrdersHistoryData, error)

Gets historical orders and deals for a period with pagination.

Parameters:

  • from - period start (time.Time, auto-converted to protobuf)
  • to - period end (time.Time, auto-converted to protobuf)
  • sortMode - sorting mode from BMT5_ENUM_ORDER_HISTORY_SORT_TYPE
  • pageNumber - page number (1-based)
  • itemsPerPage - items per page

Returns:

  • *pb.OrdersHistoryData with lists:
  • HistoryOrders []MqlOrder - historical orders
  • HistoryDeals []MqlDeal - historical deals
  • TotalOrders int32 - total orders
  • TotalDeals int32 - total deals

Example:

// History for last 7 days
from := time.Now().AddDate(0, 0, -7)
to := time.Now()

data, err := service.GetOrderHistory(ctx, from, to,
    pb.BMT5_ENUM_ORDER_HISTORY_SORT_TYPE_SORT_BY_TIME_DESC,
    1, 100)  // first page, 100 items
if err != nil {
    return err
}

fmt.Printf("Total orders: %d (showing %d)\n",
    data.TotalOrders, len(data.HistoryOrders))
fmt.Printf("Total deals: %d (showing %d)\n",
    data.TotalDeals, len(data.HistoryDeals))

for _, deal := range data.HistoryDeals {
    fmt.Printf("Deal #%d: %s, Profit: %.2f, Time: %s\n",
        deal.Ticket, deal.Symbol, deal.Profit,
        deal.Time.AsTime().Format("2006-01-02 15:04:05"))
}


5) GetPositionsHistoryΒΆ

func (s *MT5Service) GetPositionsHistory(
    ctx context.Context,
    sortType pb.AH_ENUM_POSITIONS_HISTORY_SORT_TYPE,
    from *time.Time,
    to *time.Time,
    pageNumber *int32,
    itemsPerPage *int32,
) (*pb.PositionsHistoryData, error)

Gets closed positions with aggregated P&L data.

Parameters (all optional, use nil for defaults):

  • sortType - sort type from AH_ENUM_POSITIONS_HISTORY_SORT_TYPE
  • from - position open period start (nil = no filter)
  • to - position open period end (nil = no filter)
  • pageNumber - page number (nil = 1)
  • itemsPerPage - items per page (nil = all)

Returns:

  • *pb.PositionsHistoryData with list:
  • ClosedPositions []AggregatedPositionHistory - closed positions
  • TotalClosedPositions int32 - total positions

Example:

// Get all closed positions
data, err := service.GetPositionsHistory(ctx,
    pb.AH_ENUM_POSITIONS_HISTORY_SORT_TYPE_SORT_BY_CLOSE_TIME_DESC,
    nil, nil, nil, nil)  // all parameters default
if err != nil {
    return err
}

fmt.Printf("Total closed positions: %d\n", data.TotalClosedPositions)
for _, pos := range data.ClosedPositions {
    fmt.Printf("Position ID: %d, Symbol: %s\n", pos.PositionId, pos.Symbol)
    fmt.Printf("  Volume: %.2f, Profit: %.2f, Commission: %.2f\n",
        pos.Volume, pos.Profit, pos.Commission)
    fmt.Printf("  Opened: %s, Closed: %s\n",
        pos.OpenTime.AsTime().Format("2006-01-02 15:04:05"),
        pos.CloseTime.AsTime().Format("2006-01-02 15:04:05"))
}

With time filtering:

// Closed positions for last month
from := time.Now().AddDate(0, -1, 0)
to := time.Now()
page := int32(1)
perPage := int32(50)

data, err := service.GetPositionsHistory(ctx,
    pb.AH_ENUM_POSITIONS_HISTORY_SORT_TYPE_SORT_BY_PROFIT_DESC,
    &from, &to, &page, &perPage)


πŸ’‘ Usage ExamplesΒΆ

Example 1: Checking for Open PositionsΒΆ

// ❌ BEFORE (MT5Account) - 2 calls:
data, err := account.PositionsTotal(ctx)
if err != nil {
    return err
}
total := data.TotalPositions
if total > 0 {
    fmt.Printf("You have %d open positions\n", total)
}

// βœ… AFTER (MT5Service) - 1 call:
total, err := service.GetPositionsTotal(ctx)
if err != nil {
    return err
}
if total > 0 {
    fmt.Printf("You have %d open positions\n", total)
}

Code reduction: 20% (5 lines β†’ 4 lines)


Example 2: Getting List of Positions by ProfitΒΆ

// βœ… MT5Service - get positions sorted by profit
data, err := service.GetOpenedOrders(ctx,
    pb.BMT5_ENUM_OPENED_ORDER_SORT_TYPE_SORT_BY_PROFIT_DESC)
if err != nil {
    return err
}

fmt.Println("Open positions (sorted by profit):")
totalProfit := 0.0
for _, pos := range data.OpenedPositions {
    fmt.Printf("  #%d: %s %.2f lots, Profit: %.2f\n",
        pos.Ticket, pos.Symbol, pos.Volume, pos.Profit)
    totalProfit += pos.Profit
}
fmt.Printf("Total P&L: %.2f\n", totalProfit)

Example 3: Lightweight Position MonitoringΒΆ

// βœ… MT5Service - use GetOpenedTickets for fast checking
func MonitorPositions(service *mt5.MT5Service, interval time.Duration) {
    ticker := time.NewTicker(interval)
    defer ticker.Stop()

    previousCount := 0

    for range ticker.C {
        ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)

        posTickets, orderTickets, err := service.GetOpenedTickets(ctx)
        cancel()

        if err != nil {
            fmt.Printf("❌ Error: %v\n", err)
            continue
        }

        currentCount := len(posTickets)
        if currentCount != previousCount {
            fmt.Printf("[%s] Positions changed: %d β†’ %d\n",
                time.Now().Format("15:04:05"), previousCount, currentCount)
            fmt.Printf("  Position tickets: %v\n", posTickets)
            fmt.Printf("  Pending orders: %v\n", orderTickets)
            previousCount = currentCount
        }
    }
}

Example 4: Getting Deal History for a PeriodΒΆ

// βœ… MT5Service - history for last month
func PrintMonthlyReport(service *mt5.MT5Service) error {
    ctx := context.Background()

    from := time.Now().AddDate(0, -1, 0)  // month ago
    to := time.Now()

    data, err := service.GetOrderHistory(ctx, from, to,
        pb.BMT5_ENUM_ORDER_HISTORY_SORT_TYPE_SORT_BY_TIME_DESC,
        1, 1000)  // first page, up to 1000 deals
    if err != nil {
        return err
    }

    fmt.Printf("πŸ“Š Monthly Report (%s - %s)\n",
        from.Format("2006-01-02"), to.Format("2006-01-02"))
    fmt.Printf("Total deals: %d\n", data.TotalDeals)

    totalProfit := 0.0
    winCount := 0
    lossCount := 0

    for _, deal := range data.HistoryDeals {
        totalProfit += deal.Profit
        if deal.Profit > 0 {
            winCount++
        } else if deal.Profit < 0 {
            lossCount++
        }
    }

    fmt.Printf("Total P&L: %.2f\n", totalProfit)
    fmt.Printf("Win rate: %.1f%% (%d wins / %d losses)\n",
        float64(winCount)/(float64(winCount+lossCount))*100,
        winCount, lossCount)

    return nil
}

Example 5: Analyzing Closed Positions with PaginationΒΆ

// βœ… MT5Service - processing large history volumes with pagination
func AnalyzeClosedPositions(service *mt5.MT5Service) error {
    ctx := context.Background()

    page := int32(1)
    perPage := int32(100)

    for {
        data, err := service.GetPositionsHistory(ctx,
            pb.AH_ENUM_POSITIONS_HISTORY_SORT_TYPE_SORT_BY_CLOSE_TIME_DESC,
            nil, nil, &page, &perPage)
        if err != nil {
            return err
        }

        fmt.Printf("Page %d: %d positions (total: %d)\n",
            page, len(data.ClosedPositions), data.TotalClosedPositions)

        for _, pos := range data.ClosedPositions {
            duration := pos.CloseTime.AsTime().Sub(pos.OpenTime.AsTime())
            fmt.Printf("  Position %d: %s, Duration: %v, Profit: %.2f\n",
                pos.PositionId, pos.Symbol, duration, pos.Profit)
        }

        // Check if there are more pages
        if int32(len(data.ClosedPositions)) < perPage {
            break  // this was the last page
        }

        page++
    }

    return nil
}

πŸ”§ When to UseΒΆ

βœ… GetPositionsTotalΒΆ

Use when:

  • Need a quick check for positions
  • Checking number of positions before actions
  • Monitoring without details

Example:

total, _ := service.GetPositionsTotal(ctx)
if total == 0 {
    fmt.Println("No open positions")
}

βœ… GetOpenedOrdersΒΆ

Use when:

  • Need full information about positions/orders
  • Calculating total profit/loss
  • Building a dashboard with position details

Example:

data, _ := service.GetOpenedOrders(ctx, sortByProfit)
for _, pos := range data.OpenedPositions {
    fmt.Printf("Position: %s, P&L: %.2f\n", pos.Symbol, pos.Profit)
}

βœ… GetOpenedTicketsΒΆ

Use when:

  • Need only ticket numbers (not details)
  • Lightweight monitoring of changes
  • Checking for a specific ticket

Example:

posTickets, _, _ := service.GetOpenedTickets(ctx)
hasPosition := slices.Contains(posTickets, int64(12345))

βœ… GetOrderHistoryΒΆ

Use when:

  • Need order and deal history
  • Building reports for a period
  • Analyzing trading activity

Example:

data, _ := service.GetOrderHistory(ctx, from, to, sortByTime, 1, 100)
fmt.Printf("Deals: %d\n", len(data.HistoryDeals))


βœ… GetPositionsHistoryΒΆ

Use when:

  • Need aggregated information about positions
  • Analyzing closed positions with P&L
  • Building trading statistics

Example:

data, _ := service.GetPositionsHistory(ctx, sortByProfit, nil, nil, nil, nil)
for _, pos := range data.ClosedPositions {
    fmt.Printf("Position: %s, Profit: %.2f\n", pos.Symbol, pos.Profit)
}

πŸ“Š Performance ComparisonΒΆ

Task Low-Level (lines of code) Mid-Level (lines of code) Reduction
Get position count 2-3 lines 1 line 33-50%
Get position list 3-4 lines 2-3 lines 25-33%
Get tickets 2-3 lines 1 line 33-50%
History for period 5-6 lines 3-4 lines 25-40%

πŸ’‘ RecommendationsΒΆ

  1. For quick checks β†’ use GetPositionsTotal or GetOpenedTickets
  2. For position details β†’ use GetOpenedOrders with sorting
  3. For history β†’ use GetOrderHistory (deals+orders) or GetPositionsHistory (aggregated positions)
  4. For large volumes β†’ use pagination (page, perPage parameters)
  5. For monitoring β†’ GetOpenedTickets is lighter than GetOpenedOrders

"Simple to Complex" Pattern:

// 1. Quick check for presence
total, _ := service.GetPositionsTotal(ctx)
if total == 0 {
    return nil
}

// 2. Get tickets (lightweight)
posTickets, _, _ := service.GetOpenedTickets(ctx)
fmt.Printf("Position tickets: %v\n", posTickets)

// 3. Full information (if needed)
data, _ := service.GetOpenedOrders(ctx, sortByProfit)
for _, pos := range data.OpenedPositions {
    // Detailed processing
}


🎯 Summary¢

MT5Service Position & Orders methods solve the main task - simplify data access:

  • ❌ No need to extract .TotalPositions, .OpenedPositions
  • ❌ No need to manually create complex request structures
  • ❌ No need to convert time.Time β†’ timestamppb (automatic)
  • βœ… Get data directly (int32, []int64, *protobuf.Data)
  • βœ… Pagination support for large volumes
  • βœ… Code reads like normal Go
  • βœ… Lightweight variants (GetOpenedTickets) for monitoring