|
|
|
@ -18,21 +18,32 @@ var chartpointslock sync.Mutex
|
|
|
|
|
func (ct *Cointop) updateChart() error {
|
|
|
|
|
chartlock.Lock()
|
|
|
|
|
defer chartlock.Unlock()
|
|
|
|
|
maxX := ct.maxtablewidth - 3
|
|
|
|
|
coin := ct.selectedCoinSymbol()
|
|
|
|
|
ct.chartPoints(maxX, coin)
|
|
|
|
|
|
|
|
|
|
if ct.portfoliovisible {
|
|
|
|
|
if err := ct.portfolioChart(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
coin := ct.selectedCoinSymbol()
|
|
|
|
|
ct.chartPoints(coin)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(ct.chartpoints) != 0 {
|
|
|
|
|
ct.chartview.Clear()
|
|
|
|
|
}
|
|
|
|
|
var body string
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
body = fmt.Sprintf("%s%s\n", body, s)
|
|
|
|
|
if len(ct.chartpoints) == 0 {
|
|
|
|
|
body = "\n\n\n\n\nnot enough data for chart"
|
|
|
|
|
} else {
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
body = fmt.Sprintf("%s%s\n", body, s)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ct.update(func() {
|
|
|
|
|
fmt.Fprint(ct.chartview, color.White(body))
|
|
|
|
@ -41,10 +52,11 @@ func (ct *Cointop) updateChart() error {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ct *Cointop) chartPoints(maxX int, coin string) error {
|
|
|
|
|
func (ct *Cointop) chartPoints(coin string) error {
|
|
|
|
|
maxX := ct.maxtablewidth - 3
|
|
|
|
|
chartpointslock.Lock()
|
|
|
|
|
defer chartpointslock.Unlock()
|
|
|
|
|
// TODO: not do this (SOC)
|
|
|
|
|
// TODO: not do this (SoC)
|
|
|
|
|
go ct.updateMarketbar()
|
|
|
|
|
|
|
|
|
|
chart := termui.NewLineChart()
|
|
|
|
@ -136,6 +148,114 @@ func (ct *Cointop) chartPoints(maxX int, coin string) error {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ct *Cointop) portfolioChart() error {
|
|
|
|
|
maxX := ct.maxtablewidth - 3
|
|
|
|
|
chartpointslock.Lock()
|
|
|
|
|
defer chartpointslock.Unlock()
|
|
|
|
|
// TODO: not do this (SoC)
|
|
|
|
|
go ct.updateMarketbar()
|
|
|
|
|
|
|
|
|
|
chart := termui.NewLineChart()
|
|
|
|
|
chart.Height = 10
|
|
|
|
|
chart.AxesColor = termui.ColorWhite
|
|
|
|
|
chart.LineColor = termui.ColorCyan
|
|
|
|
|
chart.Border = false
|
|
|
|
|
|
|
|
|
|
rangeseconds := ct.chartrangesmap[ct.selectedchartrange]
|
|
|
|
|
if ct.selectedchartrange == "YTD" {
|
|
|
|
|
ytd := time.Now().Unix() - int64(now.BeginningOfYear().Unix())
|
|
|
|
|
rangeseconds = time.Duration(ytd) * time.Second
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
now := time.Now()
|
|
|
|
|
nowseconds := now.Unix()
|
|
|
|
|
start := nowseconds - int64(rangeseconds.Seconds())
|
|
|
|
|
end := nowseconds
|
|
|
|
|
|
|
|
|
|
var data []float64
|
|
|
|
|
portfolio := ct.getPortfolioSlice()
|
|
|
|
|
chartname := ct.selectedCoinName()
|
|
|
|
|
for _, p := range portfolio {
|
|
|
|
|
// filter by selected chart if selected
|
|
|
|
|
if chartname != "" {
|
|
|
|
|
if chartname != p.Name {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if p.Holdings <= 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var graphData []float64
|
|
|
|
|
coin := p.Symbol
|
|
|
|
|
cachekey := strings.ToLower(fmt.Sprintf("%s_%s", coin, strings.Replace(ct.selectedchartrange, " ", "", -1)))
|
|
|
|
|
cached, found := ct.cache.Get(cachekey)
|
|
|
|
|
if found {
|
|
|
|
|
// cache hit
|
|
|
|
|
graphData, _ = cached.([]float64)
|
|
|
|
|
ct.debuglog("soft cache hit")
|
|
|
|
|
} else {
|
|
|
|
|
_ = fcache.Get(cachekey, &graphData)
|
|
|
|
|
|
|
|
|
|
if len(graphData) == 0 {
|
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
|
apiGraphData, err := ct.api.GetCoinGraphData(coin, start, end)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
for i := range apiGraphData.PriceUSD {
|
|
|
|
|
price := apiGraphData.PriceUSD[i][1]
|
|
|
|
|
graphData = append(graphData, price)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ct.cache.Set(cachekey, graphData, 10*time.Second)
|
|
|
|
|
go func() {
|
|
|
|
|
_ = fcache.Set(cachekey, graphData, 24*time.Hour)
|
|
|
|
|
}()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i := range graphData {
|
|
|
|
|
price := graphData[i]
|
|
|
|
|
sum := p.Holdings * price
|
|
|
|
|
if len(data)-1 >= i {
|
|
|
|
|
data[i] += sum
|
|
|
|
|
}
|
|
|
|
|
data = append(data, sum)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 (ct *Cointop) nextChartRange() error {
|
|
|
|
|
sel := 0
|
|
|
|
|
max := len(ct.chartranges)
|
|
|
|
@ -209,7 +329,8 @@ func (ct *Cointop) toggleCoinChart() error {
|
|
|
|
|
} else {
|
|
|
|
|
ct.selectedcoin = highlightedcoin
|
|
|
|
|
}
|
|
|
|
|
ct.updateChart()
|
|
|
|
|
ct.updateMarketbar()
|
|
|
|
|
|
|
|
|
|
go ct.updateChart()
|
|
|
|
|
go ct.updateMarketbar()
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|