diff --git a/provider/coinank/coinank_enum/interval.go b/provider/coinank/coinank_enum/interval.go new file mode 100644 index 00000000..dd73b073 --- /dev/null +++ b/provider/coinank/coinank_enum/interval.go @@ -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 +) diff --git a/provider/coinank/open_interest.go b/provider/coinank/open_interest.go new file mode 100644 index 00000000..6e412b0e --- /dev/null +++ b/provider/coinank/open_interest.go @@ -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"` +} diff --git a/provider/coinank/open_interest_test.go b/provider/coinank/open_interest_test.go new file mode 100644 index 00000000..3bbbd1f9 --- /dev/null +++ b/provider/coinank/open_interest_test.go @@ -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) +}