feat: implement coinank openapi Instruments interface (#1243)

- implement OpenInterestAll,OpenInterestChartV2,OpenInterestSymbolChart,OpenInterestKline in provider/coinank/open_interest.go
- implement OpenInterestAggKline,TickersTopOIByEx,InstrumentsOiVsMc in provider/coinank/open_interest.go
This commit is contained in:
wqqqqqq
2025-12-17 18:55:31 +08:00
committed by GitHub
parent 612e25db66
commit 182265c1d0
3 changed files with 397 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
package coinank_enum
type Interval string
const ( //not all interfaces support all interval
Second1 Interval = "1s" // one second
Second4 Interval = "4s"
Second5 Interval = "5s"
Second10 Interval = "10s"
Second30 Interval = "30s"
Minute1 Interval = "1m" // one minute
Minute3 Interval = "3m"
Minute5 Interval = "5m"
Minute10 Interval = "10m"
Minute15 Interval = "15m"
Minute30 Interval = "30m"
Hour1 Interval = "1h" // one hour
Hour2 Interval = "2h"
Hour4 Interval = "4h"
Hour5 Interval = "5h"
Hour6 Interval = "6h"
Hour8 Interval = "8h"
Hour12 Interval = "12h"
Day1 Interval = "1d" // one day
Day2 Interval = "2d"
Day3 Interval = "3d"
Day5 Interval = "5d"
Week1 Interval = "1w" // one week
Week2 Interval = "2w"
Month1 Interval = "1M" // one month
Month3 Interval = "3M"
Month6 Interval = "6M"
Year1 Interval = "1y" // one year
)
+257
View File
@@ -0,0 +1,257 @@
package coinank
import (
"context"
"encoding/json"
"nofx/provider/coinank/coinank_enum"
"strconv"
)
// OpenInterestAll coin holdings list (order by exchange)
func (c *CoinankClient) OpenInterestAll(ctx context.Context, baseCoin string) ([]OpenInterestAllResponse, error) {
paramsMap := make(map[string]string, 1)
paramsMap["baseCoin"] = baseCoin
resp, err := c.Get(ctx, "/api/openInterest/all", paramsMap)
if err != nil {
return nil, err
}
var result CoinankResponse[[]OpenInterestAllResponse]
err = json.Unmarshal([]byte(resp), &result)
if err != nil {
return nil, err
}
if !result.Success {
return nil, HttpError
}
return result.Data, nil
}
// OpenInterestChartV2 Exchange History Chart
func (c *CoinankClient) OpenInterestChartV2(ctx context.Context,
baseCoin string, exchange coinank_enum.Exchange,
interval coinank_enum.Interval, size int) (*OpenInterestChartV2Response, error) {
paramsMap := make(map[string]string, 4)
paramsMap["baseCoin"] = baseCoin
paramsMap["interval"] = string(interval)
if exchange != "" {
paramsMap["exchange"] = string(exchange)
}
if size > 0 {
paramsMap["size"] = strconv.Itoa(size)
}
resp, err := c.Get(ctx, "/api/openInterest/v2/chart", paramsMap)
if err != nil {
return nil, err
}
var result CoinankResponse[OpenInterestChartV2Response]
err = json.Unmarshal([]byte(resp), &result)
if err != nil {
return nil, err
}
if !result.Success {
return nil, HttpError
}
return &result.Data, nil
}
// OpenInterestSymbolChart Trading Pair Open Interest , endTime: Returns data before this timestamp ,is millisecond timestamp
func (c *CoinankClient) OpenInterestSymbolChart(ctx context.Context,
exchange coinank_enum.Exchange, symbol string, interval coinank_enum.Interval,
endTime int64, size int) ([]OpenInterestSymbolChartResponse, error) {
paramsMap := make(map[string]string, 5)
paramsMap["exchange"] = string(exchange)
paramsMap["symbol"] = symbol
paramsMap["interval"] = string(interval)
paramsMap["endTime"] = strconv.FormatInt(endTime, 10)
if size > 0 {
paramsMap["size"] = strconv.Itoa(size)
}
resp, err := c.Get(ctx, "/api/openInterest/symbol/Chart", paramsMap)
if err != nil {
return nil, err
}
var result CoinankResponse[[]OpenInterestSymbolChartResponse]
err = json.Unmarshal([]byte(resp), &result)
if err != nil {
return nil, err
}
if !result.Success {
return nil, HttpError
}
return result.Data, nil
}
// OpenInterestKline Trading Pair Open Interest K Line
func (c *CoinankClient) OpenInterestKline(ctx context.Context,
exchange coinank_enum.Exchange, symbol string, interval coinank_enum.Interval,
endTime int64, size int) ([]OpenInterestKlineResponse, error) {
paramsMap := make(map[string]string, 5)
paramsMap["exchange"] = string(exchange)
paramsMap["symbol"] = symbol
paramsMap["interval"] = string(interval)
paramsMap["endTime"] = strconv.FormatInt(endTime, 10)
if size > 0 {
paramsMap["size"] = strconv.Itoa(size)
}
resp, err := c.Get(ctx, "/api/openInterest/kline", paramsMap)
if err != nil {
return nil, err
}
var result CoinankResponse[[]OpenInterestKlineResponse]
err = json.Unmarshal([]byte(resp), &result)
if err != nil {
return nil, err
}
if !result.Success {
return nil, HttpError
}
return result.Data, nil
}
// OpenInterestAggKline Aggregation Open Interest K Line
func (c *CoinankClient) OpenInterestAggKline(ctx context.Context,
baseCoin string, interval coinank_enum.Interval,
endTime int64, size int) ([]OpenInterestAggKlineResponse, error) {
paramsMap := make(map[string]string, 4)
paramsMap["baseCoin"] = baseCoin
paramsMap["interval"] = string(interval)
paramsMap["endTime"] = strconv.FormatInt(endTime, 10)
if size > 0 {
paramsMap["size"] = strconv.Itoa(size)
}
resp, err := c.Get(ctx, "/api/openInterest/aggKline", paramsMap)
if err != nil {
return nil, err
}
var result CoinankResponse[[]OpenInterestAggKlineResponse]
err = json.Unmarshal([]byte(resp), &result)
if err != nil {
return nil, err
}
if !result.Success {
return nil, HttpError
}
return result.Data, nil
}
// TickersTopOIByEx Real-Time Open Interest
func (c *CoinankClient) TickersTopOIByEx(ctx context.Context, baseCoin string) (*TickersTopOIByExResponse, error) {
paramsMap := make(map[string]string, 1)
paramsMap["baseCoin"] = baseCoin
resp, err := c.Get(ctx, "/api/tickers/topOIByEx", paramsMap)
if err != nil {
return nil, err
}
var result CoinankResponse[TickersTopOIByExResponse]
err = json.Unmarshal([]byte(resp), &result)
if err != nil {
return nil, err
}
if !result.Success {
return nil, HttpError
}
return &result.Data, nil
}
// InstrumentsOiVsMc Oi/MarketCap Ratio History
func (c *CoinankClient) InstrumentsOiVsMc(ctx context.Context,
baseCoin string, interval coinank_enum.Interval, endTime int64, size int) ([]InstrumentsOiVsMcResponse, error) {
paramsMap := make(map[string]string, 4)
paramsMap["baseCoin"] = baseCoin
paramsMap["interval"] = string(interval)
paramsMap["endTime"] = strconv.FormatInt(endTime, 10)
if size > 0 {
paramsMap["size"] = strconv.Itoa(size)
}
resp, err := c.Get(ctx, "/api/instruments/oiVsMc", paramsMap)
if err != nil {
return nil, err
}
var result CoinankResponse[[]InstrumentsOiVsMcResponse]
err = json.Unmarshal([]byte(resp), &result)
if err != nil {
return nil, err
}
if !result.Success {
return nil, HttpError
}
return result.Data, nil
}
type OpenInterestAllResponse struct {
CoinCount float64 `json:"coinCount"` //total number of currency held
CoinValue float64 `json:"coinValue"` //total value of currency held
ExchangeName string `json:"exchangeName"` //data from what exchange ,if return `ALL`,means all exchange statistics info
Rate float64 `json:"rate"` //the proportion of the total
Change15M float64 `json:"change15M"` //15-minute price change
Change5M float64 `json:"change5M"` //5-minute price change
Change30M float64 `json:"change30M"` //30-minute price change
Change1H float64 `json:"change1H"` //1-hours price change
Change4H float64 `json:"change4H"` //4-hours price change
Change6H float64 `json:"change6H"` //6-hours price change
Change8H float64 `json:"change8H"` //8-hours price change
Change12H float64 `json:"change12H"` //12-hours price change
Change24H float64 `json:"change24H"` //24-hours price change
Change2D float64 `json:"change2D"` //2-day price change
Change3D float64 `json:"change3D"` //3-day price change
Change7D float64 `json:"change7D"` //7-day price change
Turnover24H float64 `json:"turnover24h"` //24-hour turnover
Ts int `json:"ts"`
}
type OpenInterestChartV2Response struct {
Tss []int64 `json:"tss"` //Horizontal axis of the chart , millisecond timestamp
Prices []float64 `json:"prices"` //chart vertical axis, coin price
DataValues map[string][]float64 `json:"dataValues"` // chart value,key is exchangeName,value is exchange holding amount
}
type OpenInterestSymbolChartResponse struct {
ExchangeName string `json:"exchangeName"` // such as `Binance`
BaseCoin string `json:"baseCoin"` // such as `BTC`
Symbol string `json:"symbol"` // such as `BTCUSDT`
ExchangeType string `json:"exchangeType"` // exchange type ,`USDT`: usdt base ,`COIN`: coin base
ContractType string `json:"contractType"` // `SWAP`:Perpetual Contract,`FUTURES` : Delivery Contract
DeliveryType string `json:"deliveryType"` // Delivery type ,`PERPETUAL`: Perpetual Contract
Ts int64 `json:"ts"`
UtcIntervals []string `json:"utcIntervals"` //symbol has utc intervals
Utc8Intervals []string `json:"utc8Intervals"` //symbol has utc+8 intervals
AtUtc bool `json:"atUtc"` //symbol is in utc intervals
AtUtc8 bool `json:"atUtc8"` //symbol is in utc+8 intervals
CreateAt string `json:"createAt"`
Volume float64 `json:"volume"` // coin volume
CoinCount float64 `json:"coinCount"` // coin number
CoinValue float64 `json:"coinValue"` // coin all value
}
type OpenInterestKlineResponse struct {
Begin int64 `json:"begin"` //start time
Open float64 `json:"open"` //open price
Close float64 `json:"close"` //close price
Low float64 `json:"low"` //low price
High float64 `json:"high"` //high price
O float64 `json:"o"` //open price
C float64 `json:"c"` //close price
L float64 `json:"l"` //low price
H float64 `json:"h"` //high price
}
type OpenInterestAggKlineResponse struct {
Begin int64 `json:"begin"` //start time
Open float64 `json:"open"` //open price
Close float64 `json:"close"` //close price
Low float64 `json:"low"` //low price
High float64 `json:"high"` //high price
}
type TickersTopOIByExResponse struct {
Coins []float64 `json:"coins"` // coin number for each exchange
Exchanges []string `json:"exchanges"` // exchange hold order (desc)
Oi []float64 `json:"oi"` // coin value for each exchange
}
type InstrumentsOiVsMcResponse struct {
OiVsMar float64 `json:"oiVsMar"`
VolVsMar float64 `json:"volVsMar"`
OiVsVol float64 `json:"oiVsVol"`
Ts int64 `json:"ts"`
}
+106
View File
@@ -0,0 +1,106 @@
package coinank
import (
"context"
"encoding/json"
"nofx/provider/coinank/coinank_enum"
"testing"
"time"
)
func TestOpenInterestAll(t *testing.T) {
client := NewCoinankClient(coinank_enum.MainUrl, TestApikey)
resp, err := client.OpenInterestAll(context.TODO(), "BTC")
if err != nil {
t.Error(err)
}
if resp[0].ExchangeName != "ALL" {
t.Error("exchange name is empty")
}
res, err := json.Marshal(resp)
if err != nil {
t.Error(err)
}
t.Logf("%s", res)
}
func TestOpenInterestChartV2(t *testing.T) {
client := NewCoinankClient(coinank_enum.MainUrl, TestApikey)
resp, err := client.OpenInterestChartV2(context.TODO(), "BTC", coinank_enum.Binance, coinank_enum.Hour1, 10)
if err != nil {
t.Error(err)
}
res, err := json.Marshal(resp)
if err != nil {
t.Error(err)
}
t.Logf("%s", res)
}
func TestOpenInterestSymbolChart(t *testing.T) {
client := NewCoinankClient(coinank_enum.MainUrl, TestApikey)
resp, err := client.OpenInterestSymbolChart(context.TODO(), coinank_enum.Binance, "BTCUSDT", coinank_enum.Hour1, time.Now().UnixMilli(), 10)
if err != nil {
t.Error(err)
}
if resp[0].BaseCoin != "BTC" {
t.Error("baseCoin is error")
}
res, err := json.Marshal(resp)
if err != nil {
t.Error(err)
}
t.Logf("%s", res)
}
func TestOpenInterestKline(t *testing.T) {
client := NewCoinankClient(coinank_enum.MainUrl, TestApikey)
resp, err := client.OpenInterestKline(context.TODO(), coinank_enum.Binance, "BTCUSDT", coinank_enum.Hour1, time.Now().UnixMilli(), 10)
if err != nil {
t.Error(err)
}
res, err := json.Marshal(resp)
if err != nil {
t.Error(err)
}
t.Logf("%s", res)
}
func TestOpenInterestAggKline(t *testing.T) {
client := NewCoinankClient(coinank_enum.MainUrl, TestApikey)
resp, err := client.OpenInterestAggKline(context.TODO(), "BTC", coinank_enum.Hour1, time.Now().UnixMilli(), 10)
if err != nil {
t.Error(err)
}
res, err := json.Marshal(resp)
if err != nil {
t.Error(err)
}
t.Logf("%s", res)
}
func TestTickersTopOIByEx(t *testing.T) {
client := NewCoinankClient(coinank_enum.MainUrl, TestApikey)
resp, err := client.TickersTopOIByEx(context.TODO(), "BTC")
if err != nil {
t.Error(err)
}
res, err := json.Marshal(resp)
if err != nil {
t.Error(err)
}
t.Logf("%s", res)
}
func TestInstrumentsOiVsMc(t *testing.T) {
client := NewCoinankClient(coinank_enum.MainUrl, TestApikey)
resp, err := client.InstrumentsOiVsMc(context.TODO(), "BTC", coinank_enum.Hour1, time.Now().UnixMilli(), 10)
if err != nil {
t.Error(err)
}
res, err := json.Marshal(resp)
if err != nil {
t.Error(err)
}
t.Logf("%s", res)
}