mmnode-ticker: display crypto assets by market cap
Examples:
# Display top 2000 assets by market cap:
$ mmnode-ticker 2000
# Display assets 201-300 by market cap, displaying all available columns:
$ mmnode-ticker --widest 201-300
# Display asset 32 by market cap:
$ mmnode-ticker 32-32
Testing/demo:
$ test/cmdtest.py -e scripts.ticker
This commit is contained in:
parent
083b29eae8
commit
060b968ad4
4 changed files with 109 additions and 13 deletions
|
|
@ -182,6 +182,7 @@ class DataSource:
|
|||
net_data_type = 'json'
|
||||
has_verbose = True
|
||||
dfl_asset_limit = 2000
|
||||
max_asset_idx = 1_000_000
|
||||
|
||||
def __init__(self):
|
||||
self.asset_limit = int(cfg.asset_limit) if is_int(cfg.asset_limit) else self.dfl_asset_limit
|
||||
|
|
@ -576,6 +577,17 @@ def main():
|
|||
do_pager('\n'.join(e['id'] for e in src_data['cc'].data))
|
||||
return
|
||||
|
||||
global cfg
|
||||
|
||||
if cfg.asset_range:
|
||||
func = DataSource.coinpaprika.parse_asset_id
|
||||
n, m = cfg.asset_range
|
||||
cfg = cfg._replace(rows =
|
||||
tuple(func(e['id'], require_label=False) for e in src_data['cc'].data[n-1:m])
|
||||
+ tuple(['-'])
|
||||
+ tuple([func('btc-bitcoin', require_label=True)])
|
||||
+ tuple(r for r in cfg.rows if isinstance(r, tuple) and r.source == 'fi'))
|
||||
|
||||
global now
|
||||
now = 1659465400 if gcfg.test_suite else time.time() # 1659524400 1659445900
|
||||
|
||||
|
|
@ -643,6 +655,21 @@ def make_cfg(gcfg_arg):
|
|||
cf_opt = cfg_in.cfg.get(key,[]) if use_cf_file else []
|
||||
return tuple(parse_parm(s) for s in (cl_opt.split(',') if cl_opt else cf_opt))
|
||||
|
||||
def parse_asset_range(s):
|
||||
max_idx = DataSource.coinpaprika.max_asset_idx
|
||||
match s.split('-'):
|
||||
case [a, b] if is_int(a) and is_int(b):
|
||||
n, m = (int(a), int(b))
|
||||
case [a] if is_int(a):
|
||||
n, m = (1, int(a))
|
||||
case _:
|
||||
return None
|
||||
if n < 1 or m < 1 or n > m:
|
||||
raise ValueError(f'‘{s}’: invalid asset range specifier')
|
||||
if m > max_idx:
|
||||
raise ValueError(f'‘{s}’: end of range must be <= {max_idx}')
|
||||
return (n, m)
|
||||
|
||||
def parse_query_arg(s):
|
||||
"""
|
||||
asset_id:amount[:to_asset_id[:to_amount]]
|
||||
|
|
@ -731,6 +758,7 @@ def make_cfg(gcfg_arg):
|
|||
'usr_rows',
|
||||
'usr_columns',
|
||||
'query',
|
||||
'asset_range',
|
||||
'adjust',
|
||||
'clsname',
|
||||
'btc_only',
|
||||
|
|
@ -767,8 +795,10 @@ def make_cfg(gcfg_arg):
|
|||
if cmd_args := gcfg._args:
|
||||
if len(cmd_args) > 1:
|
||||
die(1, 'Only one command-line argument is allowed')
|
||||
query = parse_query_arg(cmd_args[0])
|
||||
asset_range = parse_asset_range(cmd_args[0])
|
||||
query = None if asset_range else parse_query_arg(cmd_args[0])
|
||||
else:
|
||||
asset_range = None
|
||||
query = None
|
||||
|
||||
usr_rows = parse_usr_asset_arg('add_rows')
|
||||
|
|
@ -783,6 +813,7 @@ def make_cfg(gcfg_arg):
|
|||
usr_rows = usr_rows,
|
||||
usr_columns = usr_columns,
|
||||
query = query,
|
||||
asset_range = asset_range,
|
||||
adjust = (lambda x: (100 + x) / 100 if x else 1)(Decimal(gcfg.adjust or 0)),
|
||||
clsname = 'trading' if query else 'overview',
|
||||
btc_only = get_cfg_var('btc'),
|
||||
|
|
@ -930,12 +961,14 @@ class Ticker:
|
|||
if self.table_hdr:
|
||||
yield self.table_hdr
|
||||
|
||||
for row in self.rows:
|
||||
for n, row in enumerate(self.rows, cfg.asset_range[0] if cfg.asset_range else 1):
|
||||
if isinstance(row, str):
|
||||
if cfg.asset_range:
|
||||
return
|
||||
yield ('-' * self.hl_wid)
|
||||
else:
|
||||
try:
|
||||
yield self.fmt_row(self.data[row.id])
|
||||
yield self.fmt_row(self.data[row.id], idx=n)
|
||||
except KeyError:
|
||||
yield gray(f'(no data for {row.id})')
|
||||
|
||||
|
|
@ -989,7 +1022,7 @@ class Ticker:
|
|||
d['price_usd'] / self.col_usd_prices[k]
|
||||
) * self.adjust for k in self.col_ids}
|
||||
|
||||
def fmt_row(self, d, amt=None, amt_fmt=None):
|
||||
def fmt_row(self, d, amt=None, amt_fmt=None, idx=None):
|
||||
|
||||
def fmt_pct(n):
|
||||
return gray(' --') if n is None else (red, green)[n>=0](f'{n:+7.2f}')
|
||||
|
|
@ -1002,6 +1035,7 @@ class Ticker:
|
|||
amt_fmt = amt_fmt.rstrip('0').rstrip('.')
|
||||
|
||||
return self.fs_num.format(
|
||||
idx = idx,
|
||||
lbl = self.create_label(d['id']) if cfg.name_labels else d['symbol'],
|
||||
pc1 = fmt_pct(d.get('percent_change_7d')),
|
||||
pc2 = fmt_pct(d.get('percent_change_24h')),
|
||||
|
|
@ -1061,6 +1095,15 @@ class Ticker:
|
|||
self.fs_num2 = ''.join(col_fs_data[c].fs_num for c in cols2)
|
||||
self.hl_wid2 = sum(col_fs_data[c].wid for c in cols2)
|
||||
|
||||
if cfg.asset_range:
|
||||
def get_col1_w():
|
||||
for n, r in enumerate(cfg.rows):
|
||||
if isinstance(r, str):
|
||||
return len(str(n))
|
||||
col1_w = get_col1_w()
|
||||
self.fs_str = ' ' * (col1_w + 2) + self.fs_str
|
||||
self.fs_num = f'{{idx:{col1_w}}}) ' + self.fs_num
|
||||
|
||||
@property
|
||||
def table_hdr(self):
|
||||
return self.fs_str.format(
|
||||
|
|
@ -1136,7 +1179,7 @@ class Ticker:
|
|||
self.fs_str += ' {upd}'
|
||||
self.hl_wid += self.upd_w + 2
|
||||
|
||||
def fmt_row(self, d):
|
||||
def fmt_row(self, d, idx=None):
|
||||
id = d['id']
|
||||
p = self.prices[id][self.asset.id] * self.asset.amount
|
||||
p_spot = '{:{}{}.{}f}'.format(p, self.max_wid, self.comma, 8+cfg.add_prec)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
3.6.dev4
|
||||
3.6.dev5
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ opts_data = {
|
|||
],
|
||||
'text': {
|
||||
'desc': 'Display prices for cryptocurrency and other assets',
|
||||
'usage': '[opts] [TRADE_SPECIFIER]',
|
||||
'usage': '[opts] [TRADE_SPECIFIER | ASSET_RANGE]',
|
||||
'options': """
|
||||
-h, --help Print this help message
|
||||
--, --longhelp Print help message for long options (common options)
|
||||
|
|
@ -71,14 +71,19 @@ opts_data = {
|
|||
""",
|
||||
'notes': """
|
||||
|
||||
The script has two display modes: ‘overview’, the default, and ‘trading’, the
|
||||
latter being enabled when a TRADE_SPECIFIER argument (see below) is supplied
|
||||
on the command line.
|
||||
The script has three display modes: ‘overview’, enabled when no arguments are
|
||||
given on the command line; ‘trading’, when a TRADE_SPECIFIER argument (see
|
||||
below) is given; and ‘market cap’, when an ASSET_RANGE (see below) is given.
|
||||
|
||||
Overview mode displays prices of all configured assets, and optionally the
|
||||
user’s portfolio, while trading mode displays the price of a given quantity
|
||||
of an asset in relation to other assets, optionally comparing an offered
|
||||
price to the spot price.
|
||||
user’s portfolio; trading mode displays the price of a given quantity of an
|
||||
asset in relation to other assets, optionally comparing an offered price to
|
||||
the spot price; and market cap mode lists a range of crypto assets selected
|
||||
by current market cap.
|
||||
|
||||
The ASSET_RANGE argument can be either an integer N, in which case the top
|
||||
N assets by market cap will be displayed, or a hyphen-separated range N-M,
|
||||
in which case assets from N to M by market cap will be displayed.
|
||||
|
||||
ASSETS consist of either a symbol (e.g. ‘xmr’) or full ID (see --list-ids)
|
||||
consisting of symbol plus label (e.g. ‘xmr-monero’). In cases where the
|
||||
|
|
@ -199,6 +204,12 @@ $ mmnode-ticker usd:2700:btc:0.123
|
|||
# current spot price, at specified USDINR rate:
|
||||
$ mmnode-ticker -n -c inr-indian-rupee:79.5 inr:200000:btc:0.1
|
||||
|
||||
# Display top 20 crypto assets by market cap, adding a Euro column:
|
||||
$ mmnode-ticker -c eurusd=x 20
|
||||
|
||||
# Same as above, specifying assets using a range:
|
||||
$ mmnode-ticker -c eurusd=x 1-20
|
||||
|
||||
|
||||
CONFIGURED ASSETS:
|
||||
{assets}
|
||||
|
|
|
|||
|
|
@ -86,6 +86,10 @@ class CmdTestScripts(CmdTestBase):
|
|||
('ticker15', 'ticker [--cached-data --wide --btc btc:2:usd:45000]'),
|
||||
('ticker16', 'ticker [--cached-data --wide --elapsed -c eur,omr-omani-rial:2.59r'),
|
||||
('ticker17', 'ticker [--cached-data --wide --elapsed -c bgn-bulgarian-lev:0.5113r:eur'),
|
||||
('ticker18', 'ticker [--cached-data --widest --add-columns eurusd=x 10]'),
|
||||
('ticker19', 'ticker [--cached-data 1-5]'),
|
||||
('ticker20', 'ticker [--cached-data 2-5]'),
|
||||
('ticker21', 'ticker [--cached-data 5-5]'),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -319,3 +323,41 @@ class CmdTestScripts(CmdTestBase):
|
|||
'BITCOIN 23,250.77 42,731.767 1.00000000',
|
||||
'BULGARIAN LEV 0.54 1.000 0.00002340',
|
||||
])
|
||||
|
||||
def ticker18(self):
|
||||
return self.ticker(
|
||||
['10'],
|
||||
[
|
||||
r'1\) BITCOIN 23,250.77 21,848.7527 1.00000000 \+18.96 \+15.61 \+11.15 \+0.89',
|
||||
r'6\) ALGORAND 0.33 0.3120 0.00001428 \+16.47 \+13.57 \+9.69 \-0.82'
|
||||
],
|
||||
add_opts = ['--widest', '--add-columns=eurusd=x'])
|
||||
|
||||
def ticker19(self):
|
||||
return self.ticker(
|
||||
['1-5'],
|
||||
[
|
||||
'USD EURUSD=X BTC '
|
||||
r'1\) BTC 23250.77 21848.7527 1.00000000',
|
||||
r'5\) ADA 0.51 0.4764 0.00002180',
|
||||
],
|
||||
add_opts = ['--add-columns=eurusd=x'])
|
||||
|
||||
def ticker20(self):
|
||||
return self.ticker(
|
||||
['2-5'],
|
||||
[
|
||||
'USD EURUSD=X BTC '
|
||||
r'2\) ETH 1659.66 1559.5846 0.07138094',
|
||||
r'5\) ADA 0.51 0.4764 0.00002180',
|
||||
],
|
||||
add_opts = ['--add-columns=eurusd=x'])
|
||||
|
||||
def ticker21(self):
|
||||
return self.ticker(
|
||||
['5-5'],
|
||||
[
|
||||
'USD EURUSD=X BTC '
|
||||
r'5\) ADA 0.51 0.4764 0.00002180',
|
||||
],
|
||||
add_opts = ['--add-columns=eurusd=x'])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue