summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiguel Mota <hello@miguelmota.com>2021-10-23 03:52:49 -0700
committerSimon Roberts <lyricnz@gmail.com>2021-10-24 12:43:37 +1100
commit0e956d63582315bb5df836db462105a7a6751441 (patch)
tree2c5641fd0dd0e34bbb415f4194d4247cdd3ced21
parentb5b68833f5e6713ec8bf4394f0a8315ec8268b6a (diff)
portfolio: clean up fixes #243
-rw-r--r--cointop/config.go4
-rw-r--r--cointop/conversion.go18
-rw-r--r--cointop/keybindings.go4
-rw-r--r--cointop/portfolio.go42
-rw-r--r--cointop/sort.go4
-rw-r--r--cointop/table_header.go16
-rw-r--r--docs/content/faq.md16
-rw-r--r--pkg/api/impl/coingecko/coingecko.go2
-rw-r--r--pkg/api/impl/coinmarketcap/coinmarketcap.go2
-rw-r--r--pkg/api/interface.go2
10 files changed, 68 insertions, 42 deletions
diff --git a/cointop/config.go b/cointop/config.go
index 066d326..40b7af3 100644
--- a/cointop/config.go
+++ b/cointop/config.go
@@ -647,10 +647,8 @@ func (ct *Cointop) loadPortfolioHoldingsFromConfig(holdingsIfc []interface{}) er
buyPrice := 0.0
if len(tupleIfc) >= 3 {
- if parsePrice, err := ct.InterfaceToFloat64(tupleIfc[2]); err != nil {
+ if buyPrice, err = ct.InterfaceToFloat64(tupleIfc[2]); err != nil {
return err
- } else {
- buyPrice = parsePrice
}
}
diff --git a/cointop/conversion.go b/cointop/conversion.go
index 4bcc18a..51756c7 100644
--- a/cointop/conversion.go
+++ b/cointop/conversion.go
@@ -302,19 +302,19 @@ func CurrencySymbol(currency string) string {
return "?"
}
-func (ct *Cointop) Convert(convertFrom string, convertTo string, amount float64) (float64, error) {
+// Convert converts an amount to another currency type
+func (ct *Cointop) Convert(convertFrom, convertTo string, amount float64) (float64, error) {
convertFrom = strings.ToLower(convertFrom)
convertTo = strings.ToLower(convertTo)
- var rate float64
if convertFrom == convertTo {
- rate = 1.0
- } else {
- crate, err := ct.api.GetExchangeRate(convertFrom, convertTo, true)
- if err != nil {
- return 0, err
- }
- rate = crate
+ return amount, nil
+ }
+
+ rate, err := ct.api.GetExchangeRate(convertFrom, convertTo, true)
+ if err != nil {
+ return 0, err
}
+
return rate * amount, nil
}
diff --git a/cointop/keybindings.go b/cointop/keybindings.go
index 04af301..b220901 100644
--- a/cointop/keybindings.go
+++ b/cointop/keybindings.go
@@ -328,9 +328,9 @@ func (ct *Cointop) SetKeybindingAction(shortcutKey string, action string) error
case "sort_column_cost":
fn = ct.Sortfn("cost", true)
case "sort_column_pnl":
- fn = ct.Sortfn("profit", true)
+ fn = ct.Sortfn("pnl", true)
case "sort_column_pnl_percent":
- fn = ct.Sortfn("profit_percent", true)
+ fn = ct.Sortfn("pnl_percent", true)
default:
fn = ct.Keyfn(ct.Noop)
}
diff --git a/cointop/portfolio.go b/cointop/portfolio.go
index 3b3be51..61641fd 100644
--- a/cointop/portfolio.go
+++ b/cointop/portfolio.go
@@ -37,8 +37,8 @@ var SupportedPortfolioTableHeaders = []string{
"last_updated",
"cost_price",
"cost",
- "profit",
- "profit_percent",
+ "pnl",
+ "pnl_percent",
}
// DefaultPortfolioTableHeaders are the default portfolio table header columns
@@ -53,12 +53,23 @@ var DefaultPortfolioTableHeaders = []string{
"24h_change",
"7d_change",
"percent_holdings",
+ "cost_price",
+ "cost",
+ "pnl",
+ "pnl_percent",
"last_updated",
}
// HiddenBalanceChars are the characters to show when hidding balances
var HiddenBalanceChars = "********"
+var costColumns = map[string]bool{
+ "cost_price": true,
+ "cost": true,
+ "pnl": true,
+ "pnl_percent": true,
+}
+
// ValidPortfolioTableHeader returns the portfolio table headers
func (ct *Cointop) ValidPortfolioTableHeader(name string) bool {
for _, v := range SupportedPortfolioTableHeaders {
@@ -84,6 +95,25 @@ func (ct *Cointop) GetPortfolioTable() *table.Table {
headers := ct.GetPortfolioTableHeaders()
ct.ClearSyncMap(&ct.State.tableColumnWidths)
ct.ClearSyncMap(&ct.State.tableColumnAlignLeft)
+
+ displayCostColumns := false
+ for _, coin := range ct.State.coins {
+ if coin.BuyPrice > 0 && coin.BuyCurrency != "" {
+ displayCostColumns = true
+ break
+ }
+ }
+
+ if !displayCostColumns {
+ filtered := make([]string, 0)
+ for _, header := range headers {
+ if _, ok := costColumns[header]; !ok {
+ filtered = append(filtered, header)
+ }
+ }
+ headers = filtered
+ }
+
for _, coin := range ct.State.coins {
leftMargin := 1
rightMargin := 1
@@ -332,7 +362,6 @@ func (ct *Cointop) GetPortfolioTable() *table.Table {
cost = costPrice * coin.Holdings
}
}
- // text := ct.FormatPrice(cost)
text := humanize.FixedMonetaryf(cost, 2)
if ct.State.hidePortfolioBalances {
text = HiddenBalanceChars
@@ -352,7 +381,7 @@ func (ct *Cointop) GetPortfolioTable() *table.Table {
Color: ct.colorscheme.TableColumnPrice,
Text: text,
})
- case "profit":
+ case "pnl":
text := ""
colorProfit := ct.colorscheme.TableColumnChange
if coin.BuyPrice > 0 && coin.BuyCurrency != "" {
@@ -385,7 +414,7 @@ func (ct *Cointop) GetPortfolioTable() *table.Table {
Color: colorProfit,
Text: text,
})
- case "profit_percent":
+ case "pnl_percent":
profitPercent := 0.0
if coin.BuyPrice > 0 && coin.BuyCurrency != "" {
costPrice, err := ct.Convert(coin.BuyCurrency, ct.State.currencyConversion, coin.BuyPrice)
@@ -812,8 +841,7 @@ func (ct *Cointop) PrintHoldingsTable(options *TablePrintOptions) error {
records := make([][]string, len(holdings))
symbol := ct.CurrencySymbol()
- // TODO: buy_price, buy_currency, profit, profit_percent, etc
- headers := []string{"name", "symbol", "price", "holdings", "balance", "24h%", "%holdings"}
+ headers := []string{"name", "symbol", "price", "holdings", "balance", "24h%", "%holdings", "buy_price", "buy_currency", "pnl", "pnl_percent"}
if len(filterCols) > 0 {
for _, col := range filterCols {
valid := false
diff --git a/cointop/sort.go b/cointop/sort.go
index fd596be..f45b2f7 100644
--- a/cointop/sort.go
+++ b/cointop/sort.go
@@ -72,9 +72,9 @@ func (ct *Cointop) Sort(sortBy string, desc bool, list []*Coin, renderHeaders bo
return a.BuyPrice < b.BuyPrice
case "cost":
return (a.BuyPrice * a.Holdings) < (b.BuyPrice * b.Holdings) // TODO: convert?
- case "profit":
+ case "pnl":
return (a.Price - a.BuyPrice) < (b.Price - b.BuyPrice)
- case "profit_percent":
+ case "pnl_percent":
return (a.Price - a.BuyPrice) < (b.Price - b.BuyPrice)
default:
return a.Rank < b.Rank
diff --git a/cointop/table_header.go b/cointop/table_header.go
index c526c47..cc71b24 100644
--- a/cointop/table_header.go
+++ b/cointop/table_header.go
@@ -133,17 +133,17 @@ var HeaderColumns = map[string]*HeaderColumn{
},
"cost": {
Slug: "cost",
- Label: "cost[!]",
+ Label: "[!]cost",
PlainLabel: "cost",
},
- "profit": {
- Slug: "profit",
- Label: "PNL[@]",
+ "pnl": {
+ Slug: "pnl",
+ Label: "[@]PNL",
PlainLabel: "PNL",
},
- "profit_percent": {
- Slug: "profit_percent",
- Label: "PNL%[#]",
+ "pnl_percent": {
+ Slug: "pnl_percent",
+ Label: "[#]PNL%",
PlainLabel: "PNL%",
},
}
@@ -231,7 +231,7 @@ func (ct *Cointop) UpdateTableHeader() error {
}
leftAlign := ct.GetTableColumnAlignLeft(col)
switch col {
- case "price", "balance", "profit", "cost":
+ case "price", "balance", "pnl", "cost":
label = fmt.Sprintf("%s%s", ct.CurrencySymbol(), label)
}
if leftAlign {
diff --git a/docs/content/faq.md b/docs/content/faq.md
index 9da8352..cbe8547 100644
--- a/docs/content/faq.md
+++ b/docs/content/faq.md
@@ -186,11 +186,11 @@ draft: false
## How do I include buy/cost price in my portfolio?
- Currently there is no UI for this. If you want to include the cost of your coins in the Portfolio screen, you will need to edit your config.toml
+ Currently there is no UI for this. If you want to include the cost of your coins in the Portfolio screen, you will need to edit your config.toml
- Each coin consists of four values: coin name, coin amount, cost-price, cost-currency.
+ Each coin consists of four values: coin name, coin amount, cost-price, cost-currency.
- For example, the following configuration includes 100 ALGO at USD1.95 each; and 0.1 BTC at AUD50100.83 each.
+ For example, the following configuration includes 100 ALGO at USD1.95 each; and 0.1 BTC at AUD50100.83 each.
```toml
holdings = [["Algorand", "100", "1.95", "USD"], ["Bitcoin", "0.1", "50100.83", "AUD"]]
@@ -200,12 +200,12 @@ draft: false
- `cost_price` the price and currency that the coins were purchased at
- `cost` the cost (in the current currency) of the coins
- - `profit` the PNL of the coins (current value vs original cost)
- - `profit_percent` the PNL of the coins as a fraction of the original cost
+ - `pnl` the PNL of the coins (current value vs original cost)
+ - `pnl_percent` the PNL of the coins as a fraction of the original cost
With the holdings above, and the currency set to GBP (British Pounds) cointop will look something like this:
-
- ![Screen Shot 2021-10-22 at 8 41 21 am](https://user-images.githubusercontent.com/122371/138361142-8e1f32b5-ca24-471d-a628-06968f07c65f.png)
+
+ ![portfolio profit and loss](https://user-images.githubusercontent.com/122371/138361142-8e1f32b5-ca24-471d-a628-06968f07c65f.png)
## How do I hide my portfolio balances (private mode)?
@@ -520,7 +520,7 @@ draft: false
## How can I get more information when something is going wrong?
Cointop creates a logfile at `/tmp/cointop.log`. Normally nothing is written to this, but if you set the environment variable
- `DEBUG=1` cointop will write a lot of output describing its operation. Furthermore, if you also set `DEBUG_HTTP=1` it will
+ `DEBUG=1` cointop will write a lot of output describing its operation. Furthermore, if you also set `DEBUG_HTTP=1` it will
emit lots about every HTTP request that cointop makes to coingecko (backend). Developers may ask for this information
to help diagnose any problems you may experience.
diff --git a/pkg/api/impl/coingecko/coingecko.go b/pkg/api/impl/coingecko/coingecko.go
index 2b9553a..5046ecf 100644
--- a/pkg/api/impl/coingecko/coingecko.go
+++ b/pkg/api/impl/coingecko/coingecko.go
@@ -161,7 +161,7 @@ func (s *Service) GetExchangeRates(cached bool) (*types.ExchangeRatesItem, error
}
// GetExchangeRate gets the current excange rate between two currencies
-func (s *Service) GetExchangeRate(convertFrom string, convertTo string, cached bool) (float64, error) {
+func (s *Service) GetExchangeRate(convertFrom, convertTo string, cached bool) (float64, error) {
convertFrom = strings.ToLower(convertFrom)
convertTo = strings.ToLower(convertTo)
if convertFrom == convertTo {
diff --git a/pkg/api/impl/coinmarketcap/coinmarketcap.go b/pkg/api/impl/coinmarketcap/coinmarketcap.go
index e3a15fe..71a7b73 100644
--- a/pkg/api/impl/coinmarketcap/coinmarketcap.go
+++ b/pkg/api/impl/coinmarketcap/coinmarketcap.go
@@ -432,7 +432,7 @@ func getChartInterval(start, end int64) string {
}
// GetExchangeRate gets the current excange rate between two currencies
-func (s *Service) GetExchangeRate(convertFrom string, convertTo string, cached bool) (float64, error) {
+func (s *Service) GetExchangeRate(convertFrom, convertTo string, cached bool) (float64, error) {
if convertFrom == convertTo {
return 1.0, nil
}
diff --git a/pkg/api/interface.go b/pkg/api/interface.go
index 294c16c..55ffcf2 100644
--- a/pkg/api/interface.go
+++ b/pkg/api/interface.go
@@ -16,5 +16,5 @@ type Interface interface {
CoinLink(name string) string
SupportedCurrencies() []string
Price(name string, convert string) (float64, error)
- GetExchangeRate(convertFrom string, convertTo string, cached bool) (float64, error) // I don't love this caching
+ GetExchangeRate(convertFrom, convertTo string, cached bool) (float64, error) // I don't love this caching
}