From 545bc044c6e89d48e814cb64e8649ffbba637d85 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Sun, 5 Nov 2023 13:40:23 +0000 Subject: [PATCH] mmnode-ticker: add year and month percentage change columns --- mmgen_node_tools/Ticker.py | 42 +++++++++++++++++++++++++++------ mmgen_node_tools/main_ticker.py | 21 ++++++++++++----- test/cmdtest_py_d/ct_misc.py | 11 +++++---- 3 files changed, 56 insertions(+), 18 deletions(-) diff --git a/mmgen_node_tools/Ticker.py b/mmgen_node_tools/Ticker.py index 40bede8..4011c90 100755 --- a/mmgen_node_tools/Ticker.py +++ b/mmgen_node_tools/Ticker.py @@ -34,6 +34,13 @@ portfolio_fn = 'ticker-portfolio.yaml' asset_tuple = namedtuple('asset_tuple',['symbol','id','source']) last_api_host = None +percent_cols = { + 'd': 'day', + 'w': 'week', + 'm': 'month', + 'y': 'year', +} + class DataSource: source_groups = [ @@ -390,6 +397,8 @@ def gen_data(data): d['price_btc'] = Decimal(str(d['quotes']['USD']['price'])) / btcusd d['percent_change_24h'] = d['quotes']['USD']['percent_change_24h'] d['percent_change_7d'] = d['quotes']['USD']['percent_change_7d'] + d['percent_change_30d'] = d['quotes']['USD']['percent_change_30d'] + d['percent_change_1y'] = d['quotes']['USD']['percent_change_1y'] d['last_updated'] = int(datetime.datetime.fromisoformat(d['last_updated']).timestamp()) yield (d['id'],d) found[k].add(d[k]) @@ -497,6 +506,15 @@ def make_cfg(gcfg_arg): yield parse_asset_id(e,require_label=True) return tuple(gen()) + def parse_percent_cols(arg): + if arg is None: + return [] + res = arg.lower().split(',') + for s in res: + if s not in percent_cols: + die(1,f'{arg!r}: invalid --percent-cols parameter (valid letters: {fmt_list(percent_cols)})') + return res + def parse_usr_asset_arg(key,use_cf_file=False): """ asset_id[:rate[:rate_asset]] @@ -606,7 +624,8 @@ def make_cfg(gcfg_arg): 'cachedir', 'proxy', 'proxy2', - 'portfolio' ]) + 'portfolio', + 'percent_cols' ]) global gcfg,cfg_in,src_cls,cfg @@ -645,7 +664,8 @@ def make_cfg(gcfg_arg): cachedir = gcfg.cachedir or cfg_in.cfg.get('cachedir') or dfl_cachedir, proxy = proxy, proxy2 = None if proxy2 == 'none' else '' if proxy2 == '' else (proxy2 or proxy), - portfolio = get_portfolio() if cfg_in.portfolio and gcfg.portfolio and not query else None + portfolio = get_portfolio() if cfg_in.portfolio and gcfg.portfolio and not query else None, + percent_cols = parse_percent_cols(gcfg.percent_cols) ) def get_cfg_in(): @@ -802,7 +822,7 @@ class Ticker: yield '-' * self.hl_wid if not cfg.btc_only: yield self.fs_num.format( - lbl = 'TOTAL', pc1='', pc2='', upd='', amt='', + lbl = 'TOTAL', pc3='', pc4='', pc1='', pc2='', upd='', amt='', **{ k.replace('-','_'): v for k,v in self.prices['total'].items() } ) @@ -851,6 +871,8 @@ class Ticker: lbl = (self.create_label(d['id']) if gcfg.name_labels else d['symbol']), pc1 = fmt_pct(d.get('percent_change_7d')), pc2 = fmt_pct(d.get('percent_change_24h')), + pc3 = fmt_pct(d.get('percent_change_1y')), + pc4 = fmt_pct(d.get('percent_change_30d')), upd = d.get('last_updated_fmt'), amt = amt_fmt, **{ k.replace('-','_'): v * (1 if amt is None else amt) for k,v in p.items() } @@ -873,8 +895,10 @@ class Ticker: col_fs_data = { 'label': fd(f'{{lbl:{self.col1_wid}}}',f'{{lbl:{self.col1_wid}}}',self.col1_wid), - 'pct7d': fd(' {pc1:7}', ' {pc1:7}', 8), - 'pct24h': fd(' {pc2:7}', ' {pc2:7}', 8), + 'pct1y': fd(' {pc3:7}', ' {pc3:7}', 8), + 'pct1m': fd(' {pc4:7}', ' {pc4:7}', 8), + 'pct1w': fd(' {pc1:7}', ' {pc1:7}', 8), + 'pct1d': fd(' {pc2:7}', ' {pc2:7}', 8), 'update_time': fd(' {upd}', ' {upd}', max((19 if cfg.portfolio else 0),self.upd_w) + 2), 'amt': fd(' {amt}', ' {amt}', 21), } @@ -891,8 +915,10 @@ class Ticker: [asset.id for asset in self.usr_col_assets] + [a for a,b in ( ( 'btc-bitcoin', not cfg.btc_only ), - ( 'pct7d', gcfg.percent_change ), - ( 'pct24h', gcfg.percent_change ), + ( 'pct1y', 'y' in cfg.percent_cols ), + ( 'pct1m', 'm' in cfg.percent_cols ), + ( 'pct1w', 'w' in cfg.percent_cols ), + ( 'pct1d', 'd' in cfg.percent_cols ), ( 'update_time', gcfg.update_time ), ) if b] ) @@ -915,6 +941,8 @@ class Ticker: lbl = '', pc1 = ' CHG_7d', pc2 = 'CHG_24h', + pc3 = 'CHG_1y', + pc4 = 'CHG_30d', upd = 'UPDATED', amt = ' AMOUNT', usd_us_dollar = 'USD', diff --git a/mmgen_node_tools/main_ticker.py b/mmgen_node_tools/main_ticker.py index 91bc293..eafa34a 100755 --- a/mmgen_node_tools/main_ticker.py +++ b/mmgen_node_tools/main_ticker.py @@ -14,7 +14,11 @@ mmnode-ticker: Display price information for cryptocurrency and other assets opts_data = { 'sets': [ - ('wide', True, 'percent_change', True), + ('widest', True, 'percent_cols', 'd,w,m,y'), + ('widest', True, 'name_labels', True), + ('widest', True, 'thousands_comma', True), + ('widest', True, 'update_time', True), + ('wide', True, 'percent_cols', 'd,w'), ('wide', True, 'name_labels', True), ('wide', True, 'thousands_comma', True), ('wide', True, 'update_time', True), @@ -45,7 +49,9 @@ opts_data = { -F, --portfolio Display portfolio data -l, --list-ids List IDs of all available assets -n, --name-labels Label rows with asset names rather than symbols --p, --percent-change Add percentage change columns +-p, --percent-cols=C Add daily, weekly, monthly, or yearly percentage change + columns ‘C’ (specify with comma-separated letters + {pc}) -P, --pager Pipe the output to a pager -r, --add-rows=LIST Add rows for asset specifiers in LIST (comma-separated, see ASSET SPECIFIERS below). Can also be used to supply @@ -54,7 +60,8 @@ opts_data = { -T, --thousands-comma Use comma as a thousands separator -u, --update-time Include UPDATED (last update time) column -v, --verbose Be more verbose --w, --wide Display all optional columns (equivalent to -punT) +-w, --wide Display most optional columns (same as -unT -p d,w) +-W, --widest Display all optional columns (same as -unT -p d,w,m,y) -x, --proxy=P Connect via proxy ‘P’. Set to the empty string to completely disable or ‘none’ to allow override from environment. Consult the curl manpage for --proxy usage. @@ -169,9 +176,10 @@ $ mmnode-ticker -w -c eurusd=x,omr-omani-rial:2.59r -e2 -x http://vpnhost:8118 # Wide display, elapsed update time, add EUR, BGN columns and BGN/EUR rate: $ mmnode-ticker -wE -c eurusd=x,bgn-bulgarian-lev:0.5113r:eurusd=x -# Wide display, use cached data from previous network query, show portfolio -# (see above), pipe output to pager, add DOGE row: -$ mmnode-ticker -wCFP -r doge +# Widest display with all percentage change columns, use cached data from +# previous network query, show portfolio (see above), pipe output to pager, +# add DOGE row: +$ mmnode-ticker -WCFP -r doge # Display 17.234 XMR priced in all configured assets (‘trading’ mode): $ mmnode-ticker xmr:17.234 @@ -206,6 +214,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, + pc = fmt_list(Ticker.percent_cols,fmt='bare'), ), 'notes': lambda s: s.format( assets = fmt_list(assets_list_gen(cfg_in),fmt='col',indent=' '), diff --git a/test/cmdtest_py_d/ct_misc.py b/test/cmdtest_py_d/ct_misc.py index 3a9c47c..8046e51 100755 --- a/test/cmdtest_py_d/ct_misc.py +++ b/test/cmdtest_py_d/ct_misc.py @@ -138,15 +138,16 @@ class CmdTestScripts(CmdTestBase): def ticker4(self): return self.ticker( - ['--wide','--add-columns=eurusd=x,inr-indian-rupee:79.5'], + ['--widest','--add-columns=eurusd=x,inr-indian-rupee:79.5'], [ r'EURUSD=X \(EUR/USD\) = 1.0642 USD ' + r'INR \(INDIAN RUPEE\) = 0.012579 USD', - 'USD EURUSD=X INR BTC CHG_7d CHG_24h UPDATED', + 'USD EURUSD=X INR BTC CHG_1y CHG_30d CHG_7d CHG_24h UPDATED', 'BITCOIN', - r'ETHEREUM 1,659.66 1,559.5846 131,943.14 0.07138094 \+21.42 \+1.82', - r'MONERO 158.97 149.3870 12,638.36 0.00683732 \+7.28 \+1.21 2022-08-02 18:25:59', - r'INDIAN RUPEE 0.01 0.0118 1.00 0.00000054 -- --', + r'ETHEREUM 1,659.66 1,559.5846 131,943.14 0.07138094 \+36.41 \+29.99 \+21.42 \+1.82', + r'MONERO 158.97 149.3870 12,638.36 0.00683732 \+12.38 \+10.19 \+7.28 \+1.21 2022-08-02 18:25:59', + r'S&P 500 4,320.06 4,059.5604 343,444.77 0.18580285 -- -- -- -0.23', + r'INDIAN RUPEE 0.01 0.0118 1.00 0.00000054 -- -- -- --', ]) def ticker5(self):