diff --git a/server.go b/server.go index f73fc76..ae5cf67 100644 --- a/server.go +++ b/server.go @@ -225,6 +225,7 @@ type Position struct { Size float64 `json:"size"` AvgPrice float64 `json:"avgPrice"` CurPrice float64 `json:"curPrice"` + Redeemable bool `json:"redeemable"` CashPnl float64 `json:"cashPnl"` PercentPnl float64 `json:"percentPnl"` CurrentValue float64 `json:"currentValue"` @@ -553,6 +554,14 @@ func fetchPositions(wallet string) ([]Position, error) { "&sizeThreshold=0.1&limit=100&sortBy=CURRENT&sortDirection=DESC" var out []Position err := getJSON(url, &out, nil) + open := out[:0] + for _, p := range out { + if p.Redeemable && p.CurPrice == 0 { + continue + } + open = append(open, p) + } + out = open fillEndTimes(out) // Soonest resolution first; undated last. ISO timestamps sort as strings. sort.SliceStable(out, func(i, j int) bool { diff --git a/server_test.go b/server_test.go index 22861c5..4911dd8 100644 --- a/server_test.go +++ b/server_test.go @@ -157,6 +157,44 @@ func TestRefreshFastBacksOffAndKeepsLastPositions(t *testing.T) { } } +func TestFetchPositionsFiltersResolvedLosses(t *testing.T) { + cases := []struct { + name string + body string + want int + }{ + {"resolved loss", `[{"size":15,"curPrice":0,"currentValue":0,"percentPnl":-99.9991,"redeemable":true}]`, 0}, + {"unresolved zero price", `[{"curPrice":0,"redeemable":false}]`, 1}, + {"winner awaiting redemption", `[{"curPrice":1,"redeemable":true}]`, 1}, + {"missing resolution flag", `[{"curPrice":0}]`, 1}, + {"mixed positions", `[{"curPrice":0,"redeemable":true},{"curPrice":0.68,"redeemable":false},{"curPrice":1,"redeemable":true}]`, 2}, + {"empty portfolio", `[]`, 0}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(tc.body)) + })) + defer srv.Close() + origBase := polyBase + polyBase = srv.URL + t.Cleanup(func() { polyBase = origBase }) + positions, err := fetchPositions("0xtest") + if err != nil { + t.Fatal(err) + } + if len(positions) != tc.want { + t.Fatalf("got %d positions, want %d", len(positions), tc.want) + } + for _, p := range positions { + if p.Redeemable && p.CurPrice == 0 { + t.Error("resolved loss remains visible") + } + } + }) + } +} + func TestFetchPositionsSortsByEndTime(t *testing.T) { // Same calendar day for noon/evening: only gamma's timestamp separates them. poly := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {