diff --git a/pkg/types/market.go b/pkg/types/market.go index 87eaa6301..99b2f9efb 100644 --- a/pkg/types/market.go +++ b/pkg/types/market.go @@ -2,6 +2,7 @@ package types import ( "math" + "strconv" "github.com/leekchan/accounting" @@ -59,7 +60,14 @@ func (m Market) IsDustQuantity(quantity, price fixedpoint.Value) bool { // TruncateQuantity uses the step size to truncate floating number, in order to avoid the rounding issue func (m Market) TruncateQuantity(quantity fixedpoint.Value) fixedpoint.Value { - return fixedpoint.MustNewFromString(m.FormatQuantity(quantity)) + var ts = m.StepSize.Float64() + var prec = int(math.Round(math.Log10(ts) * -1.0)) + var pow10 = math.Pow10(prec) + + qf := math.Trunc(quantity.Float64() * pow10) + qf = qf / pow10 + qs := strconv.FormatFloat(qf, 'f', prec, 64) + return fixedpoint.MustNewFromString(qs) } func (m Market) TruncatePrice(price fixedpoint.Value) fixedpoint.Value { @@ -136,15 +144,18 @@ func (m Market) CanonicalizeVolume(val fixedpoint.Value) float64 { return math.Trunc(p*val.Float64()) / p } -var minNotionalSealant = fixedpoint.NewFromFloat(1.0001) - // AdjustQuantityByMinNotional adjusts the quantity to make the amount greater than the given minAmount func (m Market) AdjustQuantityByMinNotional(quantity, currentPrice fixedpoint.Value) fixedpoint.Value { // modify quantity for the min amount + quantity = m.TruncateQuantity(quantity) amount := currentPrice.Mul(quantity) if amount.Compare(m.MinNotional) < 0 { - ratio := m.MinNotional.Mul(minNotionalSealant).Div(amount) - return quantity.Mul(ratio) + ratio := m.MinNotional.Div(amount) + quantity = quantity.Mul(ratio) + + ts := m.StepSize.Float64() + prec := int(math.Round(math.Log10(ts) * -1.0)) + return quantity.Round(prec, fixedpoint.Up) } return quantity diff --git a/pkg/types/market_test.go b/pkg/types/market_test.go index 809e60b0d..493c3a21d 100644 --- a/pkg/types/market_test.go +++ b/pkg/types/market_test.go @@ -191,3 +191,53 @@ func Test_formatQuantity(t *testing.T) { }) } } + +func TestMarket_TruncateQuantity(t *testing.T) { + market := Market{ + StepSize: fixedpoint.NewFromFloat(0.0001), + } + + testCases := []struct { + input string + expect string + }{ + {"0.00573961", "0.0057"}, + {"0.00579961", "0.0057"}, + {"0.0057", "0.0057"}, + } + + for _, testCase := range testCases { + q := fixedpoint.MustNewFromString(testCase.input) + q2 := market.TruncateQuantity(q) + assert.Equalf(t, testCase.expect, q2.String(), "input: %s stepSize: %s", testCase.input, market.StepSize.String()) + } + +} + +func TestMarket_AdjustQuantityByMinNotional(t *testing.T) { + + market := Market{ + Symbol: "ETHUSDT", + StepSize: fixedpoint.NewFromFloat(0.0001), + MinQuantity: fixedpoint.NewFromFloat(0.0001), + MinNotional: fixedpoint.NewFromFloat(10.0), + VolumePrecision: 8, + PricePrecision: 2, + } + + // Quantity:0.00573961 Price:1750.99 + testCases := []struct { + input string + expect string + }{ + {"0.00573961", "0.0058"}, + } + + price := fixedpoint.NewFromFloat(1750.99) + for _, testCase := range testCases { + q := fixedpoint.MustNewFromString(testCase.input) + q2 := market.AdjustQuantityByMinNotional(q, price) + assert.Equalf(t, testCase.expect, q2.String(), "input: %s stepSize: %s", testCase.input, market.StepSize.String()) + assert.False(t, market.IsDustQuantity(q2, price)) + } +}