From 7fa0af0fa34064989a6cf589739060b44c0fc15d Mon Sep 17 00:00:00 2001 From: Miguel Mota Date: Sat, 6 Feb 2021 18:28:06 -0800 Subject: [PATCH] Add 30 day percent change column --- cointop/actions.go | 1 + cointop/coin.go | 1 + cointop/coins_table.go | 38 ++++++++++++++++++++++++++++- cointop/config.go | 6 ++--- cointop/default_shortcuts.go | 1 + cointop/keybindings.go | 2 ++ cointop/list.go | 2 ++ cointop/portfolio.go | 37 +++++++++++++++++++++++++++- cointop/sort.go | 2 ++ cointop/table_header.go | 5 ++++ pkg/api/impl/coingecko/coingecko.go | 14 ++++++++--- pkg/api/types/types.go | 1 + 12 files changed, 102 insertions(+), 8 deletions(-) diff --git a/cointop/actions.go b/cointop/actions.go index ac9a53c..5092a07 100644 --- a/cointop/actions.go +++ b/cointop/actions.go @@ -27,6 +27,7 @@ func ActionsMap() map[string]bool { "sort_column_24h_change": true, "sort_column_24h_volume": true, "sort_column_7d_change": true, + "sort_column_30d_change": true, "sort_column_asc": true, "sort_column_available_supply": true, "sort_column_desc": true, diff --git a/cointop/coin.go b/cointop/coin.go index 8ec776a..da749a4 100644 --- a/cointop/coin.go +++ b/cointop/coin.go @@ -15,6 +15,7 @@ type Coin struct { PercentChange1H float64 PercentChange24H float64 PercentChange7D float64 + PercentChange30D float64 LastUpdated string // for favorites Favorite bool diff --git a/cointop/coins_table.go b/cointop/coins_table.go index 3a62f77..1cf8070 100644 --- a/cointop/coins_table.go +++ b/cointop/coins_table.go @@ -9,6 +9,23 @@ import ( "github.com/miguelmota/cointop/pkg/table" ) +// SupportedCoinTableHeaders are all the supported coin table header columns +var SupportedCoinTableHeaders = []string{ + "rank", + "name", + "symbol", + "price", + "1h_change", + "24h_change", + "7d_change", + "30d_change", + "24h_volume", + "market_cap", + "total_supply", + "available_supply", + "last_updated", +} + // DefaultCoinTableHeaders are the default coin table header columns var DefaultCoinTableHeaders = []string{ "rank", @@ -27,7 +44,7 @@ var DefaultCoinTableHeaders = []string{ // ValidCoinsTableHeader returns true if it's a valid table header name func (ct *Cointop) ValidCoinsTableHeader(name string) bool { - for _, v := range DefaultCoinTableHeaders { + for _, v := range SupportedCoinTableHeaders { if v == name { return true } @@ -183,6 +200,25 @@ func (ct *Cointop) GetCoinsTable() *table.Table { Color: color7d, Text: text, }) + case "30d_change": + color30d := ct.colorscheme.TableColumnChange + if coin.PercentChange30D > 0 { + color30d = ct.colorscheme.TableColumnChangeUp + } + if coin.PercentChange30D < 0 { + color30d = ct.colorscheme.TableColumnChangeDown + } + text := fmt.Sprintf("%.2f%%", coin.PercentChange30D) + ct.SetTableColumnWidthFromString(header, text) + ct.SetTableColumnAlignLeft(header, false) + rowCells = append(rowCells, + &table.RowCell{ + LeftMargin: leftMargin, + RightMargin: rightMargin, + LeftAlign: false, + Color: color30d, + Text: text, + }) case "market_cap": text := humanize.Commaf(coin.MarketCap) ct.SetTableColumnWidthFromString(header, text) diff --git a/cointop/config.go b/cointop/config.go index a6127db..8295088 100644 --- a/cointop/config.go +++ b/cointop/config.go @@ -319,7 +319,7 @@ func (ct *Cointop) loadTableColumnsFromConfig() error { for _, ifc := range ifcs { if v, ok := ifc.(string); ok { if !ct.ValidCoinsTableHeader(v) { - return fmt.Errorf("invalid table header name %q. Valid names are: %s", v, strings.Join(DefaultCoinTableHeaders, ",")) + return fmt.Errorf("invalid table header name %q. Valid names are: %s", v, strings.Join(SupportedCoinTableHeaders, ",")) } columns = append(columns, v) } @@ -500,7 +500,7 @@ func (ct *Cointop) loadFavoritesFromConfig() error { continue } if !ct.ValidCoinsTableHeader(col) { - return fmt.Errorf("invalid table header name %q. Valid names are: %s", col, strings.Join(DefaultCoinTableHeaders, ",")) + return fmt.Errorf("invalid table header name %q. Valid names are: %s", col, strings.Join(SupportedCoinTableHeaders, ",")) } columns = append(columns, col) } @@ -524,7 +524,7 @@ func (ct *Cointop) loadPortfolioFromConfig() error { for _, ifc := range ifcs { if v, ok := ifc.(string); ok { if !ct.ValidPortfolioTableHeader(v) { - return fmt.Errorf("invalid table header name %q. Valid names are: %s", v, strings.Join(DefaultPortfolioTableHeaders, ",")) + return fmt.Errorf("invalid table header name %q. Valid names are: %s", v, strings.Join(SupportedPortfolioTableHeaders, ",")) } columns = append(columns, v) } diff --git a/cointop/default_shortcuts.go b/cointop/default_shortcuts.go index 2d819aa..cec8486 100644 --- a/cointop/default_shortcuts.go +++ b/cointop/default_shortcuts.go @@ -37,6 +37,7 @@ func DefaultShortcuts() map[string]string { "0": "first_page", "1": "sort_column_1h_change", "2": "sort_column_24h_change", + "3": "sort_column_30d_change", "7": "sort_column_7d_change", "a": "sort_column_available_supply", "b": "sort_column_balance", diff --git a/cointop/keybindings.go b/cointop/keybindings.go index 0b8ada9..fa4056a 100644 --- a/cointop/keybindings.go +++ b/cointop/keybindings.go @@ -225,6 +225,8 @@ func (ct *Cointop) Keybindings(g *gocui.Gui) error { fn = ct.Sortfn("24h_change", true) case "sort_column_7d_change": fn = ct.Sortfn("7d_change", true) + case "sort_column_30d_change": + fn = ct.Sortfn("30d_change", true) case "sort_column_available_supply": fn = ct.Sortfn("available_supply", true) case "toggle_row_chart": diff --git a/cointop/list.go b/cointop/list.go index 8d69f77..0bd3882 100644 --- a/cointop/list.go +++ b/cointop/list.go @@ -90,6 +90,7 @@ func (ct *Cointop) processCoins(coins []types.Coin) { PercentChange1H: v.PercentChange1H, PercentChange24H: v.PercentChange24H, PercentChange7D: v.PercentChange7D, + PercentChange30D: v.PercentChange30D, LastUpdated: v.LastUpdated, }) if ilast != nil { @@ -139,6 +140,7 @@ func (ct *Cointop) processCoins(coins []types.Coin) { c.PercentChange1H = cm.PercentChange1H c.PercentChange24H = cm.PercentChange24H c.PercentChange7D = cm.PercentChange7D + c.PercentChange30D = cm.PercentChange30D c.LastUpdated = cm.LastUpdated c.Favorite = cm.Favorite } diff --git a/cointop/portfolio.go b/cointop/portfolio.go index 46bbf12..aa2c015 100644 --- a/cointop/portfolio.go +++ b/cointop/portfolio.go @@ -17,6 +17,22 @@ import ( "github.com/miguelmota/cointop/pkg/table" ) +// SupportedPortfolioTableHeaders are all the supported portfolio table header columns +var SupportedPortfolioTableHeaders = []string{ + "rank", + "name", + "symbol", + "price", + "holdings", + "balance", + "1h_change", + "24h_change", + "7d_change", + "30d_change", + "percent_holdings", + "last_updated", +} + // DefaultPortfolioTableHeaders are the default portfolio table header columns var DefaultPortfolioTableHeaders = []string{ "rank", @@ -34,7 +50,7 @@ var DefaultPortfolioTableHeaders = []string{ // ValidPortfolioTableHeader returns the portfolio table headers func (ct *Cointop) ValidPortfolioTableHeader(name string) bool { - for _, v := range DefaultPortfolioTableHeaders { + for _, v := range SupportedPortfolioTableHeaders { if v == name { return true } @@ -202,6 +218,25 @@ func (ct *Cointop) GetPortfolioTable() *table.Table { Color: color7d, Text: text, }) + case "30d_change": + color30d := ct.colorscheme.TableColumnChange + if coin.PercentChange30D > 0 { + color30d = ct.colorscheme.TableColumnChangeUp + } + if coin.PercentChange30D < 0 { + color30d = ct.colorscheme.TableColumnChangeDown + } + text := fmt.Sprintf("%.2f%%", coin.PercentChange30D) + ct.SetTableColumnWidthFromString(header, text) + ct.SetTableColumnAlignLeft(header, false) + rowCells = append(rowCells, + &table.RowCell{ + LeftMargin: leftMargin, + RightMargin: rightMargin, + LeftAlign: false, + Color: color30d, + Text: text, + }) case "percent_holdings": percentHoldings := (coin.Balance / total) * 1e2 if math.IsNaN(percentHoldings) { diff --git a/cointop/sort.go b/cointop/sort.go index 21f27be..e0bf77f 100644 --- a/cointop/sort.go +++ b/cointop/sort.go @@ -57,6 +57,8 @@ func (ct *Cointop) Sort(sortBy string, desc bool, list []*Coin, renderHeaders bo return a.PercentChange24H < b.PercentChange24H case "7d_change": return a.PercentChange7D < b.PercentChange7D + case "30d_change": + return a.PercentChange30D < b.PercentChange30D case "total_supply": return a.TotalSupply < b.TotalSupply case "available_supply": diff --git a/cointop/table_header.go b/cointop/table_header.go index bc16d1d..7452aea 100644 --- a/cointop/table_header.go +++ b/cointop/table_header.go @@ -90,6 +90,11 @@ var HeaderColumns = map[string]*HeaderColumn{ Label: "[7]D%", PlainLabel: "7D%", }, + "30d_change": &HeaderColumn{ + Slug: "30d_change", + Label: "[3]0D%", + PlainLabel: "30D%", + }, "total_supply": &HeaderColumn{ Slug: "total_supply", Label: "[t]otal supply", diff --git a/pkg/api/impl/coingecko/coingecko.go b/pkg/api/impl/coingecko/coingecko.go index 4e13e1b..6c55785 100644 --- a/pkg/api/impl/coingecko/coingecko.go +++ b/pkg/api/impl/coingecko/coingecko.go @@ -50,7 +50,12 @@ func (s *Service) getPaginatedCoinData(convert string, offset int, names []strin page := offset + 1 // page starts at 1 sparkline := false pcp := geckoTypes.PriceChangePercentageObject - priceChangePercentage := []string{pcp.PCP1h, pcp.PCP24h, pcp.PCP7d} + priceChangePercentage := []string{ + pcp.PCP1h, + pcp.PCP24h, + pcp.PCP7d, + pcp.PCP30d, + } order := geckoTypes.OrderTypeObject.MarketCapDesc convertTo := strings.ToLower(convert) if convertTo == "" { @@ -79,18 +84,20 @@ func (s *Service) getPaginatedCoinData(convert string, offset int, names []strin var percentChange1H float64 var percentChange24H float64 var percentChange7D float64 + var percentChange30D float64 if item.PriceChangePercentage1hInCurrency != nil { percentChange1H = *item.PriceChangePercentage1hInCurrency } - if item.PriceChangePercentage24hInCurrency != nil { percentChange24H = *item.PriceChangePercentage24hInCurrency } - if item.PriceChangePercentage7dInCurrency != nil { percentChange7D = *item.PriceChangePercentage7dInCurrency } + if item.PriceChangePercentage30dInCurrency != nil { + percentChange30D = *item.PriceChangePercentage30dInCurrency + } availableSupply := item.CirculatingSupply totalSupply := item.TotalSupply @@ -110,6 +117,7 @@ func (s *Service) getPaginatedCoinData(convert string, offset int, names []strin PercentChange1H: util.FormatPercentChange(percentChange1H), PercentChange24H: util.FormatPercentChange(percentChange24H), PercentChange7D: util.FormatPercentChange(percentChange7D), + PercentChange30D: util.FormatPercentChange(percentChange30D), Volume24H: util.FormatVolume(item.TotalVolume), LastUpdated: util.FormatLastUpdated(item.LastUpdated), }) diff --git a/pkg/api/types/types.go b/pkg/api/types/types.go index 6be1e4f..b474eba 100644 --- a/pkg/api/types/types.go +++ b/pkg/api/types/types.go @@ -14,6 +14,7 @@ type Coin struct { PercentChange1H float64 `json:"percentChange1H"` PercentChange24H float64 `json:"percentChange24H"` PercentChange7D float64 `json:"percentChange7D"` + PercentChange30D float64 `json:"percentChange30D"` LastUpdated string `json:"lastUpdated"` }