Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,11 @@ $ mt5-pnl-cli pnl --from 2026-01-01 --to 2026-01-31 --by month --accounts "Trend
- `pnl` — P&L over a date range.
- Range: `--last Nd|Nw|Nm|Ny` (default `30d`; months and years are
calendar-accurate) or `--from YYYY-MM-DD [--to YYYY-MM-DD]` (`--to`
defaults to today).
defaults to today). `--last` runs from N units ago through today
inclusive, so `30d` covers 31 calendar days. Dates, `--last` and
"today" are all interpreted in **UTC**, and each deal is bucketed by
its UTC day — so from a far-offset timezone like NZ, the UTC day can
differ from your local day near midnight.
- `--by day|week|month` (default `week`; weeks start Monday, dates are
UTC).
- `--accounts "Trend EA,Scalper EA"` filters by account label
Expand Down Expand Up @@ -172,6 +176,16 @@ net < 0 a loss; a breakeven deal counts toward trades but neither
bucket. Sums accumulate at full precision and round only for display.
Profit factor = gross profit / |gross loss|.

**What counts as a trade is decided upstream.** This CLI sums every deal
in the snapshot's `closed_deals` and trusts
[mt5-pnl-exporter](https://github.com/tanem/mt5-pnl-exporter) to have
emitted only closing deals — entry legs and cash flows (deposits,
withdrawals) are filtered out there, not here — using MT5's native
signs, where commission, swap and fees are already negative for costs.
The CLI does not re-check this, so if you change that filtering or those
signs in the exporter, the P&L here changes with no error. Keep the two
in step.

## Schema compatibility

[`schema/snapshot.schema.json`](schema/snapshot.schema.json) is vendored
Expand Down
6 changes: 3 additions & 3 deletions internal/aggregate/aggregate.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ package aggregate

import (
"math"
"sort"
"slices"
"time"

"github.com/tanem/mt5-pnl-cli/internal/snapshot"
Expand Down Expand Up @@ -87,12 +87,12 @@ func Aggregate(deals []snapshot.Deal, opts Options) ([]Row, Summary) {
for p := range periodSet {
periods = append(periods, p)
}
sort.Strings(periods)
slices.Sort(periods)
accounts := make([]int64, 0, len(accountSet))
for a := range accountSet {
accounts = append(accounts, a)
}
sort.Slice(accounts, func(i, j int) bool { return accounts[i] < accounts[j] })
slices.Sort(accounts)

var rows []Row
var sum Summary
Expand Down
8 changes: 6 additions & 2 deletions internal/snapshot/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,12 @@ type Snapshot struct {
GeneratedAt string `json:"generated_at"`
Accounts []AccountSnapshot `json:"accounts"`
ClosedDeals []Deal `json:"closed_deals"`
OpenPositions []OpenPosition `json:"open_positions"`
CashFlows []Deal `json:"cash_flows"`
// OpenPositions and CashFlows are decoded for schema fidelity with the
// exporter, but intentionally not surfaced: cash flows (deposits and
// withdrawals) are deliberately excluded from trading P&L, and open
// positions are reserved for a future command.
OpenPositions []OpenPosition `json:"open_positions"`
CashFlows []Deal `json:"cash_flows"`
}

type AccountSnapshot struct {
Expand Down
Loading