exchanges/futures: Implement open interest (#1417)

* adds open interest to exchanges

* ADDS TESTING YEAH

* New endpoints, BTSE, RPCS, cached

* slight design change, begin gateio

You will need to get cached for
each exchange that supports it

* gateio, huobi, rpc

* fix up kraken, cache retrieval

* okx, gateio

* finalising all implementations and tests

* definitely my final ever commit on this

* Well, well, well

* final v2

* quick fix of bug

* test coverage, assert notempty, test helper

Added a new testhelper for currency
management because its very annoying
in a parallel test setting which wastes
so much space otherwise

* minimises REST requests for Open Interest

* types.Number merge misses

* Minimises Kraken REST calls

* len change, value -> pointer receiver

* further fixup

* fixes gateio, batch calculates open interest

* single gateio, lint const fixes

* rejig and more thorough oi for huobi

* formatting expansion

* minor fix for handling expiring contracts

* rm unused Binance strings

* add bybit support, fix bybit issues

* oopsie doopsie, dont look at my whoopsie

* Fix issue, remove feature

* move an irrelevant function for the pr

* mini bybit upgrades

* fixes cli request bug
This commit is contained in:
Scott
2024-01-12 15:27:35 +11:00
committed by GitHub
parent 614042110a
commit b71bf1f3d1
62 changed files with 22660 additions and 10095 deletions

View File

@@ -111,6 +111,13 @@ const (
gateioFlashSwapOrders = "flash_swap/orders"
gateioFlashSwapOrdersPreview = "flash_swap/orders/preview"
futuresPath = "futures/"
deliveryPath = "delivery/"
ordersPath = "/orders"
positionsPath = "/positions/"
subAccountsPath = "sub_accounts/"
priceOrdersPaths = "/price_orders"
// Withdrawals
withdrawal = "withdrawals"
)
@@ -203,18 +210,18 @@ func (g *Gateio) CreateAPIKeysOfSubAccount(ctx context.Context, arg CreateAPIKey
return nil, errors.New("sub-account key information is required")
}
var resp *CreateAPIKeyResponse
return resp, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, spotPlaceOrdersEPL, http.MethodPost, "sub_accounts/"+strconv.FormatInt(arg.SubAccountUserID, 10)+"/keys", nil, &arg, &resp)
return resp, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, spotPlaceOrdersEPL, http.MethodPost, subAccountsPath+strconv.FormatInt(arg.SubAccountUserID, 10)+"/keys", nil, &arg, &resp)
}
// GetAllAPIKeyOfSubAccount list all API Key of the sub-account
func (g *Gateio) GetAllAPIKeyOfSubAccount(ctx context.Context, userID int64) ([]CreateAPIKeyResponse, error) {
var resp []CreateAPIKeyResponse
return resp, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, spotPrivateEPL, http.MethodGet, "sub_accounts/"+strconv.FormatInt(userID, 10)+"/keys", nil, nil, &resp)
return resp, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, spotPrivateEPL, http.MethodGet, subAccountsPath+strconv.FormatInt(userID, 10)+"/keys", nil, nil, &resp)
}
// UpdateAPIKeyOfSubAccount update API key of the sub-account
func (g *Gateio) UpdateAPIKeyOfSubAccount(ctx context.Context, subAccountAPIKey string, arg CreateAPIKeySubAccountParams) error {
return g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, spotPlaceOrdersEPL, http.MethodPut, "sub_accounts/"+strconv.FormatInt(arg.SubAccountUserID, 10)+"/keys/"+subAccountAPIKey, nil, &arg, nil)
return g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, spotPlaceOrdersEPL, http.MethodPut, subAccountsPath+strconv.FormatInt(arg.SubAccountUserID, 10)+"/keys/"+subAccountAPIKey, nil, &arg, nil)
}
// GetAPIKeyOfSubAccount retrieves the API Key of the sub-account
@@ -226,7 +233,7 @@ func (g *Gateio) GetAPIKeyOfSubAccount(ctx context.Context, subAccountUserID int
return nil, errMissingAPIKey
}
var resp *CreateAPIKeyResponse
return resp, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, spotPrivateEPL, http.MethodGet, "sub_accounts/"+strconv.FormatInt(subAccountUserID, 10)+"/keys/"+apiKey, nil, nil, &resp)
return resp, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, spotPrivateEPL, http.MethodGet, subAccountsPath+strconv.FormatInt(subAccountUserID, 10)+"/keys/"+apiKey, nil, nil, &resp)
}
// LockSubAccount locks the sub-account
@@ -234,7 +241,7 @@ func (g *Gateio) LockSubAccount(ctx context.Context, subAccountUserID int64) err
if subAccountUserID == 0 {
return errInvalidSubAccountUserID
}
return g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, spotPrivateEPL, http.MethodPost, "sub_accounts/"+strconv.FormatInt(subAccountUserID, 10)+"/lock", nil, nil, nil)
return g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, spotPrivateEPL, http.MethodPost, subAccountsPath+strconv.FormatInt(subAccountUserID, 10)+"/lock", nil, nil, nil)
}
// UnlockSubAccount locks the sub-account
@@ -242,7 +249,7 @@ func (g *Gateio) UnlockSubAccount(ctx context.Context, subAccountUserID int64) e
if subAccountUserID == 0 {
return errInvalidSubAccountUserID
}
return g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, spotPrivateEPL, http.MethodPost, "sub_accounts/"+strconv.FormatInt(subAccountUserID, 10)+"/unlock", nil, nil, nil)
return g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, spotPrivateEPL, http.MethodPost, subAccountsPath+strconv.FormatInt(subAccountUserID, 10)+"/unlock", nil, nil, nil)
}
// ***************************************** Spot **************************************
@@ -1854,7 +1861,7 @@ func (g *Gateio) GetAllFutureContracts(ctx context.Context, settle string) ([]Fu
return nil, errEmptySettlementCurrency
}
var contracts []FuturesContract
return contracts, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL, "futures/"+settle+"/contracts", &contracts)
return contracts, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL, futuresPath+settle+"/contracts", &contracts)
}
// GetSingleContract returns a single contract info for the specified settle and Currency Pair (contract << in this case)
@@ -1867,7 +1874,7 @@ func (g *Gateio) GetSingleContract(ctx context.Context, settle, contract string)
return nil, errEmptySettlementCurrency
}
var futureContract *FuturesContract
return futureContract, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL, "futures/"+settle+"/contracts/"+contract, &futureContract)
return futureContract, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL, futuresPath+settle+"/contracts/"+contract, &futureContract)
}
// GetFuturesOrderbook retrieves futures order book data
@@ -1891,7 +1898,7 @@ func (g *Gateio) GetFuturesOrderbook(ctx context.Context, settle, contract, inte
params.Set("with_id", "true")
}
var response *Orderbook
return response, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL, common.EncodeURLValues("futures/"+settle+"/order_book", params), &response)
return response, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL, common.EncodeURLValues(futuresPath+settle+"/order_book", params), &response)
}
// GetFuturesTradingHistory retrieves futures trading history
@@ -1922,7 +1929,7 @@ func (g *Gateio) GetFuturesTradingHistory(ctx context.Context, settle string, co
}
var response []TradingHistoryItem
return response, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL,
common.EncodeURLValues("futures/"+settle+"/trades", params), &response)
common.EncodeURLValues(futuresPath+settle+"/trades", params), &response)
}
// GetFuturesCandlesticks retrieves specified contract candlesticks.
@@ -1954,7 +1961,7 @@ func (g *Gateio) GetFuturesCandlesticks(ctx context.Context, settle, contract st
}
var candlesticks []FuturesCandlestick
return candlesticks, g.SendHTTPRequest(ctx, exchange.RestFutures, perpetualSwapDefaultEPL,
common.EncodeURLValues("futures/"+settle+"/candlesticks", params),
common.EncodeURLValues(futuresPath+settle+"/candlesticks", params),
&candlesticks)
}
@@ -1984,7 +1991,7 @@ func (g *Gateio) PremiumIndexKLine(ctx context.Context, settleCurrency string, c
}
params.Set("interval", intervalString)
var resp []FuturesPremiumIndexKLineResponse
return resp, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL, common.EncodeURLValues("futures/"+settleCurrency+"/premium_index", params), &resp)
return resp, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL, common.EncodeURLValues(futuresPath+settleCurrency+"/premium_index", params), &resp)
}
// GetFuturesTickers retrieves futures ticker information for a specific settle and contract info.
@@ -1998,7 +2005,7 @@ func (g *Gateio) GetFuturesTickers(ctx context.Context, settle string, contract
params.Set("contract", contract.String())
}
var tickers []FuturesTicker
return tickers, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL, common.EncodeURLValues("futures/"+settle+"/tickers", params), &tickers)
return tickers, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL, common.EncodeURLValues(futuresPath+settle+"/tickers", params), &tickers)
}
// GetFutureFundingRates retrieves funding rate information.
@@ -2016,7 +2023,7 @@ func (g *Gateio) GetFutureFundingRates(ctx context.Context, settle string, contr
params.Set("limit", strconv.FormatUint(limit, 10))
}
var rates []FuturesFundingRate
return rates, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL, common.EncodeURLValues("futures/"+settle+"/funding_rate", params), &rates)
return rates, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL, common.EncodeURLValues(futuresPath+settle+"/funding_rate", params), &rates)
}
// GetFuturesInsuranceBalanceHistory retrieves futures insurance balance history
@@ -2032,7 +2039,7 @@ func (g *Gateio) GetFuturesInsuranceBalanceHistory(ctx context.Context, settle s
var balances []InsuranceBalance
return balances, g.SendHTTPRequest(ctx,
exchange.RestSpot, perpetualSwapDefaultEPL,
common.EncodeURLValues("futures/"+settle+"/insurance", params),
common.EncodeURLValues(futuresPath+settle+"/insurance", params),
&balances)
}
@@ -2063,7 +2070,7 @@ func (g *Gateio) GetFutureStats(ctx context.Context, settle string, contract cur
var stats []ContractStat
return stats, g.SendHTTPRequest(ctx,
exchange.RestSpot, perpetualSwapDefaultEPL,
common.EncodeURLValues("futures/"+settle+"/contract_stats", params),
common.EncodeURLValues(futuresPath+settle+"/contract_stats", params),
&stats)
}
@@ -2080,7 +2087,7 @@ func (g *Gateio) GetIndexConstituent(ctx context.Context, settle, index string)
var constituents *IndexConstituent
return constituents, g.SendHTTPRequest(ctx,
exchange.RestSpot, perpetualSwapDefaultEPL,
"futures/"+settle+"/index_constituents/"+indexString,
futuresPath+settle+"/index_constituents/"+indexString,
&constituents)
}
@@ -2107,7 +2114,7 @@ func (g *Gateio) GetLiquidationHistory(ctx context.Context, settle string, contr
var histories []LiquidationHistory
return histories, g.SendHTTPRequest(ctx,
exchange.RestSpot, perpetualSwapDefaultEPL,
common.EncodeURLValues("futures/"+settle+"/liq_orders", params),
common.EncodeURLValues(futuresPath+settle+"/liq_orders", params),
&histories)
}
@@ -2118,7 +2125,7 @@ func (g *Gateio) QueryFuturesAccount(ctx context.Context, settle string) (*Futur
return nil, errEmptySettlementCurrency
}
var response *FuturesAccount
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet, "futures/"+settle+"/accounts", nil, nil, &response)
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet, futuresPath+settle+"/accounts", nil, nil, &response)
}
// GetFuturesAccountBooks retrieves account books
@@ -2141,7 +2148,7 @@ func (g *Gateio) GetFuturesAccountBooks(ctx context.Context, settle string, limi
}
var response []AccountBookItem
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL,
http.MethodGet, "futures/"+settle+"/account_book",
http.MethodGet, futuresPath+settle+"/account_book",
params,
nil,
&response)
@@ -2153,7 +2160,7 @@ func (g *Gateio) GetAllFuturesPositionsOfUsers(ctx context.Context, settle strin
return nil, errEmptySettlementCurrency
}
var response *Position
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet, "futures/"+settle+"/positions", nil, nil, &response)
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet, futuresPath+settle+"/positions", nil, nil, &response)
}
// GetSinglePosition returns a single position
@@ -2167,7 +2174,7 @@ func (g *Gateio) GetSinglePosition(ctx context.Context, settle string, contract
}
var response *Position
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL,
http.MethodPost, "futures/"+settle+"/positions/"+contract.String(),
http.MethodPost, futuresPath+settle+positionsPath+contract.String(),
nil, nil, &response)
}
@@ -2187,7 +2194,7 @@ func (g *Gateio) UpdateFuturesPositionMargin(ctx context.Context, settle string,
var response *Position
return response, g.SendAuthenticatedHTTPRequest(ctx,
exchange.RestSpot, perpetualSwapPlaceOrdersEPL,
http.MethodPost, "futures/"+settle+"/positions/"+contract.String()+"/margin",
http.MethodPost, futuresPath+settle+positionsPath+contract.String()+"/margin",
params, nil, &response)
}
@@ -2210,7 +2217,7 @@ func (g *Gateio) UpdateFuturesPositionLeverage(ctx context.Context, settle strin
var response *Position
return response, g.SendAuthenticatedHTTPRequest(ctx,
exchange.RestSpot, perpetualSwapPlaceOrdersEPL, http.MethodPost,
"futures/"+settle+"/positions/"+contract.String()+"/leverage", params, nil, &response)
futuresPath+settle+positionsPath+contract.String()+"/leverage", params, nil, &response)
}
// UpdateFuturesPositionRiskLimit updates the position risk limit
@@ -2225,7 +2232,7 @@ func (g *Gateio) UpdateFuturesPositionRiskLimit(ctx context.Context, settle stri
params.Set("risk_limit", strconv.FormatUint(riskLimit, 10))
var response *Position
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPlaceOrdersEPL,
http.MethodPost, "futures/"+settle+"/positions/"+contract.String()+"/risk_limit", params, nil, &response)
http.MethodPost, futuresPath+settle+positionsPath+contract.String()+"/risk_limit", params, nil, &response)
}
// EnableOrDisableDualMode enable or disable dual mode
@@ -2238,7 +2245,7 @@ func (g *Gateio) EnableOrDisableDualMode(ctx context.Context, settle string, dua
params.Set("dual_mode", strconv.FormatBool(dualMode))
var response *DualModeResponse
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL,
http.MethodGet, "futures/"+settle+"/dual_mode",
http.MethodGet, futuresPath+settle+"/dual_mode",
params, nil, &response)
}
@@ -2253,7 +2260,7 @@ func (g *Gateio) RetrivePositionDetailInDualMode(ctx context.Context, settle str
var response []Position
return response, g.SendAuthenticatedHTTPRequest(ctx,
exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet,
"futures/"+settle+"/dual_comp/positions/"+contract.String(),
futuresPath+settle+"/dual_comp/positions/"+contract.String(),
nil, nil, &response)
}
@@ -2274,7 +2281,7 @@ func (g *Gateio) UpdatePositionMarginInDualMode(ctx context.Context, settle stri
var response []Position
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPlaceOrdersEPL,
http.MethodPost,
"futures/"+settle+"/dual_comp/positions/"+contract.String()+"/margin",
futuresPath+settle+"/dual_comp/positions/"+contract.String()+"/margin",
params, nil, &response)
}
@@ -2295,7 +2302,7 @@ func (g *Gateio) UpdatePositionLeverageInDualMode(ctx context.Context, settle st
params.Set("cross_leverage_limit", strconv.FormatFloat(crossLeverageLimit, 'f', -1, 64))
}
var response *Position
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPlaceOrdersEPL, http.MethodPost, "futures/"+settle+"/dual_comp/positions/"+contract.String()+"/leverage", params, nil, &response)
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPlaceOrdersEPL, http.MethodPost, futuresPath+settle+"/dual_comp/positions/"+contract.String()+"/leverage", params, nil, &response)
}
// UpdatePositionRiskLimitInDualMode update position risk limit in dual mode
@@ -2314,7 +2321,7 @@ func (g *Gateio) UpdatePositionRiskLimitInDualMode(ctx context.Context, settle s
var response []Position
return response, g.SendAuthenticatedHTTPRequest(ctx,
exchange.RestSpot, perpetualSwapPlaceOrdersEPL, http.MethodPost,
"futures/"+settle+"/dual_comp/positions/"+contract.String()+"/risk_limit", params,
futuresPath+settle+"/dual_comp/positions/"+contract.String()+"/risk_limit", params,
nil, &response)
}
@@ -2361,7 +2368,7 @@ func (g *Gateio) PlaceFuturesOrder(ctx context.Context, arg *OrderCreateParams)
return response, g.SendAuthenticatedHTTPRequest(ctx,
exchange.RestSpot, perpetualSwapPlaceOrdersEPL,
http.MethodPost,
"futures/"+arg.Settle+"/orders",
futuresPath+arg.Settle+ordersPath,
nil, &arg, &response)
}
@@ -2396,7 +2403,7 @@ func (g *Gateio) GetFuturesOrders(ctx context.Context, contract currency.Pair, s
}
var response []Order
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL,
http.MethodGet, "futures/"+settle+"/orders",
http.MethodGet, futuresPath+settle+ordersPath,
params, nil, &response)
}
@@ -2416,7 +2423,7 @@ func (g *Gateio) CancelMultipleFuturesOpenOrders(ctx context.Context, contract c
params.Set("contract", contract.String())
var response []Order
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapCancelOrdersEPL,
http.MethodDelete, "futures/"+settle+"/orders", params, nil, &response)
http.MethodDelete, futuresPath+settle+ordersPath, params, nil, &response)
}
// PlaceBatchFuturesOrders creates a list of futures orders
@@ -2462,7 +2469,7 @@ func (g *Gateio) PlaceBatchFuturesOrders(ctx context.Context, settle string, arg
}
var response []Order
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL,
http.MethodPost, "futures/"+settle+"/batch_orders",
http.MethodPost, futuresPath+settle+"/batch_orders",
nil, &args, &response)
}
@@ -2477,7 +2484,7 @@ func (g *Gateio) GetSingleFuturesOrder(ctx context.Context, settle, orderID stri
var response *Order
return response, g.SendAuthenticatedHTTPRequest(ctx,
exchange.RestSpot, perpetualSwapPrivateEPL,
http.MethodGet, "futures/"+settle+"/orders/"+orderID,
http.MethodGet, futuresPath+settle+"/orders/"+orderID,
nil, nil, &response)
}
@@ -2491,7 +2498,7 @@ func (g *Gateio) CancelSingleFuturesOrder(ctx context.Context, settle, orderID s
}
var response *Order
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapCancelOrdersEPL, http.MethodDelete,
"futures/"+settle+"/orders/"+orderID, nil, nil, &response)
futuresPath+settle+"/orders/"+orderID, nil, nil, &response)
}
// AmendFuturesOrder amends an existing futures order
@@ -2507,7 +2514,7 @@ func (g *Gateio) AmendFuturesOrder(ctx context.Context, settle, orderID string,
}
var response *Order
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPlaceOrdersEPL, http.MethodPut,
"futures/"+settle+"/orders/"+orderID, nil, &arg, &response)
futuresPath+settle+"/orders/"+orderID, nil, &arg, &response)
}
// GetMyPersonalTradingHistory retrieves my personal trading history
@@ -2536,7 +2543,7 @@ func (g *Gateio) GetMyPersonalTradingHistory(ctx context.Context, settle, lastID
}
var response []TradingHistoryItem
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet,
"futures/"+settle+"/my_trades", params, nil, &response)
futuresPath+settle+"/my_trades", params, nil, &response)
}
// GetFuturesPositionCloseHistory lists position close history
@@ -2562,7 +2569,7 @@ func (g *Gateio) GetFuturesPositionCloseHistory(ctx context.Context, settle stri
}
var response []PositionCloseHistoryResponse
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet,
"futures/"+settle+"/position_close", params, nil, &response)
futuresPath+settle+"/position_close", params, nil, &response)
}
// GetFuturesLiquidationHistory list liquidation history
@@ -2583,7 +2590,7 @@ func (g *Gateio) GetFuturesLiquidationHistory(ctx context.Context, settle string
var response []LiquidationHistoryItem
return response, g.SendAuthenticatedHTTPRequest(ctx,
exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet,
"futures/"+settle+"/liquidates", params, nil, &response)
futuresPath+settle+"/liquidates", params, nil, &response)
}
// CountdownCancelOrders represents a trigger time response
@@ -2597,7 +2604,7 @@ func (g *Gateio) CountdownCancelOrders(ctx context.Context, settle string, arg C
var response *TriggerTimeResponse
return response, g.SendAuthenticatedHTTPRequest(ctx,
exchange.RestSpot, perpetualSwapPlaceOrdersEPL, http.MethodPost,
"futures/"+settle+"/countdown_cancel_all", nil, &arg, &response)
futuresPath+settle+"/countdown_cancel_all", nil, &arg, &response)
}
// CreatePriceTriggeredFuturesOrder create a price-triggered order
@@ -2637,7 +2644,7 @@ func (g *Gateio) CreatePriceTriggeredFuturesOrder(ctx context.Context, settle st
}
var response *OrderID
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPlaceOrdersEPL, http.MethodPost,
"futures/"+settle+"/price_orders", nil, &arg, &response)
futuresPath+settle+priceOrdersPaths, nil, &arg, &response)
}
// ListAllFuturesAutoOrders lists all open orders
@@ -2662,7 +2669,7 @@ func (g *Gateio) ListAllFuturesAutoOrders(ctx context.Context, status, settle st
var response []PriceTriggeredOrder
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL,
http.MethodGet,
"futures/"+settle+"/price_orders",
futuresPath+settle+priceOrdersPaths,
params, nil, &response)
}
@@ -2679,7 +2686,7 @@ func (g *Gateio) CancelAllFuturesOpenOrders(ctx context.Context, settle string,
params.Set("contract", contract.String())
var response []PriceTriggeredOrder
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapCancelOrdersEPL, http.MethodDelete,
"futures/"+settle+"/price_orders", params, nil, &response)
futuresPath+settle+priceOrdersPaths, params, nil, &response)
}
// GetSingleFuturesPriceTriggeredOrder retrieves a single price triggered order
@@ -2693,7 +2700,7 @@ func (g *Gateio) GetSingleFuturesPriceTriggeredOrder(ctx context.Context, settle
var response *PriceTriggeredOrder
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL,
http.MethodGet,
"futures/"+settle+"/price_orders/"+orderID, nil, nil, &response)
futuresPath+settle+"/price_orders/"+orderID, nil, nil, &response)
}
// CancelFuturesPriceTriggeredOrder cancel a price-triggered order
@@ -2706,7 +2713,7 @@ func (g *Gateio) CancelFuturesPriceTriggeredOrder(ctx context.Context, settle, o
}
var response *PriceTriggeredOrder
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapCancelOrdersEPL, http.MethodDelete,
"futures/"+settle+"/price_orders/"+orderID, nil, nil, &response)
futuresPath+settle+"/price_orders/"+orderID, nil, nil, &response)
}
// *************************************** Delivery ***************************************
@@ -2719,7 +2726,7 @@ func (g *Gateio) GetAllDeliveryContracts(ctx context.Context, settle string) ([]
}
var contracts []DeliveryContract
return contracts, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL,
"delivery/"+settle+"/contracts", &contracts)
deliveryPath+settle+"/contracts", &contracts)
}
// GetSingleDeliveryContracts retrieves a single delivery contract instance.
@@ -2729,7 +2736,7 @@ func (g *Gateio) GetSingleDeliveryContracts(ctx context.Context, settle string,
}
var deliveryContract *DeliveryContract
return deliveryContract, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL,
"delivery/"+settle+"/contracts/"+contract.String(), &deliveryContract)
deliveryPath+settle+"/contracts/"+contract.String(), &deliveryContract)
}
// GetDeliveryOrderbook delivery orderbook
@@ -2753,7 +2760,7 @@ func (g *Gateio) GetDeliveryOrderbook(ctx context.Context, settle, interval stri
params.Set("with_id", strconv.FormatBool(withOrderbookID))
}
var orderbook *Orderbook
return orderbook, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL, common.EncodeURLValues("delivery/"+settle+"/order_book", params), &orderbook)
return orderbook, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL, common.EncodeURLValues(deliveryPath+settle+"/order_book", params), &orderbook)
}
// GetDeliveryTradingHistory retrieves futures trading history
@@ -2781,7 +2788,7 @@ func (g *Gateio) GetDeliveryTradingHistory(ctx context.Context, settle, lastID s
}
var histories []DeliveryTradingHistory
return histories, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL,
common.EncodeURLValues("delivery/"+settle+"/trades", params), &histories)
common.EncodeURLValues(deliveryPath+settle+"/trades", params), &histories)
}
// GetDeliveryFuturesCandlesticks retrieves specified contract candlesticks
@@ -2814,7 +2821,7 @@ func (g *Gateio) GetDeliveryFuturesCandlesticks(ctx context.Context, settle stri
var candlesticks []FuturesCandlestick
return candlesticks, g.SendHTTPRequest(ctx,
exchange.RestSpot, perpetualSwapDefaultEPL,
common.EncodeURLValues("delivery/"+settle+"/candlesticks", params),
common.EncodeURLValues(deliveryPath+settle+"/candlesticks", params),
&candlesticks)
}
@@ -2829,7 +2836,7 @@ func (g *Gateio) GetDeliveryFutureTickers(ctx context.Context, settle string, co
params.Set("contract", contract.String())
}
var tickers []FuturesTicker
return tickers, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL, common.EncodeURLValues("delivery/"+settle+"/tickers", params), &tickers)
return tickers, g.SendHTTPRequest(ctx, exchange.RestSpot, perpetualSwapDefaultEPL, common.EncodeURLValues(deliveryPath+settle+"/tickers", params), &tickers)
}
// GetDeliveryInsuranceBalanceHistory retrieves delivery futures insurance balance history
@@ -2844,7 +2851,7 @@ func (g *Gateio) GetDeliveryInsuranceBalanceHistory(ctx context.Context, settle
}
var balances []InsuranceBalance
return balances, g.SendHTTPRequest(ctx, exchange.RestSpot, spotDefaultEPL,
common.EncodeURLValues("delivery/"+settle+"/insurance", params),
common.EncodeURLValues(deliveryPath+settle+"/insurance", params),
&balances)
}
@@ -2855,7 +2862,7 @@ func (g *Gateio) GetDeliveryFuturesAccounts(ctx context.Context, settle string)
return nil, errEmptySettlementCurrency
}
var response *FuturesAccount
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet, "delivery/"+settle+"/accounts", nil, nil, &response)
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet, deliveryPath+settle+"/accounts", nil, nil, &response)
}
// GetDeliveryAccountBooks retrieves account books
@@ -2879,7 +2886,7 @@ func (g *Gateio) GetDeliveryAccountBooks(ctx context.Context, settle string, lim
var response []AccountBookItem
return response, g.SendAuthenticatedHTTPRequest(ctx,
exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet,
"delivery/"+settle+"/account_book",
deliveryPath+settle+"/account_book",
params, nil, &response)
}
@@ -2890,7 +2897,7 @@ func (g *Gateio) GetAllDeliveryPositionsOfUser(ctx context.Context, settle strin
}
var response *Position
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet,
"delivery/"+settle+"/positions", nil, nil, &response)
deliveryPath+settle+"/positions", nil, nil, &response)
}
// GetSingleDeliveryPosition get single position
@@ -2904,7 +2911,7 @@ func (g *Gateio) GetSingleDeliveryPosition(ctx context.Context, settle string, c
}
var response *Position
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet,
"delivery/"+settle+"/positions/"+contract.String(),
deliveryPath+settle+positionsPath+contract.String(),
nil, nil, &response)
}
@@ -2923,7 +2930,7 @@ func (g *Gateio) UpdateDeliveryPositionMargin(ctx context.Context, settle string
params.Set("change", strconv.FormatFloat(change, 'f', -1, 64))
var response *Position
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPlaceOrdersEPL, http.MethodPost,
"delivery/"+settle+"/positions/"+contract.String()+"/margin", params, nil, &response)
deliveryPath+settle+positionsPath+contract.String()+"/margin", params, nil, &response)
}
// UpdateDeliveryPositionLeverage updates position leverage
@@ -2942,7 +2949,7 @@ func (g *Gateio) UpdateDeliveryPositionLeverage(ctx context.Context, settle stri
var response *Position
return response, g.SendAuthenticatedHTTPRequest(ctx,
exchange.RestSpot, perpetualSwapPlaceOrdersEPL, http.MethodPost,
"delivery/"+settle+"/positions/"+contract.String()+"/leverage",
deliveryPath+settle+positionsPath+contract.String()+"/leverage",
params, nil, &response)
}
@@ -2958,7 +2965,7 @@ func (g *Gateio) UpdateDeliveryPositionRiskLimit(ctx context.Context, settle str
params.Set("risk_limit", strconv.FormatUint(riskLimit, 10))
var response *Position
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPlaceOrdersEPL, http.MethodPost,
"delivery/"+settle+"/positions/"+contract.String()+"/risk_limit", params, nil, &response)
deliveryPath+settle+positionsPath+contract.String()+"/risk_limit", params, nil, &response)
}
// PlaceDeliveryOrder create a futures order
@@ -2997,7 +3004,7 @@ func (g *Gateio) PlaceDeliveryOrder(ctx context.Context, arg *OrderCreateParams)
}
var response *Order
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPlaceOrdersEPL, http.MethodPost,
"delivery/"+arg.Settle+"/orders", nil, &arg, &response)
deliveryPath+arg.Settle+ordersPath, nil, &arg, &response)
}
// GetDeliveryOrders list futures orders
@@ -3031,7 +3038,7 @@ func (g *Gateio) GetDeliveryOrders(ctx context.Context, contract currency.Pair,
}
var response []Order
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet,
"delivery/"+settle+"/orders", params, nil, &response)
deliveryPath+settle+ordersPath, params, nil, &response)
}
// CancelMultipleDeliveryOrders cancel all open orders matched
@@ -3050,7 +3057,7 @@ func (g *Gateio) CancelMultipleDeliveryOrders(ctx context.Context, contract curr
params.Set("contract", contract.String())
var response []Order
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapCancelOrdersEPL, http.MethodDelete,
"delivery/"+settle+"/orders", params, nil, &response)
deliveryPath+settle+ordersPath, params, nil, &response)
}
// GetSingleDeliveryOrder Get a single order
@@ -3064,7 +3071,7 @@ func (g *Gateio) GetSingleDeliveryOrder(ctx context.Context, settle, orderID str
}
var response *Order
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet,
"delivery/"+settle+"/orders/"+orderID, nil, nil, &response)
deliveryPath+settle+"/orders/"+orderID, nil, nil, &response)
}
// CancelSingleDeliveryOrder cancel a single order
@@ -3077,7 +3084,7 @@ func (g *Gateio) CancelSingleDeliveryOrder(ctx context.Context, settle, orderID
}
var response *Order
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapCancelOrdersEPL, http.MethodDelete,
"delivery/"+settle+"/orders/"+orderID, nil, nil, &response)
deliveryPath+settle+"/orders/"+orderID, nil, nil, &response)
}
// GetDeliveryPersonalTradingHistory retrieves personal trading history
@@ -3106,7 +3113,7 @@ func (g *Gateio) GetDeliveryPersonalTradingHistory(ctx context.Context, settle,
}
var response []TradingHistoryItem
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet,
"delivery/"+settle+"/my_trades", params, nil, &response)
deliveryPath+settle+"/my_trades", params, nil, &response)
}
// GetDeliveryPositionCloseHistory retrieves position history
@@ -3132,7 +3139,7 @@ func (g *Gateio) GetDeliveryPositionCloseHistory(ctx context.Context, settle str
}
var response []PositionCloseHistoryResponse
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet,
"delivery/"+settle+"/position_close", params, nil, &response)
deliveryPath+settle+"/position_close", params, nil, &response)
}
// GetDeliveryLiquidationHistory lists liquidation history
@@ -3152,7 +3159,7 @@ func (g *Gateio) GetDeliveryLiquidationHistory(ctx context.Context, settle strin
}
var response []LiquidationHistoryItem
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet,
"delivery/"+settle+"/liquidates", params, nil, &response)
deliveryPath+settle+"/liquidates", params, nil, &response)
}
// GetDeliverySettlementHistory retrieves settlement history
@@ -3172,7 +3179,7 @@ func (g *Gateio) GetDeliverySettlementHistory(ctx context.Context, settle string
}
var response []SettlementHistoryItem
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet,
"delivery/"+settle+"/settlements", params, nil, &response)
deliveryPath+settle+"/settlements", params, nil, &response)
}
// GetDeliveryPriceTriggeredOrder creates a price-triggered order
@@ -3219,7 +3226,7 @@ func (g *Gateio) GetDeliveryPriceTriggeredOrder(ctx context.Context, settle stri
}
var response *OrderID
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodPost,
"delivery/"+settle+"/price_orders", nil, &arg, &response)
deliveryPath+settle+priceOrdersPaths, nil, &arg, &response)
}
// GetDeliveryAllAutoOrder retrieves all auto orders
@@ -3243,7 +3250,7 @@ func (g *Gateio) GetDeliveryAllAutoOrder(ctx context.Context, status, settle str
}
var response []PriceTriggeredOrder
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet,
"delivery/"+settle+"/price_orders", params, nil, &response)
deliveryPath+settle+priceOrdersPaths, params, nil, &response)
}
// CancelAllDeliveryPriceTriggeredOrder cancels all delivery price triggered orders
@@ -3258,7 +3265,7 @@ func (g *Gateio) CancelAllDeliveryPriceTriggeredOrder(ctx context.Context, settl
params.Set("contract", contract.String())
var response []PriceTriggeredOrder
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapCancelOrdersEPL, http.MethodDelete,
"delivery/"+settle+"/price_orders", params, nil, &response)
deliveryPath+settle+priceOrdersPaths, params, nil, &response)
}
// GetSingleDeliveryPriceTriggeredOrder retrieves a single price triggered order
@@ -3271,7 +3278,7 @@ func (g *Gateio) GetSingleDeliveryPriceTriggeredOrder(ctx context.Context, settl
}
var response *PriceTriggeredOrder
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapPrivateEPL, http.MethodGet,
"delivery/"+settle+"/price_orders/"+orderID, nil, nil, &response)
deliveryPath+settle+"/price_orders/"+orderID, nil, nil, &response)
}
// CancelDeliveryPriceTriggeredOrder cancel a price-triggered order
@@ -3284,7 +3291,7 @@ func (g *Gateio) CancelDeliveryPriceTriggeredOrder(ctx context.Context, settle,
}
var response *PriceTriggeredOrder
return response, g.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, perpetualSwapCancelOrdersEPL, http.MethodDelete,
"delivery/"+settle+"/price_orders/"+orderID, nil, nil, &response)
deliveryPath+settle+"/price_orders/"+orderID, nil, nil, &response)
}
// ********************************** Options ***************************************************

