From fbbe304dfb2cba4043dc0bace64aa7087593938a Mon Sep 17 00:00:00 2001 From: c9s Date: Fri, 29 Jan 2021 18:48:00 +0800 Subject: [PATCH] add trades query api --- pkg/bbgo/environment.go | 5 +++- pkg/bbgo/server.go | 32 +++++++++++++++++++-- pkg/cmd/pnl.go | 5 +++- pkg/service/order.go | 11 ++++---- pkg/service/trade.go | 61 ++++++++++++++++++++++++++++++++++++----- 5 files changed, 98 insertions(+), 16 deletions(-) diff --git a/pkg/bbgo/environment.go b/pkg/bbgo/environment.go index 41f80475d..8223ba634 100644 --- a/pkg/bbgo/environment.go +++ b/pkg/bbgo/environment.go @@ -206,7 +206,10 @@ func (environ *Environment) Init(ctx context.Context) (err error) { if strings.HasPrefix(symbol, tradingFeeCurrency) { trades, err = environ.TradeService.QueryForTradingFeeCurrency(session.Exchange.Name(), symbol, tradingFeeCurrency) } else { - trades, err = environ.TradeService.Query(session.Exchange.Name(), symbol) + trades, err = environ.TradeService.Query(service.QueryTradesOptions{ + Exchange: session.Exchange.Name(), + Symbol: symbol, + }) } if err != nil { diff --git a/pkg/bbgo/server.go b/pkg/bbgo/server.go index db8f4aed1..54020b067 100644 --- a/pkg/bbgo/server.go +++ b/pkg/bbgo/server.go @@ -30,6 +30,34 @@ func RunServer(ctx context.Context, userConfig *Config, environ *Environment) er c.JSON(http.StatusOK, gin.H{"message": "pong"}) }) + r.GET("/api/trades", func(c *gin.Context) { + exchange := c.Query("exchange") + symbol := c.Query("symbol") + gidStr := c.DefaultQuery("gid", "0") + lastGID, err := strconv.ParseInt(gidStr, 10, 64) + if err != nil { + log.WithError(err).Error("last gid parse error") + c.Status(http.StatusBadRequest) + return + } + + trades, err := environ.TradeService.Query(service.QueryTradesOptions{ + Exchange: types.ExchangeName(exchange), + Symbol: symbol, + LastGID: lastGID, + Ordering: "DESC", + }) + if err != nil { + c.Status(http.StatusBadRequest) + log.WithError(err).Error("order query error") + return + } + + c.JSON(http.StatusOK, gin.H{ + "trades": trades, + }) + }) + r.GET("/api/orders/closed", func(c *gin.Context) { exchange := c.Query("exchange") symbol := c.Query("symbol") @@ -42,11 +70,11 @@ func RunServer(ctx context.Context, userConfig *Config, environ *Environment) er return } - orders, err := environ.OrderService.Query(service.OrderQueryOptions{ + orders, err := environ.OrderService.Query(service.QueryOrdersOptions{ Exchange: types.ExchangeName(exchange), Symbol: symbol, LastGID: lastGID, - Order: "DESC", + Ordering: "DESC", }) if err != nil { c.Status(http.StatusBadRequest) diff --git a/pkg/cmd/pnl.go b/pkg/cmd/pnl.go index 3eb9c0115..9e27c6f5b 100644 --- a/pkg/cmd/pnl.go +++ b/pkg/cmd/pnl.go @@ -64,7 +64,10 @@ var PnLCmd = &cobra.Command{ log.Infof("loading all trading fee currency related trades: %s", symbol) trades, err = tradeService.QueryForTradingFeeCurrency(exchange.Name(), symbol, tradingFeeCurrency) } else { - trades, err = tradeService.Query(exchange.Name(), symbol) + trades, err = tradeService.Query(service.QueryTradesOptions{ + Exchange: exchange.Name(), + Symbol: symbol, + }) } if err != nil { diff --git a/pkg/service/order.go b/pkg/service/order.go index 9816adc38..422685fbc 100644 --- a/pkg/service/order.go +++ b/pkg/service/order.go @@ -50,18 +50,19 @@ type AggOrder struct { AveragePrice *float64 `json:"averagePrice" db:"average_price"` } -type OrderQueryOptions struct { +type QueryOrdersOptions struct { Exchange types.ExchangeName Symbol string LastGID int64 - Order string + Ordering string } -func (s *OrderService) Query(options OrderQueryOptions) ([]AggOrder, error) { +func (s *OrderService) Query(options QueryOrdersOptions) ([]AggOrder, error) { // ascending ordering := "ASC" - if len(options.Order) > 0 { - ordering = options.Order + switch v := strings.ToUpper(options.Ordering); v { + case "DESC", "ASC": + ordering = options.Ordering } var where []string diff --git a/pkg/service/trade.go b/pkg/service/trade.go index c4e1b6c35..67002d8bb 100644 --- a/pkg/service/trade.go +++ b/pkg/service/trade.go @@ -1,6 +1,7 @@ package service import ( + "strconv" "strings" "time" @@ -22,8 +23,8 @@ type TradingVolume struct { } type TradingVolumeQueryOptions struct { - GroupByPeriod string - SegmentBy string + GroupByPeriod string + SegmentBy string } type TradeService struct { @@ -157,11 +158,57 @@ func (s *TradeService) QueryForTradingFeeCurrency(ex types.ExchangeName, symbol return s.scanRows(rows) } -func (s *TradeService) Query(ex types.ExchangeName, symbol string) ([]types.Trade, error) { - rows, err := s.DB.NamedQuery(`SELECT * FROM trades WHERE exchange = :exchange AND symbol = :symbol ORDER BY gid ASC`, map[string]interface{}{ - "exchange": ex, - "symbol": symbol, - }) +type QueryTradesOptions struct { + Exchange types.ExchangeName + Symbol string + LastGID int64 + Ordering string +} + +func (s *TradeService) Query(options QueryTradesOptions) ([]types.Trade, error) { + ordering := "ASC" + switch v := strings.ToUpper(options.Ordering); v { + case "DESC", "ASC": + ordering = v + } + + var where []string + + if len(options.Exchange) > 0 { + where = append(where, `exchange = :exchange`) + } + + if len(options.Symbol) > 0 { + where = append(where, `symbol = :symbol`) + } + + if options.LastGID > 0 { + switch ordering { + case "ASC": + where = append(where, "gid > :gid") + case "DESC": + where = append(where, "gid < :gid") + + } + } + + sql := `SELECT * FROM trades` + + if len(where) > 0 { + sql += ` WHERE ` + strings.Join(where, " AND ") + } + + sql += ` ORDER BY gid ` + ordering + + sql += ` LIMIT ` + strconv.Itoa(500) + + log.Info(sql) + + args := map[string]interface{}{ + "exchange": options.Exchange, + "symbol": options.Symbol, + } + rows, err := s.DB.NamedQuery(sql, args) if err != nil { return nil, err }