mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-31 07:26:44 +00:00
exchanges/engine: Add multichain deposit/withdrawal support (#794)
* Add exchange multichain support * Start tidying up * Add multichain transfer support for Bitfinex and fix poloniex bug * Add Coinbene multichain support * Start adjusting the deposit address manager * Fix deposit tests and further enhancements * Cleanup * Add bypass flag, expand tests plus error coverage for Huobi Adjust helpers * Address nitterinos * BFX wd changes * Address nitterinos * Minor fixes rebasing on master * Fix BFX acceptableMethods test * Add some TO-DOs for 2 tests WRT races * Fix acceptableMethods test round 2 * Address nitterinos
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
@@ -21,47 +22,49 @@ import (
|
||||
|
||||
const (
|
||||
huobiAPIURL = "https://api.huobi.pro"
|
||||
huobiURL = "https://api.hbdm.com/"
|
||||
huobiFuturesURL = "https://api.hbdm.com"
|
||||
huobiURL = "https://api.hbdm.com"
|
||||
huobiFuturesURL = huobiURL
|
||||
huobiAPIVersion = "1"
|
||||
huobiAPIVersion2 = "2"
|
||||
|
||||
// Spot endpoints
|
||||
huobiMarketHistoryKline = "market/history/kline"
|
||||
huobiMarketDetail = "market/detail"
|
||||
huobiMarketDetailMerged = "market/detail/merged"
|
||||
huobi24HrMarketSummary = "/market/detail?"
|
||||
huobiMarketDepth = "market/depth"
|
||||
huobiMarketTrade = "market/trade"
|
||||
huobiMarketTickers = "market/tickers"
|
||||
huobiMarketTradeHistory = "market/history/trade"
|
||||
huobiSymbols = "common/symbols"
|
||||
huobiCurrencies = "common/currencys"
|
||||
huobiTimestamp = "common/timestamp"
|
||||
huobiAccounts = "account/accounts"
|
||||
huobiAccountBalance = "account/accounts/%s/balance"
|
||||
huobiAccountDepositAddress = "account/deposit/address"
|
||||
huobiAccountWithdrawQuota = "account/withdraw/quota"
|
||||
huobiAggregatedBalance = "subuser/aggregate-balance"
|
||||
huobiOrderPlace = "order/orders/place"
|
||||
huobiOrderCancel = "order/orders/%s/submitcancel"
|
||||
huobiOrderCancelBatch = "order/orders/batchcancel"
|
||||
huobiBatchCancelOpenOrders = "order/orders/batchCancelOpenOrders"
|
||||
huobiGetOrder = "order/orders/getClientOrder"
|
||||
huobiGetOrderMatch = "order/orders/%s/matchresults"
|
||||
huobiGetOrders = "order/orders"
|
||||
huobiGetOpenOrders = "order/openOrders"
|
||||
huobiGetOrdersMatch = "orders/matchresults"
|
||||
huobiMarginTransferIn = "dw/transfer-in/margin"
|
||||
huobiMarginTransferOut = "dw/transfer-out/margin"
|
||||
huobiMarginOrders = "margin/orders"
|
||||
huobiMarginRepay = "margin/orders/%s/repay"
|
||||
huobiMarginLoanOrders = "margin/loan-orders"
|
||||
huobiMarginAccountBalance = "margin/accounts/balance"
|
||||
huobiWithdrawCreate = "dw/withdraw/api/create"
|
||||
huobiWithdrawCancel = "dw/withdraw-virtual/%s/cancel"
|
||||
huobiStatusError = "error"
|
||||
huobiMarginRates = "margin/loan-info"
|
||||
huobiMarketHistoryKline = "/market/history/kline"
|
||||
huobiMarketDetail = "/market/detail"
|
||||
huobiMarketDetailMerged = "/market/detail/merged"
|
||||
huobi24HrMarketSummary = "/market/detail?"
|
||||
huobiMarketDepth = "/market/depth"
|
||||
huobiMarketTrade = "/market/trade"
|
||||
huobiMarketTickers = "/market/tickers"
|
||||
huobiMarketTradeHistory = "/market/history/trade"
|
||||
huobiSymbols = "/v1/common/symbols"
|
||||
huobiCurrencies = "/v1/common/currencys"
|
||||
huobiTimestamp = "/common/timestamp"
|
||||
huobiAccounts = "/account/accounts"
|
||||
huobiAccountBalance = "/account/accounts/%s/balance"
|
||||
huobiAccountDepositAddress = "/account/deposit/address"
|
||||
huobiAccountWithdrawQuota = "/account/withdraw/quota"
|
||||
huobiAccountQueryWithdrawAddress = "/account/withdraw/"
|
||||
huobiAggregatedBalance = "/subuser/aggregate-balance"
|
||||
huobiOrderPlace = "/order/orders/place"
|
||||
huobiOrderCancel = "/order/orders/%s/submitcancel"
|
||||
huobiOrderCancelBatch = "/order/orders/batchcancel"
|
||||
huobiBatchCancelOpenOrders = "/order/orders/batchCancelOpenOrders"
|
||||
huobiGetOrder = "/order/orders/getClientOrder"
|
||||
huobiGetOrderMatch = "/order/orders/%s/matchresults"
|
||||
huobiGetOrders = "/order/orders"
|
||||
huobiGetOpenOrders = "/order/openOrders"
|
||||
huobiGetOrdersMatch = "/orders/matchresults"
|
||||
huobiMarginTransferIn = "/dw/transfer-in/margin"
|
||||
huobiMarginTransferOut = "/dw/transfer-out/margin"
|
||||
huobiMarginOrders = "/margin/orders"
|
||||
huobiMarginRepay = "/margin/orders/%s/repay"
|
||||
huobiMarginLoanOrders = "/margin/loan-orders"
|
||||
huobiMarginAccountBalance = "/margin/accounts/balance"
|
||||
huobiWithdrawCreate = "/dw/withdraw/api/create"
|
||||
huobiWithdrawCancel = "/dw/withdraw-virtual/%s/cancel"
|
||||
huobiStatusError = "error"
|
||||
huobiMarginRates = "/margin/loan-info"
|
||||
huobiCurrenciesReference = "/v2/reference/currencies"
|
||||
)
|
||||
|
||||
// HUOBI is the overarching type across this package
|
||||
@@ -106,7 +109,7 @@ func (h *HUOBI) GetSpotKline(ctx context.Context, arg KlinesRequestParams) ([]Kl
|
||||
|
||||
var result response
|
||||
|
||||
err = h.SendHTTPRequest(ctx, exchange.RestSpot, common.EncodeURLValues("/"+huobiMarketHistoryKline, vals), &result)
|
||||
err = h.SendHTTPRequest(ctx, exchange.RestSpot, common.EncodeURLValues(huobiMarketHistoryKline, vals), &result)
|
||||
if result.ErrorMessage != "" {
|
||||
return nil, errors.New(result.ErrorMessage)
|
||||
}
|
||||
@@ -128,7 +131,7 @@ func (h *HUOBI) Get24HrMarketSummary(ctx context.Context, symbol currency.Pair)
|
||||
// GetTickers returns the ticker for the specified symbol
|
||||
func (h *HUOBI) GetTickers(ctx context.Context) (Tickers, error) {
|
||||
var result Tickers
|
||||
return result, h.SendHTTPRequest(ctx, exchange.RestSpot, "/"+huobiMarketTickers, &result)
|
||||
return result, h.SendHTTPRequest(ctx, exchange.RestSpot, huobiMarketTickers, &result)
|
||||
}
|
||||
|
||||
// GetMarketDetailMerged returns the ticker for the specified symbol
|
||||
@@ -147,7 +150,7 @@ func (h *HUOBI) GetMarketDetailMerged(ctx context.Context, symbol currency.Pair)
|
||||
|
||||
var result response
|
||||
|
||||
err = h.SendHTTPRequest(ctx, exchange.RestSpot, common.EncodeURLValues("/"+huobiMarketDetailMerged, vals), &result)
|
||||
err = h.SendHTTPRequest(ctx, exchange.RestSpot, common.EncodeURLValues(huobiMarketDetailMerged, vals), &result)
|
||||
if result.ErrorMessage != "" {
|
||||
return result.Tick, errors.New(result.ErrorMessage)
|
||||
}
|
||||
@@ -174,7 +177,7 @@ func (h *HUOBI) GetDepth(ctx context.Context, obd OrderBookDataRequestParams) (O
|
||||
|
||||
var result response
|
||||
|
||||
err = h.SendHTTPRequest(ctx, exchange.RestSpot, common.EncodeURLValues("/"+huobiMarketDepth, vals), &result)
|
||||
err = h.SendHTTPRequest(ctx, exchange.RestSpot, common.EncodeURLValues(huobiMarketDepth, vals), &result)
|
||||
if result.ErrorMessage != "" {
|
||||
return result.Depth, errors.New(result.ErrorMessage)
|
||||
}
|
||||
@@ -199,7 +202,7 @@ func (h *HUOBI) GetTrades(ctx context.Context, symbol currency.Pair) ([]Trade, e
|
||||
|
||||
var result response
|
||||
|
||||
err = h.SendHTTPRequest(ctx, exchange.RestSpot, common.EncodeURLValues("/"+huobiMarketTrade, vals), &result)
|
||||
err = h.SendHTTPRequest(ctx, exchange.RestSpot, common.EncodeURLValues(huobiMarketTrade, vals), &result)
|
||||
if result.ErrorMessage != "" {
|
||||
return nil, errors.New(result.ErrorMessage)
|
||||
}
|
||||
@@ -242,7 +245,7 @@ func (h *HUOBI) GetTradeHistory(ctx context.Context, symbol currency.Pair, size
|
||||
|
||||
var result response
|
||||
|
||||
err = h.SendHTTPRequest(ctx, exchange.RestSpot, common.EncodeURLValues("/"+huobiMarketTradeHistory, vals), &result)
|
||||
err = h.SendHTTPRequest(ctx, exchange.RestSpot, common.EncodeURLValues(huobiMarketTradeHistory, vals), &result)
|
||||
if result.ErrorMessage != "" {
|
||||
return nil, errors.New(result.ErrorMessage)
|
||||
}
|
||||
@@ -265,7 +268,7 @@ func (h *HUOBI) GetMarketDetail(ctx context.Context, symbol currency.Pair) (Deta
|
||||
|
||||
var result response
|
||||
|
||||
err = h.SendHTTPRequest(ctx, exchange.RestSpot, common.EncodeURLValues("/"+huobiMarketDetail, vals), &result)
|
||||
err = h.SendHTTPRequest(ctx, exchange.RestSpot, common.EncodeURLValues(huobiMarketDetail, vals), &result)
|
||||
if result.ErrorMessage != "" {
|
||||
return result.Tick, errors.New(result.ErrorMessage)
|
||||
}
|
||||
@@ -281,7 +284,7 @@ func (h *HUOBI) GetSymbols(ctx context.Context) ([]Symbol, error) {
|
||||
|
||||
var result response
|
||||
|
||||
err := h.SendHTTPRequest(ctx, exchange.RestSpot, "/v"+huobiAPIVersion+"/"+huobiSymbols, &result)
|
||||
err := h.SendHTTPRequest(ctx, exchange.RestSpot, huobiSymbols, &result)
|
||||
if result.ErrorMessage != "" {
|
||||
return nil, errors.New(result.ErrorMessage)
|
||||
}
|
||||
@@ -296,16 +299,32 @@ func (h *HUOBI) GetCurrencies(ctx context.Context) ([]string, error) {
|
||||
}
|
||||
|
||||
var result response
|
||||
err := h.SendHTTPRequest(ctx,
|
||||
exchange.RestSpot,
|
||||
"/v"+huobiAPIVersion+"/"+huobiCurrencies,
|
||||
&result)
|
||||
|
||||
err := h.SendHTTPRequest(ctx, exchange.RestSpot, huobiCurrencies, &result)
|
||||
if result.ErrorMessage != "" {
|
||||
return nil, errors.New(result.ErrorMessage)
|
||||
}
|
||||
return result.Currencies, err
|
||||
}
|
||||
|
||||
// GetCurrenciesIncludingChains returns currency and chain data
|
||||
func (h *HUOBI) GetCurrenciesIncludingChains(ctx context.Context, curr currency.Code) ([]CurrenciesChainData, error) {
|
||||
resp := struct {
|
||||
Data []CurrenciesChainData `json:"data"`
|
||||
}{}
|
||||
|
||||
vals := url.Values{}
|
||||
if !curr.IsEmpty() {
|
||||
vals.Set("currency", curr.Lower().String())
|
||||
}
|
||||
path := common.EncodeURLValues(huobiCurrenciesReference, vals)
|
||||
err := h.SendHTTPRequest(ctx, exchange.RestSpot, path, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Data, nil
|
||||
}
|
||||
|
||||
// GetTimestamp returns the Huobi server time
|
||||
func (h *HUOBI) GetTimestamp(ctx context.Context) (int64, error) {
|
||||
type response struct {
|
||||
@@ -714,7 +733,11 @@ func (h *HUOBI) GetMarginAccountBalance(ctx context.Context, symbol currency.Pai
|
||||
}
|
||||
|
||||
// Withdraw withdraws the desired amount and currency
|
||||
func (h *HUOBI) Withdraw(ctx context.Context, c currency.Code, address, addrTag string, amount, fee float64) (int64, error) {
|
||||
func (h *HUOBI) Withdraw(ctx context.Context, c currency.Code, address, addrTag, chain string, amount, fee float64) (int64, error) {
|
||||
if c.IsEmpty() || address == "" || amount <= 0 {
|
||||
return 0, errors.New("currency, address and amount must be set")
|
||||
}
|
||||
|
||||
resp := struct {
|
||||
WithdrawID int64 `json:"data"`
|
||||
}{}
|
||||
@@ -724,6 +747,7 @@ func (h *HUOBI) Withdraw(ctx context.Context, c currency.Code, address, addrTag
|
||||
Amount string `json:"amount"`
|
||||
Currency string `json:"currency"`
|
||||
Fee string `json:"fee,omitempty"`
|
||||
Chain string `json:"chain,omitempty"`
|
||||
AddrTag string `json:"addr-tag,omitempty"`
|
||||
}{
|
||||
Address: address,
|
||||
@@ -735,11 +759,15 @@ func (h *HUOBI) Withdraw(ctx context.Context, c currency.Code, address, addrTag
|
||||
data.Fee = strconv.FormatFloat(fee, 'f', -1, 64)
|
||||
}
|
||||
|
||||
if c == currency.XRP {
|
||||
if addrTag != "" {
|
||||
data.AddrTag = addrTag
|
||||
}
|
||||
|
||||
err := h.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, huobiWithdrawCreate, nil, data, &resp.WithdrawID, false)
|
||||
if chain != "" {
|
||||
data.Chain = strings.ToLower(chain)
|
||||
}
|
||||
|
||||
err := h.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, huobiWithdrawCreate, nil, data, &resp, false)
|
||||
return resp.WithdrawID, err
|
||||
}
|
||||
|
||||
@@ -757,22 +785,22 @@ func (h *HUOBI) CancelWithdraw(ctx context.Context, withdrawID int64) (int64, er
|
||||
}
|
||||
|
||||
// QueryDepositAddress returns the deposit address for a specified currency
|
||||
func (h *HUOBI) QueryDepositAddress(ctx context.Context, cryptocurrency string) (DepositAddress, error) {
|
||||
func (h *HUOBI) QueryDepositAddress(ctx context.Context, cryptocurrency currency.Code) ([]DepositAddress, error) {
|
||||
resp := struct {
|
||||
DepositAddress []DepositAddress `json:"data"`
|
||||
}{}
|
||||
|
||||
vals := url.Values{}
|
||||
vals.Set("currency", cryptocurrency)
|
||||
vals.Set("currency", cryptocurrency.Lower().String())
|
||||
|
||||
err := h.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, huobiAccountDepositAddress, vals, nil, &resp, true)
|
||||
if err != nil {
|
||||
return DepositAddress{}, err
|
||||
return nil, err
|
||||
}
|
||||
if len(resp.DepositAddress) == 0 {
|
||||
return DepositAddress{}, errors.New("deposit address data isn't populated")
|
||||
return nil, errors.New("deposit address data isn't populated")
|
||||
}
|
||||
return resp.DepositAddress[0], nil
|
||||
return resp.DepositAddress, nil
|
||||
}
|
||||
|
||||
// QueryWithdrawQuotas returns the users cryptocurrency withdraw quotas
|
||||
@@ -817,8 +845,13 @@ func (h *HUOBI) SendHTTPRequest(ctx context.Context, ep exchange.URL, path strin
|
||||
|
||||
var errCap errorCapture
|
||||
if err := json.Unmarshal(tempResp, &errCap); err == nil {
|
||||
if errCap.Code != 200 && errCap.ErrMsg != "" {
|
||||
return errors.New(errCap.ErrMsg)
|
||||
if errCap.ErrMsgType1 != "" {
|
||||
return fmt.Errorf("error code: %v error message: %s", errCap.CodeType1,
|
||||
errors.New(errCap.ErrMsgType1))
|
||||
}
|
||||
if errCap.ErrMsgType2 != "" {
|
||||
return fmt.Errorf("error code: %v error message: %s", errCap.CodeType2,
|
||||
errors.New(errCap.ErrMsgType2))
|
||||
}
|
||||
}
|
||||
return json.Unmarshal(tempResp, result)
|
||||
@@ -839,16 +872,15 @@ func (h *HUOBI) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange.UR
|
||||
|
||||
interim := json.RawMessage{}
|
||||
newRequest := func() (*request.Item, error) {
|
||||
now := time.Now()
|
||||
values.Set("AccessKeyId", h.API.Credentials.Key)
|
||||
values.Set("SignatureMethod", "HmacSHA256")
|
||||
values.Set("SignatureVersion", "2")
|
||||
values.Set("Timestamp", now.UTC().Format("2006-01-02T15:04:05"))
|
||||
values.Set("Timestamp", time.Now().UTC().Format("2006-01-02T15:04:05"))
|
||||
|
||||
if isVersion2API {
|
||||
endpoint = "/v" + huobiAPIVersion2 + "/" + endpoint
|
||||
endpoint = "/v" + huobiAPIVersion2 + endpoint
|
||||
} else {
|
||||
endpoint = "/v" + huobiAPIVersion + "/" + endpoint
|
||||
endpoint = "/v" + huobiAPIVersion + endpoint
|
||||
}
|
||||
|
||||
payload := fmt.Sprintf("%s\napi.huobi.pro\n%s\n%s",
|
||||
@@ -903,14 +935,14 @@ func (h *HUOBI) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange.UR
|
||||
var errCap ResponseV2
|
||||
if err = json.Unmarshal(interim, &errCap); err == nil {
|
||||
if errCap.Code != 200 && errCap.Message != "" {
|
||||
return errors.New(errCap.Message)
|
||||
return fmt.Errorf("error code: %v error message: %s", errCap.Code, errCap.Message)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var errCap Response
|
||||
if err = json.Unmarshal(interim, &errCap); err == nil {
|
||||
if errCap.Status == huobiStatusError && errCap.ErrorMessage != "" {
|
||||
return errors.New(errCap.ErrorMessage)
|
||||
return fmt.Errorf("error code: %v error message: %s", errCap.ErrorCode, errCap.ErrorMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,43 +18,43 @@ import (
|
||||
|
||||
const (
|
||||
// Coin Margined Swap (perpetual futures) endpoints
|
||||
huobiSwapMarkets = "swap-api/v1/swap_contract_info?"
|
||||
huobiSwapFunding = "swap-api/v1/swap_funding_rate?"
|
||||
huobiSwapIndexPriceInfo = "swap-api/v1/swap_index?"
|
||||
huobiSwapPriceLimitation = "swap-api/v1/swap_price_limit?"
|
||||
huobiSwapOpenInterestInfo = "swap-api/v1/swap_open_interest?"
|
||||
huobiSwapMarketDepth = "swap-ex/market/depth?"
|
||||
huobiKLineData = "swap-ex/market/history/kline?"
|
||||
huobiMarketDataOverview = "swap-ex/market/detail/merged?"
|
||||
huobiLastTradeContract = "swap-ex/market/trade?"
|
||||
huobiRequestBatchOfTradingRecords = "swap-ex/market/history/trade?"
|
||||
huobiInsuranceBalanceAndClawbackRate = "swap-api/v1/swap_risk_info?"
|
||||
huobiInsuranceBalanceHistory = "swap-api/v1/swap_insurance_fund?"
|
||||
huobiTieredAdjustmentFactor = "swap-api/v1/swap_adjustfactor?"
|
||||
huobiOpenInterestInfo = "swap-api/v1/swap_his_open_interest?"
|
||||
huobiSwapSystemStatus = "swap-api/v1/swap_api_state?"
|
||||
huobiSwapSentimentAccountData = "swap-api/v1/swap_elite_account_ratio?"
|
||||
huobiSwapSentimentPosition = "swap-api/v1/swap_elite_position_ratio?"
|
||||
huobiSwapLiquidationOrders = "swap-api/v1/swap_liquidation_orders?"
|
||||
huobiSwapHistoricalFundingRate = "swap-api/v1/swap_historical_funding_rate?"
|
||||
huobiPremiumIndexKlineData = "index/market/history/swap_premium_index_kline?"
|
||||
huobiPredictedFundingRateData = "index/market/history/swap_estimated_rate_kline?"
|
||||
huobiBasisData = "index/market/history/swap_basis?"
|
||||
huobiSwapAccInfo = "swap-api/v1/swap_account_info"
|
||||
huobiSwapPosInfo = "swap-api/v1/swap_position_info"
|
||||
huobiSwapAssetsAndPos = "swap-api/v1/swap_account_position_info" // nolint // false positive gosec
|
||||
huobiSwapSubAccList = "swap-api/v1/swap_sub_account_list"
|
||||
huobiSwapSubAccInfo = "swap-api/v1/swap_sub_account_info"
|
||||
huobiSwapSubAccPosInfo = "swap-api/v1/swap_sub_position_info"
|
||||
huobiSwapFinancialRecords = "swap-api/v1/swap_financial_record"
|
||||
huobiSwapSettlementRecords = "swap-api/v1/swap_user_settlement_records"
|
||||
huobiSwapAvailableLeverage = "swap-api/v1/swap_available_level_rate"
|
||||
huobiSwapOrderLimitInfo = "swap-api/v1/swap_order_limit"
|
||||
huobiSwapTradingFeeInfo = "swap-api/v1/swap_fee"
|
||||
huobiSwapTransferLimitInfo = "swap-api/v1/swap_transfer_limit"
|
||||
huobiSwapPositionLimitInfo = "swap-api/v1/swap_position_limit"
|
||||
huobiSwapInternalTransferData = "swap-api/v1/swap_master_sub_transfer"
|
||||
huobiSwapInternalTransferRecords = "swap-api/v1/swap_master_sub_transfer_record"
|
||||
huobiSwapMarkets = "/swap-api/v1/swap_contract_info"
|
||||
huobiSwapFunding = "/swap-api/v1/swap_funding_rate"
|
||||
huobiSwapIndexPriceInfo = "/swap-api/v1/swap_index"
|
||||
huobiSwapPriceLimitation = "/swap-api/v1/swap_price_limit"
|
||||
huobiSwapOpenInterestInfo = "/swap-api/v1/swap_open_interest"
|
||||
huobiSwapMarketDepth = "/swap-ex/market/depth"
|
||||
huobiKLineData = "/swap-ex/market/history/kline"
|
||||
huobiMarketDataOverview = "/swap-ex/market/detail/merged"
|
||||
huobiLastTradeContract = "/swap-ex/market/trade"
|
||||
huobiRequestBatchOfTradingRecords = "/swap-ex/market/history/trade"
|
||||
huobiInsuranceBalanceAndClawbackRate = "/swap-api/v1/swap_risk_info"
|
||||
huobiInsuranceBalanceHistory = "/swap-api/v1/swap_insurance_fund"
|
||||
huobiTieredAdjustmentFactor = "/swap-api/v1/swap_adjustfactor"
|
||||
huobiOpenInterestInfo = "/swap-api/v1/swap_his_open_interest"
|
||||
huobiSwapSystemStatus = "/swap-api/v1/swap_api_state"
|
||||
huobiSwapSentimentAccountData = "/swap-api/v1/swap_elite_account_ratio"
|
||||
huobiSwapSentimentPosition = "/swap-api/v1/swap_elite_position_ratio"
|
||||
huobiSwapLiquidationOrders = "/swap-api/v1/swap_liquidation_orders"
|
||||
huobiSwapHistoricalFundingRate = "/swap-api/v1/swap_historical_funding_rate"
|
||||
huobiPremiumIndexKlineData = "/index/market/history/swap_premium_index_kline"
|
||||
huobiPredictedFundingRateData = "/index/market/history/swap_estimated_rate_kline"
|
||||
huobiBasisData = "/index/market/history/swap_basis"
|
||||
huobiSwapAccInfo = "/swap-api/v1/swap_account_info"
|
||||
huobiSwapPosInfo = "/swap-api/v1/swap_position_info"
|
||||
huobiSwapAssetsAndPos = "/swap-api/v1/swap_account_position_info" // nolint // false positive gosec
|
||||
huobiSwapSubAccList = "/swap-api/v1/swap_sub_account_list"
|
||||
huobiSwapSubAccInfo = "/swap-api/v1/swap_sub_account_info"
|
||||
huobiSwapSubAccPosInfo = "/swap-api/v1/swap_sub_position_info"
|
||||
huobiSwapFinancialRecords = "/swap-api/v1/swap_financial_record"
|
||||
huobiSwapSettlementRecords = "/swap-api/v1/swap_user_settlement_records"
|
||||
huobiSwapAvailableLeverage = "/swap-api/v1/swap_available_level_rate"
|
||||
huobiSwapOrderLimitInfo = "/swap-api/v1/swap_order_limit"
|
||||
huobiSwapTradingFeeInfo = "/swap-api/v1/swap_fee"
|
||||
huobiSwapTransferLimitInfo = "/swap-api/v1/swap_transfer_limit"
|
||||
huobiSwapPositionLimitInfo = "/swap-api/v1/swap_position_limit"
|
||||
huobiSwapInternalTransferData = "/swap-api/v1/swap_master_sub_transfer"
|
||||
huobiSwapInternalTransferRecords = "/swap-api/v1/swap_master_sub_transfer_record"
|
||||
huobiSwapPlaceOrder = "/swap-api/v1/swap_order"
|
||||
huobiSwapPlaceBatchOrder = "/swap-api/v1/swap_batchorder"
|
||||
huobiSwapCancelOrder = "/swap-api/v1/swap_cancel"
|
||||
@@ -65,7 +65,7 @@ const (
|
||||
huobiSwapOpenOrders = "/swap-api/v1/swap_openorders"
|
||||
huobiSwapOrderHistory = "/swap-api/v1/swap_hisorders"
|
||||
huobiSwapTradeHistory = "/swap-api/v1/swap_matchresults"
|
||||
huobiSwapTriggerOrder = "swap-api/v1/swap_trigger_order"
|
||||
huobiSwapTriggerOrder = "/swap-api/v1/swap_trigger_order"
|
||||
huobiSwapCancelTriggerOrder = "/swap-api/v1/swap_trigger_cancel"
|
||||
huobiSwapCancelAllTriggerOrders = "/swap-api/v1/swap_trigger_cancelall"
|
||||
huobiSwapTriggerOrderHistory = "/swap-api/v1/swap_trigger_hisorders"
|
||||
@@ -82,7 +82,7 @@ func (h *HUOBI) QuerySwapIndexPriceInfo(ctx context.Context, code currency.Pair)
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
path = huobiSwapIndexPriceInfo + params.Encode()
|
||||
path = common.EncodeURLValues(path, params)
|
||||
}
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
@@ -90,57 +90,59 @@ func (h *HUOBI) QuerySwapIndexPriceInfo(ctx context.Context, code currency.Pair)
|
||||
// GetSwapPriceLimits gets price caps for perpetual futures
|
||||
func (h *HUOBI) GetSwapPriceLimits(ctx context.Context, code currency.Pair) (SwapPriceLimitsData, error) {
|
||||
var resp SwapPriceLimitsData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiSwapPriceLimitation+params.Encode(),
|
||||
&resp)
|
||||
path := common.EncodeURLValues(huobiSwapPriceLimitation, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// SwapOpenInterestInformation gets open interest data for perpetual futures
|
||||
func (h *HUOBI) SwapOpenInterestInformation(ctx context.Context, code currency.Pair) (SwapOpenInterestData, error) {
|
||||
var resp SwapOpenInterestData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiSwapOpenInterestInfo+params.Encode(), &resp)
|
||||
path := common.EncodeURLValues(huobiSwapOpenInterestInfo, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetSwapMarketDepth gets market depth for perpetual futures
|
||||
func (h *HUOBI) GetSwapMarketDepth(ctx context.Context, code currency.Pair, dataType string) (SwapMarketDepthData, error) {
|
||||
var resp SwapMarketDepthData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
params.Set("type", dataType)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiSwapMarketDepth+params.Encode(), &resp)
|
||||
path := common.EncodeURLValues(huobiSwapMarketDepth, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetSwapKlineData gets kline data for perpetual futures
|
||||
func (h *HUOBI) GetSwapKlineData(ctx context.Context, code currency.Pair, period string, size int64, startTime, endTime time.Time) (SwapKlineData, error) {
|
||||
var resp SwapKlineData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("contract_code", codeValue)
|
||||
if !common.StringDataCompare(validPeriods, period) {
|
||||
if !common.StringDataCompareInsensitive(validPeriods, period) {
|
||||
return resp, fmt.Errorf("invalid period value received")
|
||||
}
|
||||
params.Set("period", period)
|
||||
if size == 1 || size > 2000 {
|
||||
return resp, fmt.Errorf("invalid size")
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
params.Set("period", period)
|
||||
params.Set("size", strconv.FormatInt(size, 10))
|
||||
if !startTime.IsZero() && !endTime.IsZero() {
|
||||
if startTime.After(endTime) {
|
||||
@@ -149,69 +151,74 @@ func (h *HUOBI) GetSwapKlineData(ctx context.Context, code currency.Pair, period
|
||||
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
||||
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
||||
}
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiKLineData+params.Encode(), &resp)
|
||||
path := common.EncodeURLValues(huobiKLineData, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetSwapMarketOverview gets market data overview for perpetual futures
|
||||
func (h *HUOBI) GetSwapMarketOverview(ctx context.Context, code currency.Pair) (MarketOverviewData, error) {
|
||||
var resp MarketOverviewData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiMarketDataOverview+params.Encode(), &resp)
|
||||
path := common.EncodeURLValues(huobiMarketDataOverview, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetLastTrade gets the last trade for a given perpetual contract
|
||||
func (h *HUOBI) GetLastTrade(ctx context.Context, code currency.Pair) (LastTradeData, error) {
|
||||
var resp LastTradeData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiLastTradeContract+params.Encode(), &resp)
|
||||
path := common.EncodeURLValues(huobiLastTradeContract, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetBatchTrades gets batch trades for a specified contract (fetching size cannot be bigger than 2000)
|
||||
func (h *HUOBI) GetBatchTrades(ctx context.Context, code currency.Pair, size int64) (BatchTradesData, error) {
|
||||
var resp BatchTradesData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("contract_code", codeValue)
|
||||
if size <= 0 || size > 1200 {
|
||||
return resp, fmt.Errorf("invalid size provided values from 1-1200 supported")
|
||||
return resp, fmt.Errorf("invalid size provided, only values between 1-1200 are supported")
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
params.Set("size", strconv.FormatInt(size, 10))
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiRequestBatchOfTradingRecords+params.Encode(), &resp)
|
||||
path := common.EncodeURLValues(huobiRequestBatchOfTradingRecords, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetInsuranceData gets insurance fund data and clawback rates
|
||||
func (h *HUOBI) GetInsuranceData(ctx context.Context, code currency.Pair) (InsuranceAndClawbackData, error) {
|
||||
var resp InsuranceAndClawbackData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiInsuranceBalanceAndClawbackRate+params.Encode(), &resp)
|
||||
path := common.EncodeURLValues(huobiInsuranceBalanceAndClawbackRate, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetHistoricalInsuranceData gets historical insurance fund data and clawback rates
|
||||
func (h *HUOBI) GetHistoricalInsuranceData(ctx context.Context, code currency.Pair, pageIndex, pageSize int64) (HistoricalInsuranceFundBalance, error) {
|
||||
var resp HistoricalInsuranceFundBalance
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
if pageIndex != 0 {
|
||||
params.Set("page_index", strconv.FormatInt(pageIndex, 10))
|
||||
@@ -219,119 +226,114 @@ func (h *HUOBI) GetHistoricalInsuranceData(ctx context.Context, code currency.Pa
|
||||
if pageSize != 0 {
|
||||
params.Set("page_size", strconv.FormatInt(pageIndex, 10))
|
||||
}
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiInsuranceBalanceHistory+params.Encode(), &resp)
|
||||
path := common.EncodeURLValues(huobiInsuranceBalanceHistory, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetTieredAjustmentFactorInfo gets tiered adjustment factor data
|
||||
func (h *HUOBI) GetTieredAjustmentFactorInfo(ctx context.Context, code currency.Pair) (TieredAdjustmentFactorData, error) {
|
||||
var resp TieredAdjustmentFactorData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiTieredAdjustmentFactor+params.Encode(), &resp)
|
||||
path := common.EncodeURLValues(huobiTieredAdjustmentFactor, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetOpenInterestInfo gets open interest data
|
||||
func (h *HUOBI) GetOpenInterestInfo(ctx context.Context, code currency.Pair, period, amountType string, size int64) (OpenInterestData, error) {
|
||||
var resp OpenInterestData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("contract_code", codeValue)
|
||||
if !common.StringDataCompare(validPeriods, period) {
|
||||
if !common.StringDataCompareInsensitive(validPeriods, period) {
|
||||
return resp, fmt.Errorf("invalid period value received")
|
||||
}
|
||||
params.Set("period", period)
|
||||
if size <= 0 || size > 1200 {
|
||||
return resp, fmt.Errorf("invalid size provided values from 1-1200 supported")
|
||||
return resp, fmt.Errorf("invalid size provided, only values between 1-1200 are supported")
|
||||
}
|
||||
params.Set("size", strconv.FormatInt(size, 10))
|
||||
aType, ok := validAmountType[amountType]
|
||||
if !ok {
|
||||
return resp, fmt.Errorf("invalid trade type")
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
params.Set("period", period)
|
||||
params.Set("size", strconv.FormatInt(size, 10))
|
||||
params.Set("amount_type", strconv.FormatInt(aType, 10))
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiOpenInterestInfo+params.Encode(), &resp)
|
||||
path := common.EncodeURLValues(huobiOpenInterestInfo, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetSystemStatusInfo gets system status data
|
||||
func (h *HUOBI) GetSystemStatusInfo(ctx context.Context, code currency.Pair, period, amountType string, size int64) (SystemStatusData, error) {
|
||||
func (h *HUOBI) GetSystemStatusInfo(ctx context.Context, code currency.Pair) (SystemStatusData, error) {
|
||||
var resp SystemStatusData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
if !common.StringDataCompare(validPeriods, period) {
|
||||
return resp, fmt.Errorf("invalid period value received")
|
||||
}
|
||||
params.Set("period", period)
|
||||
if size > 0 && size <= 1200 {
|
||||
params.Set("size", strconv.FormatInt(size, 10))
|
||||
}
|
||||
aType, ok := validAmountType[amountType]
|
||||
if !ok {
|
||||
return resp, fmt.Errorf("invalid trade type")
|
||||
}
|
||||
params.Set("amount_type", strconv.FormatInt(aType, 10))
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiSwapSystemStatus+params.Encode(), &resp)
|
||||
path := common.EncodeURLValues(huobiSwapSystemStatus, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetTraderSentimentIndexAccount gets top trader sentiment function-account
|
||||
func (h *HUOBI) GetTraderSentimentIndexAccount(ctx context.Context, code currency.Pair, period string) (TraderSentimentIndexAccountData, error) {
|
||||
var resp TraderSentimentIndexAccountData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("contract_code", codeValue)
|
||||
if !common.StringDataCompare(validPeriods, period) {
|
||||
if !common.StringDataCompareInsensitive(validPeriods, period) {
|
||||
return resp, fmt.Errorf("invalid period value received")
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
params.Set("period", period)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiSwapSentimentAccountData+params.Encode(), &resp)
|
||||
path := common.EncodeURLValues(huobiSwapSentimentAccountData, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetTraderSentimentIndexPosition gets top trader sentiment function-position
|
||||
func (h *HUOBI) GetTraderSentimentIndexPosition(ctx context.Context, code currency.Pair, period string) (TraderSentimentIndexPositionData, error) {
|
||||
var resp TraderSentimentIndexPositionData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("contract_code", codeValue)
|
||||
if !common.StringDataCompare(validPeriods, period) {
|
||||
|
||||
if !common.StringDataCompareInsensitive(validPeriods, period) {
|
||||
return resp, fmt.Errorf("invalid period value received")
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
params.Set("period", period)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiSwapSentimentPosition+params.Encode(), &resp)
|
||||
path := common.EncodeURLValues(huobiSwapSentimentPosition, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetLiquidationOrders gets liquidation orders for a given perp
|
||||
func (h *HUOBI) GetLiquidationOrders(ctx context.Context, code currency.Pair, tradeType string, pageIndex, pageSize, createDate int64) (LiquidationOrdersData, error) {
|
||||
var resp LiquidationOrdersData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("contract_code", codeValue)
|
||||
if createDate != 7 && createDate != 90 {
|
||||
return resp, fmt.Errorf("invalid createDate. 7 and 90 are the only supported values")
|
||||
}
|
||||
params.Set("create_date", strconv.FormatInt(createDate, 10))
|
||||
tType, ok := validTradeTypes[tradeType]
|
||||
if !ok {
|
||||
return resp, fmt.Errorf("invalid trade type")
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
params.Set("create_date", strconv.FormatInt(createDate, 10))
|
||||
params.Set("trade_type", strconv.FormatInt(tType, 10))
|
||||
if pageIndex != 0 {
|
||||
params.Set("page_index", strconv.FormatInt(pageIndex, 10))
|
||||
@@ -339,17 +341,18 @@ func (h *HUOBI) GetLiquidationOrders(ctx context.Context, code currency.Pair, tr
|
||||
if pageSize != 0 {
|
||||
params.Set("page_size", strconv.FormatInt(pageIndex, 10))
|
||||
}
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiSwapLiquidationOrders+params.Encode(), &resp)
|
||||
path := common.EncodeURLValues(huobiSwapLiquidationOrders, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetHistoricalFundingRates gets historical funding rates for perpetual futures
|
||||
func (h *HUOBI) GetHistoricalFundingRates(ctx context.Context, code currency.Pair, pageSize, pageIndex int64) (HistoricalFundingRateData, error) {
|
||||
var resp HistoricalFundingRateData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
if pageIndex != 0 {
|
||||
params.Set("page_index", strconv.FormatInt(pageIndex, 10))
|
||||
@@ -357,70 +360,74 @@ func (h *HUOBI) GetHistoricalFundingRates(ctx context.Context, code currency.Pai
|
||||
if pageSize != 0 {
|
||||
params.Set("page_size", strconv.FormatInt(pageIndex, 10))
|
||||
}
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiSwapHistoricalFundingRate+params.Encode(), &resp)
|
||||
path := common.EncodeURLValues(huobiSwapHistoricalFundingRate, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetPremiumIndexKlineData gets kline data for premium index
|
||||
func (h *HUOBI) GetPremiumIndexKlineData(ctx context.Context, code currency.Pair, period string, size int64) (PremiumIndexKlineData, error) {
|
||||
var resp PremiumIndexKlineData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("contract_code", codeValue)
|
||||
if !common.StringDataCompare(validPeriods, period) {
|
||||
if !common.StringDataCompareInsensitive(validPeriods, period) {
|
||||
return resp, fmt.Errorf("invalid period value received")
|
||||
}
|
||||
params.Set("period", period)
|
||||
if size <= 0 || size > 1200 {
|
||||
return resp, fmt.Errorf("invalid size provided values from 1-1200 supported")
|
||||
return resp, fmt.Errorf("invalid size provided, only values between 1-1200 are supported")
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
params.Set("size", strconv.FormatInt(size, 10))
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiPremiumIndexKlineData+params.Encode(), &resp)
|
||||
params.Set("period", period)
|
||||
path := common.EncodeURLValues(huobiPremiumIndexKlineData, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetEstimatedFundingRates gets estimated funding rates for perpetual futures
|
||||
func (h *HUOBI) GetEstimatedFundingRates(ctx context.Context, code currency.Pair, period string, size int64) (EstimatedFundingRateData, error) {
|
||||
var resp EstimatedFundingRateData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("contract_code", codeValue)
|
||||
if !common.StringDataCompare(validPeriods, period) {
|
||||
if !common.StringDataCompareInsensitive(validPeriods, period) {
|
||||
return resp, fmt.Errorf("invalid period value received")
|
||||
}
|
||||
params.Set("period", period)
|
||||
if size <= 0 || size > 1200 {
|
||||
return resp, fmt.Errorf("invalid size provided values from 1-1200 supported")
|
||||
return resp, fmt.Errorf("invalid size provided, only values between 1-1200 are supported")
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
params.Set("period", period)
|
||||
params.Set("size", strconv.FormatInt(size, 10))
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiPredictedFundingRateData+params.Encode(), &resp)
|
||||
path := common.EncodeURLValues(huobiPredictedFundingRateData, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetBasisData gets basis data for perpetual futures
|
||||
func (h *HUOBI) GetBasisData(ctx context.Context, code currency.Pair, period, basisPriceType string, size int64) (BasisData, error) {
|
||||
var resp BasisData
|
||||
params := url.Values{}
|
||||
codeValue, err := h.FormatSymbol(code, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("contract_code", codeValue)
|
||||
if !common.StringDataCompare(validPeriods, period) {
|
||||
if !common.StringDataCompareInsensitive(validPeriods, period) {
|
||||
return resp, fmt.Errorf("invalid period value received")
|
||||
}
|
||||
params.Set("period", period)
|
||||
if size <= 0 || size > 1200 {
|
||||
return resp, fmt.Errorf("invalid size provided values from 1-1200 supported")
|
||||
return resp, fmt.Errorf("invalid size provided, only values between 1-1200 are supported")
|
||||
}
|
||||
params.Set("size", strconv.FormatInt(size, 10))
|
||||
if !common.StringDataCompare(validBasisPriceTypes, basisPriceType) {
|
||||
if !common.StringDataCompareInsensitive(validBasisPriceTypes, basisPriceType) {
|
||||
return resp, fmt.Errorf("invalid period value received")
|
||||
}
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, huobiBasisData+params.Encode(), &resp)
|
||||
params := url.Values{}
|
||||
params.Set("contract_code", codeValue)
|
||||
params.Set("period", period)
|
||||
params.Set("size", strconv.FormatInt(size, 10))
|
||||
path := common.EncodeURLValues(huobiBasisData, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
// GetSwapAccountInfo gets swap account info
|
||||
@@ -573,7 +580,7 @@ func (h *HUOBI) GetSwapOrderLimitInfo(ctx context.Context, code currency.Pair, o
|
||||
return resp, err
|
||||
}
|
||||
req["contract_code"] = codeValue
|
||||
if !common.StringDataCompare(validOrderTypes, orderType) {
|
||||
if !common.StringDataCompareInsensitive(validOrderTypes, orderType) {
|
||||
return resp, fmt.Errorf("inavlid ordertype provided")
|
||||
}
|
||||
req["order_price_type"] = orderType
|
||||
@@ -627,7 +634,7 @@ func (h *HUOBI) AccountTransferData(ctx context.Context, code currency.Pair, sub
|
||||
req["contract_code"] = codeValue
|
||||
req["subUid"] = subUID
|
||||
req["amount"] = amount
|
||||
if !common.StringDataCompare(validTransferType, transferType) {
|
||||
if !common.StringDataCompareInsensitive(validTransferType, transferType) {
|
||||
return resp, fmt.Errorf("inavlid transferType received")
|
||||
}
|
||||
req["type"] = transferType
|
||||
@@ -643,7 +650,7 @@ func (h *HUOBI) AccountTransferRecords(ctx context.Context, code currency.Pair,
|
||||
return resp, err
|
||||
}
|
||||
req["contract_code"] = codeValue
|
||||
if !common.StringDataCompare(validTransferType, transferType) {
|
||||
if !common.StringDataCompareInsensitive(validTransferType, transferType) {
|
||||
return resp, fmt.Errorf("inavlid transferType received")
|
||||
}
|
||||
req["type"] = transferType
|
||||
@@ -674,7 +681,7 @@ func (h *HUOBI) PlaceSwapOrders(ctx context.Context, code currency.Pair, clientO
|
||||
}
|
||||
req["direction"] = direction
|
||||
req["offset"] = offset
|
||||
if !common.StringDataCompare(validOrderTypes, orderPriceType) {
|
||||
if !common.StringDataCompareInsensitive(validOrderTypes, orderPriceType) {
|
||||
return resp, fmt.Errorf("inavlid ordertype provided")
|
||||
}
|
||||
req["order_price_type"] = orderPriceType
|
||||
@@ -742,7 +749,7 @@ func (h *HUOBI) PlaceLightningCloseOrder(ctx context.Context, contractCode curre
|
||||
req["client_order_id"] = clientOrderID
|
||||
}
|
||||
if orderPriceType != "" {
|
||||
if !common.StringDataCompare(validLightningOrderPriceType, orderPriceType) {
|
||||
if !common.StringDataCompareInsensitive(validLightningOrderPriceType, orderPriceType) {
|
||||
return resp, fmt.Errorf("invalid orderPriceType")
|
||||
}
|
||||
req["order_price_type"] = orderPriceType
|
||||
@@ -905,7 +912,7 @@ func (h *HUOBI) PlaceSwapTriggerOrder(ctx context.Context, contractCode currency
|
||||
req["volume"] = volume
|
||||
req["lever_rate"] = leverageRate
|
||||
req["order_price"] = orderPrice
|
||||
if !common.StringDataCompare(validOrderPriceType, orderPriceType) {
|
||||
if !common.StringDataCompareInsensitive(validOrderPriceType, orderPriceType) {
|
||||
return resp, fmt.Errorf("invalid order price type")
|
||||
}
|
||||
req["order_price_type"] = orderPriceType
|
||||
|
||||
@@ -23,58 +23,58 @@ import (
|
||||
|
||||
const (
|
||||
// Unauth
|
||||
fContractInfo = "api/v1/contract_contract_info?"
|
||||
fContractIndexPrice = "api/v1/contract_index?"
|
||||
fContractPriceLimitation = "api/v1/contract_price_limit?"
|
||||
fContractOpenInterest = "api/v1/contract_open_interest?"
|
||||
fEstimatedDeliveryPrice = "api/v1/contract_delivery_price?"
|
||||
fContractMarketDepth = "/market/depth?"
|
||||
fContractKline = "/market/history/kline?"
|
||||
fMarketOverview = "/market/detail/merged?"
|
||||
fLastTradeContract = "/market/trade?"
|
||||
fContractBatchTradeRecords = "/market/history/trade?"
|
||||
fInsuranceAndClawback = "api/v1/contract_risk_info?"
|
||||
fInsuranceBalanceHistory = "api/v1/contract_insurance_fund?"
|
||||
fTieredAdjustmentFactor = "api/v1/contract_adjustfactor?"
|
||||
fHisContractOpenInterest = "api/v1/contract_his_open_interest?"
|
||||
fSystemStatus = "api/v1/contract_api_state?"
|
||||
fTopAccountsSentiment = "api/v1/contract_elite_account_ratio?"
|
||||
fTopPositionsSentiment = "api/v1/contract_elite_position_ratio?"
|
||||
fLiquidationOrders = "api/v1/contract_liquidation_orders?"
|
||||
fIndexKline = "/index/market/history/index?"
|
||||
fBasisData = "/index/market/history/basis?"
|
||||
fContractInfo = "/api/v1/contract_contract_info"
|
||||
fContractIndexPrice = "/api/v1/contract_index"
|
||||
fContractPriceLimitation = "/api/v1/contract_price_limit"
|
||||
fContractOpenInterest = "/api/v1/contract_open_interest"
|
||||
fEstimatedDeliveryPrice = "/api/v1/contract_delivery_price"
|
||||
fContractMarketDepth = "/market/depth"
|
||||
fContractKline = "/market/history/kline"
|
||||
fMarketOverview = "/market/detail/merged"
|
||||
fLastTradeContract = "/market/trade"
|
||||
fContractBatchTradeRecords = "/market/history/trade"
|
||||
fInsuranceAndClawback = "/api/v1/contract_risk_info"
|
||||
fInsuranceBalanceHistory = "/api/v1/contract_insurance_fund"
|
||||
fTieredAdjustmentFactor = "/api/v1/contract_adjustfactor"
|
||||
fHisContractOpenInterest = "/api/v1/contract_his_open_interest"
|
||||
fSystemStatus = "/api/v1/contract_api_state"
|
||||
fTopAccountsSentiment = "/api/v1/contract_elite_account_ratio"
|
||||
fTopPositionsSentiment = "/api/v1/contract_elite_position_ratio"
|
||||
fLiquidationOrders = "/api/v1/contract_liquidation_orders"
|
||||
fIndexKline = "/index/market/history/index"
|
||||
fBasisData = "/index/market/history/basis"
|
||||
|
||||
// Auth
|
||||
fAccountData = "api/v1/contract_account_info"
|
||||
fPositionInformation = "api/v1/contract_position_info"
|
||||
fAllSubAccountAssets = "api/v1/contract_sub_account_list"
|
||||
fSingleSubAccountAssets = "api/v1/contract_sub_account_info"
|
||||
fSingleSubAccountPositions = "api/v1/contract_sub_position_info"
|
||||
fFinancialRecords = "api/v1/contract_financial_record"
|
||||
fSettlementRecords = "api/v1/contract_user_settlement_records"
|
||||
fOrderLimitInfo = "api/v1/contract_order_limit"
|
||||
fContractTradingFee = "api/v1/contract_fee"
|
||||
fTransferLimitInfo = "api/v1/contract_transfer_limit"
|
||||
fPositionLimitInfo = "api/v1/contract_position_limit"
|
||||
fQueryAssetsAndPositions = "api/v1/contract_account_position_info"
|
||||
fTransfer = "api/v1/contract_master_sub_transfer"
|
||||
fTransferRecords = "api/v1/contract_master_sub_transfer_record"
|
||||
fAvailableLeverage = "api/v1/contract_available_level_rate"
|
||||
fOrder = "api/v1/contract_order"
|
||||
fBatchOrder = "api/v1/contract_batchorder"
|
||||
fCancelOrder = "api/v1/contract_cancel"
|
||||
fCancelAllOrders = "api/v1/contract_cancelall"
|
||||
fFlashCloseOrder = "api/v1/lightning_close_position"
|
||||
fOrderInfo = "api/v1/contract_order_info"
|
||||
fOrderDetails = "api/v1/contract_order_detail"
|
||||
fQueryOpenOrders = "api/v1/contract_openorders"
|
||||
fOrderHistory = "api/v1/contract_hisorders"
|
||||
fMatchResult = "api/v1/contract_matchresults"
|
||||
fTriggerOrder = "api/v1/contract_trigger_order"
|
||||
fCancelTriggerOrder = "api/v1/contract_trigger_cancel"
|
||||
fCancelAllTriggerOrders = "api/v1/contract_trigger_cancelall"
|
||||
fTriggerOpenOrders = "api/v1/contract_trigger_openorders"
|
||||
fTriggerOrderHistory = "api/v1/contract_trigger_hisorders"
|
||||
fAccountData = "/api/v1/contract_account_info"
|
||||
fPositionInformation = "/api/v1/contract_position_info"
|
||||
fAllSubAccountAssets = "/api/v1/contract_sub_account_list"
|
||||
fSingleSubAccountAssets = "/api/v1/contract_sub_account_info"
|
||||
fSingleSubAccountPositions = "/api/v1/contract_sub_position_info"
|
||||
fFinancialRecords = "/api/v1/contract_financial_record"
|
||||
fSettlementRecords = "/api/v1/contract_user_settlement_records"
|
||||
fOrderLimitInfo = "/api/v1/contract_order_limit"
|
||||
fContractTradingFee = "/api/v1/contract_fee"
|
||||
fTransferLimitInfo = "/api/v1/contract_transfer_limit"
|
||||
fPositionLimitInfo = "/api/v1/contract_position_limit"
|
||||
fQueryAssetsAndPositions = "/api/v1/contract_account_position_info"
|
||||
fTransfer = "/api/v1/contract_master_sub_transfer"
|
||||
fTransferRecords = "/api/v1/contract_master_sub_transfer_record"
|
||||
fAvailableLeverage = "/api/v1/contract_available_level_rate"
|
||||
fOrder = "/api/v1/contract_order"
|
||||
fBatchOrder = "/api/v1/contract_batchorder"
|
||||
fCancelOrder = "/api/v1/contract_cancel"
|
||||
fCancelAllOrders = "/api/v1/contract_cancelall"
|
||||
fFlashCloseOrder = "/api/v1/lightning_close_position"
|
||||
fOrderInfo = "/api/v1/contract_order_info"
|
||||
fOrderDetails = "/api/v1/contract_order_detail"
|
||||
fQueryOpenOrders = "/api/v1/contract_openorders"
|
||||
fOrderHistory = "/api/v1/contract_hisorders"
|
||||
fMatchResult = "/api/v1/contract_matchresults"
|
||||
fTriggerOrder = "/api/v1/contract_trigger_order"
|
||||
fCancelTriggerOrder = "/api/v1/contract_trigger_cancel"
|
||||
fCancelAllTriggerOrders = "/api/v1/contract_trigger_cancelall"
|
||||
fTriggerOpenOrders = "/api/v1/contract_trigger_openorders"
|
||||
fTriggerOrderHistory = "/api/v1/contract_trigger_hisorders"
|
||||
)
|
||||
|
||||
// FGetContractInfo gets contract info for futures
|
||||
@@ -85,7 +85,7 @@ func (h *HUOBI) FGetContractInfo(ctx context.Context, symbol, contractType strin
|
||||
params.Set("symbol", symbol)
|
||||
}
|
||||
if contractType != "" {
|
||||
if !common.StringDataCompare(validContractTypes, contractType) {
|
||||
if !common.StringDataCompareInsensitive(validContractTypes, contractType) {
|
||||
return resp, fmt.Errorf("invalid contractType")
|
||||
}
|
||||
params.Set("contract_type", contractType)
|
||||
@@ -97,7 +97,7 @@ func (h *HUOBI) FGetContractInfo(ctx context.Context, symbol, contractType strin
|
||||
}
|
||||
params.Set("contract_code", codeValue)
|
||||
}
|
||||
path := fContractInfo + params.Encode()
|
||||
path := common.EncodeURLValues(fContractInfo, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ func (h *HUOBI) FIndexPriceInfo(ctx context.Context, symbol currency.Code) (FCon
|
||||
}
|
||||
params.Set("symbol", codeValue)
|
||||
}
|
||||
path := fContractIndexPrice + params.Encode()
|
||||
path := common.EncodeURLValues(fContractIndexPrice, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ func (h *HUOBI) FContractPriceLimitations(ctx context.Context, symbol, contractT
|
||||
params.Set("symbol", symbol)
|
||||
}
|
||||
if contractType != "" {
|
||||
if !common.StringDataCompare(validContractTypes, contractType) {
|
||||
if !common.StringDataCompareInsensitive(validContractTypes, contractType) {
|
||||
return resp, fmt.Errorf("invalid contractType: %s", contractType)
|
||||
}
|
||||
params.Set("contract_type", contractType)
|
||||
@@ -136,7 +136,7 @@ func (h *HUOBI) FContractPriceLimitations(ctx context.Context, symbol, contractT
|
||||
}
|
||||
params.Set("contract_code", codeValue)
|
||||
}
|
||||
path := fContractPriceLimitation + params.Encode()
|
||||
path := common.EncodeURLValues(fContractPriceLimitation, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ func (h *HUOBI) FContractOpenInterest(ctx context.Context, symbol, contractType
|
||||
params.Set("symbol", symbol)
|
||||
}
|
||||
if contractType != "" {
|
||||
if !common.StringDataCompare(validContractTypes, contractType) {
|
||||
if !common.StringDataCompareInsensitive(validContractTypes, contractType) {
|
||||
return resp, fmt.Errorf("invalid contractType")
|
||||
}
|
||||
params.Set("contract_type", contractType)
|
||||
@@ -160,7 +160,7 @@ func (h *HUOBI) FContractOpenInterest(ctx context.Context, symbol, contractType
|
||||
}
|
||||
params.Set("contract_code", codeValue)
|
||||
}
|
||||
path := fContractOpenInterest + params.Encode()
|
||||
path := common.EncodeURLValues(fContractOpenInterest, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ func (h *HUOBI) FGetEstimatedDeliveryPrice(ctx context.Context, symbol currency.
|
||||
return resp, err
|
||||
}
|
||||
params.Set("symbol", codeValue)
|
||||
path := fEstimatedDeliveryPrice + params.Encode()
|
||||
path := common.EncodeURLValues(fEstimatedDeliveryPrice, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -182,13 +182,13 @@ func (h *HUOBI) FGetMarketDepth(ctx context.Context, symbol currency.Pair, dataT
|
||||
var resp OBData
|
||||
var tempData FMarketDepth
|
||||
params := url.Values{}
|
||||
symbolValue, err := h.FormatSymbol(symbol, asset.Futures)
|
||||
symbolValue, err := h.formatFuturesPair(symbol)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("symbol", symbolValue)
|
||||
params.Set("type", dataType)
|
||||
path := fContractMarketDepth + params.Encode()
|
||||
path := common.EncodeURLValues(fContractMarketDepth, params)
|
||||
err = h.SendHTTPRequest(ctx, exchange.RestFutures, path, &tempData)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
@@ -213,12 +213,12 @@ func (h *HUOBI) FGetMarketDepth(ctx context.Context, symbol currency.Pair, dataT
|
||||
func (h *HUOBI) FGetKlineData(ctx context.Context, symbol currency.Pair, period string, size int64, startTime, endTime time.Time) (FKlineData, error) {
|
||||
var resp FKlineData
|
||||
params := url.Values{}
|
||||
symbolValue, err := h.FormatSymbol(symbol, asset.Futures)
|
||||
symbolValue, err := h.formatFuturesPair(symbol)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("symbol", symbolValue)
|
||||
if !common.StringDataCompare(validFuturesPeriods, period) {
|
||||
if !common.StringDataCompareInsensitive(validFuturesPeriods, period) {
|
||||
return resp, fmt.Errorf("invalid period value received")
|
||||
}
|
||||
params.Set("period", period)
|
||||
@@ -233,7 +233,7 @@ func (h *HUOBI) FGetKlineData(ctx context.Context, symbol currency.Pair, period
|
||||
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
||||
params.Set("end_time", strconv.FormatInt(endTime.Unix(), 10))
|
||||
}
|
||||
path := fContractKline + params.Encode()
|
||||
path := common.EncodeURLValues(fContractKline, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -241,12 +241,12 @@ func (h *HUOBI) FGetKlineData(ctx context.Context, symbol currency.Pair, period
|
||||
func (h *HUOBI) FGetMarketOverviewData(ctx context.Context, symbol currency.Pair) (FMarketOverviewData, error) {
|
||||
var resp FMarketOverviewData
|
||||
params := url.Values{}
|
||||
symbolValue, err := h.FormatSymbol(symbol, asset.Futures)
|
||||
symbolValue, err := h.formatFuturesPair(symbol)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("symbol", symbolValue)
|
||||
path := fMarketOverview + params.Encode()
|
||||
path := common.EncodeURLValues(fMarketOverview, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -254,12 +254,12 @@ func (h *HUOBI) FGetMarketOverviewData(ctx context.Context, symbol currency.Pair
|
||||
func (h *HUOBI) FLastTradeData(ctx context.Context, symbol currency.Pair) (FLastTradeData, error) {
|
||||
var resp FLastTradeData
|
||||
params := url.Values{}
|
||||
symbolValue, err := h.FormatSymbol(symbol, asset.Futures)
|
||||
symbolValue, err := h.formatFuturesPair(symbol)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("symbol", symbolValue)
|
||||
path := fLastTradeContract + params.Encode()
|
||||
path := common.EncodeURLValues(fLastTradeContract, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ func (h *HUOBI) FLastTradeData(ctx context.Context, symbol currency.Pair) (FLast
|
||||
func (h *HUOBI) FRequestPublicBatchTrades(ctx context.Context, symbol currency.Pair, size int64) (FBatchTradesForContractData, error) {
|
||||
var resp FBatchTradesForContractData
|
||||
params := url.Values{}
|
||||
symbolValue, err := h.FormatSymbol(symbol, asset.Futures)
|
||||
symbolValue, err := h.formatFuturesPair(symbol)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
@@ -275,7 +275,7 @@ func (h *HUOBI) FRequestPublicBatchTrades(ctx context.Context, symbol currency.P
|
||||
if size > 1 && size < 2000 {
|
||||
params.Set("size", strconv.FormatInt(size, 10))
|
||||
}
|
||||
path := fContractBatchTradeRecords + params.Encode()
|
||||
path := common.EncodeURLValues(fContractBatchTradeRecords, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -290,7 +290,7 @@ func (h *HUOBI) FQueryInsuranceAndClawbackData(ctx context.Context, symbol curre
|
||||
}
|
||||
params.Set("symbol", codeValue)
|
||||
}
|
||||
path := fInsuranceAndClawback + params.Encode()
|
||||
path := common.EncodeURLValues(fInsuranceAndClawback, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ func (h *HUOBI) FQueryHistoricalInsuranceData(ctx context.Context, symbol curren
|
||||
}
|
||||
params.Set("symbol", codeValue)
|
||||
}
|
||||
path := fInsuranceBalanceHistory + params.Encode()
|
||||
path := common.EncodeURLValues(fInsuranceBalanceHistory, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -320,7 +320,7 @@ func (h *HUOBI) FQueryTieredAdjustmentFactor(ctx context.Context, symbol currenc
|
||||
}
|
||||
params.Set("symbol", codeValue)
|
||||
}
|
||||
path := fTieredAdjustmentFactor + params.Encode()
|
||||
path := common.EncodeURLValues(fTieredAdjustmentFactor, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -331,11 +331,11 @@ func (h *HUOBI) FQueryHisOpenInterest(ctx context.Context, symbol, contractType,
|
||||
if symbol != "" {
|
||||
params.Set("symbol", symbol)
|
||||
}
|
||||
if !common.StringDataCompare(validContractTypes, contractType) {
|
||||
if !common.StringDataCompareInsensitive(validContractTypes, contractType) {
|
||||
return resp, fmt.Errorf("invalid contract type")
|
||||
}
|
||||
params.Set("contract_type", contractType)
|
||||
if !common.StringDataCompare(validPeriods, period) {
|
||||
if !common.StringDataCompareInsensitive(validPeriods, period) {
|
||||
return resp, fmt.Errorf("invalid period")
|
||||
}
|
||||
params.Set("period", period)
|
||||
@@ -347,7 +347,7 @@ func (h *HUOBI) FQueryHisOpenInterest(ctx context.Context, symbol, contractType,
|
||||
return resp, fmt.Errorf("invalid amountType")
|
||||
}
|
||||
params.Set("amount_type", strconv.FormatInt(validAmount, 10))
|
||||
path := fHisContractOpenInterest + params.Encode()
|
||||
path := common.EncodeURLValues(fHisContractOpenInterest, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -362,7 +362,7 @@ func (h *HUOBI) FQuerySystemStatus(ctx context.Context, symbol currency.Code) (F
|
||||
}
|
||||
params.Set("symbol", codeValue)
|
||||
}
|
||||
path := fSystemStatus + params.Encode()
|
||||
path := common.EncodeURLValues(fSystemStatus, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -373,11 +373,11 @@ func (h *HUOBI) FQueryTopAccountsRatio(ctx context.Context, symbol, period strin
|
||||
if symbol != "" {
|
||||
params.Set("symbol", symbol)
|
||||
}
|
||||
if !common.StringDataCompare(validPeriods, period) {
|
||||
if !common.StringDataCompareInsensitive(validPeriods, period) {
|
||||
return resp, fmt.Errorf("invalid period")
|
||||
}
|
||||
params.Set("period", period)
|
||||
path := fTopAccountsSentiment + params.Encode()
|
||||
path := common.EncodeURLValues(fTopAccountsSentiment, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -388,11 +388,11 @@ func (h *HUOBI) FQueryTopPositionsRatio(ctx context.Context, symbol, period stri
|
||||
if symbol != "" {
|
||||
params.Set("symbol", symbol)
|
||||
}
|
||||
if !common.StringDataCompare(validPeriods, period) {
|
||||
if !common.StringDataCompareInsensitive(validPeriods, period) {
|
||||
return resp, fmt.Errorf("invalid period")
|
||||
}
|
||||
params.Set("period", period)
|
||||
path := fTopPositionsSentiment + params.Encode()
|
||||
path := common.EncodeURLValues(fTopPositionsSentiment, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -416,7 +416,7 @@ func (h *HUOBI) FLiquidationOrders(ctx context.Context, symbol, tradeType string
|
||||
if pageSize != 0 {
|
||||
params.Set("page_size", strconv.FormatInt(pageIndex, 10))
|
||||
}
|
||||
path := fLiquidationOrders + params.Encode()
|
||||
path := common.EncodeURLValues(fLiquidationOrders, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -424,12 +424,12 @@ func (h *HUOBI) FLiquidationOrders(ctx context.Context, symbol, tradeType string
|
||||
func (h *HUOBI) FIndexKline(ctx context.Context, symbol currency.Pair, period string, size int64) (FIndexKlineData, error) {
|
||||
var resp FIndexKlineData
|
||||
params := url.Values{}
|
||||
symbolValue, err := h.FormatSymbol(symbol, asset.Futures)
|
||||
symbolValue, err := h.formatFuturesPair(symbol)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("symbol", symbolValue)
|
||||
if !common.StringDataCompare(validFuturesPeriods, period) {
|
||||
if !common.StringDataCompareInsensitive(validFuturesPeriods, period) {
|
||||
return resp, fmt.Errorf("invalid period value received")
|
||||
}
|
||||
params.Set("period", period)
|
||||
@@ -437,7 +437,7 @@ func (h *HUOBI) FIndexKline(ctx context.Context, symbol currency.Pair, period st
|
||||
return resp, fmt.Errorf("invalid size")
|
||||
}
|
||||
params.Set("size", strconv.FormatInt(size, 10))
|
||||
path := fIndexKline + params.Encode()
|
||||
path := common.EncodeURLValues(fIndexKline, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -445,24 +445,24 @@ func (h *HUOBI) FIndexKline(ctx context.Context, symbol currency.Pair, period st
|
||||
func (h *HUOBI) FGetBasisData(ctx context.Context, symbol currency.Pair, period, basisPriceType string, size int64) (FBasisData, error) {
|
||||
var resp FBasisData
|
||||
params := url.Values{}
|
||||
symbolValue, err := h.FormatSymbol(symbol, asset.Futures)
|
||||
symbolValue, err := h.formatFuturesPair(symbol)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("symbol", symbolValue)
|
||||
if !common.StringDataCompare(validFuturesPeriods, period) {
|
||||
if !common.StringDataCompareInsensitive(validFuturesPeriods, period) {
|
||||
return resp, fmt.Errorf("invalid period value received")
|
||||
}
|
||||
params.Set("period", period)
|
||||
if basisPriceType != "" {
|
||||
if common.StringDataCompare(validBasisPriceTypes, basisPriceType) {
|
||||
if common.StringDataCompareInsensitive(validBasisPriceTypes, basisPriceType) {
|
||||
params.Set("basis_price_type", basisPriceType)
|
||||
}
|
||||
}
|
||||
if size > 0 && size <= 2000 {
|
||||
params.Set("size", strconv.FormatInt(size, 10))
|
||||
}
|
||||
path := fBasisData + params.Encode()
|
||||
path := common.EncodeURLValues(fBasisData, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
}
|
||||
|
||||
@@ -585,7 +585,7 @@ func (h *HUOBI) FGetOrderLimits(ctx context.Context, symbol, orderPriceType stri
|
||||
req["symbol"] = symbol
|
||||
}
|
||||
if orderPriceType != "" {
|
||||
if !common.StringDataCompare(validFuturesOrderPriceTypes, orderPriceType) {
|
||||
if !common.StringDataCompareInsensitive(validFuturesOrderPriceTypes, orderPriceType) {
|
||||
return resp, fmt.Errorf("invalid orderPriceType")
|
||||
}
|
||||
req["order_price_type"] = orderPriceType
|
||||
@@ -650,7 +650,7 @@ func (h *HUOBI) FTransfer(ctx context.Context, subUID, symbol, transferType stri
|
||||
req["symbol"] = symbol
|
||||
req["subUid"] = subUID
|
||||
req["amount"] = amount
|
||||
if !common.StringDataCompare(validTransferType, transferType) {
|
||||
if !common.StringDataCompareInsensitive(validTransferType, transferType) {
|
||||
return resp, fmt.Errorf("inavlid transferType received")
|
||||
}
|
||||
req["type"] = transferType
|
||||
@@ -664,7 +664,7 @@ func (h *HUOBI) FGetTransferRecords(ctx context.Context, symbol, transferType st
|
||||
if symbol != "" {
|
||||
req["symbol"] = symbol
|
||||
}
|
||||
if !common.StringDataCompare(validTransferType, transferType) {
|
||||
if !common.StringDataCompareInsensitive(validTransferType, transferType) {
|
||||
return resp, fmt.Errorf("inavlid transferType received")
|
||||
}
|
||||
req["type"] = transferType
|
||||
@@ -703,7 +703,7 @@ func (h *HUOBI) FOrder(ctx context.Context, contractCode currency.Pair, symbol,
|
||||
req["symbol"] = symbol
|
||||
}
|
||||
if contractType != "" {
|
||||
if !common.StringDataCompare(validContractTypes, contractType) {
|
||||
if !common.StringDataCompareInsensitive(validContractTypes, contractType) {
|
||||
return resp, fmt.Errorf("invalid contractType")
|
||||
}
|
||||
req["contract_type"] = contractType
|
||||
@@ -719,10 +719,10 @@ func (h *HUOBI) FOrder(ctx context.Context, contractCode currency.Pair, symbol,
|
||||
req["client_order_id"] = clientOrderID
|
||||
}
|
||||
req["direction"] = direction
|
||||
if !common.StringDataCompare(validOffsetTypes, offset) {
|
||||
if !common.StringDataCompareInsensitive(validOffsetTypes, offset) {
|
||||
return resp, fmt.Errorf("invalid offset amounts")
|
||||
}
|
||||
if !common.StringDataCompare(validFuturesOrderPriceTypes, orderPriceType) {
|
||||
if !common.StringDataCompareInsensitive(validFuturesOrderPriceTypes, orderPriceType) {
|
||||
return resp, fmt.Errorf("invalid orderPriceType")
|
||||
}
|
||||
req["order_price_type"] = orderPriceType
|
||||
@@ -753,14 +753,14 @@ func (h *HUOBI) FPlaceBatchOrder(ctx context.Context, data []fBatchOrderData) (F
|
||||
data[x].ContractCode = formattedPair.String()
|
||||
}
|
||||
if data[x].ContractType != "" {
|
||||
if !common.StringDataCompare(validContractTypes, data[x].ContractType) {
|
||||
if !common.StringDataCompareInsensitive(validContractTypes, data[x].ContractType) {
|
||||
return resp, fmt.Errorf("invalid contractType")
|
||||
}
|
||||
}
|
||||
if !common.StringDataCompare(validOffsetTypes, data[x].Offset) {
|
||||
if !common.StringDataCompareInsensitive(validOffsetTypes, data[x].Offset) {
|
||||
return resp, fmt.Errorf("invalid offset amounts")
|
||||
}
|
||||
if !common.StringDataCompare(validFuturesOrderPriceTypes, data[x].OrderPriceType) {
|
||||
if !common.StringDataCompareInsensitive(validFuturesOrderPriceTypes, data[x].OrderPriceType) {
|
||||
return resp, fmt.Errorf("invalid orderPriceType")
|
||||
}
|
||||
}
|
||||
@@ -792,7 +792,7 @@ func (h *HUOBI) FCancelAllOrders(ctx context.Context, contractCode currency.Pair
|
||||
req["symbol"] = symbol
|
||||
}
|
||||
if contractType != "" {
|
||||
if !common.StringDataCompare(validContractTypes, contractType) {
|
||||
if !common.StringDataCompareInsensitive(validContractTypes, contractType) {
|
||||
return resp, fmt.Errorf("invalid contractType")
|
||||
}
|
||||
req["contract_type"] = contractType
|
||||
@@ -813,7 +813,7 @@ func (h *HUOBI) FFlashCloseOrder(ctx context.Context, contractCode currency.Pair
|
||||
req := make(map[string]interface{})
|
||||
req["symbol"] = symbol
|
||||
if contractType != "" {
|
||||
if !common.StringDataCompare(validContractTypes, contractType) {
|
||||
if !common.StringDataCompareInsensitive(validContractTypes, contractType) {
|
||||
return resp, fmt.Errorf("invalid contractType")
|
||||
}
|
||||
req["contract_type"] = contractType
|
||||
@@ -831,7 +831,7 @@ func (h *HUOBI) FFlashCloseOrder(ctx context.Context, contractCode currency.Pair
|
||||
req["client_order_id"] = clientOrderID
|
||||
}
|
||||
if orderPriceType != "" {
|
||||
if !common.StringDataCompare(validOPTypes, orderPriceType) {
|
||||
if !common.StringDataCompareInsensitive(validOPTypes, orderPriceType) {
|
||||
return resp, fmt.Errorf("invalid orderPriceType")
|
||||
}
|
||||
req["orderPriceType"] = orderPriceType
|
||||
@@ -985,7 +985,7 @@ func (h *HUOBI) FPlaceTriggerOrder(ctx context.Context, contractCode currency.Pa
|
||||
req["symbol"] = symbol
|
||||
}
|
||||
if contractType != "" {
|
||||
if !common.StringDataCompare(validContractTypes, contractType) {
|
||||
if !common.StringDataCompareInsensitive(validContractTypes, contractType) {
|
||||
return resp, fmt.Errorf("invalid contractType: %s", contractType)
|
||||
}
|
||||
req["contract_type"] = contractType
|
||||
@@ -1003,7 +1003,7 @@ func (h *HUOBI) FPlaceTriggerOrder(ctx context.Context, contractCode currency.Pa
|
||||
}
|
||||
req["trigger_type"] = tType
|
||||
req["direction"] = direction
|
||||
if !common.StringDataCompare(validOffsetTypes, offset) {
|
||||
if !common.StringDataCompareInsensitive(validOffsetTypes, offset) {
|
||||
return resp, fmt.Errorf("invalid offset")
|
||||
}
|
||||
req["offset"] = offset
|
||||
@@ -1011,7 +1011,7 @@ func (h *HUOBI) FPlaceTriggerOrder(ctx context.Context, contractCode currency.Pa
|
||||
req["volume"] = volume
|
||||
req["lever_rate"] = leverageRate
|
||||
req["order_price"] = orderPrice
|
||||
if !common.StringDataCompare(validOrderPriceType, orderPriceType) {
|
||||
if !common.StringDataCompareInsensitive(validOrderPriceType, orderPriceType) {
|
||||
return resp, fmt.Errorf("invalid order price type")
|
||||
}
|
||||
req["order_price_type"] = orderPriceType
|
||||
@@ -1040,7 +1040,7 @@ func (h *HUOBI) FCancelAllTriggerOrders(ctx context.Context, contractCode curren
|
||||
req["contract_code"] = codeValue
|
||||
}
|
||||
if contractType != "" {
|
||||
if !common.StringDataCompare(validContractTypes, contractType) {
|
||||
if !common.StringDataCompareInsensitive(validContractTypes, contractType) {
|
||||
return resp, nil
|
||||
}
|
||||
req["contract_type"] = contractType
|
||||
@@ -1115,18 +1115,22 @@ func (h *HUOBI) FuturesAuthenticatedHTTPRequest(ctx context.Context, ep exchange
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ep == exchange.RestFutures && ePoint[len(ePoint)-1] == '/' {
|
||||
// prevent signature errors for non-standard paths until we can
|
||||
// have a method to force update endpoints
|
||||
ePoint = ePoint[:len(ePoint)-1]
|
||||
}
|
||||
if values == nil {
|
||||
values = url.Values{}
|
||||
}
|
||||
|
||||
var tempResp json.RawMessage
|
||||
newRequest := func() (*request.Item, error) {
|
||||
now := time.Now()
|
||||
values.Set("AccessKeyId", h.API.Credentials.Key)
|
||||
values.Set("SignatureMethod", "HmacSHA256")
|
||||
values.Set("SignatureVersion", "2")
|
||||
values.Set("Timestamp", now.UTC().Format("2006-01-02T15:04:05"))
|
||||
sigPath := fmt.Sprintf("%s\napi.hbdm.com\n/%s\n%s",
|
||||
values.Set("Timestamp", time.Now().UTC().Format("2006-01-02T15:04:05"))
|
||||
sigPath := fmt.Sprintf("%s\napi.hbdm.com\n%s\n%s",
|
||||
method, endpoint, values.Encode())
|
||||
headers := make(map[string]string)
|
||||
if method == http.MethodGet {
|
||||
@@ -1142,10 +1146,8 @@ func (h *HUOBI) FuturesAuthenticatedHTTPRequest(ctx context.Context, ep exchange
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sigValues := url.Values{}
|
||||
sigValues.Add("Signature", crypto.Base64Encode(hmac))
|
||||
urlPath :=
|
||||
common.EncodeURLValues(ePoint+endpoint, values) + "&" + sigValues.Encode()
|
||||
values.Add("Signature", crypto.Base64Encode(hmac))
|
||||
urlPath := common.EncodeURLValues(ePoint+endpoint, values)
|
||||
var body io.Reader
|
||||
var payload []byte
|
||||
if data != nil {
|
||||
@@ -1176,8 +1178,13 @@ func (h *HUOBI) FuturesAuthenticatedHTTPRequest(ctx context.Context, ep exchange
|
||||
|
||||
var errCap errorCapture
|
||||
if err := json.Unmarshal(tempResp, &errCap); err == nil {
|
||||
if errCap.Code != 200 && errCap.ErrMsg != "" {
|
||||
return errors.New(errCap.ErrMsg)
|
||||
if errCap.ErrMsgType1 != "" {
|
||||
return fmt.Errorf("error code: %v error message: %s", errCap.CodeType1,
|
||||
errors.New(errCap.ErrMsgType1))
|
||||
}
|
||||
if errCap.ErrMsgType2 != "" {
|
||||
return fmt.Errorf("error code: %v error message: %s", errCap.CodeType2,
|
||||
errors.New(errCap.ErrMsgType2))
|
||||
}
|
||||
}
|
||||
return json.Unmarshal(tempResp, result)
|
||||
@@ -1193,3 +1200,11 @@ func (h *HUOBI) formatFuturesCode(p currency.Code) (string, error) {
|
||||
}
|
||||
return p.Lower().String(), nil
|
||||
}
|
||||
|
||||
// formatFuturesPair handles pairs in the format as "BTC-NW" and "BTC210827"
|
||||
func (h *HUOBI) formatFuturesPair(p currency.Pair) (string, error) {
|
||||
if common.StringDataCompareInsensitive(validContractShortTypes, p.Quote.String()) {
|
||||
return p.Format("_", true).String(), nil
|
||||
}
|
||||
return h.FormatSymbol(p, asset.Futures)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -30,8 +31,11 @@ const (
|
||||
testSymbol = "btcusdt"
|
||||
)
|
||||
|
||||
var h HUOBI
|
||||
var wsSetupRan bool
|
||||
var (
|
||||
h HUOBI
|
||||
wsSetupRan bool
|
||||
futuresTestPair = currency.NewPair(currency.BTC, currency.NewCode("NQ"))
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
h.SetDefaults()
|
||||
@@ -79,6 +83,24 @@ func setupWsTests(t *testing.T) {
|
||||
wsSetupRan = true
|
||||
}
|
||||
|
||||
func TestGetCurrenciesIncludingChains(t *testing.T) {
|
||||
t.Parallel()
|
||||
r, err := h.GetCurrenciesIncludingChains(context.Background(), currency.Code{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if len(r) == 1 {
|
||||
t.Error("expected 1 result")
|
||||
}
|
||||
r, err = h.GetCurrenciesIncludingChains(context.Background(), currency.USDT)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if len(r) < 1 {
|
||||
t.Error("expected >= 1 results")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFGetContractInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := h.FGetContractInfo(context.Background(), "", "", currency.Pair{})
|
||||
@@ -123,11 +145,7 @@ func TestFGetEstimatedDeliveryPrice(t *testing.T) {
|
||||
|
||||
func TestFGetMarketDepth(t *testing.T) {
|
||||
t.Parallel()
|
||||
cp, err := currency.NewPairFromString("BTC_NW")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = h.FGetMarketDepth(context.Background(), cp, "step5")
|
||||
_, err := h.FGetMarketDepth(context.Background(), futuresTestPair, "step5")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -135,12 +153,7 @@ func TestFGetMarketDepth(t *testing.T) {
|
||||
|
||||
func TestFGetKlineData(t *testing.T) {
|
||||
t.Parallel()
|
||||
cp, err := currency.NewPairFromString("BTC_NW")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = h.FGetKlineData(context.Background(),
|
||||
cp, "5min", 5, time.Now().Add(-time.Minute*5), time.Now())
|
||||
_, err := h.FGetKlineData(context.Background(), futuresTestPair, "5min", 5, time.Now().Add(-time.Minute*5), time.Now())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -148,11 +161,7 @@ func TestFGetKlineData(t *testing.T) {
|
||||
|
||||
func TestFGetMarketOverviewData(t *testing.T) {
|
||||
t.Parallel()
|
||||
cp, err := currency.NewPairFromString("BTC_NW")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = h.FGetMarketOverviewData(context.Background(), cp)
|
||||
_, err := h.FGetMarketOverviewData(context.Background(), futuresTestPair)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -160,11 +169,7 @@ func TestFGetMarketOverviewData(t *testing.T) {
|
||||
|
||||
func TestFLastTradeData(t *testing.T) {
|
||||
t.Parallel()
|
||||
cp, err := currency.NewPairFromString("BTC_NW")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = h.FLastTradeData(context.Background(), cp)
|
||||
_, err := h.FLastTradeData(context.Background(), futuresTestPair)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -172,11 +177,7 @@ func TestFLastTradeData(t *testing.T) {
|
||||
|
||||
func TestFRequestPublicBatchTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
cp, err := currency.NewPairFromString("BTC_NQ")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
a, err := h.FRequestPublicBatchTrades(context.Background(), cp, 50)
|
||||
a, err := h.FRequestPublicBatchTrades(context.Background(), futuresTestPair, 50)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -253,11 +254,7 @@ func TestFLiquidationOrders(t *testing.T) {
|
||||
|
||||
func TestFIndexKline(t *testing.T) {
|
||||
t.Parallel()
|
||||
cp, err := currency.NewPairFromString("BTC_NQ")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = h.FIndexKline(context.Background(), cp, "5min", 5)
|
||||
_, err := h.FIndexKline(context.Background(), futuresTestPair, "5min", 5)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -265,11 +262,7 @@ func TestFIndexKline(t *testing.T) {
|
||||
|
||||
func TestFGetBasisData(t *testing.T) {
|
||||
t.Parallel()
|
||||
cp, err := currency.NewPairFromString("BTC_NQ")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = h.FGetBasisData(context.Background(), cp, "5min", "open", 3)
|
||||
_, err := h.FGetBasisData(context.Background(), futuresTestPair, "5min", "open", 3)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -682,11 +675,11 @@ func TestFetchTradablePairs(t *testing.T) {
|
||||
|
||||
func TestUpdateTickerSpot(t *testing.T) {
|
||||
t.Parallel()
|
||||
sp, err := currency.NewPairFromString("BTC_USDT")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
_, err := h.UpdateTicker(context.Background(), currency.NewPairWithDelimiter("INV", "ALID", "-"), asset.Spot)
|
||||
if err == nil {
|
||||
t.Error("exepcted invalid pair")
|
||||
}
|
||||
_, err = h.UpdateTicker(context.Background(), sp, asset.Spot)
|
||||
_, err = h.UpdateTicker(context.Background(), currency.NewPairWithDelimiter("BTC", "USDT", "_"), asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -694,11 +687,11 @@ func TestUpdateTickerSpot(t *testing.T) {
|
||||
|
||||
func TestUpdateTickerCMF(t *testing.T) {
|
||||
t.Parallel()
|
||||
cp1, err := currency.NewPairFromString("BTC-USD")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
_, err := h.UpdateTicker(context.Background(), currency.NewPairWithDelimiter("INV", "ALID", "_"), asset.CoinMarginedFutures)
|
||||
if err == nil {
|
||||
t.Error("exepcted invalid contract code")
|
||||
}
|
||||
_, err = h.UpdateTicker(context.Background(), cp1, asset.CoinMarginedFutures)
|
||||
_, err = h.UpdateTicker(context.Background(), currency.NewPairWithDelimiter("BTC", "USD", "_"), asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -778,7 +771,7 @@ func TestUpdateOrderbookFuture(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = h.UpdateOrderbook(context.Background(), cp2, asset.Futures)
|
||||
_, err = h.UpdateOrderbook(context.Background(), cp2, asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -1077,8 +1070,7 @@ func TestGetSystemStatusInfo(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = h.GetSystemStatusInfo(context.Background(),
|
||||
cp, "5min", "cryptocurrency", 50)
|
||||
_, err = h.GetSystemStatusInfo(context.Background(), cp)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -1801,7 +1793,7 @@ func TestSpotNewOrder(t *testing.T) {
|
||||
}
|
||||
arg := SpotNewOrderRequestParams{
|
||||
Symbol: cp,
|
||||
AccountID: 1,
|
||||
AccountID: 1997024,
|
||||
Amount: 0.01,
|
||||
Price: 10.1,
|
||||
Type: SpotNewOrderRequestTypeBuyLimit,
|
||||
@@ -2019,7 +2011,7 @@ func TestSubmitOrder(t *testing.T) {
|
||||
},
|
||||
Side: order.Buy,
|
||||
Type: order.Limit,
|
||||
Price: 1,
|
||||
Price: 5,
|
||||
Amount: 1,
|
||||
ClientID: strconv.FormatInt(accounts[0].ID, 10),
|
||||
AssetType: asset.Spot,
|
||||
@@ -2125,6 +2117,7 @@ func TestModifyOrder(t *testing.T) {
|
||||
|
||||
func TestWithdraw(t *testing.T) {
|
||||
withdrawCryptoRequest := withdraw.Request{
|
||||
Exchange: h.Name,
|
||||
Amount: -1,
|
||||
Currency: currency.BTC,
|
||||
Description: "WITHDRAW IT ALL",
|
||||
@@ -2173,8 +2166,17 @@ func TestWithdrawInternationalBank(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestQueryDepositAddress(t *testing.T) {
|
||||
_, err := h.QueryDepositAddress(context.Background(),
|
||||
currency.BTC.Lower().String())
|
||||
_, err := h.QueryDepositAddress(context.Background(), currency.USDT)
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDepositAddress(t *testing.T) {
|
||||
_, err := h.GetDepositAddress(context.Background(), currency.USDT, "", "uSdTeRc20")
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
@@ -2677,3 +2679,44 @@ func TestGetHistoricTrades(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAvailableTransferChains(t *testing.T) {
|
||||
t.Parallel()
|
||||
r, err := h.GetAvailableTransferChains(context.Background(), currency.USDT)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(r) < 2 {
|
||||
t.Error("expected more than one result")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatFuturesPair(t *testing.T) {
|
||||
r, err := h.formatFuturesPair(futuresTestPair)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if r != "BTC_NQ" {
|
||||
t.Errorf("expected BTC_NQ, got %s", r)
|
||||
}
|
||||
availInstruments, err := h.FetchTradablePairs(context.Background(), asset.Futures)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(availInstruments) == 0 {
|
||||
t.Fatal("expected instruments, got 0")
|
||||
}
|
||||
// test getting a tradable pair in the format of BTC210827 but make it lower
|
||||
// case to test correct formatting
|
||||
p, err := currency.NewPairFromString(strings.ToLower(availInstruments[0]))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r, err = h.formatFuturesPair(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if r != availInstruments[0] {
|
||||
t.Errorf("expected %s, got %s", availInstruments[0], r)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,12 @@ import (
|
||||
)
|
||||
|
||||
type errorCapture struct {
|
||||
Status string `json:"status"`
|
||||
Code int64 `json:"err_code"`
|
||||
ErrMsg string `json:"err_msg"`
|
||||
Timestamp int64 `json:"ts"`
|
||||
Status string `json:"status"`
|
||||
CodeType1 interface{} `json:"err-code"` // can be either a string or int depending on the endpoint
|
||||
ErrMsgType1 string `json:"err-msg"`
|
||||
CodeType2 interface{} `json:"err_code"`
|
||||
ErrMsgType2 string `json:"err_msg"`
|
||||
Timestamp int64 `json:"ts"`
|
||||
}
|
||||
|
||||
// MarketSummary24Hr stores past 24hr market summary data of a given symbol
|
||||
@@ -27,6 +29,35 @@ type MarketSummary24Hr struct {
|
||||
}
|
||||
}
|
||||
|
||||
// CurrenciesChainData stores currency and chain info
|
||||
type CurrenciesChainData struct {
|
||||
Currency string `json:"currency"`
|
||||
AssetType uint8 `json:"assetType"`
|
||||
InstStatus string `json:"instStatus"`
|
||||
ChainData []struct {
|
||||
Chain string `json:"chain"`
|
||||
DisplayName string `json:"displayName"`
|
||||
BaseChain string `json:"baseChain"`
|
||||
BaseChainProtocol string `json:"baseChainProtocol"`
|
||||
IsDynamic bool `json:"isDynamic"`
|
||||
NumberOfConfirmations uint16 `json:"numOfConfirmations"`
|
||||
NumberOfFastConfirmations uint16 `json:"numOfFastConfirmations"`
|
||||
DepositStatus string `json:"depositStatus"`
|
||||
MinimumDepositAmount float64 `json:"minDepositAmt,string"`
|
||||
WithdrawStatus string `json:"withdrawStatus"`
|
||||
MinimumWithdrawalAmount float64 `json:"minWithdrawAmt,string"`
|
||||
WithdrawPrecision int16 `json:"withdrawPrecision"`
|
||||
MaximumWithdrawAmount float64 `json:"maxWithdrawwAmt,string"`
|
||||
WithdrawQuotaPerDay float64 `json:"withdrawQuotaPerDay,string"`
|
||||
WithdrawQuotaPerYear float64 `json:"withdrawQuotaPerYear,string"`
|
||||
WithdrawQuotaTotal float64 `json:"withdrawQuotaTotal,string"`
|
||||
WithdrawFeeType string `json:"withdrawFeeType"`
|
||||
TransactFeeWithdraw float64 `json:"transactFeeWithdraw,string"`
|
||||
AddressWithTag bool `json:"addrWithTag"`
|
||||
AddressDepositTag bool `json:"addrDepositTag"`
|
||||
} `json:"chains"`
|
||||
}
|
||||
|
||||
// WsKlineData stores kline data for futures and swap websocket
|
||||
type WsKlineData struct {
|
||||
Channel string `json:"ch"`
|
||||
@@ -699,6 +730,7 @@ type SpotNewOrderRequestParams struct {
|
||||
|
||||
// DepositAddress stores the users deposit address info
|
||||
type DepositAddress struct {
|
||||
UserID int64 `json:"userId"`
|
||||
Currency string `json:"currency"`
|
||||
Address string `json:"address"`
|
||||
AddressTag string `json:"addressTag"`
|
||||
@@ -1023,21 +1055,6 @@ type WsPong struct {
|
||||
Pong int64 `json:"pong"`
|
||||
}
|
||||
|
||||
type wsKlineResponse struct {
|
||||
Data []struct {
|
||||
Amount float64 `json:"amount"`
|
||||
Close float64 `json:"close"`
|
||||
Count float64 `json:"count"`
|
||||
High float64 `json:"high"`
|
||||
ID int64 `json:"id"`
|
||||
Low float64 `json:"low"`
|
||||
Open float64 `json:"open"`
|
||||
Volume float64 `json:"vol"`
|
||||
} `json:"data"`
|
||||
Rep string `json:"rep"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type authenticationPing struct {
|
||||
OP string `json:"op"`
|
||||
TS int64 `json:"ts"`
|
||||
@@ -1127,6 +1144,10 @@ var (
|
||||
"this_week", "next_week", "quarter", "next_quarter",
|
||||
}
|
||||
|
||||
validContractShortTypes = []string{
|
||||
"cw", "nw", "cq", "nq",
|
||||
}
|
||||
|
||||
validFuturesPeriods = []string{
|
||||
"1min", "5min", "15min", "30min", "60min", "1hour", "4hour", "1day",
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/deposit"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
||||
@@ -78,7 +79,6 @@ func (h *HUOBI) SetDefaults() {
|
||||
futures := currency.PairStore{
|
||||
RequestFormat: ¤cy.PairFormat{
|
||||
Uppercase: true,
|
||||
Delimiter: currency.UnderscoreDelimiter,
|
||||
},
|
||||
ConfigFormat: ¤cy.PairFormat{
|
||||
Uppercase: true,
|
||||
@@ -102,20 +102,22 @@ func (h *HUOBI) SetDefaults() {
|
||||
REST: true,
|
||||
Websocket: true,
|
||||
RESTCapabilities: protocol.Features{
|
||||
TickerFetching: true,
|
||||
KlineFetching: true,
|
||||
TradeFetching: true,
|
||||
OrderbookFetching: true,
|
||||
AutoPairUpdates: true,
|
||||
AccountInfo: true,
|
||||
GetOrder: true,
|
||||
GetOrders: true,
|
||||
CancelOrders: true,
|
||||
CancelOrder: true,
|
||||
SubmitOrder: true,
|
||||
CryptoDeposit: true,
|
||||
CryptoWithdrawal: true,
|
||||
TradeFee: true,
|
||||
TickerFetching: true,
|
||||
KlineFetching: true,
|
||||
TradeFetching: true,
|
||||
OrderbookFetching: true,
|
||||
AutoPairUpdates: true,
|
||||
AccountInfo: true,
|
||||
GetOrder: true,
|
||||
GetOrders: true,
|
||||
CancelOrders: true,
|
||||
CancelOrder: true,
|
||||
SubmitOrder: true,
|
||||
CryptoDeposit: true,
|
||||
CryptoWithdrawal: true,
|
||||
TradeFee: true,
|
||||
MultiChainDeposits: true,
|
||||
MultiChainWithdrawals: true,
|
||||
},
|
||||
WebsocketCapabilities: protocol.Features{
|
||||
KlineFetching: true,
|
||||
@@ -162,7 +164,7 @@ func (h *HUOBI) SetDefaults() {
|
||||
h.API.Endpoints = h.NewEndpoints()
|
||||
err = h.API.Endpoints.SetDefaultEndpoints(map[exchange.URL]string{
|
||||
exchange.RestSpot: huobiAPIURL,
|
||||
exchange.RestFutures: huobiURL,
|
||||
exchange.RestFutures: huobiFuturesURL,
|
||||
exchange.RestCoinMargined: huobiFuturesURL,
|
||||
exchange.WebsocketSpot: wsMarketURL,
|
||||
})
|
||||
@@ -1244,9 +1246,26 @@ func (h *HUOBI) GetOrderInfo(ctx context.Context, orderID string, pair currency.
|
||||
}
|
||||
|
||||
// GetDepositAddress returns a deposit address for a specified currency
|
||||
func (h *HUOBI) GetDepositAddress(ctx context.Context, cryptocurrency currency.Code, _ string) (string, error) {
|
||||
resp, err := h.QueryDepositAddress(ctx, cryptocurrency.Lower().String())
|
||||
return resp.Address, err
|
||||
func (h *HUOBI) GetDepositAddress(ctx context.Context, cryptocurrency currency.Code, _, chain string) (*deposit.Address, error) {
|
||||
resp, err := h.QueryDepositAddress(ctx, cryptocurrency)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for x := range resp {
|
||||
if chain != "" && strings.EqualFold(resp[x].Chain, chain) {
|
||||
return &deposit.Address{
|
||||
Address: resp[x].Address,
|
||||
Tag: resp[x].AddressTag,
|
||||
}, nil
|
||||
} else if chain == "" && strings.EqualFold(resp[x].Currency, cryptocurrency.String()) {
|
||||
return &deposit.Address{
|
||||
Address: resp[x].Address,
|
||||
Tag: resp[x].AddressTag,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("unable to match deposit address currency or chain")
|
||||
}
|
||||
|
||||
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is
|
||||
@@ -1259,6 +1278,7 @@ func (h *HUOBI) WithdrawCryptocurrencyFunds(ctx context.Context, withdrawRequest
|
||||
withdrawRequest.Currency,
|
||||
withdrawRequest.Crypto.Address,
|
||||
withdrawRequest.Crypto.AddressTag,
|
||||
withdrawRequest.Crypto.Chain,
|
||||
withdrawRequest.Amount,
|
||||
withdrawRequest.Crypto.FeeAmount)
|
||||
if err != nil {
|
||||
@@ -1395,6 +1415,7 @@ func (h *HUOBI) GetActiveOrders(ctx context.Context, req *order.GetOrdersRequest
|
||||
if err != nil {
|
||||
return orders, err
|
||||
}
|
||||
|
||||
var orderVars OrderVars
|
||||
for x := range openOrders.Data.Orders {
|
||||
orderVars, err = compatibleVars(openOrders.Data.Orders[x].Direction,
|
||||
@@ -1424,6 +1445,8 @@ func (h *HUOBI) GetActiveOrders(ctx context.Context, req *order.GetOrdersRequest
|
||||
Pair: p,
|
||||
})
|
||||
}
|
||||
currentPage++
|
||||
done = currentPage == openOrders.Data.TotalPage
|
||||
}
|
||||
}
|
||||
case asset.Futures:
|
||||
@@ -1464,6 +1487,8 @@ func (h *HUOBI) GetActiveOrders(ctx context.Context, req *order.GetOrdersRequest
|
||||
Pair: p,
|
||||
})
|
||||
}
|
||||
currentPage++
|
||||
done = currentPage == openOrders.Data.TotalPage
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1562,9 +1587,7 @@ func (h *HUOBI) GetOrderHistory(ctx context.Context, req *order.GetOrdersRequest
|
||||
})
|
||||
}
|
||||
currentPage++
|
||||
if currentPage == orderHistory.Data.TotalPage {
|
||||
done = true
|
||||
}
|
||||
done = currentPage == orderHistory.Data.TotalPage
|
||||
}
|
||||
}
|
||||
case asset.Futures:
|
||||
@@ -1623,9 +1646,7 @@ func (h *HUOBI) GetOrderHistory(ctx context.Context, req *order.GetOrdersRequest
|
||||
})
|
||||
}
|
||||
currentPage++
|
||||
if currentPage == openOrders.Data.TotalPage {
|
||||
done = true
|
||||
}
|
||||
done = currentPage == openOrders.Data.TotalPage
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1762,3 +1783,22 @@ func compatibleVars(side, orderPriceType string, status int64) (OrderVars, error
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetAvailableTransferChains returns the available transfer blockchains for the specific
|
||||
// cryptocurrency
|
||||
func (h *HUOBI) GetAvailableTransferChains(ctx context.Context, cryptocurrency currency.Code) ([]string, error) {
|
||||
chains, err := h.GetCurrenciesIncludingChains(ctx, cryptocurrency)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(chains) == 0 {
|
||||
return nil, errors.New("chain data isn't populated")
|
||||
}
|
||||
|
||||
var availableChains []string
|
||||
for x := range chains[0].ChainData {
|
||||
availableChains = append(availableChains, chains[0].ChainData[x].Chain)
|
||||
}
|
||||
return availableChains, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user