currencyconversion var

pull/15/head
Miguel Mota 6 years ago
parent 9bc7d61f02
commit 40f0b3a3b3

12
Gopkg.lock generated

@ -37,18 +37,6 @@
revision = "9e777a8366cce605130a531d2cd6363d07ad7317"
version = "v0.0.2"
[[projects]]
branch = "master"
name = "github.com/miguelmota/go-coinmarketcap"
packages = ["."]
revision = "42269f499a7031e0affa526258909fa73f2914cd"
[[projects]]
branch = "master"
name = "github.com/nsf/termbox-go"
packages = ["."]
revision = "7cbfaac9e282b3ea0cefeddc67b2c3ed3aaf97bc"
[[projects]]
branch = "master"
name = "go4.org"

@ -29,8 +29,3 @@
[[constraint]]
name = "github.com/fatih/color"
version = "1.6.0"
[[constraint]]
branch = "master"
name = "github.com/miguelmota/go-coinmarketcap"

@ -8,7 +8,7 @@
> Coin tracking for hackers
[![License](http://img.shields.io/badge/license-Apache-red.svg)](https://raw.githubusercontent.com/miguelmota/cointop/master/LICENSE.md) [![Build Status](https://travis-ci.org/miguelmota/cointop.svg?branch=master)](https://travis-ci.org/miguelmota/cointop) [![Go Report Card](https://goreportcard.com/badge/github.com/miguelmota/cointop?)](https://goreportcard.com/report/github.com/miguelmota/cointop) [![GoDoc](https://godoc.org/github.com/miguelmota/cointop?status.svg)](https://godoc.org/github.com/miguelmota/cointop) [![Mentioned in Awesome Terminals](https://awesome.re/mentioned-badge.svg)](https://github.com/k4m4/terminals-are-sexy)
[![License](http://img.shields.io/badge/license-Apache-blue.svg)](https://raw.githubusercontent.com/miguelmota/cointop/master/LICENSE.md) [![Build Status](https://travis-ci.org/miguelmota/cointop.svg?branch=master)](https://travis-ci.org/miguelmota/cointop) [![Go Report Card](https://goreportcard.com/badge/github.com/miguelmota/cointop?)](https://goreportcard.com/report/github.com/miguelmota/cointop) [![GoDoc](https://godoc.org/github.com/miguelmota/cointop?status.svg)](https://godoc.org/github.com/miguelmota/cointop) [![Mentioned in Awesome Terminals](https://awesome.re/mentioned-badge.svg)](https://github.com/k4m4/terminals-are-sexy)
[`cointop`](https://github.com/miguelmota/cointop) is a fast and lightweight interactive terminal based UI application for tracking and monitoring cryptocurrency coin stats in real-time.

@ -13,7 +13,7 @@ import (
func (ct *Cointop) updateChart() error {
maxX := ct.maxtablewidth - 3
coin := ct.selectedCoinName()
coin := ct.selectedCoinSymbol()
ct.chartPoints(maxX, coin)
if len(ct.chartpoints) != 0 {
ct.chartview.Clear()
@ -185,6 +185,15 @@ func (ct *Cointop) selectedCoinName() string {
return ""
}
func (ct *Cointop) selectedCoinSymbol() string {
coin := ct.selectedcoin
if coin != nil {
return coin.Symbol
}
return ""
}
func (ct *Cointop) toggleCoinChart() error {
highlightedcoin := ct.highlightedRowCoin()
if ct.selectedcoin == highlightedcoin {

@ -9,7 +9,7 @@ import (
"time"
"github.com/miguelmota/cointop/pkg/api"
types "github.com/miguelmota/cointop/pkg/api/types"
apitypes "github.com/miguelmota/cointop/pkg/api/types"
"github.com/miguelmota/cointop/pkg/cache"
"github.com/miguelmota/cointop/pkg/fcache"
"github.com/miguelmota/cointop/pkg/gocui"
@ -63,6 +63,7 @@ type Cointop struct {
helpview *gocui.View
helpviewname string
helpvisible bool
currencyconversion string
}
// Instance running cointop instance
@ -135,6 +136,7 @@ func Run() {
statusbarviewname: "statusbar",
searchfieldviewname: "searchfield",
helpviewname: "help",
currencyconversion: "USD",
}
Instance = &ct
err := ct.setupConfig()
@ -142,7 +144,7 @@ func Run() {
log.Fatal(err)
}
allcoinsmap := map[string]types.Coin{}
allcoinsmap := map[string]apitypes.Coin{}
coinscachekey := "allcoinsmap"
fcache.Get(coinscachekey, &allcoinsmap)
ct.cache.Set(coinscachekey, allcoinsmap, 10*time.Second)
@ -152,7 +154,7 @@ func Run() {
fcache.Get(chartcachekey, &globaldata)
ct.cache.Set(chartcachekey, globaldata, 10*time.Second)
var market types.GlobalMarketData
var market apitypes.GlobalMarketData
marketcachekey := "market"
fcache.Get(marketcachekey, &market)
ct.cache.Set(marketcachekey, market, 10*time.Second)

@ -23,7 +23,7 @@ func (ct *Cointop) updateCoins() error {
// cache miss
if allcoinsmap == nil {
ct.debuglog("cache miss")
allcoinsmap, err = ct.api.GetAllCoinData()
allcoinsmap, err = ct.api.GetAllCoinData(ct.currencyconversion)
if err != nil {
return err
}

@ -26,7 +26,7 @@ func (ct *Cointop) updateMarketbar() error {
ct.debuglog("soft cache hit")
}
} else {
market, err = ct.api.GetGlobalMarketData()
market, err = ct.api.GetGlobalMarketData(ct.currencyconversion)
if err != nil {
return err
}

@ -1,10 +1,10 @@
package api
import (
"strings"
"strconv"
types "github.com/miguelmota/cointop/pkg/api/types"
cmc "github.com/miguelmota/go-coinmarketcap"
apitypes "github.com/miguelmota/cointop/pkg/api/types"
cmc "github.com/miguelmota/cointop/pkg/cmc"
)
// Service service
@ -17,37 +17,43 @@ func New() *Service {
}
// GetAllCoinData gets all coin data
func (s *Service) GetAllCoinData() (map[string]types.Coin, error) {
ret := make(map[string]types.Coin)
coins, err := cmc.GetAllCoinData(0)
func (s *Service) GetAllCoinData(convert string) (map[string]apitypes.Coin, error) {
ret := make(map[string]apitypes.Coin)
coins, err := cmc.Tickers(&cmc.TickersOptions{
Convert: convert,
})
if err != nil {
return ret, err
}
for _, v := range coins {
ret[v.ID] = types.Coin{
ID: v.ID,
ret[v.Symbol] = apitypes.Coin{
ID: v.Slug,
Name: v.Name,
Symbol: v.Symbol,
Rank: v.Rank,
PriceUSD: v.PriceUSD,
PriceBTC: v.PriceBTC,
USD24HVolume: v.USD24HVolume,
MarketCapUSD: v.MarketCapUSD,
AvailableSupply: v.AvailableSupply,
AvailableSupply: v.CirculatingSupply,
TotalSupply: v.TotalSupply,
PercentChange1H: v.PercentChange1H,
PercentChange24H: v.PercentChange24H,
PercentChange7D: v.PercentChange7D,
LastUpdated: v.LastUpdated,
MarketCapUSD: v.Quotes[convert].MarketCap,
PriceUSD: v.Quotes[convert].Price,
PercentChange1H: v.Quotes[convert].PercentChange1H,
PercentChange24H: v.Quotes[convert].PercentChange24H,
PercentChange7D: v.Quotes[convert].PercentChange7D,
USD24HVolume: v.Quotes[convert].Volume24H,
PriceBTC: 0,
LastUpdated: strconv.Itoa(v.LastUpdated),
}
}
return ret, nil
}
// GetCoinGraphData gets coin graph data
func (s *Service) GetCoinGraphData(coin string, start int64, end int64) (types.CoinGraph, error) {
ret := types.CoinGraph{}
graphData, err := cmc.GetCoinGraphData(strings.ToLower(coin), start, end)
func (s *Service) GetCoinGraphData(coin string, start int64, end int64) (apitypes.CoinGraph, error) {
ret := apitypes.CoinGraph{}
graphData, err := cmc.TickerGraph(&cmc.TickerGraphOptions{
Symbol: coin,
Start: start,
End: end,
})
if err != nil {
return ret, err
}
@ -60,9 +66,12 @@ func (s *Service) GetCoinGraphData(coin string, start int64, end int64) (types.C
}
// GetGlobalMarketGraphData gets global market graph data
func (s *Service) GetGlobalMarketGraphData(start int64, end int64) (types.MarketGraph, error) {
ret := types.MarketGraph{}
graphData, err := cmc.GetGlobalMarketGraphData(start, end)
func (s *Service) GetGlobalMarketGraphData(start int64, end int64) (apitypes.MarketGraph, error) {
ret := apitypes.MarketGraph{}
graphData, err := cmc.GlobalMarketGraph(&cmc.GlobalMarketGraphOptions{
Start: start,
End: end,
})
if err != nil {
return ret, err
}
@ -73,19 +82,21 @@ func (s *Service) GetGlobalMarketGraphData(start int64, end int64) (types.Market
}
// GetGlobalMarketData gets global market data
func (s *Service) GetGlobalMarketData() (types.GlobalMarketData, error) {
ret := types.GlobalMarketData{}
market, err := cmc.GetGlobalMarketData()
func (s *Service) GetGlobalMarketData(convert string) (apitypes.GlobalMarketData, error) {
ret := apitypes.GlobalMarketData{}
market, err := cmc.GlobalMarket(&cmc.GlobalMarketOptions{
Convert: convert,
})
if err != nil {
return ret, err
}
ret = types.GlobalMarketData{
TotalMarketCapUSD: market.TotalMarketCapUSD,
Total24HVolumeUSD: market.Total24HVolumeUSD,
ret = apitypes.GlobalMarketData{
TotalMarketCapUSD: market.Quotes[convert].TotalMarketCap,
Total24HVolumeUSD: market.Quotes[convert].TotalVolume24H,
BitcoinPercentageOfMarketCap: market.BitcoinPercentageOfMarketCap,
ActiveCurrencies: market.ActiveCurrencies,
ActiveAssets: market.ActiveCurrencies,
ActiveMarkets: market.ActiveAssets,
ActiveAssets: 0,
ActiveMarkets: market.ActiveMarkets,
}
return ret, nil
}

@ -6,10 +6,10 @@ import (
// Interface interface
type Interface interface {
GetAllCoinData() (map[string]types.Coin, error)
GetAllCoinData(convert string) (map[string]types.Coin, error)
GetCoinGraphData(coin string, start int64, end int64) (types.CoinGraph, error)
GetGlobalMarketGraphData(start int64, end int64) (types.MarketGraph, error)
GetGlobalMarketData() (types.GlobalMarketData, error)
GetGlobalMarketData(convert string) (types.GlobalMarketData, error)
//GetCoinData(coin string) (types.Coin, error)
//GetAltcoinMarketGraphData(start int64, end int64) (types.MarketGraph, error)
//GetCoinPriceUSD(coin string) (float64, error)

@ -0,0 +1,356 @@
// Package coinmarketcap Coin Market Cap API client for Go
package coinmarketcap
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"strconv"
"strings"
"github.com/anaskhan96/soup"
"github.com/coincircle/go-coinmarketcap/types"
)
var (
siteURL = "https://coinmarketcap.com"
baseURL = "https://api.coinmarketcap.com/v2"
coinGraphURL = "https://graphs2.coinmarketcap.com/currencies"
globalMarketGraphURL = "https://graphs2.coinmarketcap.com/global/marketcap-total"
altcoinMarketGraphURL = "https://graphs2.coinmarketcap.com/global/marketcap-altcoin"
)
// Interface interface
type Interface interface {
Listings() ([]*types.Listing, error)
Tickers(options *TickersOptions) (map[string]*types.Ticker, error)
Ticker(options *TickerOptions) (*types.Ticker, error)
TickerGraph(options *TickerGraphOptions) (*types.TickerGraph, error)
GlobalMarket(options *GlobalMarketOptions) (*types.GlobalMarket, error)
GlobalMarketGraph(options *GlobalMarketGraphOptions) (*types.MarketGraph, error)
GlobalAltcoinMarketGraph(options *GlobalAltcoinMarketGraphOptions) (*types.MarketGraph, error)
Markets(options *MarketsOptions) ([]*types.Market, error)
Price(options *PriceOptions) (float64, error)
CoinID(symbol string) (int, error)
CoinSlug(symbol string) (string, error)
}
// listingsMedia listings response media
type listingsMedia struct {
Data []*types.Listing `json:"data"`
}
// Listings gets all coin listings
func Listings() ([]*types.Listing, error) {
url := fmt.Sprintf("%s/listings", baseURL)
resp, err := makeReq(url)
var body listingsMedia
err = json.Unmarshal(resp, &body)
if err != nil {
return nil, err
}
return body.Data, nil
}
// TickersOptions options for tickers method
type TickersOptions struct {
Start int
Limit int
Convert string
}
// tickerMedia tickers response media
type tickersMedia struct {
Data map[string]*types.Ticker `json:"data"`
}
// Tickers gets ticker information on coins
func Tickers(options *TickersOptions) (map[string]*types.Ticker, error) {
var params []string
if options.Start >= 0 {
params = append(params, fmt.Sprintf("start=%v", options.Start))
}
if options.Limit >= 0 {
params = append(params, fmt.Sprintf("limit=%v", options.Limit))
}
if options.Convert != "" {
params = append(params, fmt.Sprintf("convert=%v", options.Convert))
}
url := fmt.Sprintf("%s/ticker?%s", baseURL, strings.Join(params, "&"))
resp, err := makeReq(url)
var body tickersMedia
err = json.Unmarshal(resp, &body)
if err != nil {
return nil, err
}
tickers := make(map[string]*types.Ticker)
data := body.Data
for _, v := range data {
tickers[strings.ToUpper(string(v.Symbol))] = v
}
return tickers, nil
}
// TickerOptions options for ticker method
type TickerOptions struct {
Symbol string
Convert string
}
type tickerMedia struct {
Data *types.Ticker `json:"data"`
}
// Ticker gets ticker information about a cryptocurrency
func Ticker(options *TickerOptions) (*types.Ticker, error) {
var params []string
if options.Convert != "" {
params = append(params, fmt.Sprintf("convert=%v", options.Convert))
}
id, err := CoinID(options.Symbol)
if err != nil {
return nil, err
}
url := fmt.Sprintf("%s/ticker/%v?%s", baseURL, id, strings.Join(params, "&"))
resp, err := makeReq(url)
if err != nil {
return nil, err
}
var body tickerMedia
err = json.Unmarshal(resp, &body)
if err != nil {
return nil, err
}
return body.Data, nil
}
// TickerGraphOptions options for ticker graph
type TickerGraphOptions struct {
Symbol string
Start int64
End int64
}
// TickerGraph gets graph data points for a cryptocurrency
func TickerGraph(options *TickerGraphOptions) (*types.TickerGraph, error) {
slug, err := CoinSlug(options.Symbol)
if err != nil {
return nil, err
}
url := fmt.Sprintf("%s/%s/%d/%d", coinGraphURL, slug, options.Start*1000, options.End*1000)
resp, err := makeReq(url)
if err != nil {
return nil, err
}
var data *types.TickerGraph
err = json.Unmarshal(resp, &data)
if err != nil {
return nil, err
}
return data, nil
}
// GlobalMarketOptions options for global data method
type GlobalMarketOptions struct {
Convert string
}
// globalMedia global data response media
type globalMarketMedia struct {
Data *types.GlobalMarket `json:"data"`
}
// GlobalMarket gets information about the global market of the cryptocurrencies
func GlobalMarket(options *GlobalMarketOptions) (*types.GlobalMarket, error) {
var params []string
if options.Convert != "" {
params = append(params, fmt.Sprintf("convert=%v", options.Convert))
}
url := fmt.Sprintf("%s/global?%s", baseURL, strings.Join(params, "&"))
resp, err := makeReq(url)
var body globalMarketMedia
err = json.Unmarshal(resp, &body)
if err != nil {
return nil, err
}
return body.Data, nil
}
// GlobalMarketGraphOptions options for global market graph method
type GlobalMarketGraphOptions struct {
Start int64
End int64
}
// GlobalMarketGraph get graph data points of global market
func GlobalMarketGraph(options *GlobalMarketGraphOptions) (*types.MarketGraph, error) {
url := fmt.Sprintf("%s/%d/%d", globalMarketGraphURL, options.Start*1000, options.End*1000)
resp, err := makeReq(url)
if err != nil {
return nil, err
}
var data *types.MarketGraph
err = json.Unmarshal(resp, &data)
if err != nil {
return nil, err
}
return data, nil
}
// GlobalAltcoinMarketGraphOptions options for global altcoin market graph method
type GlobalAltcoinMarketGraphOptions struct {
Start int64
End int64
}
// GlobalAltcoinMarketGraph gets graph data points of altcoin market
func GlobalAltcoinMarketGraph(options *GlobalAltcoinMarketGraphOptions) (*types.MarketGraph, error) {
url := fmt.Sprintf("%s/%d/%d", altcoinMarketGraphURL, options.Start*1000, options.End*1000)
resp, err := makeReq(url)
if err != nil {
return nil, err
}
var data *types.MarketGraph
err = json.Unmarshal(resp, &data)
if err != nil {
return nil, err
}
return data, nil
}
// MarketsOptions options for markets method
type MarketsOptions struct {
Symbol string
}
// Markets get market data for a cryptocurrency
func Markets(options *MarketsOptions) ([]*types.Market, error) {
slug, err := CoinSlug(options.Symbol)
if err != nil {
return nil, err
}
url := fmt.Sprintf("%s/currencies/%s/#markets", siteURL, slug)
var markets []*types.Market
response, err := soup.Get(url)
if err != nil {
return nil, err
}
rows := soup.HTMLParse(response).Find("table", "id", "markets-table").Find("tbody").FindAll("tr")
for _, row := range rows {
var data []string
for _, column := range row.FindAll("td") {
attrs := column.Attrs()
if attrs["data-sort"] != "" {
data = append(data, attrs["data-sort"])
} else {
data = append(data, column.Text())
}
}
markets = append(markets, &types.Market{
Rank: toInt(data[0]),
Exchange: data[1],
Pair: data[2],
VolumeUSD: toFloat(data[3]),
Price: toFloat(data[4]),
VolumePercent: toFloat(data[5]),
Updated: data[6],
})
}
return markets, nil
}
// PriceOptions options for price method
type PriceOptions struct {
Symbol string
Convert string
}
// Price gets price of a cryptocurrency
func Price(options *PriceOptions) (float64, error) {
coins, err := Tickers(&TickersOptions{
Convert: options.Convert,
})
if err != nil {
return 0, err
}
coin := coins[options.Symbol]
if coin == nil {
return 0, errors.New("coin not found")
}
return coin.Quotes[options.Convert].Price, nil
}
// CoinID gets the ID for the cryptocurrency
func CoinID(symbol string) (int, error) {
symbol = strings.ToUpper(strings.TrimSpace(symbol))
coins, err := Tickers(&TickersOptions{})
if err != nil {
return 0, err
}
coin := coins[symbol]
if coin == nil {
return 0, errors.New("coin not found")
}
return coin.ID, nil
}
// CoinSlug gets the slug for the cryptocurrency
func CoinSlug(symbol string) (string, error) {
symbol = strings.ToUpper(strings.TrimSpace(symbol))
coins, err := Tickers(&TickersOptions{})
if err != nil {
return "", err
}
coin := coins[symbol]
if coin == nil {
return "", errors.New("coin not found")
}
return coin.Slug, nil
}
// toInt helper for parsing strings to int
func toInt(rawInt string) int {
parsed, _ := strconv.Atoi(strings.Replace(strings.Replace(rawInt, "$", "", -1), ",", "", -1))
return parsed
}
// toFloat helper for parsing strings to float
func toFloat(rawFloat string) float64 {
parsed, _ := strconv.ParseFloat(strings.Replace(strings.Replace(strings.Replace(rawFloat, "$", "", -1), ",", "", -1), "%", "", -1), 64)
return parsed
}
// doReq HTTP client
func doReq(req *http.Request) ([]byte, error) {
client := &http.Client{}
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 {
return nil, fmt.Errorf("%s", body)
}
return body, nil
}
// makeReq HTTP request helper
func makeReq(url string) ([]byte, error) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
resp, err := doReq(req)
if err != nil {
return nil, err
}
return resp, err
}

@ -0,0 +1,73 @@
package types
// Listing struct
type Listing struct {
ID int `json:"id"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Slug string `json:"website_slug"`
}
// Ticker struct
type Ticker struct {
ID int `json:"id"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Slug string `json:"website_slug"`
Rank int `json:"rank"`
CirculatingSupply float64 `json:"circulating_supply"`
TotalSupply float64 `json:"total_supply"`
MaxSupply float64 `json:"max_supply"`
Quotes map[string]*TickerQuote `json:"quotes"`
LastUpdated int `json:"last_updated"`
}
// TickerQuote struct
type TickerQuote struct {
Price float64 `json:"price"`
Volume24H float64 `json:"volume_24h"`
MarketCap float64 `json:"market_cap"`
PercentChange1H float64 `json:"percent_change_1h"`
PercentChange24H float64 `json:"percent_change_24h"`
PercentChange7D float64 `json:"percent_change_7d"`
}
// GlobalMarket struct
type GlobalMarket struct {
ActiveCurrencies int `json:"active_cryptocurrencies"`
ActiveMarkets int `json:"active_markets"`
BitcoinPercentageOfMarketCap float64 `json:"bitcoin_percentage_of_market_cap"`
LastUpdated int `json:"last_updated"`
Quotes map[string]*GlobalMarketQuote `json:"quotes"`
}
// GlobalMarketQuote struct
type GlobalMarketQuote struct {
TotalMarketCap float64 `json:"total_market_cap"`
TotalVolume24H float64 `json:"total_volume_24h"`
}
// TickerGraph struct
type TickerGraph struct {
MarketCapByAvailableSupply [][]float64 `json:"market_cap_by_available_supply"`
PriceBTC [][]float64 `json:"price_btc"`
PriceUSD [][]float64 `json:"price_usd"`
VolumeUSD [][]float64 `json:"volume_usd"`
}
// Market struct
type Market struct {
Rank int
Exchange string
Pair string
VolumeUSD float64
Price float64
VolumePercent float64
Updated string
}
// MarketGraph struct
type MarketGraph struct {
MarketCapByAvailableSupply [][]float64 `json:"market_cap_by_available_supply"`
VolumeUSD [][]float64 `json:"volume_usd"`
}

@ -1,26 +0,0 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
.DS_Store

@ -1,9 +0,0 @@
language: go
go:
- "1.9.x"
- "1.10.x"
- "master"
script:
- make test

@ -1,24 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/anaskhan96/soup"
packages = ["."]
revision = "7a8d31f81bad1a5abeed0d0219c35e5e295a5a76"
version = "v1.0.1"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = [
"html",
"html/atom"
]
revision = "dc948dff8834a7fe1ca525f8d04e261c2b56e70d"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "ef92c4a55490132c4b677cba28dd5f0ee0bb397d0b3581ea46df6c3f4f169646"
solver-name = "gps-cdcl"
solver-version = 1

@ -1,34 +0,0 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true
[[constraint]]
name = "github.com/anaskhan96/soup"
version = "1.0.1"
[prune]
go-tests = true
unused-packages = true

@ -1,21 +0,0 @@
MIT license
Copyright (C) 2015 Miguel Mota
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -1,5 +0,0 @@
all:
@echo "no default"
test:
go test -v

@ -1,47 +0,0 @@
# go-coinmarketcap
> The Unofficial [CoinMarketCap](https://coinmarketcap.com/) API client for Go.
[![License](http://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/miguelmota/go-coinmarketcap/master/LICENSE.md) [![Build Status](https://travis-ci.org/miguelmota/go-coinmarketcap.svg?branch=master)](https://travis-ci.org/miguelmota/go-coinmarketcap) [![Go Report Card](https://goreportcard.com/badge/github.com/miguelmota/go-coinmarketcap?)](https://goreportcard.com/report/github.com/miguelmota/go-coinmarketcap) [![GoDoc](https://godoc.org/github.com/miguelmota/go-coinmarketcap?status.svg)](https://godoc.org/github.com/miguelmota/go-coinmarketcap)
## Documentation
[https://godoc.org/github.com/miguelmota/go-coinmarketcap](https://godoc.org/github.com/miguelmota/go-coinmarketcap)
## Install
```bash
go get -u github.com/miguelmota/go-coinmarketcap
```
## Getting started
```go
package main
import (
"fmt"
"log"
cmc "github.com/miguelmota/go-coinmarketcap"
)
func main() {
coins, err := cmc.GetAllCoinData(0)
if err != nil {
log.Fatal(err)
}
for _, coin := range coins {
fmt.Println(coin.Symbol, coin.PriceUSD)
}
}
```
## Examples
Check out the [`./example`](./example) directory and documentation.
## License
MIT

@ -1,210 +0,0 @@
// Package coinmarketcap Coin Market Cap API client for Go
package coinmarketcap
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strconv"
"strings"
"github.com/anaskhan96/soup"
)
var (
baseURL = "https://api.coinmarketcap.com/v1"
coinGraphURL = "https://graphs2.coinmarketcap.com/currencies"
globalMarketGraphURL = "https://graphs2.coinmarketcap.com/global/marketcap-total"
altcoinMarketGraphURL = "https://graphs2.coinmarketcap.com/global/marketcap-altcoin"
)
// GetGlobalMarketData get information about the global market data of the cryptocurrencies
func GetGlobalMarketData() (GlobalMarketData, error) {
url := fmt.Sprintf(baseURL + "/global/")
resp, err := makeReq(url)
var data GlobalMarketData
err = json.Unmarshal(resp, &data)
if err != nil {
return GlobalMarketData{}, err
}
return data, nil
}
// GetGlobalMarketGraphData get graph data points of global market
func GetGlobalMarketGraphData(start int64, end int64) (MarketGraph, error) {
url := fmt.Sprintf("%s/%d/%d", globalMarketGraphURL, start*1000, end*1000)
resp, err := makeReq(url)
if err != nil {
return MarketGraph{}, err
}
var data MarketGraph
err = json.Unmarshal(resp, &data)
if err != nil {
return MarketGraph{}, err
}
return data, nil
}
// GetAltcoinMarketGraphData get graph data points of altcoin market
func GetAltcoinMarketGraphData(start int64, end int64) (MarketGraph, error) {
url := fmt.Sprintf("%s/%d/%d", altcoinMarketGraphURL, start*1000, end*1000)
resp, err := makeReq(url)
if err != nil {
return MarketGraph{}, err
}
var data MarketGraph
err = json.Unmarshal(resp, &data)
if err != nil {
return MarketGraph{}, err
}
return data, nil
}
// GetCoinData get information about a crypto currency
func GetCoinData(coin string) (Coin, error) {
coin = strings.ToLower(coin)
url := fmt.Sprintf("%s/ticker/%s", baseURL, coin)
resp, err := makeReq(url)
if err != nil {
return Coin{}, err
}
var data []Coin
err = json.Unmarshal(resp, &data)
if err != nil {
return Coin{}, err
}
return data[0], nil
}
// GetAllCoinData get information about all coins listed in Coin Market Cap
func GetAllCoinData(limit int) (map[string]Coin, error) {
var l string
if limit >= 0 {
l = fmt.Sprintf("?limit=%v", limit)
}
url := fmt.Sprintf("%s/ticker/%s", baseURL, l)
resp, err := makeReq(url)
var data []Coin
err = json.Unmarshal(resp, &data)
if err != nil {
return nil, err
}
// creating map from the array
allCoins := make(map[string]Coin)
for i := 0; i < len(data); i++ {
allCoins[data[i].ID] = data[i]
}
return allCoins, nil
}
// GetCoinGraphData get graph data points for a crypto currency
func GetCoinGraphData(coin string, start int64, end int64) (CoinGraph, error) {
url := fmt.Sprintf("%s/%s/%d/%d", coinGraphURL, strings.ToLower(coin), start*1000, end*1000)
resp, err := makeReq(url)
if err != nil {
return CoinGraph{}, err
}
var data CoinGraph
err = json.Unmarshal(resp, &data)
if err != nil {
return CoinGraph{}, err
}
return data, nil
}
// GetCoinPriceUSD get USD price of crypto currency
func GetCoinPriceUSD(coin string) (float64, error) {
data, err := GetCoinData(strings.ToLower(coin))
if err != nil {
return float64(0), nil
}
return data.PriceUSD, nil
}
// GetCoinMarkets get market data for a coin name
func GetCoinMarkets(coin string) ([]Market, error) {
url := fmt.Sprintf("https://coinmarketcap.com/currencies/%s/#markets", strings.ToLower(coin))
var markets []Market
response, err := soup.Get(url)
if err != nil {
return nil, err
}
rows := soup.HTMLParse(response).Find("table", "id", "markets-table").Find("tbody").FindAll("tr")
for _, row := range rows {
var data []string
for _, column := range row.FindAll("td") {
attrs := column.Attrs()
if attrs["data-sort"] != "" {
data = append(data, attrs["data-sort"])
} else {
data = append(data, column.Text())
}
}
markets = append(markets, Market{
Rank: toInt(data[0]),
Exchange: data[1],
Pair: data[2],
VolumeUSD: toFloat(data[3]),
Price: toFloat(data[4]),
VolumePercent: toFloat(data[5]),
Updated: data[6],
})
}
return markets, nil
}
// doReq HTTP client
func doReq(req *http.Request) ([]byte, error) {
client := &http.Client{}
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 {
return nil, fmt.Errorf("%s", body)
}
return body, nil
}
// makeReq HTTP request helper
func makeReq(url string) ([]byte, error) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
resp, err := doReq(req)
if err != nil {
return nil, err
}
return resp, err
}
// toInt helper for parsing strings to int
func toInt(rawInt string) int {
parsed, _ := strconv.Atoi(strings.Replace(strings.Replace(rawInt, "$", "", -1), ",", "", -1))
return parsed
}
// toFloat helper for parsing strings to float
func toFloat(rawFloat string) float64 {
parsed, _ := strconv.ParseFloat(strings.Replace(strings.Replace(strings.Replace(rawFloat, "$", "", -1), ",", "", -1), "%", "", -1), 64)
return parsed
}

@ -1,219 +0,0 @@
package coinmarketcap
import (
"testing"
"time"
)
func TestGetGlobalMarketData(t *testing.T) {
market, err := GetGlobalMarketData()
if err != nil {
t.FailNow()
}
if market.ActiveAssets == 0 {
t.FailNow()
}
if market.ActiveCurrencies == 0 {
t.FailNow()
}
if market.ActiveMarkets == 0 {
t.FailNow()
}
if market.BitcoinPercentageOfMarketCap == 0 {
t.FailNow()
}
if market.Total24HVolumeUSD == 0 {
t.FailNow()
}
if market.TotalMarketCapUSD == 0 {
t.FailNow()
}
}
func TestGetGlobalMarketGraphData(t *testing.T) {
var threeMonths int64 = (60 * 60 * 24 * 90)
end := time.Now().Unix()
start := end - threeMonths
graph, err := GetGlobalMarketGraphData(start, end)
if err != nil {
t.FailNow()
}
if graph.MarketCapByAvailableSupply[0][0] == 0 {
t.FailNow()
}
if graph.VolumeUSD[0][0] == 0 {
t.FailNow()
}
}
func TestGetAltcoinMarketGraphData(t *testing.T) {
var threeMonths int64 = (60 * 60 * 24 * 90)
end := time.Now().Unix()
start := end - threeMonths
graph, err := GetAltcoinMarketGraphData(start, end)
if err != nil {
t.FailNow()
}
if graph.MarketCapByAvailableSupply[0][0] == 0 {
t.FailNow()
}
if graph.VolumeUSD[0][0] == 0 {
t.FailNow()
}
}
func TestGetCoinData(t *testing.T) {
coin, err := GetCoinData("ethereum")
if err != nil {
t.FailNow()
}
if coin.AvailableSupply == 0 {
t.FailNow()
}
if coin.ID == "" {
t.FailNow()
}
if coin.LastUpdated == "" {
t.FailNow()
}
if coin.MarketCapUSD == 0 {
t.FailNow()
}
if coin.Name == "" {
t.FailNow()
}
if coin.PercentChange1H == 0 {
t.FailNow()
}
if coin.PercentChange24H == 0 {
t.FailNow()
}
if coin.PercentChange7D == 0 {
t.FailNow()
}
if coin.PriceBTC == 0 {
t.FailNow()
}
if coin.PriceUSD == 0 {
t.FailNow()
}
if coin.Rank == 0 {
t.FailNow()
}
if coin.Symbol == "" {
t.FailNow()
}
if coin.TotalSupply == 0 {
t.FailNow()
}
if coin.USD24HVolume == 0 {
t.FailNow()
}
}
func TestGetAllCoinData(t *testing.T) {
coins, err := GetAllCoinData(10)
if err != nil {
t.FailNow()
}
if len(coins) != 10 {
t.FailNow()
}
}
func TestGetCoinGraphData(t *testing.T) {
var threeMonths int64 = (60 * 60 * 24 * 90)
end := time.Now().Unix()
start := end - threeMonths
graph, err := GetCoinGraphData("ethereum", start, end)
if err != nil {
t.FailNow()
}
if graph.MarketCapByAvailableSupply[0][0] == 0 {
t.FailNow()
}
if graph.PriceBTC[0][0] == 0 {
t.FailNow()
}
if graph.PriceUSD[0][0] == 0 {
t.FailNow()
}
if graph.VolumeUSD[0][0] == 0 {
t.FailNow()
}
}
func TestGetCoinPriceUSD(t *testing.T) {
price, err := GetCoinPriceUSD("ethereum")
if err != nil {
t.FailNow()
}
if price <= 0 {
t.FailNow()
}
}
func TestGetCoinMarkets(t *testing.T) {
markets, err := GetCoinMarkets("ethereum")
if err != nil {
t.FailNow()
}
if len(markets) == 0 {
t.FailNow()
}
market := markets[0]
if market.Rank == 0 {
t.FailNow()
}
if market.Exchange == "" {
t.FailNow()
}
if market.Pair == "" {
t.FailNow()
}
if market.VolumeUSD == 0 {
t.FailNow()
}
if market.Price == 0 {
t.FailNow()
}
if market.VolumePercent == 0 {
t.FailNow()
}
if market.Updated == "" {
}
}
func TestDoReq(t *testing.T) {
// TODO
}
func TestMakeReq(t *testing.T) {
// TODO
}
func TestToInt(t *testing.T) {
v := toInt("5")
if v != 5 {
t.FailNow()
}
}
func TestToFloat(t *testing.T) {
v := toFloat("5.2")
if v != 5.2 {
t.FailNow()
}
}

@ -1,20 +0,0 @@
package main
import (
"fmt"
"log"
cmc "github.com/miguelmota/go-coinmarketcap"
)
func main() {
// get data for all coins
coins, err := cmc.GetAllCoinData(0)
if err != nil {
log.Fatal(err)
}
for _, coin := range coins {
fmt.Println(coin.Symbol, coin.PriceUSD)
}
}

@ -1,18 +0,0 @@
package main
import (
"fmt"
"log"
cmc "github.com/miguelmota/go-coinmarketcap"
)
func main() {
// Get info about coin
coinInfo, err := cmc.GetCoinData("ethereum")
if err != nil {
log.Fatal(err)
}
fmt.Println(coinInfo)
}

@ -1,25 +0,0 @@
package main
import (
"fmt"
"log"
"time"
cmc "github.com/miguelmota/go-coinmarketcap"
)
func main() {
threeMonths := int64(60 * 60 * 24 * 90)
now := time.Now()
secs := now.Unix()
start := secs - threeMonths
end := secs
// Get graph data for coin
coinGraphData, err := cmc.GetCoinGraphData("ethereum", start, end)
if err != nil {
log.Fatal(err)
}
fmt.Println(coinGraphData)
}

@ -1,18 +0,0 @@
package main
import (
"fmt"
"log"
cmc "github.com/miguelmota/go-coinmarketcap"
)
func main() {
// Get global market data
marketInfo, err := cmc.GetGlobalMarketData()
if err != nil {
log.Fatal(err)
}
fmt.Println(marketInfo)
}

@ -1,66 +0,0 @@
package coinmarketcap
// Interface interface
type Interface interface {
GetGlobalMarketData() (GlobalMarketData, error)
GetGlobalMarketGraphData(start int64, end int64) (MarketGraph, error)
GetAltcoinMarketGraphData(start int64, end int64) (MarketGraph, error)
GetCoinData(coin string) (Coin, error)
GetAllCoinData(limit int) (map[string]Coin, error)
GetCoinGraphData(coin string, start int64, end int64) (CoinGraph, error)
GetCoinPriceUSD(coin string) (float64, error)
GetCoinMarkets(coin string) ([]Market, error)
}
// Coin struct
type Coin struct {
ID string `json:"id"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Rank int `json:"rank,string"`
PriceUSD float64 `json:"price_usd,string"`
PriceBTC float64 `json:"price_btc,string"`
USD24HVolume float64 `json:"24h_volume_usd,string"`
MarketCapUSD float64 `json:"market_cap_usd,string"`
AvailableSupply float64 `json:"available_supply,string"`
TotalSupply float64 `json:"total_supply,string"`
PercentChange1H float64 `json:"percent_change_1h,string"`
PercentChange24H float64 `json:"percent_change_24h,string"`
PercentChange7D float64 `json:"percent_change_7d,string"`
LastUpdated string `json:"last_updated"`
}
// GlobalMarketData struct
type GlobalMarketData struct {
TotalMarketCapUSD float64 `json:"total_market_cap_usd"`
Total24HVolumeUSD float64 `json:"total_24h_volume_usd"`
BitcoinPercentageOfMarketCap float64 `json:"bitcoin_percentage_of_market_cap"`
ActiveCurrencies int `json:"active_currencies"`
ActiveAssets int `json:"active_assets"`
ActiveMarkets int `json:"active_markets"`
}
// CoinGraph struct
type CoinGraph struct {
MarketCapByAvailableSupply [][]float64 `json:"market_cap_by_available_supply"`
PriceBTC [][]float64 `json:"price_btc"`
PriceUSD [][]float64 `json:"price_usd"`
VolumeUSD [][]float64 `json:"volume_usd"`
}
// Market struct
type Market struct {
Rank int
Exchange string
Pair string
VolumeUSD float64
Price float64
VolumePercent float64
Updated string
}
// MarketGraph struct
type MarketGraph struct {
MarketCapByAvailableSupply [][]float64 `json:"market_cap_by_available_supply"`
VolumeUSD [][]float64 `json:"volume_usd"`
}
Loading…
Cancel
Save