Skip to content

Commit

Permalink
fix: Update mexc provider to use v3 api
Browse files Browse the repository at this point in the history
  • Loading branch information
rbajollari committed Mar 28, 2024
1 parent 48cb7fb commit cec517b
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 57 deletions.
121 changes: 70 additions & 51 deletions oracle/provider/mexc.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ package provider
import (
"context"
"encoding/json"
"fmt"
"math/big"
"net/http"
"net/url"
"strconv"
"strings"
"sync"

Expand All @@ -17,9 +20,9 @@ import (

const (
mexcWSHost = "wbs.mexc.com"
mexcWSPath = "/raw/ws"
mexcRestHost = "https://www.mexc.com"
mexcRestPath = "/open/api/v2/market/ticker"
mexcWSPath = "/ws"
mexcRestHost = "https://api.mexc.com/"
mexcRestPath = "/api/v3/ticker/price"
)

var _ Provider = (*MexcProvider)(nil)
Expand All @@ -28,9 +31,7 @@ type (
// MexcProvider defines an Oracle provider implemented by the Mexc public
// API.
//
// REF: https://mxcdevelop.github.io/apidocs/spot_v2_en/#ticker-information
// REF: https://mxcdevelop.github.io/apidocs/spot_v2_en/#k-line
// REF: https://mxcdevelop.github.io/apidocs/spot_v2_en/#overview
// REF: https://mexcdevelop.github.io/apidocs/spot_v3_en/
MexcProvider struct {
wsc *WebsocketController
logger zerolog.Logger
Expand All @@ -42,41 +43,43 @@ type (

// MexcTickerResponse is the ticker price response object.
MexcTickerResponse struct {
Symbol map[string]MexcTicker `json:"data"` // e.x. ATOM_USDT
Symbol string `json:"s"` // e.x. ATOMUSDT
Metadata MexcTicker `json:"d"` // Metadata for ticker
}
MexcTicker struct {
LastPrice float64 `json:"p"` // Last price ex.: 0.0025
Volume float64 `json:"v"` // Total traded base asset volume ex.: 1000
LastPrice string `json:"b"` // Best bid price ex.: 0.0025
Volume string `json:"B"` // Best bid qty ex.: 1000
}

// MexcCandle is the candle websocket response object.
MexcCandleResponse struct {
Symbol string `json:"symbol"` // Symbol ex.: ATOM_USDT
Metadata MexcCandle `json:"data"` // Metadata for candle
Symbol string `json:"s"` // Symbol ex.: ATOMUSDT
Metadata MexcCandle `json:"d"` // Metadata for candle
}
MexcCandle struct {
Close float64 `json:"c"` // Price at close
TimeStamp int64 `json:"t"` // Close time in unix epoch ex.: 1645756200000
Volume float64 `json:"v"` // Volume during period
Data MexcCandleData `json:"k"`
}
MexcCandleData struct {
Close *big.Float `json:"c"` // Price at close
TimeStamp int64 `json:"T"` // Close time in unix epoch ex.: 1645756200
Volume *big.Float `json:"v"` // Volume during period
}

// MexcCandleSubscription Msg to subscribe all the candle channels.
MexcCandleSubscription struct {
OP string `json:"op"` // kline
Symbol string `json:"symbol"` // streams to subscribe ex.: atom_usdt
Interval string `json:"interval"` // Min1、Min5、Min15、Min30
Method string `json:"method"` // ex.: SUBSCRIPTION
Params []string `json:"params"` // ex.: [[email protected]@<symbol>@<interval>]
}

// MexcTickerSubscription Msg to subscribe all the ticker channels.
MexcTickerSubscription struct {
OP string `json:"op"` // kline
Method string `json:"method"` // ex.: SUBSCRIPTION
Params []string `json:"params"` // ex.: [[email protected]@<symbol>]
}

// MexcPairSummary defines the response structure for a Mexc pair
// summary.
MexcPairSummary struct {
Data []MexcPairData `json:"data"`
}
MexcPairSummary []MexcPairData

// MexcPairData defines the data response structure for an Mexc pair.
MexcPairData struct {
Expand Down Expand Up @@ -144,12 +147,13 @@ func (p *MexcProvider) StartConnections() {
}

func (p *MexcProvider) getSubscriptionMsgs(cps ...types.CurrencyPair) []interface{} {
subscriptionMsgs := make([]interface{}, 0, len(cps)+1)
subscriptionMsgs := make([]interface{}, 0, len(cps)*2)
mexcPairs := make([]string, 0, len(cps))
for _, cp := range cps {
mexcPair := currencyPairToMexcPair(cp)
subscriptionMsgs = append(subscriptionMsgs, newMexcCandleSubscriptionMsg(mexcPair))
mexcPairs = append(mexcPairs, currencyPairToMexcPair(cp))
}
subscriptionMsgs = append(subscriptionMsgs, newMexcTickerSubscriptionMsg())
subscriptionMsgs = append(subscriptionMsgs, newMexcCandleSubscriptionMsg(mexcPairs))
subscriptionMsgs = append(subscriptionMsgs, newMexcTickerSubscriptionMsg(mexcPairs))
return subscriptionMsgs
}

Expand Down Expand Up @@ -195,20 +199,14 @@ func (p *MexcProvider) messageReceived(_ int, _ *WebsocketConnection, bz []byte)
)

tickerErr = json.Unmarshal(bz, &tickerResp)
for _, cp := range p.subscribedPairs {
mexcPair := currencyPairToMexcPair(cp)
if tickerResp.Symbol[mexcPair].LastPrice != 0 {
p.setTickerPair(
tickerResp.Symbol[mexcPair],
mexcPair,
)
telemetryWebsocketMessage(ProviderMexc, MessageTypeTicker)
return
}
if tickerResp.Metadata.LastPrice != "" {
p.setTickerPair(tickerResp.Metadata, tickerResp.Symbol)
telemetryWebsocketMessage(ProviderMexc, MessageTypeTicker)
return
}

candleErr = json.Unmarshal(bz, &candleResp)
if candleResp.Metadata.Close != 0 {
if candleResp.Metadata.Data.Close != nil {
p.setCandlePair(candleResp.Metadata, candleResp.Symbol)
telemetryWebsocketMessage(ProviderMexc, MessageTypeCandle)
return
Expand All @@ -224,11 +222,20 @@ func (p *MexcProvider) messageReceived(_ int, _ *WebsocketConnection, bz []byte)
}

func (mt MexcTicker) toTickerPrice() (types.TickerPrice, error) {
price, err := decmath.NewDecFromFloat(mt.LastPrice)
tickerPrice, err := strconv.ParseFloat(mt.LastPrice, 64)
if err != nil {
return types.TickerPrice{}, err
}
volume, err := decmath.NewDecFromFloat(mt.Volume)
price, err := decmath.NewDecFromFloat(tickerPrice)
if err != nil {
return types.TickerPrice{}, err
}

tickerVolume, err := strconv.ParseFloat(mt.Volume, 64)
if err != nil {
return types.TickerPrice{}, err
}
volume, err := decmath.NewDecFromFloat(tickerVolume)
if err != nil {
return types.TickerPrice{}, err
}
Expand All @@ -241,19 +248,23 @@ func (mt MexcTicker) toTickerPrice() (types.TickerPrice, error) {
}

func (mc MexcCandle) toCandlePrice() (types.CandlePrice, error) {
close, err := decmath.NewDecFromFloat(mc.Close)
candleClose, _ := mc.Data.Close.Float64()
close, err := decmath.NewDecFromFloat(candleClose)
if err != nil {
return types.CandlePrice{}, err
}
volume, err := decmath.NewDecFromFloat(mc.Volume)

candleVolume, _ := mc.Data.Volume.Float64()
volume, err := decmath.NewDecFromFloat(candleVolume)
if err != nil {
return types.CandlePrice{}, err
}

candle := types.CandlePrice{
Price: close,
Volume: volume,
// convert seconds -> milli
TimeStamp: SecondsToMilli(mc.TimeStamp),
TimeStamp: SecondsToMilli(mc.Data.TimeStamp),
}
return candle, nil
}
Expand All @@ -279,9 +290,9 @@ func (p *MexcProvider) GetAvailablePairs() (map[string]struct{}, error) {
return nil, err
}

availablePairs := make(map[string]struct{}, len(pairsSummary.Data))
for _, pairName := range pairsSummary.Data {
availablePairs[strings.ToUpper(strings.ReplaceAll(pairName.Symbol, "_", ""))] = struct{}{}
availablePairs := make(map[string]struct{}, len(pairsSummary))
for _, pairName := range pairsSummary {
availablePairs[strings.ToUpper(pairName.Symbol)] = struct{}{}
}

return availablePairs, nil
Expand All @@ -290,21 +301,29 @@ func (p *MexcProvider) GetAvailablePairs() (map[string]struct{}, error) {
// currencyPairToMexcPair receives a currency pair and return mexc
// ticker symbol atomusdt@ticker.
func currencyPairToMexcPair(cp types.CurrencyPair) string {
return strings.ToUpper(cp.Base + "_" + cp.Quote)
return strings.ToUpper(cp.Base + cp.Quote)
}

// newMexcCandleSubscriptionMsg returns a new candle subscription Msg.
func newMexcCandleSubscriptionMsg(param string) MexcCandleSubscription {
func newMexcCandleSubscriptionMsg(symbols []string) MexcCandleSubscription {
params := make([]string, len(symbols))
for i, symbol := range symbols {
params[i] = fmt.Sprintf("[email protected]@%s@Min1", symbol)
}
return MexcCandleSubscription{
OP: "sub.kline",
Symbol: param,
Interval: "Min1",
Method: "SUBSCRIPTION",
Params: params,
}
}

// newMexcTickerSubscriptionMsg returns a new ticker subscription Msg.
func newMexcTickerSubscriptionMsg() MexcTickerSubscription {
func newMexcTickerSubscriptionMsg(symbols []string) MexcTickerSubscription {
params := make([]string, len(symbols))
for i, symbol := range symbols {
params[i] = fmt.Sprintf("[email protected]@%s", symbol)
}
return MexcTickerSubscription{
OP: "sub.overview",
Method: "SUBSCRIPTION",
Params: params,
}
}
12 changes: 6 additions & 6 deletions oracle/provider/mexc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func TestMexcProvider_GetTickerPrices(t *testing.T) {
volume := sdk.MustNewDecFromStr("2396974.02000000")

tickerMap := map[string]types.TickerPrice{}
tickerMap["ATOM_USDT"] = types.TickerPrice{
tickerMap["ATOMUSDT"] = types.TickerPrice{
Price: lastPrice,
Volume: volume,
}
Expand All @@ -45,12 +45,12 @@ func TestMexcProvider_GetTickerPrices(t *testing.T) {
volume := sdk.MustNewDecFromStr("2396974.02000000")

tickerMap := map[string]types.TickerPrice{}
tickerMap["ATOM_USDT"] = types.TickerPrice{
tickerMap["ATOMUSDT"] = types.TickerPrice{
Price: lastPriceAtom,
Volume: volume,
}

tickerMap["LUNA_USDT"] = types.TickerPrice{
tickerMap["LUNAUSDT"] = types.TickerPrice{
Price: lastPriceLuna,
Volume: volume,
}
Expand All @@ -77,7 +77,7 @@ func TestMexcProvider_GetTickerPrices(t *testing.T) {
func TestMexcCurrencyPairToMexcPair(t *testing.T) {
cp := types.CurrencyPair{Base: "ATOM", Quote: "USDT"}
MexcSymbol := currencyPairToMexcPair(cp)
require.Equal(t, MexcSymbol, "ATOM_USDT")
require.Equal(t, MexcSymbol, "ATOMUSDT")
}

func TestMexcProvider_getSubscriptionMsgs(t *testing.T) {
Expand All @@ -88,8 +88,8 @@ func TestMexcProvider_getSubscriptionMsgs(t *testing.T) {
subMsgs := provider.getSubscriptionMsgs(cps...)

msg, _ := json.Marshal(subMsgs[0])
require.Equal(t, "{\"op\":\"sub.kline\",\"symbol\":\"ATOM_USDT\",\"interval\":\"Min1\"}", string(msg))
require.Equal(t, "{\"method\":\"SUBSCRIPTION\",\"params\":[\"[email protected]@ATOMUSDT@Min1\"]}", string(msg))

msg, _ = json.Marshal(subMsgs[1])
require.Equal(t, "{\"op\":\"sub.overview\"}", string(msg))
require.Equal(t, "{\"method\":\"SUBSCRIPTION\",\"params\":[\"[email protected]@ATOMUSDT\"]}", string(msg))
}

0 comments on commit cec517b

Please sign in to comment.