mirror of https://github.com/miguelmota/cointop
parent
65faa8b0a3
commit
75b86fcee4
@ -0,0 +1,114 @@
|
|||||||
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||||
|
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/anaskhan96/soup"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "cd07662ec9300d16d2ece1c24b0b29ad89f65ff4"
|
||||||
|
version = "v1.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/bradfitz/slice"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "d9036e2120b5ddfa53f3ebccd618c4af275f47da"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/dustin/go-humanize"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "bb3d318650d48840a39aa21a027c6630e198e626"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/fatih/color"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "507f6050b8568533fb3f5504de8e5205fa62a114"
|
||||||
|
version = "v1.6.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/gizak/termui"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "24acd523c756fd9728824cdfac66aad9d8982fb7"
|
||||||
|
version = "v2.2.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/jroimartin/gocui"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "4f518eddb04b8f73870836b6d1941e8aa3c06637"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/maruel/panicparse"
|
||||||
|
packages = ["stack"]
|
||||||
|
revision = "785840568bdc7faa0dfb1cd6c643207f03271f64"
|
||||||
|
version = "v1.1.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/mattn/go-colorable"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
|
||||||
|
version = "v0.0.9"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/mattn/go-isatty"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
||||||
|
version = "v0.0.3"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/mattn/go-runewidth"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "9e777a8366cce605130a531d2cd6363d07ad7317"
|
||||||
|
version = "v0.0.2"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/miguelmota/go-coinmarketcap"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "05fd2d0c45f763462f90e630da2ddc0392d2cdd3"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/mitchellh/go-wordwrap"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "ad45545899c7b13c020ea92b2072220eefad42b8"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/nsf/termbox-go"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "e2050e41c8847748ec5288741c0b19a8cb26d084"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/willf/pad"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "b3d7806010228b1a954b4d9c4ee4cf6cb476b063"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "go4.org"
|
||||||
|
packages = ["reflectutil"]
|
||||||
|
revision = "e6a7f04a962e05f288f348eec6de20fe93b6b292"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/net"
|
||||||
|
packages = [
|
||||||
|
"html",
|
||||||
|
"html/atom"
|
||||||
|
]
|
||||||
|
revision = "6078986fec03a1dcc236c34816c71b0e05018fda"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/sys"
|
||||||
|
packages = ["unix"]
|
||||||
|
revision = "378d26f46672a356c46195c28f61bdb4c0a781dd"
|
||||||
|
|
||||||
|
[solve-meta]
|
||||||
|
analyzer-name = "dep"
|
||||||
|
analyzer-version = 1
|
||||||
|
inputs-digest = "ff54fa52bac3cde3f10f5c237dad28da497594584e4291356b5efd040501fe4e"
|
||||||
|
solver-name = "gps-cdcl"
|
||||||
|
solver-version = 1
|
@ -0,0 +1,58 @@
|
|||||||
|
# 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]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/bradfitz/slice"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/dustin/go-humanize"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/fatih/color"
|
||||||
|
version = "1.6.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/gizak/termui"
|
||||||
|
version = "2.2.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/jroimartin/gocui"
|
||||||
|
branch = "master"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/miguelmota/go-coinmarketcap"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/willf/pad"
|
||||||
|
|
||||||
|
[prune]
|
||||||
|
go-tests = true
|
||||||
|
unused-packages = true
|
@ -0,0 +1,500 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bradfitz/slice"
|
||||||
|
humanize "github.com/dustin/go-humanize"
|
||||||
|
"github.com/fatih/color"
|
||||||
|
"github.com/gizak/termui"
|
||||||
|
"github.com/jroimartin/gocui"
|
||||||
|
"github.com/miguelmota/cointop/table"
|
||||||
|
cmc "github.com/miguelmota/go-coinmarketcap"
|
||||||
|
"github.com/willf/pad"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
white = color.New(color.FgWhite).SprintFunc()
|
||||||
|
green = color.New(color.FgGreen).SprintFunc()
|
||||||
|
red = color.New(color.FgRed).SprintFunc()
|
||||||
|
cyan = color.New(color.FgCyan).SprintFunc()
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
oneMinute int64 = 60
|
||||||
|
oneHour = oneMinute * 60
|
||||||
|
oneDay = oneHour * 24
|
||||||
|
oneWeek = oneDay * 7
|
||||||
|
oneMonth = oneDay * 30
|
||||||
|
oneYear = oneDay * 365
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cointop cointop
|
||||||
|
type Cointop struct {
|
||||||
|
g *gocui.Gui
|
||||||
|
chartview *gocui.View
|
||||||
|
chartpoints [][]termui.Cell
|
||||||
|
headersview *gocui.View
|
||||||
|
tableview *gocui.View
|
||||||
|
table *table.Table
|
||||||
|
sortdesc bool
|
||||||
|
currentsort string
|
||||||
|
coins []*cmc.Coin
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *Cointop) chartPoints(maxX int, coin string) error {
|
||||||
|
chart := termui.NewLineChart()
|
||||||
|
chart.Height = 10
|
||||||
|
chart.AxesColor = termui.ColorWhite
|
||||||
|
chart.LineColor = termui.ColorCyan
|
||||||
|
chart.Border = false
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
secs := now.Unix()
|
||||||
|
start := secs - oneDay
|
||||||
|
end := secs
|
||||||
|
|
||||||
|
_ = coin
|
||||||
|
//graphData, err := cmc.GetCoinGraphData(coin, start, end)
|
||||||
|
graphData, err := cmc.GetGlobalMarketGraphData(start, end)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var data []float64
|
||||||
|
/*
|
||||||
|
for i := range graphData.PriceUSD {
|
||||||
|
data = append(data, graphData.PriceUSD[i][1])
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
for i := range graphData.MarketCapByAvailableSupply {
|
||||||
|
data = append(data, graphData.MarketCapByAvailableSupply[i][1])
|
||||||
|
}
|
||||||
|
chart.Data = data
|
||||||
|
termui.Body = termui.NewGrid()
|
||||||
|
termui.Body.Width = maxX
|
||||||
|
termui.Body.AddRows(
|
||||||
|
termui.NewRow(
|
||||||
|
termui.NewCol(12, 0, chart),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
var points [][]termui.Cell
|
||||||
|
// calculate layout
|
||||||
|
termui.Body.Align()
|
||||||
|
w := termui.Body.Width
|
||||||
|
h := 10
|
||||||
|
row := termui.Body.Rows[0]
|
||||||
|
b := row.Buffer()
|
||||||
|
for i := 0; i < h; i = i + 1 {
|
||||||
|
var rowpoints []termui.Cell
|
||||||
|
for j := 0; j < w; j = j + 1 {
|
||||||
|
p := b.At(j, i)
|
||||||
|
rowpoints = append(rowpoints, p)
|
||||||
|
}
|
||||||
|
points = append(points, rowpoints)
|
||||||
|
}
|
||||||
|
|
||||||
|
ct.chartpoints = points
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
g, err := gocui.NewGui(gocui.Output256)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("new gocui: %v", err)
|
||||||
|
}
|
||||||
|
defer g.Close()
|
||||||
|
g.Cursor = true
|
||||||
|
g.Mouse = true
|
||||||
|
g.Highlight = true
|
||||||
|
|
||||||
|
ct := Cointop{
|
||||||
|
g: g,
|
||||||
|
}
|
||||||
|
g.SetManagerFunc(ct.layout)
|
||||||
|
|
||||||
|
if err := ct.keybindings(g); err != nil {
|
||||||
|
log.Fatalf("keybindings: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
|
||||||
|
log.Fatalf("main loop: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *Cointop) quit(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
return gocui.ErrQuit
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *Cointop) keybindings(g *gocui.Gui) error {
|
||||||
|
if err := g.SetKeybinding("", gocui.KeyArrowDown, gocui.ModNone, ct.cursorDown); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", 'j', gocui.ModNone, ct.cursorDown); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", gocui.KeyArrowUp, gocui.ModNone, ct.cursorUp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", 'k', gocui.ModNone, ct.cursorUp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", gocui.KeyCtrlD, gocui.ModNone, ct.pageDown); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", gocui.KeyCtrlU, gocui.ModNone, ct.pageUp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", 'r', gocui.ModNone, ct.sort("rank", false)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", 'n', gocui.ModNone, ct.sort("name", true)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", 's', gocui.ModNone, ct.sort("symbol", false)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", 'p', gocui.ModNone, ct.sort("price", true)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", 'm', gocui.ModNone, ct.sort("marketcap", true)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", 'v', gocui.ModNone, ct.sort("24hvolume", true)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", '1', gocui.ModNone, ct.sort("1hchange", true)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", '2', gocui.ModNone, ct.sort("24hchange", true)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", '7', gocui.ModNone, ct.sort("7dchange", true)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", 't', gocui.ModNone, ct.sort("totalsupply", true)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", 'a', gocui.ModNone, ct.sort("availablesupply", true)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", 'l', gocui.ModNone, ct.sort("lastupdated", true)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, ct.quit); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", 'q', gocui.ModNone, ct.quit); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("", gocui.KeyEsc, gocui.ModNone, ct.quit); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *Cointop) sort(sortby string, desc bool) func(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
return func(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
if ct.currentsort == sortby {
|
||||||
|
ct.sortdesc = !ct.sortdesc
|
||||||
|
} else {
|
||||||
|
ct.currentsort = sortby
|
||||||
|
ct.sortdesc = desc
|
||||||
|
}
|
||||||
|
slice.Sort(ct.coins[:], func(i, j int) bool {
|
||||||
|
if ct.sortdesc {
|
||||||
|
i, j = j, i
|
||||||
|
}
|
||||||
|
a := ct.coins[i]
|
||||||
|
b := ct.coins[j]
|
||||||
|
switch sortby {
|
||||||
|
case "rank":
|
||||||
|
return a.Rank < b.Rank
|
||||||
|
case "name":
|
||||||
|
return a.Name < b.Name
|
||||||
|
case "symbol":
|
||||||
|
return a.Symbol < b.Symbol
|
||||||
|
case "price":
|
||||||
|
return a.PriceUSD < b.PriceUSD
|
||||||
|
case "marketcap":
|
||||||
|
return a.MarketCapUSD < b.MarketCapUSD
|
||||||
|
case "24hvolume":
|
||||||
|
return a.USD24HVolume < b.USD24HVolume
|
||||||
|
case "1hchange":
|
||||||
|
return a.PercentChange1H < b.PercentChange1H
|
||||||
|
case "24hchange":
|
||||||
|
return a.PercentChange24H < b.PercentChange24H
|
||||||
|
case "7dchange":
|
||||||
|
return a.PercentChange7D < b.PercentChange7D
|
||||||
|
case "totalsupply":
|
||||||
|
return a.TotalSupply < b.TotalSupply
|
||||||
|
case "availablesupply":
|
||||||
|
return a.AvailableSupply < b.AvailableSupply
|
||||||
|
case "lastupdated":
|
||||||
|
return a.LastUpdated < b.LastUpdated
|
||||||
|
default:
|
||||||
|
return a.Rank < b.Rank
|
||||||
|
}
|
||||||
|
})
|
||||||
|
g.Update(func(g *gocui.Gui) error {
|
||||||
|
ct.tableview.Clear()
|
||||||
|
ct.setTable()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
g.Update(func(g *gocui.Gui) error {
|
||||||
|
ct.chartview.Clear()
|
||||||
|
maxX, _ := g.Size()
|
||||||
|
_, cy := ct.chartview.Cursor()
|
||||||
|
coin := "ethereum"
|
||||||
|
ct.chartPoints(maxX, coin)
|
||||||
|
ct.setChart()
|
||||||
|
fmt.Fprint(v, cy)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *Cointop) cursorDown(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
if ct.tableview == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, y := ct.tableview.Origin()
|
||||||
|
cx, cy := ct.tableview.Cursor()
|
||||||
|
numRows := len(ct.coins) - 1
|
||||||
|
//fmt.Fprint(v, cy)
|
||||||
|
if (cy + y + 1) > numRows {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := ct.tableview.SetCursor(cx, cy+1); err != nil {
|
||||||
|
ox, oy := ct.tableview.Origin()
|
||||||
|
if err := ct.tableview.SetOrigin(ox, oy+1); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *Cointop) cursorUp(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
if ct.tableview == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ox, oy := ct.tableview.Origin()
|
||||||
|
cx, cy := ct.tableview.Cursor()
|
||||||
|
//fmt.Fprint(v, oy)
|
||||||
|
if err := ct.tableview.SetCursor(cx, cy-1); err != nil && oy > 0 {
|
||||||
|
if err := ct.tableview.SetOrigin(ox, oy-1); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *Cointop) pageDown(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
if ct.tableview == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, y := ct.tableview.Origin()
|
||||||
|
cx, cy := ct.tableview.Cursor()
|
||||||
|
numRows := len(ct.coins) - 1
|
||||||
|
_, sy := ct.tableview.Size()
|
||||||
|
rows := sy
|
||||||
|
if (cy + y + rows) > numRows {
|
||||||
|
// go to last row
|
||||||
|
ct.tableview.SetCursor(cx, numRows)
|
||||||
|
ox, _ := ct.tableview.Origin()
|
||||||
|
ct.tableview.SetOrigin(ox, numRows)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := ct.tableview.SetCursor(cx, cy+rows); err != nil {
|
||||||
|
ox, oy := ct.tableview.Origin()
|
||||||
|
if err := ct.tableview.SetOrigin(ox, oy+rows); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *Cointop) pageUp(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
if ct.tableview == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ox, oy := v.Origin()
|
||||||
|
cx, cy := v.Cursor()
|
||||||
|
_, sy := v.Size()
|
||||||
|
rows := sy
|
||||||
|
//fmt.Fprint(v, oy)
|
||||||
|
if err := v.SetCursor(cx, cy-rows); err != nil && oy > 0 {
|
||||||
|
if err := v.SetOrigin(ox, oy-rows); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchData() ([]*cmc.Coin, error) {
|
||||||
|
limit := 100
|
||||||
|
result := []*cmc.Coin{}
|
||||||
|
coins, err := cmc.GetAllCoinData(int(limit))
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range coins {
|
||||||
|
coin := coins[i]
|
||||||
|
result = append(result, &coin)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *Cointop) layout(g *gocui.Gui) error {
|
||||||
|
maxX, maxY := g.Size()
|
||||||
|
|
||||||
|
chartHeight := 10
|
||||||
|
if v, err := g.SetView("chart", 0, 0, maxX, chartHeight); err != nil {
|
||||||
|
if err != gocui.ErrUnknownView {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Frame = false
|
||||||
|
ct.chartview = v
|
||||||
|
ct.setChart()
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := g.SetView("header", 0, chartHeight, maxX, maxY); err != nil {
|
||||||
|
if err != gocui.ErrUnknownView {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t := table.New().SetWidth(maxX)
|
||||||
|
|
||||||
|
headers := []string{
|
||||||
|
pad.Right("[r]ank", 13, " "),
|
||||||
|
pad.Right("[n]ame", 13, " "),
|
||||||
|
pad.Right("[s]ymbol", 8, " "),
|
||||||
|
pad.Left("[p]rice", 10, " "),
|
||||||
|
pad.Left("[m]arket cap", 17, " "),
|
||||||
|
pad.Left("24H [v]olume", 15, " "),
|
||||||
|
pad.Left("[1]H%", 9, " "),
|
||||||
|
pad.Left("[2]4H%", 9, " "),
|
||||||
|
pad.Left("[7]D%", 9, " "),
|
||||||
|
pad.Left("[t]otal supply", 20, " "),
|
||||||
|
pad.Left("[a]vailable supply", 19, " "),
|
||||||
|
pad.Left("[l]ast updated", 17, " "),
|
||||||
|
}
|
||||||
|
for _, h := range headers {
|
||||||
|
t.AddCol(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Format().Fprint(v)
|
||||||
|
v.Highlight = true
|
||||||
|
v.SelBgColor = gocui.ColorGreen
|
||||||
|
v.SelFgColor = gocui.ColorBlack
|
||||||
|
v.Frame = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := g.SetView("table", 0, chartHeight+1, maxX, maxY); err != nil {
|
||||||
|
if err != gocui.ErrUnknownView {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Highlight = true
|
||||||
|
v.SelBgColor = gocui.ColorCyan
|
||||||
|
v.SelFgColor = gocui.ColorBlack
|
||||||
|
v.Frame = false
|
||||||
|
ct.tableview = v
|
||||||
|
ct.setTable()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *Cointop) setChart() error {
|
||||||
|
maxX, _ := ct.g.Size()
|
||||||
|
if len(ct.chartpoints) == 0 {
|
||||||
|
ct.chartPoints(maxX, "bitcoin")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range ct.chartpoints {
|
||||||
|
var s string
|
||||||
|
for j := range ct.chartpoints[i] {
|
||||||
|
p := ct.chartpoints[i][j]
|
||||||
|
s = fmt.Sprintf("%s%c", s, p.Ch)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(ct.chartview, s)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *Cointop) setTable() error {
|
||||||
|
maxX, _ := ct.g.Size()
|
||||||
|
ct.table = table.New().SetWidth(maxX)
|
||||||
|
ct.table.AddCol("")
|
||||||
|
ct.table.AddCol("")
|
||||||
|
ct.table.AddCol("")
|
||||||
|
ct.table.AddCol("")
|
||||||
|
ct.table.AddCol("")
|
||||||
|
ct.table.AddCol("")
|
||||||
|
ct.table.AddCol("")
|
||||||
|
ct.table.AddCol("")
|
||||||
|
ct.table.AddCol("")
|
||||||
|
ct.table.AddCol("")
|
||||||
|
ct.table.AddCol("")
|
||||||
|
ct.table.AddCol("")
|
||||||
|
ct.table.HideColumHeaders = true
|
||||||
|
var err error
|
||||||
|
if len(ct.coins) == 0 {
|
||||||
|
ct.coins, err = fetchData()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, coin := range ct.coins {
|
||||||
|
unix, _ := strconv.ParseInt(coin.LastUpdated, 10, 64)
|
||||||
|
lastUpdated := time.Unix(unix, 0).Format("15:04:05 Jan 02")
|
||||||
|
colorprice := cyan
|
||||||
|
color1h := white
|
||||||
|
color24h := white
|
||||||
|
color7d := white
|
||||||
|
if coin.PercentChange1H > 0 {
|
||||||
|
color1h = green
|
||||||
|
}
|
||||||
|
if coin.PercentChange1H < 0 {
|
||||||
|
color1h = red
|
||||||
|
}
|
||||||
|
if coin.PercentChange24H > 0 {
|
||||||
|
color24h = green
|
||||||
|
}
|
||||||
|
if coin.PercentChange24H < 0 {
|
||||||
|
color24h = red
|
||||||
|
}
|
||||||
|
if coin.PercentChange7D > 0 {
|
||||||
|
color7d = green
|
||||||
|
}
|
||||||
|
if coin.PercentChange7D < 0 {
|
||||||
|
color7d = red
|
||||||
|
}
|
||||||
|
ct.table.AddRow(
|
||||||
|
pad.Left(fmt.Sprint(coin.Rank), 4, " "),
|
||||||
|
pad.Right(coin.Name, 22, " "),
|
||||||
|
pad.Right(coin.Symbol, 6, " "),
|
||||||
|
colorprice(pad.Left(humanize.Commaf(coin.PriceUSD), 12, " ")),
|
||||||
|
pad.Left(humanize.Commaf(coin.MarketCapUSD), 17, " "),
|
||||||
|
pad.Left(humanize.Commaf(coin.USD24HVolume), 15, " "),
|
||||||
|
color1h(pad.Left(fmt.Sprintf("%.2f%%", coin.PercentChange1H), 9, " ")),
|
||||||
|
color24h(pad.Left(fmt.Sprintf("%.2f%%", coin.PercentChange24H), 9, " ")),
|
||||||
|
color7d(pad.Left(fmt.Sprintf("%.2f%%", coin.PercentChange7D), 9, " ")),
|
||||||
|
pad.Left(humanize.Commaf(coin.TotalSupply), 20, " "),
|
||||||
|
pad.Left(humanize.Commaf(coin.AvailableSupply), 18, " "),
|
||||||
|
pad.Left(fmt.Sprintf("%s", lastUpdated), 18, " "),
|
||||||
|
// add %percent of cap
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ct.table.Format().Fprint(ct.tableview)
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,614 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"math"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/bradfitz/slice"
|
|
||||||
humanize "github.com/dustin/go-humanize"
|
|
||||||
"github.com/fatih/color"
|
|
||||||
"github.com/gizak/termui"
|
|
||||||
"github.com/jroimartin/gocui"
|
|
||||||
"github.com/miguelmota/cointop/table"
|
|
||||||
cmc "github.com/miguelmota/go-coinmarketcap"
|
|
||||||
"github.com/willf/pad"
|
|
||||||
)
|
|
||||||
|
|
||||||
var white = color.New(color.FgWhite).SprintFunc()
|
|
||||||
var cyan = color.New(color.FgCyan).SprintFunc()
|
|
||||||
var red = color.New(color.FgRed).SprintFunc()
|
|
||||||
var green = color.New(color.FgGreen).SprintFunc()
|
|
||||||
|
|
||||||
func fmtTime(v interface{}) string {
|
|
||||||
t := v.(time.Time)
|
|
||||||
return t.Format("2006-01-02 15:04:05")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ltTime(a interface{}, b interface{}) bool {
|
|
||||||
return a.(time.Time).Before(b.(time.Time))
|
|
||||||
}
|
|
||||||
|
|
||||||
func round(num float64) int {
|
|
||||||
return int(num + math.Copysign(0.5, num))
|
|
||||||
}
|
|
||||||
|
|
||||||
func toFixed(num float64, precision int) float64 {
|
|
||||||
output := math.Pow(10, float64(precision))
|
|
||||||
return float64(round(num*output)) / output
|
|
||||||
}
|
|
||||||
|
|
||||||
func chartCells(maxX int, coin string) [][]termui.Cell {
|
|
||||||
//_ = termui.Init()
|
|
||||||
//defer termui.Close()
|
|
||||||
|
|
||||||
// quit on Ctrl-c
|
|
||||||
/*
|
|
||||||
termui.Handle("/sys/kbd/C-c", func(termui.Event) {
|
|
||||||
termui.StopLoop()
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
chart := termui.NewLineChart()
|
|
||||||
//chart.DataLabels = []string{""}
|
|
||||||
chart.Height = 10
|
|
||||||
chart.AxesColor = termui.ColorWhite
|
|
||||||
chart.LineColor = termui.ColorCyan //| termui.AttrBold
|
|
||||||
chart.Border = false
|
|
||||||
|
|
||||||
var (
|
|
||||||
oneMinute int64 = 60
|
|
||||||
oneHour = oneMinute * 60
|
|
||||||
oneDay = oneHour * 24
|
|
||||||
//oneWeek = oneDay * 7
|
|
||||||
//oneMonth = oneDay * 30
|
|
||||||
//oneYear = oneDay * 365
|
|
||||||
)
|
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
secs := now.Unix()
|
|
||||||
start := secs - oneDay
|
|
||||||
end := secs
|
|
||||||
|
|
||||||
_ = coin
|
|
||||||
//graphData, err := cmc.GetCoinGraphData(coin, start, end)
|
|
||||||
graphData, err := cmc.GetGlobalMarketGraphData(start, end)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var data []float64
|
|
||||||
/*
|
|
||||||
for i := range graphData.PriceUSD {
|
|
||||||
data = append(data, graphData.PriceUSD[i][1])
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
for i := range graphData.MarketCapByAvailableSupply {
|
|
||||||
data = append(data, graphData.MarketCapByAvailableSupply[i][1])
|
|
||||||
}
|
|
||||||
chart.Data = data
|
|
||||||
//h := chart.InnerHeight()
|
|
||||||
//w := chart.InnerWidth()
|
|
||||||
|
|
||||||
// add grid rows and columns
|
|
||||||
termui.Body = termui.NewGrid()
|
|
||||||
//termui.Body.Rows = termui.Body.Rows[:0]
|
|
||||||
termui.Body.Width = maxX
|
|
||||||
termui.Body.AddRows(
|
|
||||||
termui.NewRow(
|
|
||||||
termui.NewCol(12, 0, chart),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
var points [][]termui.Cell
|
|
||||||
|
|
||||||
// calculate layout
|
|
||||||
termui.Body.Align()
|
|
||||||
// render to terminal
|
|
||||||
//termui.Render(termui.Body)
|
|
||||||
w := termui.Body.Width
|
|
||||||
h := 10
|
|
||||||
row := termui.Body.Rows[0]
|
|
||||||
b := row.Buffer()
|
|
||||||
for i := 0; i < h; i = i + 1 {
|
|
||||||
var rowpoints []termui.Cell
|
|
||||||
for j := 0; j < w; j = j + 1 {
|
|
||||||
_ = b
|
|
||||||
p := b.At(j, i)
|
|
||||||
c := p
|
|
||||||
rowpoints = append(rowpoints, c)
|
|
||||||
}
|
|
||||||
points = append(points, rowpoints)
|
|
||||||
}
|
|
||||||
//termui.Loop()
|
|
||||||
|
|
||||||
return points
|
|
||||||
}
|
|
||||||
|
|
||||||
var points [][]termui.Cell
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
g, err := gocui.NewGui(gocui.Output256)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("new gocui: %v", err)
|
|
||||||
}
|
|
||||||
defer g.Close()
|
|
||||||
|
|
||||||
g.Cursor = true
|
|
||||||
g.Mouse = true
|
|
||||||
g.Highlight = true
|
|
||||||
g.SetManagerFunc(layout)
|
|
||||||
|
|
||||||
if err := keybindings(g); err != nil {
|
|
||||||
log.Fatalf("keybindings: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
|
|
||||||
log.Fatalf("main loop: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func quit(g *gocui.Gui, v *gocui.View) error {
|
|
||||||
return gocui.ErrQuit
|
|
||||||
}
|
|
||||||
|
|
||||||
func keybindings(g *gocui.Gui) error {
|
|
||||||
if err := g.SetKeybinding("", gocui.KeyArrowDown, gocui.ModNone, cursorDown); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := g.SetKeybinding("", 'j', gocui.ModNone, cursorDown); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := g.SetKeybinding("", gocui.KeyArrowUp, gocui.ModNone, cursorUp); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := g.SetKeybinding("", 'k', gocui.ModNone, cursorUp); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := g.SetKeybinding("", gocui.KeyCtrlD, gocui.ModNone, pageDown); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := g.SetKeybinding("", gocui.KeyCtrlU, gocui.ModNone, pageUp); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := g.SetKeybinding("", 'r', gocui.ModNone, sort("rank", false)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := g.SetKeybinding("", 'n', gocui.ModNone, sort("name", true)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := g.SetKeybinding("", 's', gocui.ModNone, sort("symbol", false)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := g.SetKeybinding("", 'p', gocui.ModNone, sort("price", true)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := g.SetKeybinding("", 'm', gocui.ModNone, sort("marketcap", true)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := g.SetKeybinding("", 'v', gocui.ModNone, sort("24hvolume", true)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := g.SetKeybinding("", '1', gocui.ModNone, sort("1hchange", true)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := g.SetKeybinding("", '2', gocui.ModNone, sort("24hchange", true)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := g.SetKeybinding("", '7', gocui.ModNone, sort("7dchange", true)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := g.SetKeybinding("", 't', gocui.ModNone, sort("totalsupply", true)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := g.SetKeybinding("", 'a', gocui.ModNone, sort("availablesupply", true)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := g.SetKeybinding("", 'l', gocui.ModNone, sort("lastupdated", true)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := g.SetKeybinding("", 'q', gocui.ModNone, quit); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := g.SetKeybinding("", gocui.KeyEsc, gocui.ModNone, quit); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type strategy func(g *gocui.Gui, v *gocui.View) error
|
|
||||||
|
|
||||||
var sortDesc bool
|
|
||||||
var currentsort string
|
|
||||||
|
|
||||||
func sort(sortBy string, desc bool) strategy {
|
|
||||||
return func(g *gocui.Gui, v *gocui.View) error {
|
|
||||||
|
|
||||||
if currentsort == sortBy {
|
|
||||||
sortDesc = !sortDesc
|
|
||||||
} else {
|
|
||||||
currentsort = sortBy
|
|
||||||
sortDesc = desc
|
|
||||||
}
|
|
||||||
|
|
||||||
slice.Sort(coins[:], func(i, j int) bool {
|
|
||||||
if sortDesc == true {
|
|
||||||
i, j = j, i
|
|
||||||
}
|
|
||||||
a := coins[i]
|
|
||||||
b := coins[j]
|
|
||||||
switch sortBy {
|
|
||||||
case "rank":
|
|
||||||
return a.Rank < b.Rank
|
|
||||||
case "name":
|
|
||||||
return a.Name < b.Name
|
|
||||||
case "symbol":
|
|
||||||
return a.Symbol < b.Symbol
|
|
||||||
case "price":
|
|
||||||
return a.PriceUSD < b.PriceUSD
|
|
||||||
case "marketcap":
|
|
||||||
return a.MarketCapUSD < b.MarketCapUSD
|
|
||||||
case "24hvolume":
|
|
||||||
return a.USD24HVolume < b.USD24HVolume
|
|
||||||
case "1hchange":
|
|
||||||
return a.PercentChange1H < b.PercentChange1H
|
|
||||||
case "24hchange":
|
|
||||||
return a.PercentChange24H < b.PercentChange24H
|
|
||||||
case "7dchange":
|
|
||||||
return a.PercentChange7D < b.PercentChange7D
|
|
||||||
case "totalsupply":
|
|
||||||
return a.TotalSupply < b.TotalSupply
|
|
||||||
case "availablesupply":
|
|
||||||
return a.AvailableSupply < b.AvailableSupply
|
|
||||||
case "lastupdated":
|
|
||||||
return a.LastUpdated < b.LastUpdated
|
|
||||||
default:
|
|
||||||
return a.Rank < b.Rank
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
g.Update(func(g *gocui.Gui) error {
|
|
||||||
v, _ = g.View("table")
|
|
||||||
v.Clear()
|
|
||||||
setTable(g)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
g.Update(func(g *gocui.Gui) error {
|
|
||||||
v, _ = g.View("chart")
|
|
||||||
v.Clear()
|
|
||||||
|
|
||||||
maxX, _ := g.Size()
|
|
||||||
_, cy := v.Cursor()
|
|
||||||
coin := "ethereum"
|
|
||||||
points = chartCells(maxX, coin)
|
|
||||||
setChart(g, v)
|
|
||||||
fmt.Fprint(v, cy)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var coins []*cmc.Coin
|
|
||||||
|
|
||||||
func cursorDown(g *gocui.Gui, v *gocui.View) error {
|
|
||||||
v, _ = g.View("table")
|
|
||||||
if v != nil {
|
|
||||||
_, y := v.Origin()
|
|
||||||
cx, cy := v.Cursor()
|
|
||||||
numRows := len(coins) - 1
|
|
||||||
//fmt.Fprint(v, cy)
|
|
||||||
if (cy + y + 1) > numRows {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err := v.SetCursor(cx, cy+1); err != nil {
|
|
||||||
ox, oy := v.Origin()
|
|
||||||
if err := v.SetOrigin(ox, oy+1); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func cursorUp(g *gocui.Gui, v *gocui.View) error {
|
|
||||||
v, _ = g.View("table")
|
|
||||||
if v != nil {
|
|
||||||
ox, oy := v.Origin()
|
|
||||||
cx, cy := v.Cursor()
|
|
||||||
//fmt.Fprint(v, oy)
|
|
||||||
if err := v.SetCursor(cx, cy-1); err != nil && oy > 0 {
|
|
||||||
if err := v.SetOrigin(ox, oy-1); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func pageDown(g *gocui.Gui, v *gocui.View) error {
|
|
||||||
v, _ = g.View("table")
|
|
||||||
if v != nil {
|
|
||||||
_, y := v.Origin()
|
|
||||||
cx, cy := v.Cursor()
|
|
||||||
numRows := len(coins) - 1
|
|
||||||
_, sy := v.Size()
|
|
||||||
rows := sy
|
|
||||||
if (cy + y + rows) > numRows {
|
|
||||||
// go to last row
|
|
||||||
v.SetCursor(cx, numRows)
|
|
||||||
ox, _ := v.Origin()
|
|
||||||
v.SetOrigin(ox, numRows)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err := v.SetCursor(cx, cy+rows); err != nil {
|
|
||||||
ox, oy := v.Origin()
|
|
||||||
if err := v.SetOrigin(ox, oy+rows); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func pageUp(g *gocui.Gui, v *gocui.View) error {
|
|
||||||
v, _ = g.View("table")
|
|
||||||
if v != nil {
|
|
||||||
ox, oy := v.Origin()
|
|
||||||
cx, cy := v.Cursor()
|
|
||||||
_, sy := v.Size()
|
|
||||||
rows := sy
|
|
||||||
//fmt.Fprint(v, oy)
|
|
||||||
if err := v.SetCursor(cx, cy-rows); err != nil && oy > 0 {
|
|
||||||
if err := v.SetOrigin(ox, oy-rows); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchData() ([]*cmc.Coin, error) {
|
|
||||||
limit := 100
|
|
||||||
result := []*cmc.Coin{}
|
|
||||||
coins, err := cmc.GetAllCoinData(int(limit))
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range coins {
|
|
||||||
coin := coins[i]
|
|
||||||
result = append(result, &coin)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func layout(g *gocui.Gui) error {
|
|
||||||
maxX, maxY := g.Size()
|
|
||||||
|
|
||||||
chartHeight := 10
|
|
||||||
if v, err := g.SetView("chart", 0, 0, maxX, chartHeight); err != nil {
|
|
||||||
if err != gocui.ErrUnknownView {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
//v.Frame = false
|
|
||||||
setChart(g, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if v, err := g.SetView("header", 0, chartHeight, maxX, maxY); err != nil {
|
|
||||||
if err != gocui.ErrUnknownView {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
t := table.New().SetWidth(maxX)
|
|
||||||
|
|
||||||
headers := []string{
|
|
||||||
pad.Right("[r]ank", 13, " "),
|
|
||||||
pad.Right("[n]ame", 13, " "),
|
|
||||||
pad.Right("[s]ymbol", 8, " "),
|
|
||||||
pad.Left("[p]rice", 10, " "),
|
|
||||||
pad.Left("[m]arket cap", 17, " "),
|
|
||||||
pad.Left("24H [v]olume", 15, " "),
|
|
||||||
pad.Left("[1]H%", 9, " "),
|
|
||||||
pad.Left("[2]4H%", 9, " "),
|
|
||||||
pad.Left("[7]D%", 9, " "),
|
|
||||||
pad.Left("[t]otal supply", 20, " "),
|
|
||||||
pad.Left("[a]vailable supply", 19, " "),
|
|
||||||
pad.Left("[l]ast updated", 17, " "),
|
|
||||||
}
|
|
||||||
for _, h := range headers {
|
|
||||||
t.AddCol(h)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Format().Fprint(v)
|
|
||||||
v.Highlight = true
|
|
||||||
v.SelBgColor = gocui.ColorGreen
|
|
||||||
v.SelFgColor = gocui.ColorBlack
|
|
||||||
v.Frame = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if v, err := g.SetView("table", 0, chartHeight+1, maxX, maxY); err != nil {
|
|
||||||
if err != gocui.ErrUnknownView {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_ = v
|
|
||||||
_ = maxY
|
|
||||||
setTable(g)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setChart(g *gocui.Gui, v *gocui.View) error {
|
|
||||||
v.Frame = false
|
|
||||||
/*
|
|
||||||
tm.Clear()
|
|
||||||
tm.MoveCursor(0, 0)
|
|
||||||
chart := tm.NewLineChart(maxX/2, 9)
|
|
||||||
//chart.Flags = tm.DRAW_INDEPENDENT
|
|
||||||
chart.Flags = tm.DRAW_RELATIVE
|
|
||||||
data := new(tm.DataTable)
|
|
||||||
data.AddColumn("")
|
|
||||||
data.AddColumn("")
|
|
||||||
|
|
||||||
var (
|
|
||||||
oneMinute int64 = 60
|
|
||||||
oneHour = oneMinute * 60
|
|
||||||
oneDay = oneHour * 24
|
|
||||||
//oneWeek = oneDay * 7
|
|
||||||
oneMonth = oneDay * 30
|
|
||||||
//oneYear = oneDay * 365
|
|
||||||
)
|
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
secs := now.Unix()
|
|
||||||
//start := secs - oneDay
|
|
||||||
start := secs - oneMonth
|
|
||||||
end := secs
|
|
||||||
|
|
||||||
coin := "ethereum"
|
|
||||||
graphData, err := cmc.GetCoinGraphData(coin, start, end)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var dt []float64
|
|
||||||
for i := range graphData.PriceUSD {
|
|
||||||
dt = append(dt, graphData.PriceUSD[i][1])
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, d := range dt {
|
|
||||||
_ = d
|
|
||||||
_ = i
|
|
||||||
data.AddRow(float64(i), d)
|
|
||||||
}
|
|
||||||
_ = dt
|
|
||||||
|
|
||||||
out := chart.Draw(data, []int{0, 6})
|
|
||||||
fmt.Fprint(v, out)
|
|
||||||
//tm.Println(out)
|
|
||||||
var buf bytes.Buffer
|
|
||||||
tm.Output = bufio.NewWriter(&buf)
|
|
||||||
//tm.Output = bufio.NewWriter(v)
|
|
||||||
_ = buf
|
|
||||||
tm.Flush()
|
|
||||||
_ = v
|
|
||||||
//buf.WriteTo(v)
|
|
||||||
//buf.WriteTo(os.Stdout)
|
|
||||||
*/
|
|
||||||
|
|
||||||
maxX, _ := g.Size()
|
|
||||||
if len(points) == 0 {
|
|
||||||
points = chartCells(maxX, "bitcoin")
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range points {
|
|
||||||
var s string
|
|
||||||
for j := range points[i] {
|
|
||||||
p := points[i][j]
|
|
||||||
s = fmt.Sprintf("%s%c", s, p.Ch)
|
|
||||||
}
|
|
||||||
fmt.Fprintln(v, s)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setTable(g *gocui.Gui) error {
|
|
||||||
maxX, _ := g.Size()
|
|
||||||
v, _ := g.View("table")
|
|
||||||
t := table.New().SetWidth(maxX)
|
|
||||||
|
|
||||||
t.AddCol("")
|
|
||||||
t.AddCol("")
|
|
||||||
t.AddCol("")
|
|
||||||
t.AddCol("")
|
|
||||||
t.AddCol("")
|
|
||||||
t.AddCol("")
|
|
||||||
t.AddCol("")
|
|
||||||
t.AddCol("")
|
|
||||||
t.AddCol("")
|
|
||||||
t.AddCol("")
|
|
||||||
t.AddCol("")
|
|
||||||
t.AddCol("")
|
|
||||||
t.HideColumHeaders = true
|
|
||||||
|
|
||||||
var err error
|
|
||||||
if len(coins) == 0 {
|
|
||||||
coins, err = fetchData()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, coin := range coins {
|
|
||||||
unix, _ := strconv.ParseInt(coin.LastUpdated, 10, 64)
|
|
||||||
lastUpdated := time.Unix(unix, 0).Format("15:04:05 Jan 02")
|
|
||||||
colorprice := cyan
|
|
||||||
color1h := white
|
|
||||||
color24h := white
|
|
||||||
color7d := white
|
|
||||||
if coin.PercentChange1H > 0 {
|
|
||||||
color1h = green
|
|
||||||
}
|
|
||||||
if coin.PercentChange1H < 0 {
|
|
||||||
color1h = red
|
|
||||||
}
|
|
||||||
if coin.PercentChange24H > 0 {
|
|
||||||
color24h = green
|
|
||||||
}
|
|
||||||
if coin.PercentChange24H < 0 {
|
|
||||||
color24h = red
|
|
||||||
}
|
|
||||||
if coin.PercentChange7D > 0 {
|
|
||||||
color7d = green
|
|
||||||
}
|
|
||||||
if coin.PercentChange7D < 0 {
|
|
||||||
color7d = red
|
|
||||||
}
|
|
||||||
_ = color7d
|
|
||||||
t.AddRow(
|
|
||||||
pad.Left(fmt.Sprint(coin.Rank), 4, " "),
|
|
||||||
pad.Right(coin.Name, 22, " "),
|
|
||||||
pad.Right(coin.Symbol, 6, " "),
|
|
||||||
colorprice(pad.Left(humanize.Commaf(coin.PriceUSD), 12, " ")),
|
|
||||||
pad.Left(humanize.Commaf(coin.MarketCapUSD), 17, " "),
|
|
||||||
pad.Left(humanize.Commaf(coin.USD24HVolume), 15, " "),
|
|
||||||
color1h(pad.Left(fmt.Sprintf("%.2f%%", coin.PercentChange1H), 9, " ")),
|
|
||||||
color24h(pad.Left(fmt.Sprintf("%.2f%%", coin.PercentChange24H), 9, " ")),
|
|
||||||
color7d(pad.Left(fmt.Sprintf("%.2f%%", coin.PercentChange7D), 9, " ")),
|
|
||||||
pad.Left(humanize.Commaf(coin.TotalSupply), 20, " "),
|
|
||||||
pad.Left(humanize.Commaf(coin.AvailableSupply), 18, " "),
|
|
||||||
pad.Left(fmt.Sprintf("%s", lastUpdated), 18, " "),
|
|
||||||
// add %percent of cap
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
//t.SortAsc("Name").SortDesc("Age").Sort().Format().Fprint(v)
|
|
||||||
t.Format().Fprint(v)
|
|
||||||
//v.Editable = true
|
|
||||||
//v.SetCursor(0, 2)
|
|
||||||
v.Highlight = true
|
|
||||||
v.SelBgColor = gocui.ColorCyan
|
|
||||||
v.SelFgColor = gocui.ColorBlack
|
|
||||||
v.Frame = false
|
|
||||||
//v.Autoscroll = true
|
|
||||||
|
|
||||||
//buffer := ln.Buffer()
|
|
||||||
//buffer.
|
|
||||||
|
|
||||||
// Sort by time
|
|
||||||
// t.SortAscFn("Created", ltTime).Sort().Format().Fprint(v)
|
|
||||||
return nil
|
|
||||||
}
|
|
Loading…
Reference in New Issue