mmnode-ticker: sort output by various parameters
Supported parameters:
d - 1-day % change
w - 1-week % change
m - 1-month % change
y - 1-year % change
p - asset price
c - market cap
Examples:
# Display top 50 assets by market cap, sorting by price change
# in last 24 hours:
$ mmnode-ticker --sort=d 50
This commit is contained in:
parent
e6d62fd18b
commit
0a953e3ca0
4 changed files with 118 additions and 3 deletions
|
|
@ -24,7 +24,7 @@ from subprocess import run, PIPE, CalledProcessError
|
|||
from decimal import Decimal
|
||||
from collections import namedtuple
|
||||
|
||||
from mmgen.color import red, yellow, green, blue, orange, gray, cyan
|
||||
from mmgen.color import red, yellow, green, blue, orange, gray, cyan, pink
|
||||
from mmgen.util import msg, msg_r, rmsg, Msg, Msg_r, die, fmt, fmt_list, fmt_dict, list_gen, suf, is_int
|
||||
from mmgen.ui import do_pager
|
||||
|
||||
|
|
@ -41,6 +41,15 @@ percent_cols = {
|
|||
'm': 'month',
|
||||
'y': 'year'}
|
||||
|
||||
sp = namedtuple('sort_parameter', ['key', 'desc'])
|
||||
sort_params = {
|
||||
'd': sp('percent_change_24h', '1-day % change'),
|
||||
'w': sp('percent_change_7d', '1-week % change'),
|
||||
'm': sp('percent_change_30d', '1-month % change'),
|
||||
'y': sp('percent_change_1y', '1-year % change'),
|
||||
'p': sp('price_usd', 'asset price'),
|
||||
'c': sp('market_cap', 'market cap')}
|
||||
|
||||
class RowDict(dict):
|
||||
|
||||
def __iter__(self):
|
||||
|
|
@ -274,6 +283,7 @@ class DataSource:
|
|||
'percent_change_30d': data['pct_chg_4wks'],
|
||||
'percent_change_7d': data['pct_chg_1wk'],
|
||||
'percent_change_24h': data['regularMarketChangePercent']['raw'] * 100,
|
||||
'market_cap': 0, # dummy - required for sorting
|
||||
'last_updated': data['regularMarketTime']}
|
||||
|
||||
def rate_limit_errmsg(self, elapsed):
|
||||
|
|
@ -752,6 +762,19 @@ def make_cfg(gcfg_arg):
|
|||
'' if proxy == '' else 'none' if (proxy and proxy.lower() == 'none')
|
||||
else (proxy or cfg_in.cfg.get(name)))
|
||||
|
||||
def get_sort_opt():
|
||||
match get_cfg_var('sort'):
|
||||
case None:
|
||||
return None
|
||||
case s if s in sort_params:
|
||||
return (s, True)
|
||||
case s if s in ['r' + ch for ch in sort_params]:
|
||||
return (s[1], False)
|
||||
case s:
|
||||
die(1,
|
||||
f'{s!r}: invalid parameter for --sort option (must be one of {fmt_list(sort_params)})'
|
||||
'\nTo reverse the sort, prefix the code letter with ‘r’')
|
||||
|
||||
cfg_tuple = namedtuple('global_cfg',[
|
||||
'rows',
|
||||
'usr_rows',
|
||||
|
|
@ -766,6 +789,7 @@ def make_cfg(gcfg_arg):
|
|||
'proxy',
|
||||
'proxy2',
|
||||
'portfolio',
|
||||
'sort',
|
||||
'percent_cols',
|
||||
'asset_limit',
|
||||
'cached_data',
|
||||
|
|
@ -823,6 +847,7 @@ def make_cfg(gcfg_arg):
|
|||
proxy = proxy,
|
||||
proxy2 = None if proxy2 == 'none' else '' if proxy2 == '' else (proxy2 or proxy),
|
||||
portfolio = portfolio,
|
||||
sort = get_sort_opt(),
|
||||
percent_cols = parse_percent_cols(get_cfg_var('percent_cols')),
|
||||
asset_limit = get_cfg_var('asset_limit'),
|
||||
cached_data = get_cfg_var('cached_data'),
|
||||
|
|
@ -869,6 +894,8 @@ class Ticker:
|
|||
|
||||
def __init__(self, data):
|
||||
|
||||
global cfg
|
||||
|
||||
self.comma = ',' if cfg.thousands_comma else ''
|
||||
|
||||
self.col1_wid = max(len('TOTAL'), (
|
||||
|
|
@ -885,6 +912,18 @@ class Ticker:
|
|||
for row in rows:
|
||||
self.max_rank = max(self.max_rank, int(data[row.id]['rank']))
|
||||
|
||||
if cfg.sort:
|
||||
code, reverse = cfg.sort
|
||||
key = sort_params[code].key
|
||||
sort_func = lambda row: data[row.id][key]
|
||||
pf_sort_func = lambda row: data[row[0]][key]
|
||||
for group in self.rows.keys():
|
||||
if group not in self.hidden_groups:
|
||||
self.rows[group] = sorted(self.rows[group], key=sort_func, reverse=reverse)
|
||||
if cfg.portfolio:
|
||||
cfg = cfg._replace(
|
||||
portfolio = sorted(cfg.portfolio, key=pf_sort_func, reverse=reverse))
|
||||
|
||||
self.col_usd_prices = {k: self.data[k]['price_usd'] for k in self.col_ids}
|
||||
self.prices = {row.id: self.get_row_prices(row.id) for row in self.rows if row.id in data}
|
||||
self.prices['usd-us-dollar'] = self.get_row_prices('usd-us-dollar')
|
||||
|
|
@ -951,6 +990,10 @@ class Ticker:
|
|||
|
||||
yield 'Current time: {}'.format(cyan(time.strftime('%F %X', time.gmtime(now)) + ' UTC'))
|
||||
|
||||
if cfg.sort:
|
||||
text = sort_params[cfg.sort[0]].desc + ('' if cfg.sort[1] else ' [reversed]')
|
||||
yield f'Sort order: {pink(text.upper())}'
|
||||
|
||||
for asset in self.usr_col_assets:
|
||||
if asset.symbol != 'USD':
|
||||
usdprice = self.data[asset.id]['price_usd']
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
3.6.dev6
|
||||
3.6.dev7
|
||||
|
|
|
|||
|
|
@ -57,6 +57,9 @@ opts_data = {
|
|||
-r, --add-rows=LIST Add rows for asset specifiers in LIST (comma-separated,
|
||||
see ASSET SPECIFIERS below). Can also be used to supply
|
||||
a USD exchange rate for missing assets.
|
||||
-s, --sort=P Sort output according to parameter P. Valid parameters
|
||||
are {sp_codes}. See SORT PARAMETERS below.
|
||||
To reverse the sort, prefix the parameter with ‘r’.
|
||||
-t, --testing Print command(s) to be executed to stdout and exit
|
||||
-T, --thousands-comma Use comma as a thousands separator
|
||||
-u, --update-time Include UPDATED (last update time) column
|
||||
|
|
@ -133,6 +136,10 @@ A TRADE_SPECIFIER is a single argument in the format:
|
|||
a USD rate for the missing asset(s) must be supplied via the --add-columns
|
||||
or --add-rows options.
|
||||
|
||||
SORT PARAMETERS:
|
||||
|
||||
{sp_fmt}
|
||||
|
||||
|
||||
PROXY NOTE
|
||||
|
||||
|
|
@ -225,6 +232,7 @@ To add a portfolio, edit the file
|
|||
dfl_cachedir = os.path.relpath(dfl_cachedir, start=homedir),
|
||||
ds = fmt_dict(DataSource.get_sources(), fmt='equal_compact'),
|
||||
al = DataSource.coinpaprika.dfl_asset_limit,
|
||||
sp_codes = fmt_list(sort_params, fmt='fancy'),
|
||||
pc = fmt_list(Ticker.percent_cols, fmt='fancy')),
|
||||
'notes': lambda s: s.format(
|
||||
assets = fmt_list(assets_list_gen(cfg_in), fmt='col', indent=' '),
|
||||
|
|
@ -232,6 +240,7 @@ To add a portfolio, edit the file
|
|||
pf_cfg = os.path.relpath(cfg_in.portfolio_file, start=homedir),
|
||||
al = DataSource.coinpaprika.dfl_asset_limit,
|
||||
cc = src_cls['cc'](),
|
||||
sp_fmt = '\n '.join(f'‘{k}’ - {v.desc}' for k, v in sort_params.items()),
|
||||
fi = src_cls['fi']())
|
||||
}
|
||||
}
|
||||
|
|
@ -246,7 +255,7 @@ gcfg = Config(opts_data=opts_data, caller_post_init=True)
|
|||
|
||||
src_cls, cfg_in = Ticker.make_cfg(gcfg)
|
||||
|
||||
from .Ticker import dfl_cachedir, homedir, DataSource, assets_list_gen
|
||||
from .Ticker import dfl_cachedir, homedir, DataSource, assets_list_gen, sort_params
|
||||
|
||||
gcfg._post_init()
|
||||
|
||||
|
|
|
|||
|
|
@ -90,6 +90,14 @@ class CmdTestScripts(CmdTestBase):
|
|||
('ticker19', 'ticker [--cached-data 1-5]'),
|
||||
('ticker20', 'ticker [--cached-data 2-5]'),
|
||||
('ticker21', 'ticker [--cached-data 5-5]'),
|
||||
('ticker22', 'ticker [--sort=rp]'),
|
||||
('ticker23', 'ticker [--sort=rp xmr:10]'),
|
||||
('ticker24', 'ticker [--sort=p]'),
|
||||
('ticker25', 'ticker [--sort=p 200]'),
|
||||
('ticker26', 'ticker [--sort=c -r algo,ada]'),
|
||||
('ticker27', 'ticker [--sort=rp -r algo,ada]'),
|
||||
('ticker28', 'ticker [--sort=d -r algo,ada]'),
|
||||
('ticker29', 'ticker [--sort=y -r algo,ada]'),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -365,3 +373,58 @@ class CmdTestScripts(CmdTestBase):
|
|||
r'8\) ADA 17.11161 0.51 0.4764 0.00002180',
|
||||
],
|
||||
add_opts = ['--add-columns=eurusd=x'])
|
||||
|
||||
def ticker22(self):
|
||||
return self.ticker(
|
||||
[],
|
||||
['MONERO', 'ETHEREUM', 'BITCOIN', 'SILVER', 'BRENT', 'GOLD'],
|
||||
add_opts = ['--name-labels', '--sort=rp'])
|
||||
|
||||
def ticker23(self):
|
||||
return self.ticker(
|
||||
[],
|
||||
['MONERO', 'ETHEREUM', 'BITCOIN', 'SILVER', 'BRENT', 'GOLD'],
|
||||
add_opts = ['--name-labels', '--sort=rp', 'xmr:10'])
|
||||
|
||||
def ticker24(self):
|
||||
return self.ticker(
|
||||
[],
|
||||
['BITCOIN', 'ETHEREUM', 'MONERO', 'GOLD', 'BRENT', 'SILVER'],
|
||||
add_opts = ['--name-labels', '--sort=p'])
|
||||
|
||||
def ticker25(self):
|
||||
return self.ticker(
|
||||
[],
|
||||
[
|
||||
r' 1\) BITCOIN',
|
||||
r' 2\) ETHEREUM',
|
||||
r'30\) MONERO',
|
||||
r'23\) LITECOIN',
|
||||
r' 8\) CARDANO',
|
||||
r'33\) ALGORAND'
|
||||
],
|
||||
add_opts = ['--name-labels', '--sort=p', '200'])
|
||||
|
||||
def ticker26(self):
|
||||
return self.ticker(
|
||||
[],
|
||||
['BITCOIN', 'ETHEREUM', 'MONERO', 'CARDANO', 'ALGORAND'],
|
||||
add_opts = ['--name-labels', '--sort=c', '-r', 'ada,algo'])
|
||||
|
||||
def ticker27(self):
|
||||
return self.ticker(
|
||||
[],
|
||||
['MONERO', 'ETHEREUM', 'BITCOIN', 'S&P', 'NASDAQ', 'DOW', 'ALGORAND', 'CARDANO'],
|
||||
add_opts = ['--name-labels', '--sort=rp', '--add-rows=ada-cardano,algo-algorand'])
|
||||
|
||||
def ticker28(self):
|
||||
return self.ticker(
|
||||
[],
|
||||
['ETHEREUM', 'MONERO', 'BITCOIN', 'NASDAQ', 'S&P', 'DOW', 'CARDANO', 'ALGORAND'],
|
||||
add_opts = ['--widest', '--sort=d', '-r', 'ada,algo'])
|
||||
|
||||
def ticker29(self):
|
||||
return self.ticker(
|
||||
[],
|
||||
['ETHEREUM', 'BITCOIN', 'MONERO', 'S&P', 'DOW', 'NASDAQ', 'CARDANO', 'ALGORAND'],
|
||||
add_opts = ['--widest', '-s', 'y', '-r', 'ada,algo'])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue