Merge pull request #1665 from c9s/c9s/improve-pv-slice-parsing

IMPROVE: improve price volume slice parsing
This commit is contained in:
c9s 2024-07-02 14:59:05 +08:00 committed by GitHub
commit e293ec5c70
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 51 additions and 2 deletions

View File

@ -1,6 +1,7 @@
package types package types
import ( import (
"bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"sort" "sort"
@ -180,15 +181,40 @@ func (slice *PriceVolumeSlice) UnmarshalJSON(b []byte) error {
return nil 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
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 // ParsePriceVolumeSliceJSON tries to parse a 2 dimensional string array into a PriceVolumeSlice
// //
// [["9000", "10"], ["9900", "10"], ... ] // [["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) { func ParsePriceVolumeSliceJSON(b []byte) (slice PriceVolumeSlice, err error) {
var as [][]fixedpoint.Value var as [][]fixedpoint.Value
err = json.Unmarshal(b, &as) err = json.Unmarshal(b, &as)
if err != nil { 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 { for _, a := range as {

View File

@ -3,10 +3,33 @@ package types
import ( import (
"testing" "testing"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/stretchr/testify/assert" "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) { func TestPriceVolumeSlice_Remove(t *testing.T) {
for _, descending := range []bool{true, false} { for _, descending := range []bool{true, false} {
slice := PriceVolumeSlice{} slice := PriceVolumeSlice{}