pkg/exchange: refactor get symbol api

This commit is contained in:
Edwin 2023-10-31 11:56:15 +08:00
parent 3491b93c53
commit 4bc177f21b
4 changed files with 116 additions and 22 deletions

View File

@ -9,6 +9,17 @@ import (
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
) )
type SymbolStatus string
const (
// SymbolOffline represent market is suspended, users cannot trade.
SymbolOffline SymbolStatus = "offline"
// SymbolGray represents market is online, but user trading is not available.
SymbolGray SymbolStatus = "gray"
// SymbolOnline trading begins, users can trade.
SymbolOnline SymbolStatus = "online"
)
type Symbol struct { type Symbol struct {
Symbol string `json:"symbol"` Symbol string `json:"symbol"`
SymbolName string `json:"symbolName"` SymbolName string `json:"symbolName"`
@ -18,10 +29,10 @@ type Symbol struct {
MaxTradeAmount fixedpoint.Value `json:"maxTradeAmount"` MaxTradeAmount fixedpoint.Value `json:"maxTradeAmount"`
TakerFeeRate fixedpoint.Value `json:"takerFeeRate"` TakerFeeRate fixedpoint.Value `json:"takerFeeRate"`
MakerFeeRate fixedpoint.Value `json:"makerFeeRate"` MakerFeeRate fixedpoint.Value `json:"makerFeeRate"`
PriceScale int `json:"priceScale"` PriceScale fixedpoint.Value `json:"priceScale"`
QuantityScale int `json:"quantityScale"` QuantityScale fixedpoint.Value `json:"quantityScale"`
MinTradeUSDT fixedpoint.Value `json:"minTradeUSDT"` MinTradeUSDT fixedpoint.Value `json:"minTradeUSDT"`
Status string `json:"status"` Status SymbolStatus `json:"status"`
BuyLimitPriceRatio fixedpoint.Value `json:"buyLimitPriceRatio"` BuyLimitPriceRatio fixedpoint.Value `json:"buyLimitPriceRatio"`
SellLimitPriceRatio fixedpoint.Value `json:"sellLimitPriceRatio"` SellLimitPriceRatio fixedpoint.Value `json:"sellLimitPriceRatio"`
} }

View File

@ -1,6 +1,7 @@
package bitget package bitget
import ( import (
"math"
"strings" "strings"
"github.com/c9s/bbgo/pkg/exchange/bitget/bitgetapi" "github.com/c9s/bbgo/pkg/exchange/bitget/bitgetapi"
@ -23,3 +24,25 @@ func toGlobalBalance(asset bitgetapi.AccountAsset) types.Balance {
MaxWithdrawAmount: fixedpoint.Zero, MaxWithdrawAmount: fixedpoint.Zero,
} }
} }
func toGlobalMarket(s bitgetapi.Symbol) types.Market {
if s.Status != bitgetapi.SymbolOnline {
log.Warnf("The symbol %s is not online", s.Symbol)
}
return types.Market{
Symbol: s.SymbolName,
LocalSymbol: s.Symbol,
PricePrecision: s.PriceScale.Int(),
VolumePrecision: s.QuantityScale.Int(),
QuoteCurrency: s.QuoteCoin,
BaseCurrency: s.BaseCoin,
MinNotional: s.MinTradeUSDT,
MinAmount: s.MinTradeUSDT,
MinQuantity: s.MinTradeAmount,
MaxQuantity: s.MaxTradeAmount,
StepSize: fixedpoint.NewFromFloat(1.0 / math.Pow10(s.QuantityScale.Int())),
TickSize: fixedpoint.NewFromFloat(1.0 / math.Pow10(s.PriceScale.Int())),
MinPrice: fixedpoint.Zero,
MaxPrice: fixedpoint.Zero,
}
}

View File

