From 0a6d24195ba7185bbbf6c11aba5109977e343b6d Mon Sep 17 00:00:00 2001 From: c9s Date: Tue, 2 Jul 2024 14:45:58 +0800 Subject: [PATCH 1/2] improve pv slice parsing --- pkg/types/price_volume_slice.go | 24 +++++++++++++++++++++++- pkg/types/price_volume_slice_test.go | 25 ++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/pkg/types/price_volume_slice.go b/pkg/types/price_volume_slice.go index 95d1127fd..0e3821612 100644 --- a/pkg/types/price_volume_slice.go +++ b/pkg/types/price_volume_slice.go @@ -1,6 +1,7 @@ package types import ( + "bytes" "encoding/json" "fmt" "sort" @@ -180,6 +181,22 @@ func (slice *PriceVolumeSlice) UnmarshalJSON(b []byte) error { return nil } +func ParsePriceVolumeKvSliceJSON(b []byte) (PriceVolumeSlice, error) { + type S PriceVolumeSlice + var ts S + + err := json.Unmarshal(b, &ts) + if err != nil { + return nil, err + } + + if len(ts) > 0 && ts[0].Price.IsZero() { + return nil, fmt.Errorf("unable to parse price volume slice correctly, input given: %s", string(b)) + } + + return PriceVolumeSlice(ts), nil +} + // ParsePriceVolumeSliceJSON tries to parse a 2 dimensional string array into a PriceVolumeSlice // // [["9000", "10"], ["9900", "10"], ... ] @@ -188,7 +205,12 @@ func ParsePriceVolumeSliceJSON(b []byte) (slice PriceVolumeSlice, err error) { err = json.Unmarshal(b, &as) if err != nil { - return slice, err + // fallback unmarshalling: if the prefix looks like an object array + if bytes.HasPrefix(b, []byte(`[{`)) { + return ParsePriceVolumeKvSliceJSON(b) + } + + return nil, err } for _, a := range as { diff --git a/pkg/types/price_volume_slice_test.go b/pkg/types/price_volume_slice_test.go index cf0b1e8ab..05b9135d8 100644 --- a/pkg/types/price_volume_slice_test.go +++ b/pkg/types/price_volume_slice_test.go @@ -3,10 +3,33 @@ package types import ( "testing" - "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/fixedpoint" ) +func TestPriceVolumeSlice_UnmarshalJSON(t *testing.T) { + t.Run("array of array", func(t *testing.T) { + input := []byte(`[["19000.0","3.0"],["19111.0","2.0"]]`) + slice, err := ParsePriceVolumeSliceJSON(input) + if assert.NoError(t, err) { + assert.Len(t, slice, 2) + assert.Equal(t, "19000", slice[0].Price.String()) + assert.Equal(t, "3", slice[0].Volume.String()) + } + }) + + t.Run("array of object", func(t *testing.T) { + input := []byte(`[{ "Price": "19000.0", "Volume":"3.0"},{"Price": "19111.0","Volume": "2.0" }]`) + slice, err := ParsePriceVolumeSliceJSON(input) + if assert.NoError(t, err) { + assert.Len(t, slice, 2) + assert.Equal(t, "19000", slice[0].Price.String()) + assert.Equal(t, "3", slice[0].Volume.String()) + } + }) +} + func TestPriceVolumeSlice_Remove(t *testing.T) { for _, descending := range []bool{true, false} { slice := PriceVolumeSlice{} From bc12e885019717175199896ef4384af590e59241 Mon Sep 17 00:00:00 2001 From: c9s Date: Tue, 2 Jul 2024 14:47:36 +0800 Subject: [PATCH 2/2] add func doc comments --- pkg/types/price_volume_slice.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/types/price_volume_slice.go b/pkg/types/price_volume_slice.go index 0e3821612..5ca022dbb 100644 --- a/pkg/types/price_volume_slice.go +++ b/pkg/types/price_volume_slice.go @@ -181,6 +181,8 @@ func (slice *PriceVolumeSlice) UnmarshalJSON(b []byte) error { return nil } +// ParsePriceVolumeKvSliceJSON parses a JSON array of objects into PriceVolumeSlice +// [{"Price":...,"Volume":...}, ...] func ParsePriceVolumeKvSliceJSON(b []byte) (PriceVolumeSlice, error) { type S PriceVolumeSlice var ts S @@ -200,6 +202,8 @@ func ParsePriceVolumeKvSliceJSON(b []byte) (PriceVolumeSlice, error) { // ParsePriceVolumeSliceJSON tries to parse a 2 dimensional string array into a PriceVolumeSlice // // [["9000", "10"], ["9900", "10"], ... ] +// +// if parse failed, then it will try to parse the JSON array of objects, function ParsePriceVolumeKvSliceJSON will be called. func ParsePriceVolumeSliceJSON(b []byte) (slice PriceVolumeSlice, err error) { var as [][]fixedpoint.Value