From a298950be8c8f2d695eb23521a25d3707fc65863 Mon Sep 17 00:00:00 2001 From: c9s Date: Fri, 23 Feb 2024 18:45:58 +0800 Subject: [PATCH 1/2] move trading related utility functions to the tradingutil package --- pkg/strategy/grid2/strategy.go | 11 +++++---- pkg/strategy/grid2/trade.go | 45 ---------------------------------- pkg/util/tradingutil/trades.go | 21 +++++++++++++++- 3 files changed, 26 insertions(+), 51 deletions(-) delete mode 100644 pkg/strategy/grid2/trade.go diff --git a/pkg/strategy/grid2/strategy.go b/pkg/strategy/grid2/strategy.go index 209b82feb..c742de011 100644 --- a/pkg/strategy/grid2/strategy.go +++ b/pkg/strategy/grid2/strategy.go @@ -22,6 +22,7 @@ import ( "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/util" + "github.com/c9s/bbgo/pkg/util/tradingutil" ) const ID = "grid2" @@ -351,7 +352,7 @@ func (s *Strategy) calculateProfit(o types.Order, buyPrice, buyQuantity fixedpoi } func (s *Strategy) verifyOrderTrades(o types.Order, trades []types.Trade) bool { - tq := aggregateTradesQuantity(trades) + tq := tradingutil.AggregateTradesQuantity(trades) // on MAX: if order.status == filled, it does not mean order.executedQuantity == order.quantity // order.executedQuantity can be less than order.quantity @@ -400,8 +401,8 @@ func (s *Strategy) aggregateOrderQuoteAmountAndFee(o types.Order) (fixedpoint.Va // if one of the trades is missing, we need to query the trades from the RESTful API if s.verifyOrderTrades(o, orderTrades) { // if trades are verified - quoteAmount := aggregateTradesQuoteQuantity(orderTrades) - fees := collectTradeFee(orderTrades) + quoteAmount := tradingutil.AggregateTradesQuoteQuantity(orderTrades) + fees := tradingutil.CollectTradeFee(orderTrades) if fee, ok := fees[feeCurrency]; ok { return quoteAmount, fee, feeCurrency } @@ -428,9 +429,9 @@ func (s *Strategy) aggregateOrderQuoteAmountAndFee(o types.Order) (fixedpoint.Va } } - quoteAmount := aggregateTradesQuoteQuantity(orderTrades) + quoteAmount := tradingutil.AggregateTradesQuoteQuantity(orderTrades) // still try to aggregate the trades quantity if we can: - fees := collectTradeFee(orderTrades) + fees := tradingutil.CollectTradeFee(orderTrades) if fee, ok := fees[feeCurrency]; ok { return quoteAmount, fee, feeCurrency } diff --git a/pkg/strategy/grid2/trade.go b/pkg/strategy/grid2/trade.go deleted file mode 100644 index dbb11bf34..000000000 --- a/pkg/strategy/grid2/trade.go +++ /dev/null @@ -1,45 +0,0 @@ -package grid2 - -import ( - "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" -) - -// collectTradeFee collects the fee from the given trade slice -func collectTradeFee(trades []types.Trade) map[string]fixedpoint.Value { - fees := make(map[string]fixedpoint.Value) - for _, t := range trades { - if t.FeeDiscounted { - continue - } - - if fee, ok := fees[t.FeeCurrency]; ok { - fees[t.FeeCurrency] = fee.Add(t.Fee) - } else { - fees[t.FeeCurrency] = t.Fee - } - } - return fees -} - -func aggregateTradesQuantity(trades []types.Trade) fixedpoint.Value { - tq := fixedpoint.Zero - for _, t := range trades { - tq = tq.Add(t.Quantity) - } - return tq -} - -// aggregateTradesQuoteQuantity aggregates the quote quantity from the given trade slice -func aggregateTradesQuoteQuantity(trades []types.Trade) fixedpoint.Value { - quoteQuantity := fixedpoint.Zero - for _, t := range trades { - if t.QuoteQuantity.IsZero() { - quoteQuantity = quoteQuantity.Add(t.Price.Mul(t.Quantity)) - } else { - quoteQuantity = quoteQuantity.Add(t.QuoteQuantity) - } - } - - return quoteQuantity -} diff --git a/pkg/util/tradingutil/trades.go b/pkg/util/tradingutil/trades.go index 1bedf7f2c..f82a857ff 100644 --- a/pkg/util/tradingutil/trades.go +++ b/pkg/util/tradingutil/trades.go @@ -9,16 +9,21 @@ import ( func CollectTradeFee(trades []types.Trade) map[string]fixedpoint.Value { fees := make(map[string]fixedpoint.Value) for _, t := range trades { + if t.FeeDiscounted { + continue + } + if fee, ok := fees[t.FeeCurrency]; ok { fees[t.FeeCurrency] = fee.Add(t.Fee) } else { fees[t.FeeCurrency] = t.Fee } } - return fees } +// AggregateTradesQuantity sums up the quantity from the given trades +// totalQuantity = SUM(trade1.Quantity, trade2.Quantity, ...) func AggregateTradesQuantity(trades []types.Trade) fixedpoint.Value { tq := fixedpoint.Zero for _, t := range trades { @@ -26,3 +31,17 @@ func AggregateTradesQuantity(trades []types.Trade) fixedpoint.Value { } return tq } + +// AggregateTradesQuoteQuantity aggregates the quote quantity from the given trade slice +func AggregateTradesQuoteQuantity(trades []types.Trade) fixedpoint.Value { + quoteQuantity := fixedpoint.Zero + for _, t := range trades { + if t.QuoteQuantity.IsZero() { + quoteQuantity = quoteQuantity.Add(t.Price.Mul(t.Quantity)) + } else { + quoteQuantity = quoteQuantity.Add(t.QuoteQuantity) + } + } + + return quoteQuantity +} From 36e90cf5cabb860128787a4fdf0a8c260f2bf02f Mon Sep 17 00:00:00 2001 From: c9s Date: Fri, 23 Feb 2024 18:50:57 +0800 Subject: [PATCH 2/2] grid2: rename filterPrice to roundAndTruncatePrice --- pkg/strategy/grid2/grid.go | 8 ++++---- pkg/strategy/grid2/grid_test.go | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/strategy/grid2/grid.go b/pkg/strategy/grid2/grid.go index 8156382af..0957d7b3a 100644 --- a/pkg/strategy/grid2/grid.go +++ b/pkg/strategy/grid2/grid.go @@ -35,8 +35,8 @@ type Grid struct { type Pin fixedpoint.Value -// filterPrice filters price with the given precision -func filterPrice(p fixedpoint.Value, prec int) fixedpoint.Value { +// roundAndTruncatePrice rounds the given price at prec-1 and then truncate the price at prec +func roundAndTruncatePrice(p fixedpoint.Value, prec int) fixedpoint.Value { var pow10 = math.Pow10(prec) pp := math.Round(p.Float64()*pow10*10.0) / 10.0 pp = math.Trunc(pp) / pow10 @@ -71,12 +71,12 @@ func calculateArithmeticPins(lower, upper, spread, tickSize fixedpoint.Value) [] var ts = tickSize.Float64() var prec = int(math.Round(math.Log10(ts) * -1.0)) for p := lower; p.Compare(upper.Sub(spread)) <= 0; p = p.Add(spread) { - price := filterPrice(p, prec) + price := roundAndTruncatePrice(p, prec) pins = append(pins, Pin(price)) } // this makes sure there is no error at the upper price - upperPrice := filterPrice(upper, prec) + upperPrice := roundAndTruncatePrice(upper, prec) pins = append(pins, Pin(upperPrice)) return pins diff --git a/pkg/strategy/grid2/grid_test.go b/pkg/strategy/grid2/grid_test.go index ac47f3072..21d008f74 100644 --- a/pkg/strategy/grid2/grid_test.go +++ b/pkg/strategy/grid2/grid_test.go @@ -243,8 +243,8 @@ func Test_filterPrice1(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - rst := filterPrice(tt.args.p, tt.args.prec) - assert.Equalf(t, tt.want, rst.String(), "filterPrice(%v, %v)", tt.args.p, tt.args.prec) + rst := roundAndTruncatePrice(tt.args.p, tt.args.prec) + assert.Equalf(t, tt.want, rst.String(), "roundAndTruncatePrice(%v, %v)", tt.args.p, tt.args.prec) }) } }