π
π Get Deals This Month (GetDealsThisMonth)ΒΆ
Sugar method: Returns closed positions ("deals") that were opened this month (the 1st, 00:00 local, to now).
API Information:
- Method:
sugar.GetDealsThisMonth() - Timeout: 30 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) GetDealsThisMonth() ([]*pb.PositionHistoryInfo, error) {
now := time.Now()
startOfMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
return s.positionsOpenedBetween(startOfMonth, now, 30*time.Second)
}
positionsOpenedBetween reads PositionsHistory (sorted by open time) with cursor paging - page size
1000, PageToken = the previous NextPageToken - until the last page, so long ranges are complete. The range filters by the position's open time:
a position opened last month and closed this month is not included. Still-open positions are not in the list.
The timeout covers all pages together.
Time zone note: the month is the calendar month of the computer running the program (time.Local): the 1st, 00:00
local, 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 month 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 month range) |
| Output | Type | Description |
|---|---|---|
[]*pb.PositionHistoryInfo |
slice | Closed positions opened this month |
error |
error |
"PositionsHistory failed: ..." if a page query failed (or the timeout expired) |
π¬ Just the EssentialsΒΆ
- What it is: Get closed trades opened between the 1st day of the month 00:00 and the current time.
- Why you need it: Monthly performance tracking, strategy evaluation, profit/loss reports.
- Sanity check: Returns an empty (possibly
nil) slice if there are no deals - checklen(deals). Auto-calculates month range.
π― When to UseΒΆ
β Monthly reports - Generate month-to-date summaries
β Performance tracking - Monitor monthly profit/loss
β Strategy analysis - Review month's trading performance
β Goal tracking - Check progress toward monthly targets
π Usage ExamplesΒΆ
1) Basic usage - show this month's dealsΒΆ
deals, err := sugar.GetDealsThisMonth()
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
if len(deals) == 0 {
fmt.Println("No deals this month")
return
}
fmt.Printf("This month's deals: %d\n\n", len(deals))
totalProfit := 0.0
for i, deal := range deals {
fmt.Printf("%d. #%d %s: $%.2f\n",
i+1, deal.PositionTicket, deal.Symbol, deal.Profit)
totalProfit += deal.Profit
}
fmt.Printf("\nMonth total: $%.2f\n", totalProfit)
2) Monthly performance summaryΒΆ
deals, _ := sugar.GetDealsThisMonth()
if len(deals) == 0 {
fmt.Println("No trading this month")
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++
}
}
winRate := float64(winCount) / float64(len(deals)) * 100
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Println("β THIS MONTH'S PERFORMANCE β")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
monthName := time.Now().Format("January 2006")
fmt.Printf("Month: %s\n\n", monthName)
fmt.Printf("Total trades: %d\n", len(deals))
fmt.Printf("Winners: %d (%.1f%%)\n", winCount, winRate)
fmt.Printf("Losers: %d (%.1f%%)\n", lossCount, 100-winRate)
fmt.Printf("Total P/L: $%.2f\n", totalProfit)
if totalProfit > 0 {
fmt.Println("\nβ
Profitable month so far")
} else {
fmt.Println("\nβ Losing month so far")
}
3) Check monthly target progressΒΆ
monthlyTarget := 2000.0 // $2000 per month
deals, _ := sugar.GetDealsThisMonth()
if len(deals) == 0 {
fmt.Printf("Monthly target: $%.2f\n", monthlyTarget)
fmt.Println("No trades yet this month")
return
}
actualProfit := 0.0
for _, deal := range deals {
actualProfit += deal.Profit
}
progress := (actualProfit / monthlyTarget) * 100
// Calculate days into month
now := time.Now()
dayOfMonth := now.Day()
daysInMonth := time.Date(now.Year(), now.Month()+1, 0, 0, 0, 0, 0, now.Location()).Day()
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Println("β MONTHLY TARGET PROGRESS β")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Printf("Target: $%.2f\n", monthlyTarget)
fmt.Printf("Current: $%.2f\n", actualProfit)
fmt.Printf("Progress: %.1f%%\n\n", progress)
fmt.Printf("Day %d of %d (%.0f%% of month)\n",
dayOfMonth, daysInMonth,
float64(dayOfMonth)/float64(daysInMonth)*100)
remaining := monthlyTarget - actualProfit
if actualProfit >= monthlyTarget {
fmt.Printf("\nπ― Target achieved! (+$%.2f)\n",
actualProfit-monthlyTarget)
} else {
fmt.Printf("\nπ $%.2f remaining\n", remaining)
// Project if on track
projected := (actualProfit / float64(dayOfMonth)) * float64(daysInMonth)
fmt.Printf("Projected month-end: $%.2f\n", projected)
if projected >= monthlyTarget {
fmt.Println("β
On track to meet target")
} else {
fmt.Println("β οΈ Behind pace")
}
}
4) Weekly breakdown of this monthΒΆ
deals, _ := sugar.GetDealsThisMonth()
if len(deals) == 0 {
fmt.Println("No deals this month")
return
}
// Group by week number
weeklyStats := make(map[int]struct {
Count int
Profit float64
})
for _, deal := range deals {
_, week := deal.CloseTime.AsTime().ISOWeek() // CloseTime is broker server time
stats := weeklyStats[week]
stats.Count++
stats.Profit += deal.Profit
weeklyStats[week] = stats
}
fmt.Println("This Month - Weekly Breakdown:")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
// Get current week range
_, currentWeek := time.Now().ISOWeek()
// Print weeks in order
for week := currentWeek - 3; week <= currentWeek; week++ {
stats, exists := weeklyStats[week]
if !exists {
continue
}
status := "β
"
if stats.Profit < 0 {
status = "β"
}
fmt.Printf("%s Week %d: %d trades, $%.2f\n",
status, week, stats.Count, stats.Profit)
}
5) Top 5 most profitable trades this monthΒΆ
deals, _ := sugar.GetDealsThisMonth()
if len(deals) == 0 {
fmt.Println("No deals this month")
return
}
// Sort by profit (descending)
sort.Slice(deals, func(i, j int) bool {
return deals[i].Profit > deals[j].Profit
})
fmt.Println("Top 5 Most Profitable Trades This Month:")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
count := 5
if len(deals) < 5 {
count = len(deals)
}
for i := 0; i < count; i++ {
deal := deals[i]
fmt.Printf("%d. #%d %s %.2f lots: $%.2f\n",
i+1, deal.PositionTicket, deal.Symbol,
deal.Volume, deal.Profit)
}
6) Symbol performance this monthΒΆ
deals, _ := sugar.GetDealsThisMonth()
if len(deals) == 0 {
fmt.Println("No deals this month")
return
}
symbolStats := make(map[string]struct {
Count int
Profit float64
Wins int
})
for _, deal := range deals {
stats := symbolStats[deal.Symbol]
stats.Count++
stats.Profit += deal.Profit
if deal.Profit > 0 {
stats.Wins++
}
symbolStats[deal.Symbol] = stats
}
fmt.Println("This Month - Symbol Performance:")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
for symbol, stats := range symbolStats {
winRate := float64(stats.Wins) / float64(stats.Count) * 100
avgProfit := stats.Profit / float64(stats.Count)
status := "β
"
if stats.Profit < 0 {
status = "β"
}
fmt.Printf("%s %-8s: %d trades (%.0f%% win), $%.2f (avg: $%.2f)\n",
status, symbol, stats.Count, winRate,
stats.Profit, avgProfit)
}
7) Month-over-month comparisonΒΆ
thisMonthDeals, _ := sugar.GetDealsThisMonth()
// Get last month's range
now := time.Now()
firstOfThisMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
firstOfLastMonth := firstOfThisMonth.AddDate(0, -1, 0)
lastMonthDeals, _ := sugar.GetDealsDateRange(
firstOfLastMonth,
firstOfThisMonth.Add(-time.Second),
)
thisMonthProfit := 0.0
for _, deal := range thisMonthDeals {
thisMonthProfit += deal.Profit
}
lastMonthProfit := 0.0
for _, deal := range lastMonthDeals {
lastMonthProfit += deal.Profit
}
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Println("β MONTH-OVER-MONTH COMPARISON β")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
lastMonthName := firstOfLastMonth.Format("January")
thisMonthName := now.Format("January")
fmt.Printf("%s: %d trades, $%.2f\n",
lastMonthName, len(lastMonthDeals), lastMonthProfit)
fmt.Printf("%s: %d trades, $%.2f\n",
thisMonthName, len(thisMonthDeals), thisMonthProfit)
diff := thisMonthProfit - lastMonthProfit
fmt.Printf("\nDifference: $%.2f ", diff)
if diff > 0 {
if lastMonthProfit != 0 {
pct := (diff / lastMonthProfit) * 100
fmt.Printf("π (+%.1f%%)\n", pct)
} else {
fmt.Println("π")
}
} else if diff < 0 {
if lastMonthProfit != 0 {
pct := (-diff / lastMonthProfit) * 100
fmt.Printf("π (-%.1f%%)\n", pct)
} else {
fmt.Println("π")
}
} else {
fmt.Println("β‘οΈ (No change)")
}
8) Daily average this monthΒΆ
deals, _ := sugar.GetDealsThisMonth()
if len(deals) == 0 {
fmt.Println("No deals this month")
return
}
totalProfit := 0.0
for _, deal := range deals {
totalProfit += deal.Profit
}
now := time.Now()
daysElapsed := now.Day()
daysInMonth := time.Date(now.Year(), now.Month()+1, 0, 0, 0, 0, 0, now.Location()).Day()
avgPerDay := totalProfit / float64(daysElapsed)
projectedMonthEnd := avgPerDay * float64(daysInMonth)
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Println("β MONTHLY DAILY AVERAGES β")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Printf("Days elapsed: %d / %d\n", daysElapsed, daysInMonth)
fmt.Printf("Total profit: $%.2f\n", totalProfit)
fmt.Printf("Avg per day: $%.2f\n", avgPerDay)
fmt.Printf("Projected end: $%.2f\n", projectedMonthEnd)
9) Risk/reward analysis this monthΒΆ
deals, _ := sugar.GetDealsThisMonth()
if len(deals) == 0 {
fmt.Println("No deals this month")
return
}
var totalWins float64
var totalLosses float64
winCount := 0
lossCount := 0
for _, deal := range deals {
if deal.Profit > 0 {
totalWins += deal.Profit
winCount++
} else if deal.Profit < 0 {
totalLosses += deal.Profit
lossCount++
}
}
avgWin := 0.0
if winCount > 0 {
avgWin = totalWins / float64(winCount)
}
avgLoss := 0.0
if lossCount > 0 {
avgLoss = totalLosses / float64(lossCount)
}
riskRewardRatio := 0.0
if avgLoss != 0 {
riskRewardRatio = avgWin / -avgLoss
}
profitFactor := 0.0
if totalLosses != 0 {
profitFactor = totalWins / -totalLosses
}
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Println("β RISK/REWARD ANALYSIS β")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Printf("Avg Win: $%.2f\n", avgWin)
fmt.Printf("Avg Loss: $%.2f\n", avgLoss)
fmt.Printf("Risk/Reward: %.2f:1\n", riskRewardRatio)
fmt.Printf("Profit Factor: %.2f\n\n", profitFactor)
if profitFactor >= 2.0 {
fmt.Println("β
Excellent risk management")
} else if profitFactor >= 1.5 {
fmt.Println("β
Good risk management")
} else if profitFactor >= 1.0 {
fmt.Println("π‘ Acceptable")
} else {
fmt.Println("β οΈ Needs improvement")
}
10) Advanced monthly statistics analyzerΒΆ
type MonthlyStats struct {
MonthName string
TotalDeals int
TotalProfit float64
WinRate float64
ProfitFactor float64
BestWeek int
BestWeekProfit float64
DaysTraded int
AvgDailyProfit float64
LargestWin float64
LargestLoss float64
}
func AnalyzeMonthlyPerformance(sugar *mt5.MT5Sugar) (*MonthlyStats, error) {
deals, err := sugar.GetDealsThisMonth()
if err != nil {
return nil, err
}
now := time.Now()
stats := &MonthlyStats{
MonthName: now.Format("January 2006"),
TotalDeals: len(deals),
}
if len(deals) == 0 {
return stats, nil
}
winCount := 0
var totalWins, totalLosses float64
weeklyProfit := make(map[int]float64)
tradingDays := make(map[string]bool)
for _, deal := range deals {
stats.TotalProfit += deal.Profit
tradingDays[deal.CloseTime.AsTime().Format("2006-01-02")] = true
if deal.Profit > 0 {
winCount++
totalWins += deal.Profit
if deal.Profit > stats.LargestWin {
stats.LargestWin = deal.Profit
}
} else if deal.Profit < 0 {
totalLosses += deal.Profit
if deal.Profit < stats.LargestLoss {
stats.LargestLoss = deal.Profit
}
}
_, week := deal.CloseTime.AsTime().ISOWeek()
weeklyProfit[week] += deal.Profit
}
stats.WinRate = float64(winCount) / float64(len(deals)) * 100
stats.DaysTraded = len(tradingDays)
if stats.DaysTraded > 0 {
stats.AvgDailyProfit = stats.TotalProfit / float64(stats.DaysTraded)
}
if totalLosses != 0 {
stats.ProfitFactor = totalWins / -totalLosses
}
// Find best week
for week, profit := range weeklyProfit {
if profit > stats.BestWeekProfit {
stats.BestWeekProfit = profit
stats.BestWeek = week
}
}
return stats, nil
}
func (s *MonthlyStats) Print() {
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Println("β MONTHLY STATISTICS ANALYSIS β")
fmt.Println("βββββββββββββββββββββββββββββββββββββββββ")
fmt.Printf("Month: %s\n\n", s.MonthName)
if s.TotalDeals == 0 {
fmt.Println("No trading activity this month")
return
}
fmt.Printf("Total Deals: %d\n", s.TotalDeals)
fmt.Printf("Total Profit: $%.2f\n", s.TotalProfit)
fmt.Printf("Win Rate: %.1f%%\n", s.WinRate)
fmt.Printf("Profit Factor: %.2f\n\n", s.ProfitFactor)
fmt.Printf("Days Traded: %d\n", s.DaysTraded)
fmt.Printf("Avg Daily Profit: $%.2f\n\n", s.AvgDailyProfit)
fmt.Printf("Largest Win: $%.2f\n", s.LargestWin)
fmt.Printf("Largest Loss: $%.2f\n\n", s.LargestLoss)
fmt.Printf("Best Week: Week %d ($%.2f)\n", s.BestWeek, s.BestWeekProfit)
fmt.Println("\nMonth Assessment:")
if s.TotalProfit > 0 && s.WinRate >= 60 && s.ProfitFactor >= 1.5 {
fmt.Println("π Excellent month")
} else if s.TotalProfit > 0 && s.WinRate >= 50 {
fmt.Println("β
Good month")
} else if s.TotalProfit >= 0 {
fmt.Println("π‘ Breakeven month")
} else {
fmt.Println("β Losing month - review strategy")
}
}
// Usage:
stats, _ := AnalyzeMonthlyPerformance(sugar)
stats.Print()
π Related MethodsΒΆ
π¬ Other time periods:
GetDealsToday()- Today's dealsGetDealsYesterday()- Yesterday's dealsGetDealsThisWeek()- This week's dealsGetDealsDateRange()- Custom date range
π¬ Profit calculations:
GetProfitThisMonth()- Just this month's profit total
β οΈ Common PitfallsΒΆ
1) Early month = incomplete dataΒΆ
// β WRONG - comparing incomplete month to complete month
thisMonthProfit, _ := sugar.GetProfitThisMonth() // Day 5
lastMonthProfit := 2000.0 // Full 30 days
// Not fair comparison!
// β
CORRECT - adjust for days
daysPassed := time.Now().Day()
dailyAvg := thisMonthProfit / float64(daysPassed)
fmt.Printf("Daily average: $%.2f\n", dailyAvg)
2) Not handling timezone and open-time filteringΒΆ
// β WRONG - assuming "this month" is the broker's month of CLOSED trades
// The range is the calendar month of YOUR computer and is matched against OPEN time:
// a position opened on the 31st of last month and closed today is missing
deals, _ := sugar.GetDealsThisMonth()
// β
CORRECT - widen the range and filter on CloseTime yourself when that matters
deals, _ = sugar.GetDealsDateRange(time.Now().AddDate(0, -2, 0), time.Now())
3) Assuming deals existΒΆ
// β WRONG - division by zero
deals, _ := sugar.GetDealsThisMonth()
avgProfit := totalProfit / float64(len(deals)) // NaN if empty!
// β
CORRECT - check length
if len(deals) > 0 {
avgProfit := totalProfit / float64(len(deals))
}
π Pro TipsΒΆ
-
Month starts 1st - Always starts from 1st day 00:00:00 (local calendar)
-
Incomplete data - Mid-month calls return partial month
-
Performance - 30-second timeout (longer than the 15 s of day/week queries)
-
Empty OK - Returns empty slice if no trades (not error)
-
Auto-range - Automatically calculates from 1st to now
-
Profit field only -
Profitdoes not include commission, swap or fee
π Month Range CalculationΒΆ
Month range calculation:
now = time.Now()
startOfMonth = Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) // time.Local
Returns closed positions whose OPEN time is between startOfMonth and now
(sent as PositionOpenTimeFromUtc / PositionOpenTimeToUtc), sorted by open time ascending
See also: GetDealsToday.md, GetDealsThisWeek.md, GetProfitThisMonth.md, GetDealsDateRange.md