Skip to content

Commit

Permalink
add: exchanges endpoints (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
JulianToledano authored Nov 23, 2023
1 parent ab510ef commit 9b7094e
Show file tree
Hide file tree
Showing 5 changed files with 360 additions and 5 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ Coingecko API client for golang.
| /asset_platforms || AssetPlatforms |
| /coins/categories/list || CategoriesList |
| /coins/categories/ || Categories |
| /exchanges | | |
| /exchanges/list | | |
| /exchanges/{id} | | |
| /exchanges/{id}/tickers | | |
| /exchanges/{id}/volume_chart | | |
| /exchanges | | Exchanges |
| /exchanges/list | | ExchangesList |
| /exchanges/{id} | | ExchangesId |
| /exchanges/{id}/tickers | | ExchangesIdTickers |
| /exchanges/{id}/volume_chart | | ExchangesIdVolumeChart |
| /derivaties || |
| /derivaties/exchanges || |
| /derivaties/exchanges/{id} || |
Expand Down
1 change: 1 addition & 0 deletions endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ var (
coinsURL = fmt.Sprintf("%s/coins", baseURL)
assetPlatformsURL = fmt.Sprintf("%s/asset_platforms", baseURL)
categoriesURL = fmt.Sprintf("%s/categories", coinsURL)
exchangesURL = fmt.Sprintf("%s/exchanges", baseURL)
contractURL = fmt.Sprintf("%s/coins", baseURL)
exchangeRatesURL = fmt.Sprintf("%s/exchange_rates", baseURL)
trendingURL = fmt.Sprintf("%s/search/trending", baseURL)
Expand Down
188 changes: 188 additions & 0 deletions exchanges.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package goingecko

import (
"encoding/json"
"errors"
"fmt"
"github.com/JulianToledano/goingecko/exchanges"
"net/url"
)

// Exchanges List all exchanges
// Cache / Update Frequency: every 60 seconds
// Parameters
// per_page (string) Total results per page:
//
// Valid values: 1...250
// Total results per page
// Default value:: 100
//
// page (string) page through results
func (c *Client) Exchanges(perPage, page string) (*exchanges.ExchangesList, error) {
params := url.Values{}
if perPage != "" {
params.Add("per_page", perPage)
}
if page != "" {
params.Add("page", page)
}

rUrl := fmt.Sprintf("%s?%s", exchangesURL, params.Encode())
resp, err := c.MakeReq(rUrl)
if err != nil {
return nil, err
}

var data *exchanges.ExchangesList
err = json.Unmarshal(resp, &data)
if err != nil {
return nil, err
}

return data, nil
}

// ExchangesList Use this to obtain all the markets' id in order to make API calls
// Cache / Update Frequency: every 5 minutes
func (c *Client) ExchangesList() ([]exchanges.ExchangeId, error) {
rUrl := fmt.Sprintf("%s/list", exchangesURL)
resp, err := c.MakeReq(rUrl)
if err != nil {
return nil, err
}

var data []exchanges.ExchangeId
err = json.Unmarshal(resp, &data)
if err != nil {
return nil, err
}

return data, nil
}

// ExchangesId Get exchange volume in BTC and tickers.
// For derivatives (e.g. bitmex, binance_futures), please use /derivatives/exchange/{id} endpoint.
//
// IMPORTANT:
// Ticker object is limited to 100 items, to get more tickers, use /exchanges/{id}/tickers
// Ticker is_stale is true when ticker that has not been updated/unchanged from the exchange for more than 8 hours.
// Ticker is_anomaly is true if ticker's price is outliered by our system.
// You are responsible for managing how you want to display these information (e.g. footnote, different background, change opacity, hide)
//
// Dictionary:
//
// last: latest unconverted price in the respective pair target currency
// volume: unconverted 24h trading volume in the respective pair target currency
// converted_last: latest converted price in BTC, ETH, and USD
// converted_volume: converted 24h trading volume in BTC, ETH, and USD
// timestamp: returns the last time that the price has changed
// last_traded_at: returns the last time that the price has changed
// last_fetch_at: returns the last time we call the API
// Cache / Update Frequency: every 60 seconds
func (c *Client) ExchangesId(id string) (*exchanges.ExchangeWithTicker, error) {
rUrl := fmt.Sprintf("%s/%s", exchangesURL, id)
resp, err := c.MakeReq(rUrl)
if err != nil {
return nil, err
}

var data *exchanges.ExchangeWithTicker
err = json.Unmarshal(resp, &data)
if err != nil {
return nil, err
}

return data, nil
}

// ExchangesIdTickers Get exchange tickers (paginated)
// IMPORTANT:
// Ticker is_stale is true when ticker that has not been updated/unchanged from the exchange for more than 8 hours.
// Ticker is_anomaly is true if ticker's price is outliered by our system.
// You are responsible for managing how you want to display these information (e.g. footnote, different background, change opacity, hide)
//
// Dictionary:
//
// last: latest unconverted price in the respective pair target currency
// volume: unconverted 24h trading volume in the respective pair target currency
// converted_last: latest converted price in BTC, ETH, and USD
// converted_volume: converted 24h trading volume in BTC, ETH, and USD
// timestamp: returns the last time that the price has changed
// last_traded_at: returns the last time that the price has changed
// last_fetch_at: returns the last time we call the API
// Cache / Update Frequency: every 60 seconds
// Parameters:
//
// id* - string - pass the exchange id (can be obtained from /exchanges/list) eg. binance
// coinIds - string - filter tickers by coin_ids (ref: v3/coins/list)
// includeExchangeLogo - string - flag to show exchange_logo. valid values: true, false
// page - integer - Page through results
// depth - string - lag to show 2% orderbook depth. i.e., cost_to_move_up_usd and cost_to_move_down_usd. valid values: true, false
// order - string - valid values: trust_score_desc (default), trust_score_asc and volume_desc
func (c *Client) ExchangesIdTickers(id, coinIds, includeExchangeLogo string, page int32, depth, order string) (*exchanges.Tickers, error) {
params := url.Values{}
if coinIds != "" {
params.Add("coin_ids", coinIds)
}
if includeExchangeLogo != "" {
params.Add("include_exchange_logo", includeExchangeLogo)
}
if page > 0 {
params.Add("page", string(page))
}
if depth != "0" {
params.Add("depth", depth)
}
if order != "0" {
params.Add("order", order)
}
rUrl := fmt.Sprintf("%s/%s/tickers?%s", exchangesURL, id, params.Encode())
resp, err := c.MakeReq(rUrl)
if err != nil {
return nil, err
}

var data *exchanges.Tickers
err = json.Unmarshal(resp, &data)
if err != nil {
return nil, err
}

return data, nil
}

// ExchangesIdVolumeChart Get 24 hour rolling trading volume data (in BTC) for a given exchange.
// Data granularity is automatic (cannot be adjusted)
//
// 1 day = 10-minutely
// 2-90 days = hourly
// 91 days above = daily
//
// Note: exclusive endpoint is available for paid users to query more than 1 year of historical data
//
// Cache / Update Frequency: every 60 seconds
// Parameters:
// id* - string - pass the exchange id (can be obtained from /exchanges/list) eg. binance
// days* - string - Data up to number of days ago (1/7/14/30/90/180/365)
func (c *Client) ExchangesIdVolumeChart(id, days string) ([]exchanges.Volume, error) {
if _, ok := exchanges.VolumeChartValidDays[days]; !ok {
return nil, errors.New("not valid day")
}

params := url.Values{}
params.Add("days", days)

rUrl := fmt.Sprintf("%s/%s/volume_chart?%s", exchangesURL, id, params.Encode())
resp, err := c.MakeReq(rUrl)
if err != nil {
return nil, err
}

var data []exchanges.Volume
err = json.Unmarshal(resp, &data)
if err != nil {
return nil, err
}

return data, nil
}
103 changes: 103 additions & 0 deletions exchanges/exchanges.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package exchanges

type Exchange struct {
ID string `json:"id"`
Name string `json:"name"`
YearEstablished int32 `json:"year_established"`
Country string `json:"country"`
Description string `json:"description"`
Url string `json:"url"`
Image string `json:"image"`
HasTradingIncentive bool `json:"has_trading_incentive"`
TrustScore int32 `json:"trust_score"`
TrustScoreRank int32 `json:"trust_score_rank"`
TradeVolume24h float64 `json:"trade_volume_24h_btc"`
TradeVolume24jBtcNormalice float64 `json:"trade_volume_24h_btc_normalized"`
}

type ExchangesList []Exchange

type ExchangeId struct {
ID string `json:"id"`
Name string `json:"name"`
}

type ExchangeWithTicker struct {
Name string `json:"name"`
YearEstablished int32 `json:"year_established"`
Country string `json:"country"`
Description string `json:"description"`
Url string `json:"url"`
Image string `json:"image"`
FacebookUrl string `json:"facebook_url"`
RedditYrl string `json:"reddit_url"`
TelegramUrl string `json:"telegram_url"`
SlackUrl string `json:"slack_url"`
OtherUrl1 string `json:"other_url_1"`
OtherUrl2 string `json:"other_url_2"`
TwitterHandle string `json:"twitter_handle"`
HasTradingIncentive bool `json:"has_trading_incentive"`
Centralized bool `json:"centralized"`
PublicNotice string `json:"public_notice"`
AlertNotice string `json:"alert_notice"`
TrustScore int32 `json:"trust_score"`
TrustScoreRank int32 `json:"trust_score_rank"`
TradeVolume24hBtc float64 `json:"trade_volume_24h_btc"`
TradeVolume24hBtcNormalized float64 `json:"trade_volume_24h_btc_normalized"`
Tickers []Ticker `json:"tickers"`
StatusUpdates []StatusUpdates `json:"status_updates"`
}

type Tickers struct {
Name string `json:"name"`
Tickers []Ticker `json:"tickers"`
}

type Ticker struct {
Base string `json:"base"`
Target string `json:"target"`
Market Market `json:"Market"`
Last float64 `json:"Last"`
Volume float64 `json:"volume"`
ConvertedLast Converted `json:"converted_last"`
ConvertedVolume Converted `json:"converted_volume"`
TrustScore string `json:"trust_score"`
BidAskSpreadPercentage float64 `json:"bid_ask_spread_percentage"`
Timestamp string `json:"timestamp"`
LastTradedAt string `json:"last_traded_at"`
LastFetchAt string `json:"last_fetch_at"`
IsAnomaly bool `json:"is_anomaly"`
IsStale bool `json:"is_stale"`
TradeUrl string `json:"trade_url"`
TokenInfoUrl string `json:"token_info_url"`
CoinID string `json:"coin_id"`
TargetCoinID string `json:"target_coin_id"`
}

type StatusUpdates struct {
// ??
}

type Market struct {
Name string `json:"name"`
Identifier string `json:"identifier"`
HasTradingIncentive bool `json:"has_trading_incentive"`
}

type Converted struct {
Btc float64 `json:"btc"`
Eth float64 `json:"eth"`
Usd float64 `json:"usd"`
}

var VolumeChartValidDays = map[string]struct{}{
"1": {},
"7": {},
"14": {},
"30": {},
"90": {},
"180": {},
"365": {},
}

type Volume []interface{}
63 changes: 63 additions & 0 deletions test/exchanges_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package test

import (
"github.com/JulianToledano/goingecko"
"testing"
)

func TestExchanges(t *testing.T) {

cgClient := goingecko.NewClient(nil)

data, err := cgClient.Exchanges("", "")
if data == nil {
t.Errorf("Error")
}
if err != nil {
t.Errorf("Error: %s", err)
}
}

func TestExchangesList(t *testing.T) {
cgClient := goingecko.NewClient(nil)
data, err := cgClient.ExchangesList()
if data == nil {
t.Errorf("Error")
}
if err != nil {
t.Errorf("Error: %s", err)
}
}

func TestExchangesId(t *testing.T) {
cgClient := goingecko.NewClient(nil)
data, err := cgClient.ExchangesId("sushiswap")
if data == nil {
t.Errorf("Error")
}
if err != nil {
t.Errorf("Error: %s", err)
}
}

func TestExchangesIdTickers(t *testing.T) {
cgClient := goingecko.NewClient(nil)
data, err := cgClient.ExchangesIdTickers("sushiswap", "", "", 0, "", "")
if data == nil {
t.Errorf("Error")
}
if err != nil {
t.Errorf("Error: %s", err)
}
}

func TestExchangesIdVolumeChart(t *testing.T) {
cgClient := goingecko.NewClient(nil)
data, err := cgClient.ExchangesIdVolumeChart("sushiswap", "1")
if data == nil {
t.Errorf("Error")
}
if err != nil {
t.Errorf("Error: %s", err)
}
}

0 comments on commit 9b7094e

Please sign in to comment.