diff --git a/feeder/priceprovider/priceprovider.go b/feeder/priceprovider/priceprovider.go index b23a2d2..639d220 100644 --- a/feeder/priceprovider/priceprovider.go +++ b/feeder/priceprovider/priceprovider.go @@ -44,6 +44,8 @@ func NewPriceProvider( source = sources.NewTickSource(symbolsFromPairToSymbolMapping(pairToSymbolMap), sources.BinancePriceUpdate, logger) case sources.Coingecko: source = sources.NewTickSource(symbolsFromPairToSymbolMapping(pairToSymbolMap), sources.CoingeckoPriceUpdate(config), logger) + case sources.Bybit: + source = sources.NewTickSource(symbolsFromPairToSymbolMapping(pairToSymbolMap), sources.BybitPriceUpdate, logger) case sources.GateIo: source = sources.NewTickSource(symbolsFromPairToSymbolMapping(pairToSymbolMap), sources.GateIoPriceUpdate, logger) case sources.CoinMarketCap: diff --git a/feeder/priceprovider/sources/bybit.go b/feeder/priceprovider/sources/bybit.go new file mode 100644 index 0000000..fc469b8 --- /dev/null +++ b/feeder/priceprovider/sources/bybit.go @@ -0,0 +1,68 @@ +package sources + +import ( + "encoding/json" + "github.com/NibiruChain/nibiru/x/common/set" + "github.com/NibiruChain/pricefeeder/types" + "io" + "net/http" + "strconv" +) + +const ( + Bybit = "bybit" +) + +var _ types.FetchPricesFunc = BybitPriceUpdate + +type BybitTicker struct { + Symbol string `json:"symbol"` + Price string `json:"lastPrice"` +} + +type Response struct { + Data struct { + List []BybitTicker `json:"list"` + } `json:"result"` +} + +// BybitPriceUpdate returns the prices for given symbols or an error. +// Uses BYBIT API at https://bybit-exchange.github.io/docs/v5/market/tickers. +func BybitPriceUpdate(symbols set.Set[types.Symbol]) (rawPrices map[types.Symbol]float64, err error) { + + url := "https://api.bybit.com/v5/market/tickers?category=spot" + + resp, err := http.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + b, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var response Response + err = json.Unmarshal(b, &response) + if err != nil { + return nil, err + } + + rawPrices = make(map[types.Symbol]float64) + + for _, ticker := range response.Data.List { + + symbol := types.Symbol(ticker.Symbol) + price, err := strconv.ParseFloat(ticker.Price, 64) + if err != nil { + return rawPrices, err + } + + if _, ok := symbols[symbol]; ok { + rawPrices[symbol] = price + } + + } + return rawPrices, nil +} diff --git a/feeder/priceprovider/sources/bybit_test.go b/feeder/priceprovider/sources/bybit_test.go new file mode 100644 index 0000000..63deb22 --- /dev/null +++ b/feeder/priceprovider/sources/bybit_test.go @@ -0,0 +1,20 @@ +package sources + +import ( + "testing" + + "github.com/NibiruChain/nibiru/x/common/set" + "github.com/NibiruChain/pricefeeder/types" + "github.com/stretchr/testify/require" +) + +func TestBybitPriceUpdate(t *testing.T) { + + t.Run("success", func(t *testing.T) { + rawPrices, err := BybitPriceUpdate(set.New[types.Symbol]("BTCUSDT", "ETHUSDT")) + require.NoError(t, err) + require.Equal(t, 2, len(rawPrices)) + require.NotZero(t, rawPrices["BTCUSDT"]) + require.NotZero(t, rawPrices["ETHUSDT"]) + }) +}