mirror of https://github.com/miguelmota/cointop
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
400 lines
10 KiB
Go
400 lines
10 KiB
Go
// Package coingecko is forked from https://github.com/superoo7/go-gecko
|
|
package coingecko
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"os"
|
|
|
|
"github.com/cointop-sh/cointop/pkg/api/vendors/coingecko/format"
|
|
"github.com/cointop-sh/cointop/pkg/api/vendors/coingecko/v3/types"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
var baseURL = "https://api.coingecko.com/api/v3"
|
|
|
|
// Client struct
|
|
type Client struct {
|
|
httpClient *http.Client
|
|
}
|
|
|
|
// NewClient create new client object
|
|
func NewClient(httpClient *http.Client) *Client {
|
|
if httpClient == nil {
|
|
httpClient = http.DefaultClient
|
|
}
|
|
return &Client{httpClient: httpClient}
|
|
}
|
|
|
|
// helper
|
|
// doReq HTTP client
|
|
func doReq(req *http.Request, client *http.Client) ([]byte, error) {
|
|
debugHttp := os.Getenv("DEBUG_HTTP") != ""
|
|
if debugHttp {
|
|
log.Debugf("doReq %s %s", req.Method, req.URL)
|
|
}
|
|
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if 200 != resp.StatusCode {
|
|
if debugHttp {
|
|
log.Warnf("doReq Got Status '%s' from %s %s", resp.Status, req.Method, req.URL)
|
|
log.Debugf("doReq Got Body: %s", body)
|
|
}
|
|
return nil, fmt.Errorf("%s", body)
|
|
}
|
|
return body, nil
|
|
}
|
|
|
|
// MakeReq HTTP request helper
|
|
func (c *Client) MakeReq(url string) ([]byte, error) {
|
|
req, err := http.NewRequest("GET", url, nil)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
resp, err := doReq(req, c.httpClient)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, err
|
|
}
|
|
|
|
// API
|
|
|
|
// Ping /ping endpoint
|
|
func (c *Client) Ping() (*types.Ping, error) {
|
|
url := fmt.Sprintf("%s/ping", baseURL)
|
|
resp, err := c.MakeReq(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var data *types.Ping
|
|
err = json.Unmarshal(resp, &data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
// SimpleSinglePrice /simple/price Single ID and Currency (ids, vsCurrency)
|
|
func (c *Client) SimpleSinglePrice(id string, vsCurrency string) (*types.SimpleSinglePrice, error) {
|
|
idParam := []string{strings.ToLower(id)}
|
|
vcParam := []string{strings.ToLower(vsCurrency)}
|
|
|
|
t, err := c.SimplePrice(idParam, vcParam)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
curr := (*t)[id]
|
|
data := &types.SimpleSinglePrice{ID: id, Currency: vsCurrency, MarketPrice: curr[vsCurrency]}
|
|
return data, nil
|
|
}
|
|
|
|
// SimplePrice /simple/price Multiple ID and Currency (ids, vs_currencies)
|
|
func (c *Client) SimplePrice(ids []string, vsCurrencies []string) (*map[string]map[string]float32, error) {
|
|
params := url.Values{}
|
|
idsParam := strings.Join(ids[:], ",")
|
|
vsCurrenciesParam := strings.Join(vsCurrencies[:], ",")
|
|
|
|
params.Add("ids", idsParam)
|
|
params.Add("vs_currencies", vsCurrenciesParam)
|
|
|
|
url := fmt.Sprintf("%s/simple/price?%s", baseURL, params.Encode())
|
|
resp, err := c.MakeReq(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
t := make(map[string]map[string]float32)
|
|
err = json.Unmarshal(resp, &t)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &t, nil
|
|
}
|
|
|
|
// SimpleSupportedVSCurrencies /simple/supported_vs_currencies
|
|
func (c *Client) SimpleSupportedVSCurrencies() (*types.SimpleSupportedVSCurrencies, error) {
|
|
url := fmt.Sprintf("%s/simple/supported_vs_currencies", baseURL)
|
|
resp, err := c.MakeReq(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var data *types.SimpleSupportedVSCurrencies
|
|
err = json.Unmarshal(resp, &data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return data, nil
|
|
}
|
|
|
|
// CoinsList /coins/list
|
|
func (c *Client) CoinsList() (*types.CoinList, error) {
|
|
url := fmt.Sprintf("%s/coins/list", baseURL)
|
|
resp, err := c.MakeReq(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var data *types.CoinList
|
|
err = json.Unmarshal(resp, &data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
// CoinsMarket /coins/market
|
|
func (c *Client) CoinsMarket(vsCurrency string, ids []string, order string, perPage int, page int, sparkline bool, priceChangePercentage []string) (*types.CoinsMarket, error) {
|
|
if len(vsCurrency) == 0 {
|
|
return nil, fmt.Errorf("vsCurrency is required")
|
|
}
|
|
params := url.Values{}
|
|
// vsCurrency
|
|
params.Add("vs_currency", vsCurrency)
|
|
// order
|
|
if len(order) == 0 {
|
|
order = types.OrderTypeObject.MarketCapDesc
|
|
}
|
|
params.Add("order", order)
|
|
// ids
|
|
if len(ids) != 0 {
|
|
idsParam := strings.Join(ids[:], ",")
|
|
params.Add("ids", idsParam)
|
|
}
|
|
// per_page
|
|
if perPage <= 0 || perPage > 250 {
|
|
perPage = 100
|
|
}
|
|
params.Add("per_page", format.Int2String(perPage))
|
|
params.Add("page", format.Int2String(page))
|
|
// sparkline
|
|
params.Add("sparkline", format.Bool2String(sparkline))
|
|
// price_change_percentage
|
|
if len(priceChangePercentage) != 0 {
|
|
priceChangePercentageParam := strings.Join(priceChangePercentage[:], ",")
|
|
params.Add("price_change_percentage", priceChangePercentageParam)
|
|
}
|
|
url := fmt.Sprintf("%s/coins/markets?%s", baseURL, params.Encode())
|
|
resp, err := c.MakeReq(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var data *types.CoinsMarket
|
|
err = json.Unmarshal(resp, &data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
// CoinsID /coins/{id}
|
|
func (c *Client) CoinsID(id string, localization bool, tickers bool, marketData bool, communityData bool, developerData bool, sparkline bool) (*types.CoinsID, error) {
|
|
|
|
if len(id) == 0 {
|
|
return nil, fmt.Errorf("id is required")
|
|
}
|
|
params := url.Values{}
|
|
params.Add("localization", format.Bool2String(localization))
|
|
params.Add("tickers", format.Bool2String(tickers))
|
|
params.Add("market_data", format.Bool2String(marketData))
|
|
params.Add("community_data", format.Bool2String(communityData))
|
|
params.Add("developer_data", format.Bool2String(developerData))
|
|
params.Add("sparkline", format.Bool2String(sparkline))
|
|
url := fmt.Sprintf("%s/coins/%s?%s", baseURL, id, params.Encode())
|
|
resp, err := c.MakeReq(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var data *types.CoinsID
|
|
err = json.Unmarshal(resp, &data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
// CoinsIDTickers /coins/{id}/tickers
|
|
func (c *Client) CoinsIDTickers(id string, page int) (*types.CoinsIDTickers, error) {
|
|
if len(id) == 0 {
|
|
return nil, fmt.Errorf("id is required")
|
|
}
|
|
params := url.Values{}
|
|
if page > 0 {
|
|
params.Add("page", format.Int2String(page))
|
|
}
|
|
url := fmt.Sprintf("%s/coins/%s/tickers?%s", baseURL, id, params.Encode())
|
|
resp, err := c.MakeReq(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var data *types.CoinsIDTickers
|
|
err = json.Unmarshal(resp, &data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
// CoinsIDHistory /coins/{id}/history?date={date}&localization=false
|
|
func (c *Client) CoinsIDHistory(id string, date string, localization bool) (*types.CoinsIDHistory, error) {
|
|
if len(id) == 0 || len(date) == 0 {
|
|
return nil, fmt.Errorf("id and date is required")
|
|
}
|
|
params := url.Values{}
|
|
params.Add("date", date)
|
|
params.Add("localization", format.Bool2String(localization))
|
|
|
|
url := fmt.Sprintf("%s/coins/%s/history?%s", baseURL, id, params.Encode())
|
|
resp, err := c.MakeReq(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var data *types.CoinsIDHistory
|
|
err = json.Unmarshal(resp, &data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
// CoinsIDMarketChart /coins/{id}/market_chart?vsCurrency={usd, eur, jpy, etc.}&days={1,14,30,max}
|
|
func (c *Client) CoinsIDMarketChart(id string, vsCurrency string, days string) (*types.CoinsIDMarketChart, error) {
|
|
if len(id) == 0 || len(vsCurrency) == 0 || len(days) == 0 {
|
|
return nil, fmt.Errorf("id, vsCurrency, and days is required")
|
|
}
|
|
|
|
params := url.Values{}
|
|
params.Add("vs_currency", vsCurrency)
|
|
params.Add("days", days)
|
|
|
|
url := fmt.Sprintf("%s/coins/%s/market_chart?%s", baseURL, id, params.Encode())
|
|
resp, err := c.MakeReq(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
m := types.CoinsIDMarketChart{}
|
|
err = json.Unmarshal(resp, &m)
|
|
if err != nil {
|
|
return &m, err
|
|
}
|
|
|
|
return &m, nil
|
|
}
|
|
|
|
// CoinsIDStatusUpdates
|
|
|
|
// CoinsIDContractAddress https://api.coingecko.com/api/v3/coins/{id}/contract/{contract_address}
|
|
// func CoinsIDContractAddress(id string, address string) (nil, error) {
|
|
// url := fmt.Sprintf("%s/coins/%s/contract/%s", baseURL, id, address)
|
|
// resp, err := request.MakeReq(url)
|
|
// if err != nil {
|
|
// return nil, err
|
|
// }
|
|
// }
|
|
|
|
// EventsCountries https://api.coingecko.com/api/v3/events/countries
|
|
func (c *Client) EventsCountries() ([]types.EventCountryItem, error) {
|
|
url := fmt.Sprintf("%s/events/countries", baseURL)
|
|
resp, err := c.MakeReq(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var data *types.EventsCountries
|
|
err = json.Unmarshal(resp, &data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return data.Data, nil
|
|
|
|
}
|
|
|
|
// EventsTypes https://api.coingecko.com/api/v3/events/types
|
|
func (c *Client) EventsTypes() (*types.EventsTypes, error) {
|
|
url := fmt.Sprintf("%s/events/types", baseURL)
|
|
resp, err := c.MakeReq(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var data *types.EventsTypes
|
|
err = json.Unmarshal(resp, &data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return data, nil
|
|
|
|
}
|
|
|
|
// ExchangeRates https://api.coingecko.com/api/v3/exchange_rates
|
|
func (c *Client) ExchangeRates() (*types.ExchangeRatesItem, error) {
|
|
url := fmt.Sprintf("%s/exchange_rates", baseURL)
|
|
resp, err := c.MakeReq(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var data *types.ExchangeRatesResponse
|
|
err = json.Unmarshal(resp, &data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &data.Rates, nil
|
|
}
|
|
|
|
// Global https://api.coingecko.com/api/v3/global
|
|
func (c *Client) Global() (*types.Global, error) {
|
|
url := fmt.Sprintf("%s/global", baseURL)
|
|
resp, err := c.MakeReq(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var data *types.GlobalResponse
|
|
err = json.Unmarshal(resp, &data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &data.Data, nil
|
|
}
|
|
|
|
// GlobalCharts https://www.coingecko.com/market_cap/total_charts_data?duration=7&locale=en&vs_currency=usd
|
|
func (c *Client) GlobalCharts(vsCurrency string, days string) (*types.GlobalCharts, error) {
|
|
if len(vsCurrency) == 0 || len(days) == 0 {
|
|
return nil, fmt.Errorf("vsCurrency, and days is required")
|
|
}
|
|
|
|
params := url.Values{}
|
|
params.Add("locale", "en")
|
|
params.Add("vs_currency", vsCurrency)
|
|
params.Add("duration", days)
|
|
|
|
url := fmt.Sprintf("https://www.coingecko.com/market_cap/total_charts_data?%s", params.Encode())
|
|
resp, err := c.MakeReq(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
m := types.GlobalCharts{}
|
|
err = json.Unmarshal(resp, &m)
|
|
if err != nil {
|
|
return &m, err
|
|
}
|
|
|
|
return &m, nil
|
|
}
|