Skip to content
This repository was archived by the owner on Dec 16, 2025. It is now read-only.

Commit 3b37cc3

Browse files
authored
Scale large numbers by adding Million Billion Trillion suffix (#200)
Add option for scaling Thousand Million Billion Trillion numbers by adding suffix.
1 parent e1aded9 commit 3b37cc3

8 files changed

Lines changed: 195 additions & 14 deletions

File tree

cointop/coins_table.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ func (ct *Cointop) GetCoinsTable() *table.Table {
136136
})
137137
case "24h_volume":
138138
text := humanize.Monetaryf(coin.Volume24H, 0)
139+
if ct.IsActiveTableCompactNotation() {
140+
text = humanize.ScaleNumericf(coin.Volume24H, 3)
141+
}
139142
ct.SetTableColumnWidthFromString(header, text)
140143
ct.SetTableColumnAlignLeft(header, false)
141144
rowCells = append(rowCells,
@@ -243,6 +246,9 @@ func (ct *Cointop) GetCoinsTable() *table.Table {
243246
})
244247
case "market_cap":
245248
text := humanize.Monetaryf(coin.MarketCap, 0)
249+
if ct.IsActiveTableCompactNotation() {
250+
text = humanize.ScaleNumericf(coin.MarketCap, 3)
251+
}
246252
ct.SetTableColumnWidthFromString(header, text)
247253
ct.SetTableColumnAlignLeft(header, false)
248254
rowCells = append(rowCells,
@@ -255,6 +261,9 @@ func (ct *Cointop) GetCoinsTable() *table.Table {
255261
})
256262
case "total_supply":
257263
text := humanize.Numericf(coin.TotalSupply, 0)
264+
if ct.IsActiveTableCompactNotation() {
265+
text = humanize.ScaleNumericf(coin.TotalSupply, 3)
266+
}
258267
ct.SetTableColumnWidthFromString(header, text)
259268
ct.SetTableColumnAlignLeft(header, false)
260269
rowCells = append(rowCells,
@@ -267,6 +276,9 @@ func (ct *Cointop) GetCoinsTable() *table.Table {
267276
})
268277
case "available_supply":
269278
text := humanize.Numericf(coin.AvailableSupply, 0)
279+
if ct.IsActiveTableCompactNotation() {
280+
text = humanize.ScaleNumericf(coin.AvailableSupply, 3)
281+
}
270282
ct.SetTableColumnWidthFromString(header, text)
271283
ct.SetTableColumnAlignLeft(header, false)
272284
rowCells = append(rowCells,

cointop/cointop.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ type State struct {
8989
priceAlerts *PriceAlerts
9090
priceAlertEditID string
9191
priceAlertNewID string
92+
93+
compactNotation bool
94+
tableCompactNotation bool
95+
favoritesCompactNotation bool
96+
portfolioCompactNotation bool
9297
}
9398

9499
// Cointop cointop
@@ -181,6 +186,9 @@ var DefaultCurrency = "USD"
181186
// DefaultChartRange ...
182187
var DefaultChartRange = "1Y"
183188

189+
// DefaultCompactNotation ...
190+
var DefaultCompactNotation = false
191+
184192
// DefaultMaxChartWidth ...
185193
var DefaultMaxChartWidth = 175
186194

@@ -291,6 +299,10 @@ func NewCointop(config *Config) (*Cointop, error) {
291299
Entries: make([]*PriceAlert, 0),
292300
SoundEnabled: true,
293301
},
302+
compactNotation: DefaultCompactNotation,
303+
tableCompactNotation: DefaultCompactNotation,
304+
favoritesCompactNotation: DefaultCompactNotation,
305+
portfolioCompactNotation: DefaultCompactNotation,
294306
},
295307
Views: &Views{
296308
Chart: NewChartView(),

cointop/config.go

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ type ConfigFileConfig struct {
4848
Colorscheme interface{} `toml:"colorscheme"`
4949
RefreshRate interface{} `toml:"refresh_rate"`
5050
CacheDir interface{} `toml:"cache_dir"`
51+
CompactNotation interface{} `toml:"compact_notation"`
5152
Table map[string]interface{} `toml:"table"`
5253
Chart map[string]interface{} `toml:"chart"`
5354
}
@@ -70,6 +71,7 @@ func (ct *Cointop) SetupConfig() error {
7071
ct.loadColorschemeFromConfig,
7172
ct.loadRefreshRateFromConfig,
7273
ct.loadCacheDirFromConfig,
74+
ct.loadCompactNotationFromConfig,
7375
ct.loadPriceAlertsFromConfig,
7476
ct.loadPortfolioFromConfig,
7577
}
@@ -215,10 +217,11 @@ func (ct *Cointop) ConfigToToml() ([]byte, error) {
215217
var favoritesBySymbolIfc []interface{}
216218
favoritesMapIfc := map[string]interface{}{
217219
// DEPRECATED: favorites by 'symbol' is deprecated because of collisions. Kept for backward compatibility.
218-
"symbols": favoritesBySymbolIfc,
219-
"names": favoritesIfc,
220-
"columns": ct.State.favoritesTableColumns,
221-
"character": ct.State.favoriteChar,
220+
"symbols": favoritesBySymbolIfc,
221+
"names": favoritesIfc,
222+
"columns": ct.State.favoritesTableColumns,
223+
"character": ct.State.favoriteChar,
224+
"compact_notation": ct.State.favoritesCompactNotation,
222225
}
223226

224227
var holdingsIfc [][]string
@@ -236,8 +239,9 @@ func (ct *Cointop) ConfigToToml() ([]byte, error) {
236239
return holdingsIfc[i][0] < holdingsIfc[j][0]
237240
})
238241
portfolioIfc := map[string]interface{}{
239-
"holdings": holdingsIfc,
240-
"columns": ct.State.portfolioTableColumns,
242+
"holdings": holdingsIfc,
243+
"columns": ct.State.portfolioTableColumns,
244+
"compact_notation": ct.State.portfolioCompactNotation,
241245
}
242246

243247
cmcIfc := map[string]interface{}{
@@ -264,6 +268,7 @@ func (ct *Cointop) ConfigToToml() ([]byte, error) {
264268
tableMapIfc := map[string]interface{}{
265269
"columns": ct.State.coinsTableColumns,
266270
"keep_row_focus_on_sort": ct.State.keepRowFocusOnSort,
271+
"compact_notation": ct.State.tableCompactNotation,
267272
}
268273

269274
chartMapIfc := map[string]interface{}{
@@ -286,6 +291,7 @@ func (ct *Cointop) ConfigToToml() ([]byte, error) {
286291
CacheDir: ct.State.cacheDir,
287292
Table: tableMapIfc,
288293
Chart: chartMapIfc,
294+
CompactNotation: ct.State.compactNotation,
289295
}
290296

291297
var b bytes.Buffer
@@ -310,6 +316,11 @@ func (ct *Cointop) loadTableConfig() error {
310316
if ok {
311317
ct.State.keepRowFocusOnSort = keepRowFocusOnSortIfc.(bool)
312318
}
319+
320+
if compactNotation, ok := ct.config.Table["compact_notation"]; ok {
321+
ct.State.tableCompactNotation = compactNotation.(bool)
322+
}
323+
313324
return nil
314325
}
315326

@@ -458,6 +469,16 @@ func (ct *Cointop) loadCacheDirFromConfig() error {
458469
return nil
459470
}
460471

472+
// loadCompactNotationFromConfig loads compact-notation setting from config file to struct
473+
func (ct *Cointop) loadCompactNotationFromConfig() error {
474+
log.Debug("loadCompactNotationFromConfig()")
475+
if compactNotation, ok := ct.config.CompactNotation.(bool); ok {
476+
ct.State.compactNotation = compactNotation
477+
}
478+
479+
return nil
480+
}
481+
461482
// LoadAPIChoiceFromConfig loads API choices from config file to struct
462483
func (ct *Cointop) loadAPIChoiceFromConfig() error {
463484
log.Debug("loadAPIKeysFromConfig()")
@@ -480,6 +501,8 @@ func (ct *Cointop) loadFavoritesFromConfig() error {
480501
}
481502
ct.State.favoriteChar = favoriteChar
482503
}
504+
} else if k == "compact_notation" {
505+
ct.State.favoritesCompactNotation = valueIfc.(bool)
483506
}
484507
ifcs, ok := valueIfc.([]interface{})
485508
if !ok {
@@ -568,6 +591,8 @@ func (ct *Cointop) loadPortfolioFromConfig() error {
568591
return err
569592
}
570593
}
594+
} else if key == "compact_notation" {
595+
ct.State.portfolioCompactNotation = valueIfc.(bool)
571596
} else {
572597
// Backward compatibility < v1.6.0
573598
holdings, err := ct.InterfaceToFloat64(valueIfc)

cointop/marketbar.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ func (ct *Cointop) UpdateMarketbar() error {
4040
total = math.Round(total*1e2) / 1e2
4141
totalstr = humanize.Monetaryf(total, 2)
4242
}
43+
if ct.State.compactNotation {
44+
totalstr = humanize.ScaleNumericf(total, 3)
45+
}
4346

4447
timeframe := ct.State.selectedChartRange
4548
chartname := ct.SelectedCoinName()
@@ -153,12 +156,19 @@ func (ct *Cointop) UpdateMarketbar() error {
153156
separator2 = "\n" + offset
154157
}
155158

159+
marketCapStr := humanize.Monetaryf(market.TotalMarketCapUSD, 0)
160+
volumeStr := humanize.Monetaryf(market.Total24HVolumeUSD, 0)
161+
if ct.State.compactNotation {
162+
marketCapStr = humanize.ScaleNumericf(market.TotalMarketCapUSD, 3)
163+
volumeStr = humanize.ScaleNumericf(market.Total24HVolumeUSD, 3)
164+
}
165+
156166
content = fmt.Sprintf(
157167
"%sGlobal ▶ Market Cap: %s %s 24H Volume: %s %s BTC Dominance: %.2f%%",
158168
chartInfo,
159-
fmt.Sprintf("%s%s", ct.CurrencySymbol(), humanize.Monetaryf(market.TotalMarketCapUSD, 0)),
169+
fmt.Sprintf("%s%s", ct.CurrencySymbol(), marketCapStr),
160170
separator1,
161-
fmt.Sprintf("%s%s", ct.CurrencySymbol(), humanize.Monetaryf(market.Total24HVolumeUSD, 0)),
171+
fmt.Sprintf("%s%s", ct.CurrencySymbol(), volumeStr),
162172
separator2,
163173
market.BitcoinPercentageOfMarketCap,
164174
)

cointop/table_header.go

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ var ArrowDown = "▼"
2121
type HeaderColumn struct {
2222
Slug string
2323
Label string
24+
ShortLabel string // only columns with a ShortLabel can be scaled?
2425
PlainLabel string
2526
}
2627

@@ -69,11 +70,13 @@ var HeaderColumns = map[string]*HeaderColumn{
6970
"market_cap": {
7071
Slug: "market_cap",
7172
Label: "[m]arket cap",
73+
ShortLabel: "[m]cap",
7274
PlainLabel: "market cap",
7375
},
7476
"24h_volume": {
7577
Slug: "24h_volume",
7678
Label: "24H [v]olume",
79+
ShortLabel: "24[v]",
7780
PlainLabel: "24H volume",
7881
},
7982
"1h_change": {
@@ -104,11 +107,13 @@ var HeaderColumns = map[string]*HeaderColumn{
104107
"total_supply": {
105108
Slug: "total_supply",
106109
Label: "[t]otal supply",
110+
ShortLabel: "[t]ot",
107111
PlainLabel: "total supply",
108112
},
109113
"available_supply": {
110114
Slug: "available_supply",
111115
Label: "[a]vailable supply",
116+
ShortLabel: "[a]vl",
112117
PlainLabel: "available supply",
113118
},
114119
"percent_holdings": {
@@ -123,6 +128,15 @@ var HeaderColumns = map[string]*HeaderColumn{
123128
},
124129
}
125130

131+
// GetLabel fetch the label to use for the heading (depends on configuration)
132+
func (ct *Cointop) GetLabel(h *HeaderColumn) string {
133+
// TODO: technically this should support nosort
134+
if ct.IsActiveTableCompactNotation() && h.ShortLabel != "" {
135+
return h.ShortLabel
136+
}
137+
return h.Label
138+
}
139+
126140
// TableHeaderView is structure for table header view
127141
type TableHeaderView = ui.View
128142

@@ -145,6 +159,22 @@ func (ct *Cointop) GetActiveTableHeaders() []string {
145159
return cols
146160
}
147161

162+
// GetActiveTableHeaders returns the list of active table headers
163+
func (ct *Cointop) IsActiveTableCompactNotation() bool {
164+
var compact bool
165+
switch ct.State.selectedView {
166+
case PortfolioView:
167+
compact = ct.State.portfolioCompactNotation
168+
case CoinsView:
169+
compact = ct.State.tableCompactNotation
170+
case FavoritesView:
171+
compact = ct.State.favoritesCompactNotation
172+
default:
173+
compact = ct.State.tableCompactNotation
174+
}
175+
return compact
176+
}
177+
148178
// UpdateTableHeader renders the table header
149179
func (ct *Cointop) UpdateTableHeader() error {
150180
log.Debug("UpdateTableHeader()")
@@ -175,7 +205,7 @@ func (ct *Cointop) UpdateTableHeader() error {
175205
}
176206
}
177207
}
178-
label := hc.Label
208+
label := ct.GetLabel(hc)
179209
if noSort {
180210
label = hc.PlainLabel
181211
}
@@ -240,7 +270,7 @@ func (ct *Cointop) SetTableColumnWidth(header string, width int) {
240270
prev = prevIfc.(int)
241271
} else {
242272
hc := HeaderColumns[header]
243-
prev = utf8.RuneCountInString(hc.Label) + 1
273+
prev = utf8.RuneCountInString(ct.GetLabel(hc)) + 1
244274
switch header {
245275
case "price", "balance":
246276
prev++

docs/content/faq.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,12 @@ draft: false
357357

358358
Supported columns relating to price change are `1h_change`, `24h_change`, `7d_change`, `30d_change`, `1y_change`
359359

360+
## How can I use K (thousand), M (million), B (billion), T (trillion) suffixes for shorter numbers?
361+
362+
There is a setting at the top-level of the configuration file called `compact_notation=true` which changes the marketbar values `market cap`, `volume` and `portfolio total value`.
363+
364+
The same setting can be applied at in the `[table]` section to impact the `24h_volume`, `market_cap`, `total_supply`, `available_supply` columns in the main coin view; and in the `[favorites]` section to change the same columns. The setting also changes the column names to be shorter.
365+
360366
## How can use a different config file other than the default?
361367

362368
Run cointop with the `--config` flag, eg `cointop --config="/path/to/config.toml"`, to use the specified file as the config.

0 commit comments

Comments
 (0)