types: fix AdjustQuantityByMinNotional by round up the quantity

This commit is contained in:
c9s 2023-03-23 17:35:54 +08:00
parent c3ca5b75ac
commit 02c28a07cc
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
2 changed files with 66 additions and 5 deletions

View File

@ -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

View File

@ -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))
}
}