Skip to content

Commit

Permalink
Add configurable portfolio table columns
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelmota committed Jan 30, 2021
1 parent 23fe262 commit c36f3de
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 103 deletions.
106 changes: 72 additions & 34 deletions cointop/config.go
Expand Up @@ -58,9 +58,6 @@ func (ct *Cointop) SetupConfig() error {
if err := ct.loadTableColumnsFromConfig(); err != nil {
return err
}
if err := ct.loadPortfolioColumnsFromConfig(); err != nil {
return err
}
if err := ct.loadShortcutsFromConfig(); err != nil {
return err
}
Expand Down Expand Up @@ -241,6 +238,9 @@ func (ct *Cointop) configToToml() ([]byte, error) {
var tuple []string = []string{coinName, amount}
holdingsIfc = append(holdingsIfc, tuple)
}
sort.Slice(holdingsIfc, func(i, j int) bool {
return holdingsIfc[i][0] < holdingsIfc[j][0]
})
portfolioIfc["holdings"] = holdingsIfc

if reflect.DeepEqual(DefaultPortfolioTableHeaders, ct.State.portfolioTableColumns) {
Expand Down Expand Up @@ -338,11 +338,6 @@ func (ct *Cointop) loadTableColumnsFromConfig() error {
return nil
}

// LoadPortfolioColumnsFromConfig loads preferred portfolio table columns from config file to struct
func (ct *Cointop) loadPortfolioColumnsFromConfig() error {
return nil
}

// LoadShortcutsFromConfig loads keyboard shortcuts from config file to struct
func (ct *Cointop) loadShortcutsFromConfig() error {
ct.debuglog("loadShortcutsFromConfig()")
Expand Down Expand Up @@ -508,41 +503,88 @@ func (ct *Cointop) loadPortfolioFromConfig() error {

for key, valueIfc := range ct.config.Portfolio {
if key == "columns" {
}
if key == "holdings" {
holdingsIfc, ok := valueIfc.([][]interface{})
if !ok {
continue
}
fmt.Println(holdingsIfc)
}
}
/*
for name, holdingsIfc := range ct.config.Portfolio {
if name == "columns" {
continue
var columns []string
ifcs, ok := valueIfc.([]interface{})
if ok {
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, ","))
}
columns = append(columns, v)
}
}
if len(columns) > 0 {
ct.State.portfolioTableColumns = columns
}
}
if name == "holdings" {
} else if key == "holdings" {
holdingsIfc, ok := valueIfc.([]interface{})
if !ok {
continue
}

var holdings float64
var ok bool
if holdings, ok = holdingsIfc.(float64); !ok {
if holdingsInt, ok := holdingsIfc.(int64); ok {
holdings = float64(holdingsInt)
for _, itemIfc := range holdingsIfc {
tupleIfc, ok := itemIfc.([]interface{})
if !ok {
continue
}
if len(tupleIfc) > 2 {
continue
}
name, ok := tupleIfc[0].(string)
if !ok {
continue
}

holdings, err := ct.InterfaceToFloat64(tupleIfc[1])
if err != nil {
return nil
}

if err := ct.SetPortfolioEntry(name, holdings); err != nil {
return err
}
}
} else {
// Backward compatibility < v1.6.0
holdings, err := ct.InterfaceToFloat64(valueIfc)
if err != nil {
return err
}

if err := ct.SetPortfolioEntry(name, holdings); err != nil {
if err := ct.SetPortfolioEntry(key, holdings); err != nil {
return err
}
}
*/
}

return nil
}

// InterfaceToFloat64 attempts to convert interface to float64
func (ct *Cointop) InterfaceToFloat64(value interface{}) (float64, error) {
var num float64
var err error
switch v := value.(type) {
case string:
num, err = strconv.ParseFloat(v, 64)
if err != nil {
return 0, err
}
case int:
num = float64(v)
case int32:
num = float64(v)
case int64:
num = float64(v)
case float64:
num = v
}

return num, nil
}

// LoadPriceAlertsFromConfig loads price alerts from config file to struct
func (ct *Cointop) loadPriceAlertsFromConfig() error {
ct.debuglog("loadPriceAlertsFromConfig()")
Expand Down Expand Up @@ -570,11 +612,7 @@ func (ct *Cointop) loadPriceAlertsFromConfig() error {
if _, ok := PriceAlertOperatorMap[operator]; !ok {
return ErrInvalidPriceAlert
}
targetPriceStr, ok := priceAlert[2].(string)
if !ok {
return ErrInvalidPriceAlert
}
targetPrice, err := strconv.ParseFloat(targetPriceStr, 64)
targetPrice, err := ct.InterfaceToFloat64(priceAlert[2])
if err != nil {
return err
}
Expand Down
187 changes: 122 additions & 65 deletions cointop/portfolio.go
Expand Up @@ -26,7 +26,9 @@ var DefaultPortfolioTableHeaders = []string{
"price",
"holdings",
"balance",
"1h_change",
"24h_change",
"7d_change",
"percent_holdings",
"last_updated",
}
Expand Down Expand Up @@ -68,13 +70,27 @@ func (ct *Cointop) GetPortfolioTable() *table.Table {
}

colorbalance := ct.colorscheme.TableColumnPrice
color1h := ct.colorscheme.TableColumnChange
color24h := ct.colorscheme.TableColumnChange
color7d := ct.colorscheme.TableColumnChange
if coin.PercentChange1H > 0 {
color1h = ct.colorscheme.TableColumnChangeUp
}
if coin.PercentChange1H < 0 {
color1h = ct.colorscheme.TableColumnChangeDown
}
if coin.PercentChange24H > 0 {
color24h = ct.colorscheme.TableColumnChangeUp
}
if coin.PercentChange24H < 0 {
color24h = ct.colorscheme.TableColumnChangeDown
}
if coin.PercentChange7D > 0 {
color7d = ct.colorscheme.TableColumnChangeUp
}
if coin.PercentChange7D < 0 {
color7d = ct.colorscheme.TableColumnChangeDown
}

percentHoldings := (coin.Balance / total) * 1e2
if math.IsNaN(percentHoldings) {
Expand All @@ -83,71 +99,112 @@ func (ct *Cointop) GetPortfolioTable() *table.Table {
unix, _ := strconv.ParseInt(coin.LastUpdated, 10, 64)
lastUpdated := time.Unix(unix, 0).Format("15:04:05 Jan 02")

t.AddRowCells(
&table.RowCell{
LeftMargin: 0,
Width: 6,
LeftAlign: false,
Color: ct.colorscheme.Default,
Text: rank,
},
&table.RowCell{
LeftMargin: 1,
Width: 22,
LeftAlign: true,
Color: namecolor,
Text: name,
},
&table.RowCell{
LeftMargin: 1,
Width: 6,
LeftAlign: true,
Color: ct.colorscheme.TableRow,
Text: symbol,
},
&table.RowCell{
LeftMargin: 1,
Width: 14,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: humanize.Commaf(coin.Price),
},
&table.RowCell{
LeftMargin: 1,
Width: 16,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: strconv.FormatFloat(coin.Holdings, 'f', -1, 64),
},
&table.RowCell{
LeftMargin: 1,
Width: 16,
LeftAlign: false,
Color: colorbalance,
Text: humanize.Commaf(coin.Balance),
},
&table.RowCell{
LeftMargin: 1,
Width: 10,
LeftAlign: false,
Color: color24h,
Text: fmt.Sprintf("%.2f%%", coin.PercentChange24H),
},
&table.RowCell{
LeftMargin: 1,
Width: 14,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: fmt.Sprintf("%.2f%%", percentHoldings),
},
&table.RowCell{
LeftMargin: 1,
Width: 18,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: lastUpdated,
},
)
headers := ct.GetPortfolioTableHeaders()
var rowCells []*table.RowCell
for _, header := range headers {
switch header {
case "rank":
rowCells = append(rowCells, &table.RowCell{
LeftMargin: 0,
Width: 6,
LeftAlign: false,
Color: ct.colorscheme.Default,
Text: rank,
})
case "name":
rowCells = append(rowCells,
&table.RowCell{
LeftMargin: 1,
Width: 22,
LeftAlign: true,
Color: namecolor,
Text: name,
})
case "symbol":
rowCells = append(rowCells,
&table.RowCell{
LeftMargin: 1,
Width: 6,
LeftAlign: true,
Color: ct.colorscheme.TableRow,
Text: symbol,
})
case "price":
rowCells = append(rowCells,
&table.RowCell{
LeftMargin: 1,
Width: 14,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: humanize.Commaf(coin.Price),
})
case "holdings":
rowCells = append(rowCells,
&table.RowCell{
LeftMargin: 1,
Width: 16,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: strconv.FormatFloat(coin.Holdings, 'f', -1, 64),
})
case "balance":
rowCells = append(rowCells,
&table.RowCell{
LeftMargin: 1,
Width: 16,
LeftAlign: false,
Color: colorbalance,
Text: humanize.Commaf(coin.Balance),
})
case "1h_change":
rowCells = append(rowCells,
&table.RowCell{
LeftMargin: 1,
Width: 10,
LeftAlign: false,
Color: color1h,
Text: fmt.Sprintf("%.2f%%", coin.PercentChange1H),
})
case "24h_change":
rowCells = append(rowCells,
&table.RowCell{
LeftMargin: 1,
Width: 10,
LeftAlign: false,
Color: color24h,
Text: fmt.Sprintf("%.2f%%", coin.PercentChange24H),
})
case "7d_change":
rowCells = append(rowCells,
&table.RowCell{
LeftMargin: 1,
Width: 10,
LeftAlign: false,
Color: color7d,
Text: fmt.Sprintf("%.2f%%", coin.PercentChange7D),
})
case "percent_holdings":
rowCells = append(rowCells,
&table.RowCell{
LeftMargin: 1,
Width: 14,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: fmt.Sprintf("%.2f%%", percentHoldings),
})
case "last_updated":
rowCells = append(rowCells,
&table.RowCell{
LeftMargin: 1,
Width: 18,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: lastUpdated,
})
}
}

t.AddRowCells(rowCells...)
}

return t
Expand Down
8 changes: 4 additions & 4 deletions cointop/price_alerts.go
Expand Up @@ -20,7 +20,7 @@ func (ct *Cointop) GetPriceAlertsTableHeaders() []string {
return []string{
"name",
"symbol",
"targetprice",
"target_price",
"price",
"frequency",
}
Expand Down Expand Up @@ -296,11 +296,11 @@ func (ct *Cointop) HidePriceAlertsUpdateMenu() error {

// EnterKeyPressHandler is the key press handle for update menus
func (ct *Cointop) EnterKeyPressHandler() error {
if ct.IsPortfolioVisible() {
return ct.SetPortfolioHoldings()
if ct.IsPriceAlertsVisible() {
return ct.CreatePriceAlert()
}

return ct.CreatePriceAlert()
return ct.SetPortfolioHoldings()
}

// CreatePriceAlert sets price from inputed value
Expand Down

0 comments on commit c36f3de

Please sign in to comment.