Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Huobi: V2 subscription support #1703

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
344 changes: 173 additions & 171 deletions exchanges/huobi/cfutures_types.go

Large diffs are not rendered by default.

222 changes: 112 additions & 110 deletions exchanges/huobi/futures_types.go

Large diffs are not rendered by default.

2,401 changes: 722 additions & 1,679 deletions exchanges/huobi/huobi_test.go

Large diffs are not rendered by default.

624 changes: 258 additions & 366 deletions exchanges/huobi/huobi_types.go

Large diffs are not rendered by default.

1,085 changes: 489 additions & 596 deletions exchanges/huobi/huobi_websocket.go

Large diffs are not rendered by default.

251 changes: 84 additions & 167 deletions exchanges/huobi/huobi_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ func (h *HUOBI) SetDefaults() {
exchange.RestSpot: huobiAPIURL,
gbjk marked this conversation as resolved.
Show resolved Hide resolved
exchange.RestFutures: huobiFuturesURL,
exchange.RestCoinMargined: huobiFuturesURL,
exchange.WebsocketSpot: wsMarketURL,
exchange.WebsocketSpot: wsSpotURL + wsPublicPath,
})
if err != nil {
log.Errorln(log.ExchangeSys, err)
Expand Down Expand Up @@ -220,7 +220,7 @@ func (h *HUOBI) Setup(exch *config.Exchange) error {

err = h.Websocket.Setup(&stream.WebsocketSetup{
ExchangeConfig: exch,
DefaultURL: wsMarketURL,
DefaultURL: wsSpotURL + wsPublicPath,
RunningURL: wsRunningURL,
Connector: h.WsConnect,
Subscriber: h.Subscribe,
Expand All @@ -245,7 +245,7 @@ func (h *HUOBI) Setup(exch *config.Exchange) error {
RateLimit: request.NewWeightedRateLimitByDuration(20 * time.Millisecond),
ResponseCheckTimeout: exch.WebsocketResponseCheckTimeout,
ResponseMaxLimit: exch.WebsocketResponseMaxLimit,
URL: wsAccountsOrdersURL,
URL: wsSpotURL + wsPrivatePath,
Authenticated: true,
})
}
Expand Down Expand Up @@ -301,7 +301,8 @@ func (h *HUOBI) FetchTradablePairs(ctx context.Context, a asset.Item) (currency.
}
pairs = make([]currency.Pair, 0, len(symbols.Data))
expiryCodeDates := map[string]currency.Code{}
for _, c := range symbols.Data {
for i := range symbols.Data {
c := symbols.Data[i]
if c.ContractStatus != 1 {
continue
}
Expand Down Expand Up @@ -397,7 +398,7 @@ func (h *HUOBI) UpdateTickers(ctx context.Context, a asset.Item) error {
}
continue
}
tt := time.UnixMilli(ticks[i].Timestamp)
tt := ticks[i].Timestamp.Time()
err = ticker.ProcessTicker(&ticker.Price{
High: ticks[i].High.Float64(),
Low: ticks[i].Low.Float64(),
Expand Down Expand Up @@ -465,7 +466,7 @@ func (h *HUOBI) UpdateTickers(ctx context.Context, a asset.Item) error {
Pair: cp,
ExchangeName: h.Name,
AssetType: a,
LastUpdated: time.UnixMilli(ticks[i].Timestamp),
LastUpdated: ticks[i].Timestamp.Time(),
})
if err != nil {
errs = common.AppendError(errs, err)
Expand Down Expand Up @@ -694,72 +695,50 @@ func (h *HUOBI) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (ac
info.Exchange = h.Name
switch assetType {
case asset.Spot:
if h.Websocket.CanUseAuthenticatedWebsocketForWrapper() {
resp, err := h.wsGetAccountsList(ctx)
if err != nil {
return info, err
}
var currencyDetails []account.Balance
for i := range resp.Data {
if len(resp.Data[i].List) == 0 {
continue
}
currData := account.Balance{
Currency: currency.NewCode(resp.Data[i].List[0].Currency),
Total: resp.Data[i].List[0].Balance,
}
if len(resp.Data[i].List) > 1 && resp.Data[i].List[1].Type == "frozen" {
currData.Hold = resp.Data[i].List[1].Balance
}
currencyDetails = append(currencyDetails, currData)
accounts, err := h.GetAccountID(ctx)
if err != nil {
return info, err
}
for i := range accounts {
if accounts[i].Type != "spot" {
continue
}
acc.Currencies = currencyDetails
} else {
accounts, err := h.GetAccountID(ctx)
acc.ID = strconv.FormatInt(accounts[i].ID, 10)
balances, err := h.GetAccountBalance(ctx, acc.ID)
if err != nil {
return info, err
}
for i := range accounts {
if accounts[i].Type != "spot" {
continue
}
acc.ID = strconv.FormatInt(accounts[i].ID, 10)
balances, err := h.GetAccountBalance(ctx, acc.ID)
if err != nil {
return info, err
}

var currencyDetails []account.Balance
balance:
for j := range balances {
frozen := balances[j].Type == "frozen"
for i := range currencyDetails {
if currencyDetails[i].Currency.String() == balances[j].Currency {
if frozen {
currencyDetails[i].Hold = balances[j].Balance
} else {
currencyDetails[i].Total = balances[j].Balance
}
continue balance
var currencyDetails []account.Balance
balance:
for j := range balances {
frozen := balances[j].Type == "frozen"
for i := range currencyDetails {
if currencyDetails[i].Currency.String() == balances[j].Currency {
if frozen {
currencyDetails[i].Hold = balances[j].Balance
} else {
currencyDetails[i].Total = balances[j].Balance
}
continue balance
}
}

if frozen {
currencyDetails = append(currencyDetails,
account.Balance{
Currency: currency.NewCode(balances[j].Currency),
Hold: balances[j].Balance,
})
} else {
currencyDetails = append(currencyDetails,
account.Balance{
Currency: currency.NewCode(balances[j].Currency),
Total: balances[j].Balance,
})
}
if frozen {
currencyDetails = append(currencyDetails,
account.Balance{
Currency: currency.NewCode(balances[j].Currency),
Hold: balances[j].Balance,
})
} else {
currencyDetails = append(currencyDetails,
account.Balance{
Currency: currency.NewCode(balances[j].Currency),
Total: balances[j].Balance,
})
}
acc.Currencies = currencyDetails
}
acc.Currencies = currencyDetails
}

case asset.CoinMarginedFutures:
Expand Down Expand Up @@ -942,7 +921,7 @@ func (h *HUOBI) GetRecentTrades(ctx context.Context, p currency.Pair, a asset.It
Side: side,
Price: sTrades[i].Trades[j].Price,
Amount: sTrades[i].Trades[j].Amount,
Timestamp: time.UnixMilli(sTrades[i].Timestamp),
Timestamp: sTrades[i].Timestamp.Time(),
})
}
}
Expand All @@ -969,7 +948,7 @@ func (h *HUOBI) GetRecentTrades(ctx context.Context, p currency.Pair, a asset.It
Side: side,
Price: fTrades.Data[i].Data[j].Price,
Amount: fTrades.Data[i].Data[j].Amount,
Timestamp: time.UnixMilli(fTrades.Data[i].Data[j].Timestamp),
Timestamp: fTrades.Data[i].Data[j].Timestamp.Time(),
})
}
}
Expand All @@ -995,7 +974,7 @@ func (h *HUOBI) GetRecentTrades(ctx context.Context, p currency.Pair, a asset.It
Side: side,
Price: cTrades.Data[i].Price,
Amount: cTrades.Data[i].Amount,
Timestamp: time.UnixMilli(cTrades.Data[i].Timestamp),
Timestamp: cTrades.Data[i].Timestamp.Time(),
})
}
}
Expand Down Expand Up @@ -1316,24 +1295,15 @@ func (h *HUOBI) GetOrderInfo(ctx context.Context, orderID string, pair currency.
var orderDetail order.Detail
switch assetType {
case asset.Spot:
var respData *OrderInfo
if h.Websocket.CanUseAuthenticatedWebsocketForWrapper() {
resp, err := h.wsGetOrderDetails(ctx, orderID)
if err != nil {
return nil, err
}
respData = &resp.Data
} else {
oID, err := strconv.ParseInt(orderID, 10, 64)
if err != nil {
return nil, err
}
resp, err := h.GetOrder(ctx, oID)
if err != nil {
return nil, err
}
respData = &resp
oID, err := strconv.ParseInt(orderID, 10, 64)
if err != nil {
return nil, err
}
resp, err := h.GetOrder(ctx, oID)
if err != nil {
return nil, err
}
respData := &resp
if respData.ID == 0 {
return nil, fmt.Errorf("%s - order not found for orderid %s", h.Name, orderID)
}
Expand Down Expand Up @@ -1543,87 +1513,34 @@ func (h *HUOBI) GetActiveOrders(ctx context.Context, req *order.MultiOrderReques
if req.Side == order.Sell {
side = req.Side.Lower()
}
if h.Websocket.CanUseAuthenticatedWebsocketForWrapper() {
for i := range req.Pairs {
resp, err := h.wsGetOrdersList(ctx, -1, req.Pairs[i])
if err != nil {
return orders, err
}
for j := range resp.Data {
sideData := strings.Split(resp.Data[j].OrderState, "-")
side = sideData[0]
var orderID = strconv.FormatInt(resp.Data[j].OrderID, 10)
orderSide, err := order.StringToOrderSide(side)
if err != nil {
h.Websocket.DataHandler <- order.ClassificationError{
Exchange: h.Name,
OrderID: orderID,
Err: err,
}
}
orderType, err := order.StringToOrderType(sideData[1])
if err != nil {
h.Websocket.DataHandler <- order.ClassificationError{
Exchange: h.Name,
OrderID: orderID,
Err: err,
}
}
orderStatus, err := order.StringToOrderStatus(resp.Data[j].OrderState)
if err != nil {
h.Websocket.DataHandler <- order.ClassificationError{
Exchange: h.Name,
OrderID: orderID,
Err: err,
}
}
orders = append(orders, order.Detail{
Exchange: h.Name,
AccountID: strconv.FormatInt(resp.Data[j].AccountID, 10),
OrderID: orderID,
Pair: req.Pairs[i],
Type: orderType,
Side: orderSide,
Date: time.UnixMilli(resp.Data[j].CreatedAt),
Status: orderStatus,
Price: resp.Data[j].Price,
Amount: resp.Data[j].OrderAmount,
ExecutedAmount: resp.Data[j].FilledAmount,
RemainingAmount: resp.Data[j].UnfilledAmount,
Fee: resp.Data[j].FilledFees,
})
}
}
} else {
creds, err := h.GetCredentials(ctx)
creds, err := h.GetCredentials(ctx)
if err != nil {
return nil, err
}
for i := range req.Pairs {
resp, err := h.GetOpenOrders(ctx,
req.Pairs[i],
creds.ClientID,
side,
500)
if err != nil {
return nil, err
}
for i := range req.Pairs {
resp, err := h.GetOpenOrders(ctx,
req.Pairs[i],
creds.ClientID,
side,
500)
if err != nil {
return nil, err
}
for x := range resp {
orderDetail := order.Detail{
OrderID: strconv.FormatInt(resp[x].ID, 10),
Price: resp[x].Price,
Amount: resp[x].Amount,
ExecutedAmount: resp[x].FilledAmount,
RemainingAmount: resp[x].Amount - resp[x].FilledAmount,
Pair: req.Pairs[i],
Exchange: h.Name,
Date: time.UnixMilli(resp[x].CreatedAt),
AccountID: strconv.FormatInt(resp[x].AccountID, 10),
Fee: resp[x].FilledFees,
}
setOrderSideStatusAndType(resp[x].State, resp[x].Type, &orderDetail)
orders = append(orders, orderDetail)
for x := range resp {
orderDetail := order.Detail{
OrderID: strconv.FormatInt(resp[x].ID, 10),
Price: resp[x].Price,
Amount: resp[x].Amount,
ExecutedAmount: resp[x].FilledAmount,
RemainingAmount: resp[x].Amount - resp[x].FilledAmount,
Pair: req.Pairs[i],
Exchange: h.Name,
Date: time.UnixMilli(resp[x].CreatedAt),
AccountID: strconv.FormatInt(resp[x].AccountID, 10),
Fee: resp[x].FilledFees,
}
setOrderSideStatusAndType(resp[x].State, resp[x].Type, &orderDetail)
orders = append(orders, orderDetail)
}
}
case asset.CoinMarginedFutures:
Expand Down Expand Up @@ -1950,7 +1867,7 @@ func (h *HUOBI) GetHistoricCandles(ctx context.Context, pair currency.Pair, a as
}

for x := range candles {
timestamp := time.Unix(candles[x].IDTimestamp, 0)
timestamp := candles[x].IDTimestamp.Time()
if timestamp.Before(req.Start) || timestamp.After(req.End) {
continue
}
Expand All @@ -1971,7 +1888,7 @@ func (h *HUOBI) GetHistoricCandles(ctx context.Context, pair currency.Pair, a as
return nil, err
}
for x := range candles.Data {
timestamp := time.Unix(candles.Data[x].IDTimestamp, 0)
timestamp := candles.Data[x].IDTimestamp.Time()
if timestamp.Before(req.Start) || timestamp.After(req.End) {
continue
}
Expand All @@ -1992,7 +1909,7 @@ func (h *HUOBI) GetHistoricCandles(ctx context.Context, pair currency.Pair, a as
return nil, err
}
for x := range candles.Data {
timestamp := time.Unix(candles.Data[x].IDTimestamp, 0)
timestamp := candles.Data[x].IDTimestamp.Time()
if timestamp.Before(req.Start) || timestamp.After(req.End) {
continue
}
Expand Down Expand Up @@ -2032,7 +1949,7 @@ func (h *HUOBI) GetHistoricCandlesExtended(ctx context.Context, pair currency.Pa
}
for x := range candles.Data {
// align response data
timestamp := time.Unix(candles.Data[x].IDTimestamp, 0).UTC()
timestamp := candles.Data[x].IDTimestamp.Time()
if timestamp.Before(req.Start) || timestamp.After(req.End) {
continue
}
Expand All @@ -2057,7 +1974,7 @@ func (h *HUOBI) GetHistoricCandlesExtended(ctx context.Context, pair currency.Pa
}
for x := range candles.Data {
// align response data
timestamp := time.Unix(candles.Data[x].IDTimestamp, 0)
timestamp := candles.Data[x].IDTimestamp.Time()
if timestamp.Before(req.Start) || timestamp.After(req.End) {
continue
}
Expand Down Expand Up @@ -2212,10 +2129,10 @@ func (h *HUOBI) GetFuturesContractDetails(ctx context.Context, item asset.Item)
if err != nil {
return nil, err
}
if result.Data[x].DeliveryTime > 0 {
e = time.UnixMilli(result.Data[x].DeliveryTime)
if result.Data[x].DeliveryTime.Time().IsZero() {
e = result.Data[x].DeliveryTime.Time()
} else {
e = time.UnixMilli(result.Data[x].SettlementTime)
e = result.Data[x].SettlementTime.Time()
}
contractLength := e.Sub(s)
var ct futures.ContractType
Expand Down
1 change: 1 addition & 0 deletions exchanges/huobi/testdata/wsAllTrades.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"ch":"market.btcusdt.trade.detail","ts":1630994963175,"tick":{"id":137005445109,"ts":1630994963173,"data":[{"id":137005445109359290000000000,"ts":1630994963173,"tradeId":102523573486,"amount":0.006754,"price":52648.62,"direction":"buy"}]}}
1 change: 1 addition & 0 deletions exchanges/huobi/testdata/wsCandles.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"ch":"market.btcusdt.kline.1min","ts":1489474082831,"tick":{"id":1489464480,"amount":1821.49,"count":4,"open":7962.62,"close":8014.56,"low":5110.14,"high":14962.77,"vol":4.4}}
Loading
Loading