Files
gocryptotrader/types/number.go
Ryan O'Hara-Reid 7f412e2772 Kucoin: Update order execution limits (#2124)
* refactor(kucoin): enhance contract and symbol structures, update order execution limits tests

* fix(number): handle null input in UnmarshalJSON and update tests

* Update exchanges/kucoin/kucoin_futures_types.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* Update exchanges/kucoin/kucoin_futures_types.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* Update exchanges/kucoin/kucoin_wrapper.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* Update exchanges/kucoin/kucoin_wrapper.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* Update exchanges/kucoin/kucoin_wrapper.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* Update exchanges/kucoin/kucoin_types.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* Update exchanges/kucoin/kucoin_wrapper.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* glorious: destroyed this code across all implementations

* glorious: rename

* ai overlord: nit

* Update exchanges/kucoin/kucoin_futures_types.go

Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>

* thrasher: nits

---------

Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
Co-authored-by: Scott <gloriousCode@users.noreply.github.com>
Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
2025-12-17 12:42:34 +11:00

81 lines
2.2 KiB
Go

package types
import (
"errors"
"fmt"
"strconv"
"github.com/shopspring/decimal"
)
var errInvalidNumberValue = errors.New("invalid value for Number type")
// Number represents a floating point number, and implements json.Unmarshaller and json.Marshaller
type Number float64
// UnmarshalJSON implements json.Unmarshaler
func (f *Number) UnmarshalJSON(data []byte) error {
switch c := data[0]; c { // From json.decode literalInterface
case 'n': // null
*f = Number(0)
return nil
case 't', 'f': // true, false
return fmt.Errorf("%w: %s", errInvalidNumberValue, data)
case '"': // string
if len(data) < 2 || data[len(data)-1] != '"' {
return fmt.Errorf("%w: %s", errInvalidNumberValue, data)
}
data = data[1 : len(data)-1] // Naive Unquote
default: // Should be a number
if c != '-' && (c < '0' || c > '9') { // Invalid json syntax
return fmt.Errorf("%w: %s", errInvalidNumberValue, data)
}
}
if len(data) == 0 {
*f = Number(0)
return nil
}
val, err := strconv.ParseFloat(string(data), 64)
if err != nil {
return fmt.Errorf("%w: %s", errInvalidNumberValue, data) // We don't use err; We know it's not valid and errInvalidNumberValue is clearer
}
*f = Number(val)
return nil
}
// MarshalJSON implements json.Marshaler by formatting to a json string
// 1337.37 will marshal to "1337.37"
// 0 will marshal to an empty string: ""
func (f Number) MarshalJSON() ([]byte, error) {
if f == 0 {
return []byte(`""`), nil
}
val := strconv.FormatFloat(float64(f), 'f', -1, 64)
return []byte(`"` + val + `"`), nil
}
// Float64 returns the underlying float64
func (f Number) Float64() float64 {
return float64(f)
}
// Int64 returns the truncated integer component of the number
func (f Number) Int64() int64 {
// It's likely this is sufficient, since Numbers probably have not had floating point math performed on them
// However if issues arise then we can switch to math.Round
return int64(f)
}
// Decimal returns a decimal.Decimal
func (f Number) Decimal() decimal.Decimal {
return decimal.NewFromFloat(float64(f))
}
// String returns a string representation of the number
func (f Number) String() string {
return strconv.FormatFloat(float64(f), 'f', -1, 64)
}