@ -0,0 +1,66 @@
package bitget
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/c9s/bbgo/pkg/exchange/bitget/bitgetapi"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types"
)
func TestToGlobalMarket(t *testing.T) {
// sample:
//{
// "symbol":"BTCUSDT_SPBL",
// "symbolName":"BTCUSDT",
// "baseCoin":"BTC",
// "quoteCoin":"USDT",
// "minTradeAmount":"0.0001",
// "maxTradeAmount":"10000",
// "takerFeeRate":"0.001",
// "makerFeeRate":"0.001",
// "priceScale":"4",
// "quantityScale":"8",
// "minTradeUSDT":"5",
// "status":"online",
// "buyLimitPriceRatio": "0.05",
// "sellLimitPriceRatio": "0.05"
// }
inst := bitgetapi.Symbol{
Symbol: "BTCUSDT_SPBL",
SymbolName: "BTCUSDT",
BaseCoin: "BTC",
QuoteCoin: "USDT",
MinTradeAmount: fixedpoint.NewFromFloat(0.0001),
MaxTradeAmount: fixedpoint.NewFromFloat(10000),
TakerFeeRate: fixedpoint.NewFromFloat(0.001),
MakerFeeRate: fixedpoint.NewFromFloat(0.001),
PriceScale: fixedpoint.NewFromFloat(4),
QuantityScale: fixedpoint.NewFromFloat(8),
MinTradeUSDT: fixedpoint.NewFromFloat(5),
Status: bitgetapi.SymbolOnline,
BuyLimitPriceRatio: fixedpoint.NewFromFloat(0.05),
SellLimitPriceRatio: fixedpoint.NewFromFloat(0.05),
}
exp := types.Market{
Symbol: inst.SymbolName,
LocalSymbol: inst.Symbol,
PricePrecision: 4,
VolumePrecision: 8,
QuoteCurrency: inst.QuoteCoin,
BaseCurrency: inst.BaseCoin,
MinNotional: inst.MinTradeUSDT,
MinAmount: inst.MinTradeUSDT,
MinQuantity: inst.MinTradeAmount,
MaxQuantity: inst.MaxTradeAmount,
StepSize: fixedpoint.NewFromFloat(0.00000001),
MinPrice: fixedpoint.Zero,
MaxPrice: fixedpoint.Zero,
TickSize: fixedpoint.NewFromFloat(0.0001),
}
assert.Equal(t, toGlobalMarket(inst), exp)
}

View File

@ -2,12 +2,13 @@ package bitget
import ( import (
"context" "context"
"math" "fmt"
"time"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/time/rate"
"github.com/c9s/bbgo/pkg/exchange/bitget/bitgetapi" "github.com/c9s/bbgo/pkg/exchange/bitget/bitgetapi"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/types"
) )
@ -19,6 +20,11 @@ var log = logrus.WithFields(logrus.Fields{
"exchange": ID, "exchange": ID,
}) })
var (
// queryMarketRateLimiter has its own rate limit. https://bitgetlimited.github.io/apidoc/en/spot/#get-symbols
queryMarketRateLimiter = rate.NewLimiter(rate.Every(time.Second/10), 5)
)
type Exchange struct { type Exchange struct {
key, secret, passphrase string key, secret, passphrase string
@ -54,7 +60,10 @@ func (e *Exchange) NewStream() types.Stream {
} }
func (e *Exchange) QueryMarkets(ctx context.Context) (types.MarketMap, error) { func (e *Exchange) QueryMarkets(ctx context.Context) (types.MarketMap, error) {
// TODO implement me if err := queryMarketRateLimiter.Wait(ctx); err != nil {
return nil, fmt.Errorf("markets rate limiter wait error: %w", err)
}
req := e.client.NewGetSymbolsRequest() req := e.client.NewGetSymbolsRequest()
symbols, err := req.Do(ctx) symbols, err := req.Do(ctx)
if err != nil { if err != nil {
@ -64,22 +73,7 @@ func (e *Exchange) QueryMarkets(ctx context.Context) (types.MarketMap, error) {
markets := types.MarketMap{} markets := types.MarketMap{}
for _, s := range symbols { for _, s := range symbols {
symbol := toGlobalSymbol(s.SymbolName) symbol := toGlobalSymbol(s.SymbolName)
markets[symbol] = types.Market{ markets[symbol] = toGlobalMarket(s)
Symbol: s.SymbolName,
LocalSymbol: s.Symbol,
PricePrecision: s.PriceScale,
VolumePrecision: s.QuantityScale,
QuoteCurrency: s.QuoteCoin,
BaseCurrency: s.BaseCoin,
MinNotional: s.MinTradeUSDT,
MinAmount: s.MinTradeUSDT,
MinQuantity: s.MinTradeAmount,
MaxQuantity: s.MaxTradeAmount,
StepSize: fixedpoint.NewFromFloat(math.Pow10(-s.QuantityScale)),
TickSize: fixedpoint.NewFromFloat(math.Pow10(-s.PriceScale)),
MinPrice: fixedpoint.Zero,
MaxPrice: fixedpoint.Zero,
}
} }
return markets, nil return markets, nil