View File

@@ -13,6 +13,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/key"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/core"
"github.com/thrasher-corp/gocryptotrader/currency"
@@ -1107,7 +1108,8 @@ func TestGetFutureStats(t *testing.T) {
if err != nil {
t.Error(err)
}
if _, err := g.GetFutureStats(context.Background(), settle, futuresTradablePair, time.Time{}, kline.OneHour, 0); err != nil {
_, err = g.GetFutureStats(context.Background(), settle, futuresTradablePair, time.Time{}, 0, 0)
if err != nil {
t.Errorf("%s GetFutureStats() error %v", g.Name, err)
}
}
@@ -3499,3 +3501,33 @@ func TestGetHistoricalFundingRates(t *testing.T) {
assert.NotEmpty(t, history, "should return values")
}
func TestGetOpenInterest(t *testing.T) {
t.Parallel()
_, err := g.GetOpenInterest(context.Background(), key.PairAsset{
Base: currency.ETH.Item,
Quote: currency.USDT.Item,
Asset: asset.USDTMarginedFutures,
})
assert.ErrorIs(t, err, asset.ErrNotSupported)
resp, err := g.GetOpenInterest(context.Background(), key.PairAsset{
Base: futuresTradablePair.Base.Item,
Quote: futuresTradablePair.Quote.Item,
Asset: asset.Futures,
})
assert.NoError(t, err)
assert.Len(t, resp, 1)
resp, err = g.GetOpenInterest(context.Background(), key.PairAsset{
Base: deliveryFuturesTradablePair.Base.Item,
Quote: deliveryFuturesTradablePair.Quote.Item,
Asset: asset.DeliveryFutures,
})
assert.NoError(t, err)
assert.Len(t, resp, 1)
resp, err = g.GetOpenInterest(context.Background())
assert.NoError(t, err)
assert.NotEmpty(t, resp)
}

View File

@@ -13,6 +13,7 @@ import (
"github.com/shopspring/decimal"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/key"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
@@ -124,6 +125,10 @@ func (g *Gateio) SetDefaults() {
FundingRateBatching: map[asset.Item]bool{
asset.Futures: true,
},
OpenInterest: exchange.OpenInterestSupport{
Supported: true,
SupportsRestBatch: true,
},
},
},
Enabled: exchange.FeaturesEnabled{
@@ -2343,3 +2348,138 @@ func contractToFundingRate(name string, item asset.Item, fPair currency.Pair, co
func (g *Gateio) IsPerpetualFutureCurrency(a asset.Item, _ currency.Pair) (bool, error) {
return a == asset.Futures, nil
}
// GetOpenInterest returns the open interest rate for a given asset pair
func (g *Gateio) GetOpenInterest(ctx context.Context, k ...key.PairAsset) ([]futures.OpenInterest, error) {
for i := range k {
if k[i].Asset != asset.DeliveryFutures && k[i].Asset != asset.Futures {
// avoid API calls or returning errors after a successful retrieval
return nil, fmt.Errorf("%w %v %v", asset.ErrNotSupported, k[i].Asset, k[i].Pair())
}
}
if len(k) == 1 {
p, isEnabled, err := g.MatchSymbolCheckEnabled(k[0].Pair().String(), k[0].Asset, false)
if err != nil {
return nil, err
}
if !isEnabled {
return nil, fmt.Errorf("%w %v", asset.ErrNotEnabled, k[0].Pair())
}
switch k[0].Asset {
case asset.DeliveryFutures:
contractResp, err := g.GetSingleDeliveryContracts(ctx, "usdt", p)
if err != nil {
return nil, err
}
openInterest := contractResp.QuantoMultiplier.Float64() * float64(contractResp.PositionSize) * contractResp.IndexPrice.Float64()
return []futures.OpenInterest{
{
Key: key.ExchangePairAsset{
Exchange: g.Name,
Base: k[0].Base,
Quote: k[0].Quote,
Asset: k[0].Asset,
},
OpenInterest: openInterest,
},
}, nil
case asset.Futures:
for _, s := range []string{"usd", "usdt", "btc"} {
contractResp, err := g.GetSingleContract(ctx, s, p.String())
if err != nil {
continue
}
openInterest := contractResp.QuantoMultiplier.Float64() * float64(contractResp.PositionSize) * contractResp.IndexPrice.Float64()
return []futures.OpenInterest{
{
Key: key.ExchangePairAsset{
Exchange: g.Name,
Base: k[0].Base,
Quote: k[0].Quote,
Asset: k[0].Asset,
},
OpenInterest: openInterest,
},
}, nil
}
}
}
var resp []futures.OpenInterest
for _, a := range g.GetAssetTypes(true) {
switch a {
case asset.DeliveryFutures:
contractResp, err := g.GetAllDeliveryContracts(ctx, "usdt")
if err != nil {
return nil, err
}
for i := range contractResp {
p, isEnabled, err := g.MatchSymbolCheckEnabled(contractResp[i].Name, a, true)
if err != nil && !errors.Is(err, currency.ErrPairNotFound) {
return nil, err
}
if !isEnabled {
continue
}
var appendData bool
for j := range k {
if k[j].Pair().Equal(p) {
appendData = true
break
}
}
if len(k) > 0 && !appendData {
continue
}
openInterest := contractResp[i].QuantoMultiplier.Float64() * float64(contractResp[i].PositionSize) * contractResp[i].IndexPrice.Float64()
resp = append(resp, futures.OpenInterest{
Key: key.ExchangePairAsset{
Exchange: g.Name,
Base: p.Base.Item,
Quote: p.Quote.Item,
Asset: a,
},
OpenInterest: openInterest,
})
}
case asset.Futures:
for _, s := range []string{"usd", "usdt", "btc"} {
contractResp, err := g.GetAllFutureContracts(ctx, s)
if err != nil {
return nil, err
}
for i := range contractResp {
p, isEnabled, err := g.MatchSymbolCheckEnabled(contractResp[i].Name, a, true)
if err != nil && !errors.Is(err, currency.ErrPairNotFound) {
return nil, err
}
if !isEnabled {
continue
}
var appendData bool
for j := range k {
if k[j].Pair().Equal(p) {
appendData = true
break
}
}
if len(k) > 0 && !appendData {
continue
}
openInterest := contractResp[i].QuantoMultiplier.Float64() * float64(contractResp[i].PositionSize) * contractResp[i].IndexPrice.Float64()
resp = append(resp, futures.OpenInterest{
Key: key.ExchangePairAsset{
Exchange: g.Name,
Base: p.Base.Item,
Quote: p.Quote.Item,
Asset: a,
},
OpenInterest: openInterest,
})
}
}
}
}
return resp, nil
}