mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-21 22:43:52 +00:00
add back legacy implementation
This commit is contained in:
parent
cdba7924b4
commit
eb70410f80
3
.github/workflows/go.yml
vendored
3
.github/workflows/go.yml
vendored
|
@ -44,3 +44,6 @@ jobs:
|
|||
|
||||
- name: Test
|
||||
run: go test -v ./pkg/...
|
||||
|
||||
- name: TestDnum
|
||||
run: go test -tag dnum -v ./pkg/...
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//go:build !dnum
|
||||
|
||||
package fixedpoint
|
||||
|
||||
import (
|
||||
|
@ -6,7 +8,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
@ -18,6 +19,37 @@ const DefaultPow = 1e8
|
|||
|
||||
type Value int64
|
||||
|
||||
const Zero = Value(0)
|
||||
const One = Value(1e8)
|
||||
const NegOne = Value(-1e8)
|
||||
|
||||
type RoundingMode int
|
||||
|
||||
const (
|
||||
Up RoundingMode = iota
|
||||
Down
|
||||
HalfUp
|
||||
)
|
||||
|
||||
// Trunc returns the integer portion (truncating any fractional part)
|
||||
func (v Value) Trunc() Value {
|
||||
return NewFromFloat(math.Floor(v.Float64()))
|
||||
}
|
||||
|
||||
func (v Value) Round(r int, mode RoundingMode) Value {
|
||||
pow := math.Pow10(r)
|
||||
result := v.Float64() * pow
|
||||
switch mode {
|
||||
case Up:
|
||||
return NewFromFloat(math.Ceil(result) / pow)
|
||||
case HalfUp:
|
||||
return NewFromFloat(math.Floor(result+0.5) / pow)
|
||||
case Down:
|
||||
return NewFromFloat(math.Floor(result) / pow)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func (v Value) Value() (driver.Value, error) {
|
||||
return v.Float64(), nil
|
||||
}
|
||||
|
@ -62,8 +94,22 @@ func (v Value) String() string {
|
|||
return strconv.FormatFloat(float64(v)/DefaultPow, 'f', -1, 64)
|
||||
}
|
||||
|
||||
func (v Value) FormatString(prec int) string {
|
||||
return strconv.FormatFloat(float64(v)/DefaultPow, 'f', prec, 64)
|
||||
}
|
||||
|
||||
func (v Value) Percentage() string {
|
||||
return fmt.Sprintf("%.2f%%", v.Float64()*100.0)
|
||||
if v == 0 {
|
||||
return "0"
|
||||
}
|
||||
return strconv.FormatFloat(float64(v)/DefaultPow*100., 'f', -1, 64) + "%"
|
||||
}
|
||||
|
||||
func (v Value) FormatPercentage(prec int) string {
|
||||
if v == 0 {
|
||||
return "0"
|
||||
}
|
||||
return strconv.FormatFloat(float64(v)/DefaultPow*100., 'f', prec, 64) + "%"
|
||||
}
|
||||
|
||||
func (v Value) SignedPercentage() string {
|
||||
|
@ -78,35 +124,48 @@ func (v Value) Int64() int64 {
|
|||
}
|
||||
|
||||
func (v Value) Int() int {
|
||||
return int(v.Float64())
|
||||
n := v.Int64()
|
||||
if int64(int(n)) != n {
|
||||
panic("unable to convert Value to int32")
|
||||
}
|
||||
return int(n)
|
||||
}
|
||||
|
||||
// BigMul is the math/big version multiplication
|
||||
func (v Value) BigMul(v2 Value) Value {
|
||||
x := new(big.Int).Mul(big.NewInt(int64(v)), big.NewInt(int64(v2)))
|
||||
return Value(x.Int64() / DefaultPow)
|
||||
func (v Value) Neg() Value {
|
||||
return -v
|
||||
}
|
||||
|
||||
// TODO inf
|
||||
func (v Value) Sign() int {
|
||||
if v > 0 {
|
||||
return 1
|
||||
} else if v == 0 {
|
||||
return 0
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
func (v Value) IsZero() bool {
|
||||
return v == 0
|
||||
}
|
||||
|
||||
func Mul(x, y Value) Value {
|
||||
return NewFromFloat(x.Float64() * y.Float64())
|
||||
}
|
||||
|
||||
func (v Value) Mul(v2 Value) Value {
|
||||
return NewFromFloat(v.Float64() * v2.Float64())
|
||||
}
|
||||
|
||||
func (v Value) MulInt(v2 int) Value {
|
||||
return NewFromFloat(v.Float64() * float64(v2))
|
||||
}
|
||||
|
||||
func (v Value) MulFloat64(v2 float64) Value {
|
||||
return NewFromFloat(v.Float64() * v2)
|
||||
func Div(x, y Value) Value {
|
||||
return NewFromFloat(x.Float64() / y.Float64())
|
||||
}
|
||||
|
||||
func (v Value) Div(v2 Value) Value {
|
||||
return NewFromFloat(v.Float64() / v2.Float64())
|
||||
}
|
||||
|
||||
func (v Value) DivFloat64(v2 float64) Value {
|
||||
return NewFromFloat(v.Float64() / v2)
|
||||
}
|
||||
|
||||
func (v Value) Floor() Value {
|
||||
return NewFromFloat(math.Floor(v.Float64()))
|
||||
}
|
||||
|
@ -141,7 +200,7 @@ func (v *Value) UnmarshalYAML(unmarshal func(a interface{}) error) (err error) {
|
|||
|
||||
var i int64
|
||||
if err = unmarshal(&i); err == nil {
|
||||
*v = NewFromInt64(i)
|
||||
*v = NewFromInt(i)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -173,15 +232,13 @@ func (v *Value) UnmarshalJSON(data []byte) error {
|
|||
switch d := a.(type) {
|
||||
case float64:
|
||||
*v = NewFromFloat(d)
|
||||
|
||||
case float32:
|
||||
*v = NewFromFloat32(d)
|
||||
|
||||
case int:
|
||||
*v = NewFromInt(d)
|
||||
*v = NewFromFloat(float64(d))
|
||||
|
||||
case int64:
|
||||
*v = NewFromInt64(d)
|
||||
*v = NewFromInt(d)
|
||||
case int:
|
||||
*v = NewFromInt(int64(d))
|
||||
|
||||
case string:
|
||||
v2, err := NewFromString(d)
|
||||
|
@ -199,14 +256,6 @@ func (v *Value) UnmarshalJSON(data []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func Must(v Value, err error) Value {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
var ErrPrecisionLoss = errors.New("precision loss")
|
||||
|
||||
func Parse(input string) (num int64, numDecimalPoints int, err error) {
|
||||
|
@ -271,20 +320,6 @@ func Parse(input string) (num int64, numDecimalPoints int, err error) {
|
|||
return num, numDecimalPoints, nil
|
||||
}
|
||||
|
||||
func NewFromAny(any interface{}) (Value, error) {
|
||||
switch v := any.(type) {
|
||||
case string:
|
||||
return NewFromString(v)
|
||||
case float64:
|
||||
return NewFromFloat(v), nil
|
||||
case int64:
|
||||
return NewFromInt64(v), nil
|
||||
|
||||
default:
|
||||
return 0, fmt.Errorf("fixedpoint unsupported type %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func NewFromString(input string) (Value, error) {
|
||||
length := len(input)
|
||||
|
||||
|
@ -317,23 +352,48 @@ func MustNewFromString(input string) Value {
|
|||
return v
|
||||
}
|
||||
|
||||
func NewFromBytes(input []byte) (Value, error) {
|
||||
return NewFromString(string(input))
|
||||
}
|
||||
|
||||
func MustNewFromBytes(input []byte) (v Value) {
|
||||
var err error
|
||||
if v, err = NewFromString(string(input)); err != nil {
|
||||
return Zero
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func Must(v Value, err error) Value {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func NewFromFloat(val float64) Value {
|
||||
return Value(int64(math.Round(val * DefaultPow)))
|
||||
}
|
||||
|
||||
func NewFromFloat32(val float32) Value {
|
||||
return Value(int64(math.Round(float64(val) * DefaultPow)))
|
||||
}
|
||||
|
||||
func NewFromInt(val int) Value {
|
||||
return Value(int64(val * DefaultPow))
|
||||
}
|
||||
|
||||
func NewFromInt64(val int64) Value {
|
||||
func NewFromInt(val int64) Value {
|
||||
return Value(val * DefaultPow)
|
||||
}
|
||||
|
||||
func NumFractionalDigits(a Value) int {
|
||||
func (a Value) MulExp(exp int) Value {
|
||||
return Value(int64(float64(a) * math.Pow(10, float64(exp))))
|
||||
}
|
||||
|
||||
func (a Value) NumIntDigits() int {
|
||||
digits := 0
|
||||
target := int64(a)
|
||||
for pow := int64(DefaultPow); pow <= target; pow *= 10 {
|
||||
digits++
|
||||
}
|
||||
return digits
|
||||
}
|
||||
|
||||
// TODO: speedup
|
||||
func (a Value) NumFractionalDigits() int {
|
||||
numPow := 0
|
||||
for pow := int64(DefaultPow); pow%10 != 1; pow /= 10 {
|
||||
numPow++
|
||||
|
@ -345,6 +405,26 @@ func NumFractionalDigits(a Value) int {
|
|||
return numPow - numZeros
|
||||
}
|
||||
|
||||
func Compare(x, y Value) int {
|
||||
if x > y {
|
||||
return 1
|
||||
} else if x == y {
|
||||
return 0
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
func (x Value) Compare(y Value) int {
|
||||
if x > y {
|
||||
return 1
|
||||
} else if x == y {
|
||||
return 0
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
func Min(a, b Value) Value {
|
||||
if a < b {
|
||||
return a
|
||||
|
@ -361,6 +441,14 @@ func Max(a, b Value) Value {
|
|||
return b
|
||||
}
|
||||
|
||||
func Equal(x, y Value) bool {
|
||||
return x == y
|
||||
}
|
||||
|
||||
func (x Value) Eq(y Value) bool {
|
||||
return x == y
|
||||
}
|
||||
|
||||
func Abs(a Value) Value {
|
||||
if a < 0 {
|
||||
return -a
|
|
@ -1,3 +1,5 @@
|
|||
//go:build dnum
|
||||
|
||||
package fixedpoint
|
||||
|
||||
import (
|
||||
|
@ -1026,8 +1028,7 @@ func Must(v Value, err error) Value {
|
|||
|
||||
// v * 10^(exp)
|
||||
func (v Value) MulExp(exp int) Value {
|
||||
v.exp += exp
|
||||
return v
|
||||
return Value{v.coef, v.sign, v.exp + exp}
|
||||
}
|
||||
|
||||
// Sub returns the difference of two Value's
|
||||
|
|
14
pkg/fixedpoint/dec_dnum_test.go
Normal file
14
pkg/fixedpoint/dec_dnum_test.go
Normal file
|
@ -0,0 +1,14 @@
|
|||
//go:build dnum
|
||||
|
||||
package fixedpoint
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDelta(t *testing.T) {
|
||||
f1 := MustNewFromString("0.0009763593380614657")
|
||||
f2 := NewFromInt(42300)
|
||||
assert.InDelta(t, f1.Mul(f2).Float64(), 41.3, 1e-14)
|
||||
}
|
28
pkg/fixedpoint/dec_legacy_test.go
Normal file
28
pkg/fixedpoint/dec_legacy_test.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
//go:build !dnum
|
||||
|
||||
package fixedpoint
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNumFractionalDigitsLegacy(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
v Value
|
||||
want int
|
||||
}{
|
||||
{
|
||||
name: "over the default precision",
|
||||
v: MustNewFromString("0.123456789"),
|
||||
want: 8,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.v.NumFractionalDigits(); got != tt.want {
|
||||
t.Errorf("NumFractionalDigitsLegacy() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -86,97 +86,17 @@ func TestFromString(t *testing.T) {
|
|||
assert.Equal(t, "0.004075", f.String())
|
||||
f = MustNewFromString("0.03")
|
||||
assert.Equal(t, "0.03", f.String())
|
||||
}
|
||||
|
||||
func TestDelta(t *testing.T) {
|
||||
f1 := MustNewFromString("0.0009763593380614657")
|
||||
f2 := NewFromInt(42300)
|
||||
assert.InDelta(t, f1.Mul(f2).Float64(), 41.3, 1e-14)
|
||||
f = MustNewFromString("0.75%")
|
||||
assert.Equal(t, "0.0075", f.String())
|
||||
}
|
||||
|
||||
// Not used
|
||||
/*func TestParse(t *testing.T) {
|
||||
type args struct {
|
||||
input string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantNum int64
|
||||
wantNumDecimalPoints int
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
args: args{input: "-99.9"},
|
||||
wantNum: -999,
|
||||
wantNumDecimalPoints: 1,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
args: args{input: "0.75%"},
|
||||
wantNum: 75,
|
||||
wantNumDecimalPoints: 4,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
args: args{input: "0.12345678"},
|
||||
wantNum: 12345678,
|
||||
wantNumDecimalPoints: 8,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
args: args{input: "a"},
|
||||
wantNum: 0,
|
||||
wantNumDecimalPoints: 0,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
args: args{input: "0.1"},
|
||||
wantNum: 1,
|
||||
wantNumDecimalPoints: 1,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
args: args{input: "100"},
|
||||
wantNum: 100,
|
||||
wantNumDecimalPoints: 0,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
args: args{input: "100.9999"},
|
||||
wantNum: 1009999,
|
||||
wantNumDecimalPoints: 4,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotNum, gotNumDecimalPoints, err := Parse(tt.args.input)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if gotNum != tt.wantNum {
|
||||
t.Errorf("Parse() gotNum = %v, want %v", gotNum, tt.wantNum)
|
||||
}
|
||||
if gotNumDecimalPoints != tt.wantNumDecimalPoints {
|
||||
t.Errorf("Parse() gotNumDecimalPoints = %v, want %v", gotNumDecimalPoints, tt.wantNumDecimalPoints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}*/
|
||||
|
||||
func TestNumFractionalDigits(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
v Value
|
||||
want int
|
||||
}{
|
||||
{
|
||||
name: "over the default precision",
|
||||
v: MustNewFromString("0.123456789"),
|
||||
want: 9,
|
||||
},
|
||||
{
|
||||
name: "ignore the integer part",
|
||||
v: MustNewFromString("123.4567"),
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
//go:build dnum
|
||||
// +build dnum
|
||||
|
||||
// Copyright Suneido Software Corp. All rights reserved.
|
||||
// Governed by the MIT license found in the LICENSE file.
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user