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 methodsexamples/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ΒΆ
Returns the number of open positions.
Low-level equivalent: PositionsTotal(ctx) with .TotalPositions extraction.
Example:
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 fromBMT5_ENUM_OPENED_ORDER_SORT_TYPE:SORT_BY_TICKET_ASC- by ticket ascendingSORT_BY_TICKET_DESC- by ticket descendingSORT_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.OpenedOrdersDatawith lists:OpenedPositions []MqlPosition- open positionsOpenedOrders []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ΒΆ
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 positionsorderTickets []int64- ticket numbers of pending orderserror
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 fromBMT5_ENUM_ORDER_HISTORY_SORT_TYPEpageNumber- page number (1-based)itemsPerPage- items per page
Returns:
*pb.OrdersHistoryDatawith lists:HistoryOrders []MqlOrder- historical ordersHistoryDeals []MqlDeal- historical dealsTotalOrders int32- total ordersTotalDeals 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 fromAH_ENUM_POSITIONS_HISTORY_SORT_TYPEfrom- 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.PositionsHistoryDatawith list:ClosedPositions []AggregatedPositionHistory- closed positionsTotalClosedPositions 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:
β 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ΒΆ
- For quick checks β use
GetPositionsTotalorGetOpenedTickets - For position details β use
GetOpenedOrderswith sorting - For history β use
GetOrderHistory(deals+orders) orGetPositionsHistory(aggregated positions) - For large volumes β use pagination (page, perPage parameters)
- For monitoring β
GetOpenedTicketsis lighter thanGetOpenedOrders
"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
}
π Related SectionsΒΆ
- MT5Service Overview - mid-level API overview
- Account Methods (Mid-Level) - account methods
- Symbol Methods (Mid-Level) - symbol methods
- Position & Orders Information (Low-Level) - low-level position/orders API
- Trading Methods (Mid-Level) - order placement methods
- Trading Operations (Low-Level) - low-level trading API
- Streaming Methods (Mid-Level) - real-time position updates
- Streaming Methods (Low-Level) - low-level streaming API
- MT5Account Master Overview - low-level API master reference
π― 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