π
πΌ Get Deals Today (GetDealsToday)ΒΆ
Sugar method: Returns closed positions ("deals") that were opened today (local midnight to now).
API Information:
- Method:
sugar.GetDealsToday() - Timeout: 15 seconds
- Returns: Slice of position history info (one entry per closed position; a position closed in parts has one entry per partial close), sorted by open time (oldest first)
π Method SignatureΒΆ
How it works:
func (s *MT5Sugar) GetDealsToday() ([]*pb.PositionHistoryInfo, error) {
now := time.Now()
return s.positionsOpenedBetween(startOfLocalDay(now), now, 15*time.Second)
}
// positionsOpenedBetween returns ALL closed positions whose open time lies in [from, to] (real moments).
// It reads the history with cursor paging (page_size 1000, next_page_token) until the last page, so a long
// range is never cut to the first page. The timeout covers all pages together.
func (s *MT5Sugar) positionsOpenedBetween(from, to time.Time, timeout time.Duration) ([]*pb.PositionHistoryInfo, error) {
ctx, cancel := context.WithTimeout(s.ctx, timeout)
defer cancel()
var all []*pb.PositionHistoryInfo
token := ""
for {
// A Go time.Time is a moment: the window goes in the *Utc fields (see MT5Service.GetPositionsHistory)
data, err := s.GetAccount().PositionsHistory(ctx, &pb.PositionsHistoryRequest{
SortType: pb.AH_ENUM_POSITIONS_HISTORY_SORT_TYPE_AH_POSITION_OPEN_TIME_ASC,
PositionOpenTimeFromUtc: timestamppb.New(from),
PositionOpenTimeToUtc: timestamppb.New(to),
PageToken: token,
PageSize: 1000,
})
if err != nil {
return nil, fmt.Errorf("PositionsHistory failed: %w", err)
}
all = append(all, data.HistoryPositions...)
token = data.NextPageToken
if token == "" || len(data.HistoryPositions) == 0 {
return all, nil
}
}
}
"Deals" are closed positions from PositionsHistory (one entry per closed position, not per MT5 deal; a position closed in parts has one entry per partial close, each with the closed volume). The range filters by the position's open time: a position opened yesterday and closed today is not included. Still-open positions are not in the list. All pages are read (cursor paging, 1000 per page); the timeout covers all pages together.
Time zone note: "today" is the calendar day of the computer running the program (time.Local): local midnight to now.
The window is sent in the request's UTC fields (PositionOpenTimeFromUtc /
PositionOpenTimeToUtc), so the broker's time zone does not shift it. If you want the broker's trading day instead, run
the program with TZ set to the broker's time zone or pass explicit boundaries to GetDealsDateRange().
π½ Input / β¬οΈ OutputΒΆ
| Input | Type | Description |
|---|---|---|
| None | - | No parameters (auto-calculates today's range) |
| Output | Type | Description |
|---|---|---|
[]*pb.PositionHistoryInfo |
slice | Closed positions opened today |
error |
error |
"PositionsHistory failed: ..." if a page query failed (or the timeout expired) |
π¬ Just the EssentialsΒΆ
- What it is: Get closed trades opened today (00:00 to current time, local clock).
- Why you need it: Daily performance tracking, today's profit/loss analysis, trade review.
- Sanity check: Returns an empty (possibly
nil) slice if there are no deals - checklen(deals). Automatically calculates today's time range.
π― When to UseΒΆ
β Daily reports - Generate today's trading summary
β Performance tracking - Monitor today's profit/loss
β Trade journal - Review today's completed trades
β Real-time updates - Check latest closed positions
π Usage ExamplesΒΆ
1) Basic usage - show today's dealsΒΆ
deals, err := sugar.GetDealsToday()
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
if len(deals) == 0 {
fmt.Println("No deals today")
return
}
fmt.Printf("Today's deals: %d\n\n", len(deals))
for i, deal := range deals {
fmt.Printf("%d. Ticket #%d: %s %.2f lots\n",
i+1, deal.PositionTicket, deal.Symbol, deal.Volume)
fmt.Printf(" Profit: $%.2f\n", deal.Profit)
}
2) Calculate today's profitΒΆ
deals, _ := sugar.GetDealsToday()
if len(deals) == 0 {
fmt.Println("No trades today")
return
}
totalProfit := 0.0
winCount := 0
lossCount := 0
for _, deal := range deals {
totalProfit += deal.Profit
if deal.Profit > 0 {
winCount++
} else if deal.Profit < 0 {
lossCount++
}
}
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Println("β TODAY'S PERFORMANCE β")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Printf("Total trades: %d\n", len(deals))
fmt.Printf("Winners: %d (%.1f%%)\n", winCount,
float64(winCount)/float64(len(deals))*100)
fmt.Printf("Losers: %d (%.1f%%)\n", lossCount,
float64(lossCount)/float64(len(deals))*100)
fmt.Printf("Total P/L: $%.2f\n", totalProfit)
if totalProfit > 0 {
fmt.Println("β
Profitable day")
} else {
fmt.Println("β Losing day")
}
3) Today's trading summary by symbolΒΆ
deals, _ := sugar.GetDealsToday()
if len(deals) == 0 {
fmt.Println("No deals today")
return
}
// Group by symbol
symbolStats := make(map[string]struct {
Count int
Profit float64
})
for _, deal := range deals {
stats := symbolStats[deal.Symbol]
stats.Count++
stats.Profit += deal.Profit
symbolStats[deal.Symbol] = stats
}
fmt.Println("Today's Performance by Symbol:")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
for symbol, stats := range symbolStats {
fmt.Printf("%-8s: %d trades, $%.2f\n",
symbol, stats.Count, stats.Profit)
}
4) Find largest win/loss todayΒΆ
deals, _ := sugar.GetDealsToday()
if len(deals) == 0 {
fmt.Println("No deals today")
return
}
var largestWin *pb.PositionHistoryInfo
var largestLoss *pb.PositionHistoryInfo
for _, deal := range deals {
if largestWin == nil || deal.Profit > largestWin.Profit {
largestWin = deal
}
if largestLoss == nil || deal.Profit < largestLoss.Profit {
largestLoss = deal
}
}
fmt.Println("Today's Extremes:")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
if largestWin != nil {
fmt.Printf("π Largest win:\n")
fmt.Printf(" #%d %s %.2f lots: $%.2f\n",
largestWin.PositionTicket, largestWin.Symbol,
largestWin.Volume, largestWin.Profit)
}
if largestLoss != nil && largestLoss.Profit < 0 {
fmt.Printf("\nπ Largest loss:\n")
fmt.Printf(" #%d %s %.2f lots: $%.2f\n",
largestLoss.PositionTicket, largestLoss.Symbol,
largestLoss.Volume, largestLoss.Profit)
}
5) Track hourly trading activityΒΆ
deals, _ := sugar.GetDealsToday()
if len(deals) == 0 {
fmt.Println("No deals today")
return
}
// Group by close hour (CloseTime is broker server time)
hourlyActivity := make(map[int]int)
for _, deal := range deals {
hour := deal.CloseTime.AsTime().Hour()
hourlyActivity[hour]++
}
fmt.Println("Hourly Trading Activity:")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
for hour := 0; hour < 24; hour++ {
count := hourlyActivity[hour]
if count > 0 {
fmt.Printf("%02d:00 - %02d:59: %d trades\n",
hour, hour, count)
}
}
6) Check if breakeven or profitable todayΒΆ
deals, _ := sugar.GetDealsToday()
if len(deals) == 0 {
fmt.Println("No trades today - day just started?")
return
}
totalProfit := 0.0
for _, deal := range deals {
totalProfit += deal.Profit
}
fmt.Printf("Today: %d trades, $%.2f\n", len(deals), totalProfit)
switch {
case totalProfit > 100:
fmt.Println("π Great day! Target exceeded")
case totalProfit > 0:
fmt.Println("β
Profitable day")
case totalProfit == 0:
fmt.Println("β‘οΈ Breakeven")
case totalProfit > -100:
fmt.Println("β οΈ Small loss - recoverable")
default:
fmt.Println("π Significant loss - stop trading")
}
7) Real-time deal monitorΒΆ
func MonitorTodaysDeals(sugar *mt5.MT5Sugar, interval time.Duration) {
ticker := time.NewTicker(interval)
defer ticker.Stop()
previousCount := 0
for range ticker.C {
deals, _ := sugar.GetDealsToday()
currentCount := len(deals)
if currentCount > previousCount {
// New deals closed
newDeals := currentCount - previousCount
// Last element = most recently OPENED of today's closed positions
// (the list is sorted by open time, not close time)
if len(deals) > 0 {
latest := deals[len(deals)-1]
fmt.Printf("[%s] %d new deal(s) closed!\n",
time.Now().Format("15:04:05"), newDeals)
fmt.Printf(" #%d %s: $%.2f\n",
latest.PositionTicket, latest.Symbol, latest.Profit)
}
}
previousCount = currentCount
}
}
// Usage: Monitor every 10 seconds
go MonitorTodaysDeals(sugar, 10*time.Second)
8) Daily performance gradeΒΆ
deals, _ := sugar.GetDealsToday()
if len(deals) == 0 {
fmt.Println("No trades today - grade: N/A")
return
}
totalProfit := 0.0
winCount := 0
for _, deal := range deals {
totalProfit += deal.Profit
if deal.Profit > 0 {
winCount++
}
}
winRate := float64(winCount) / float64(len(deals)) * 100
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Println("β TODAY'S PERFORMANCE GRADE β")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Printf("Trades: %d\n", len(deals))
fmt.Printf("Win rate: %.1f%%\n", winRate)
fmt.Printf("P/L: $%.2f\n\n", totalProfit)
// Grade based on win rate and profitability
grade := ""
if totalProfit > 0 && winRate >= 70 {
grade = "π A+ (Excellent)"
} else if totalProfit > 0 && winRate >= 60 {
grade = "β A (Very Good)"
} else if totalProfit > 0 && winRate >= 50 {
grade = "β
B (Good)"
} else if totalProfit >= 0 {
grade = "π‘ C (Fair)"
} else if totalProfit > -100 {
grade = "β οΈ D (Poor)"
} else {
grade = "β F (Fail)"
}
fmt.Printf("Grade: %s\n", grade)
9) Export today's deals to CSVΒΆ
deals, _ := sugar.GetDealsToday()
if len(deals) == 0 {
fmt.Println("No deals to export")
return
}
filename := fmt.Sprintf("deals_%s.csv",
time.Now().Format("2006-01-02"))
file, _ := os.Create(filename)
defer file.Close()
writer := csv.NewWriter(file)
defer writer.Flush()
// Header
writer.Write([]string{
"Ticket", "Symbol", "Volume", "Profit",
"Open Time", "Close Time", "Duration"})
// Data
for _, deal := range deals {
// OpenTime/CloseTime are *timestamppb.Timestamp in broker server time
openTime := deal.OpenTime.AsTime()
closeTime := deal.CloseTime.AsTime()
duration := closeTime.Sub(openTime)
writer.Write([]string{
fmt.Sprintf("%d", deal.PositionTicket),
deal.Symbol,
fmt.Sprintf("%.2f", deal.Volume),
fmt.Sprintf("%.2f", deal.Profit),
openTime.Format("15:04:05"),
closeTime.Format("15:04:05"),
duration.String(),
})
}
fmt.Printf("β
Exported %d deals to %s\n", len(deals), filename)
10) Advanced daily statistics managerΒΆ
type DailyDealStats struct {
TotalDeals int
WinningDeals int
LosingDeals int
TotalProfit float64
LargestWin float64
LargestLoss float64
AvgProfit float64
WinRate float64
}
func GetDailyDealStats(sugar *mt5.MT5Sugar) (*DailyDealStats, error) {
deals, err := sugar.GetDealsToday()
if err != nil {
return nil, err
}
stats := &DailyDealStats{
TotalDeals: len(deals),
}
if len(deals) == 0 {
return stats, nil
}
stats.LargestWin = 0
stats.LargestLoss = 0
for _, deal := range deals {
stats.TotalProfit += deal.Profit
if deal.Profit > 0 {
stats.WinningDeals++
if deal.Profit > stats.LargestWin {
stats.LargestWin = deal.Profit
}
} else if deal.Profit < 0 {
stats.LosingDeals++
if deal.Profit < stats.LargestLoss {
stats.LargestLoss = deal.Profit
}
}
}
stats.AvgProfit = stats.TotalProfit / float64(len(deals))
stats.WinRate = float64(stats.WinningDeals) / float64(len(deals)) * 100
return stats, nil
}
func (s *DailyDealStats) Print() {
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Println("β DAILY DEAL STATISTICS β")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
if s.TotalDeals == 0 {
fmt.Println("No deals today")
return
}
fmt.Printf("Total Deals: %d\n", s.TotalDeals)
fmt.Printf("Winning: %d (%.1f%%)\n",
s.WinningDeals, s.WinRate)
fmt.Printf("Losing: %d (%.1f%%)\n",
s.LosingDeals, 100-s.WinRate)
fmt.Printf("\n")
fmt.Printf("Total Profit: $%.2f\n", s.TotalProfit)
fmt.Printf("Average P/L: $%.2f\n", s.AvgProfit)
fmt.Printf("Largest Win: $%.2f\n", s.LargestWin)
fmt.Printf("Largest Loss: $%.2f\n", s.LargestLoss)
}
// Usage:
stats, _ := GetDailyDealStats(sugar)
stats.Print()
π Related MethodsΒΆ
π¬ Other time periods:
GetDealsYesterday()- Yesterday's dealsGetDealsThisWeek()- This week's dealsGetDealsThisMonth()- This month's dealsGetDealsDateRange()- Custom date range
π¬ Profit calculations:
GetProfitToday()- Just today's profit total (sum ofProfit)GetDailyStats()- Win/loss statistics built from this method
β οΈ Common PitfallsΒΆ
1) Assuming deals existΒΆ
// β WRONG - might panic if no deals
deals, _ := sugar.GetDealsToday()
firstDeal := deals[0] // Panic if empty!
// β
CORRECT - check length first
deals, _ := sugar.GetDealsToday()
if len(deals) > 0 {
firstDeal := deals[0]
}
2) Not considering timezoneΒΆ
// β WRONG - assuming "today" is the broker's trading day
// The window is the calendar day of YOUR computer (time.Local)
deals, _ := sugar.GetDealsToday()
// β
CORRECT - pass explicit boundaries in the broker's time zone when the day must match the broker's day
// (the times are real moments: they are sent as UTC, so any time zone works)
broker := time.FixedZone("broker", 3*60*60) // e.g. a broker at UTC+3
from := time.Date(2026, 10, 16, 0, 0, 0, 0, broker)
to := from.AddDate(0, 0, 1).Add(-time.Nanosecond)
deals, _ := sugar.GetDealsDateRange(from, to)
2b) Expecting positions opened before todayΒΆ
// β WRONG - a position opened yesterday and closed today is NOT returned:
// the range filters on the position's OPEN time
deals, _ := sugar.GetDealsToday()
// β
CORRECT - widen the range and filter on CloseTime yourself
deals, _ := sugar.GetDealsThisWeek()
3) Treating as real-time feedΒΆ
// β WRONG - this is closed positions only!
deals, _ := sugar.GetDealsToday()
// This doesn't include currently OPEN positions
// β
CORRECT - for open positions use different method
openPositions, _ := sugar.GetOpenPositions() // Current positions
closedDeals, _ := sugar.GetDealsToday() // Closed today
π Pro TipsΒΆ
-
Empty slice OK - Returns an empty slice if no deals (not an error)
-
Closed only - Only includes closed positions, not currently open
-
Local calendar - "Today" is local midnight to now on the computer running the program, matched against the position's open time (sent to the server as UTC)
-
Performance - Uses 15-second timeout
-
Auto-range - Automatically calculates today's range (local 00:00 to now)
-
Profit field only -
Profitdoes not include commission, swap or fee; addCommission,SwapandFeeyourself for the net result
π Deal StructureΒΆ
Each deal (*pb.PositionHistoryInfo) is one closed position:
Index - Index in the result
PositionTicket - Position ticket number
OrderType - pb.AH_ENUM_POSITIONS_HISTORY_ORDER_TYPE (e.g. ..._AH_ORDER_TYPE_BUY / ..._AH_ORDER_TYPE_SELL)
Symbol - Trading symbol (e.g., "EURUSD")
Volume - Trade volume in lots
OpenPrice - Entry price
ClosePrice - Exit price
StopLoss - Stop Loss
TakeProfit - Take Profit
Profit - Realized profit/loss (without commission, swap and fee)
Commission - Trading commission
Fee - Fees
Swap - Swap charges
MarketValue - Market value
OpenTime - Open time (*timestamppb.Timestamp, broker server time); OpenTimeUtc = same moment in UTC
CloseTime - Close time (*timestamppb.Timestamp, broker server time); CloseTimeUtc = same moment in UTC
Comment - Comment
Magic - Magic number
See also: GetDealsYesterday.md, GetDealsThisWeek.md, GetProfitToday.md, GetDealsDateRange.md