From 902e27ede4b2fa7e5afe9120756101212a6c085c Mon Sep 17 00:00:00 2001 From: c9s Date: Sun, 26 Dec 2021 15:44:41 +0800 Subject: [PATCH] xmaker: truncate quantity when hedging --- pkg/strategy/xmaker/strategy.go | 1 + pkg/types/market.go | 20 ++++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/pkg/strategy/xmaker/strategy.go b/pkg/strategy/xmaker/strategy.go index 6dd4d35c9..47bb41f14 100644 --- a/pkg/strategy/xmaker/strategy.go +++ b/pkg/strategy/xmaker/strategy.go @@ -501,6 +501,7 @@ func (s *Strategy) Hedge(ctx context.Context, pos fixedpoint.Value) { } quantity := fixedpoint.Abs(pos) + quantity = s.sourceMarket.TruncateQuantity(quantity) if pos < 0 { side = types.SideTypeSell diff --git a/pkg/types/market.go b/pkg/types/market.go index 2d5076298..de2039f71 100644 --- a/pkg/types/market.go +++ b/pkg/types/market.go @@ -8,6 +8,8 @@ import ( "time" "github.com/leekchan/accounting" + + "github.com/c9s/bbgo/pkg/fixedpoint" ) type Duration time.Duration @@ -49,7 +51,7 @@ func (d *Duration) UnmarshalJSON(data []byte) error { } type Market struct { - Symbol string `json:"symbol"` + Symbol string `json:"symbol"` // LocalSymbol is used for exchange's API (exchange package internal) LocalSymbol string `json:"localSymbol,omitempty"` @@ -57,7 +59,7 @@ type Market struct { // PricePrecision is the precision used for formatting price, 8 = 8 decimals // can be converted from price tick step size, e.g. // int(math.Log10(price step size)) - PricePrecision int `json:"pricePrecision"` + PricePrecision int `json:"pricePrecision"` // VolumePrecision is the precision used for formatting quantity and volume, 8 = 8 decimals // can be converted from step size, e.g. @@ -65,10 +67,10 @@ type Market struct { VolumePrecision int `json:"volumePrecision"` // QuoteCurrency is the currency name for quote, e.g. USDT in BTC/USDT, USDC in BTC/USDC - QuoteCurrency string `json:"quoteCurrency"` + QuoteCurrency string `json:"quoteCurrency"` // BaseCurrency is the current name for base, e.g. BTC in BTC/USDT, ETH in ETH/USDC - BaseCurrency string `json:"baseCurrency"` + BaseCurrency string `json:"baseCurrency"` // The MIN_NOTIONAL filter defines the minimum notional value allowed for an order on a symbol. // An order's notional value is the price * quantity @@ -84,7 +86,7 @@ type Market struct { // StepSize is the step size of quantity // can be converted from precision, e.g. // 1.0 / math.Pow10(m.BaseUnitPrecision) - StepSize float64 `json:"stepSize,omitempty"` + StepSize float64 `json:"stepSize,omitempty"` MinPrice float64 `json:"minPrice,omitempty"` MaxPrice float64 `json:"maxPrice,omitempty"` @@ -93,6 +95,12 @@ type Market struct { TickSize float64 `json:"tickSize,omitempty"` } +// 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 { + stepRound := math.Pow10(-int(math.Log10(m.StepSize))) + return fixedpoint.NewFromFloat(math.Trunc(quantity.Float64()*stepRound) / stepRound) +} + func (m Market) BaseCurrencyFormatter() *accounting.Accounting { a := accounting.DefaultAccounting(m.BaseCurrency, m.VolumePrecision) a.Format = "%v %s" @@ -172,4 +180,4 @@ type MarketMap map[string]Market func (m MarketMap) Add(market Market) { m[market.Symbol] = market -} \ No newline at end of file +}