From 3fd9c971bf6b76b85e82fb44378c502b6707b254 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Sat, 6 Aug 2022 09:48:48 +0000 Subject: [PATCH] minor cleanups --- README.md | 23 ++++++--- mmgen_node_tools/Ticker.py | 87 +++++++++++++++++++-------------- mmgen_node_tools/main_ticker.py | 30 +++++++----- test/test_py_d/ts_misc.py | 2 +- 4 files changed, 86 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 088a344..9c72f4e 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,10 @@ First, install [MMGen][6]. Then, - $ git clone https://github.com/mmgen/mmgen-node-tools - $ cd mmgen-node-tools - $ python3 -m build --no-isolation - $ python3 -m pip install --user dist/*.whl + $ git clone https://github.com/mmgen/mmgen-node-tools + $ cd mmgen-node-tools + $ python3 -m build --no-isolation + $ python3 -m pip install --user dist/*.whl Also make sure that `~/.local/bin` is in `PATH`. @@ -24,9 +24,18 @@ Also make sure that `~/.local/bin` is in `PATH`. *NOTE: the tests require that the MMGen and MMGen Node Tools repositories be located in the same directory.* - $ test/init.sh - $ test/test-release.sh -A # BTC-only testing - $ test/test-release.sh # Full testing +Initialize the test framework (must be run at least once after cloning, and +possibly again after a pull if tests have been updated): + + $ test/init.sh + +BTC-only testing: + + $ test/test-release.sh -A + +Full testing: + + $ test/test-release.sh - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mmgen_node_tools/Ticker.py b/mmgen_node_tools/Ticker.py index 618b701..b667ccd 100755 --- a/mmgen_node_tools/Ticker.py +++ b/mmgen_node_tools/Ticker.py @@ -87,11 +87,11 @@ def gen_data(data): usr_wants = { 'id': ( {a.id for a in usr_assets if a.id} - - {a.id for a in usr_assets if a.amount and a.id} - {'usd-us-dollar'} ) + {a.id for a in usr_assets if a.rate and a.id} - {'usd-us-dollar'} ) , 'symbol': ( {a.symbol for a in usr_assets if not a.id} - - {a.symbol for a in usr_assets if a.amount} - {'USD'} ), + {a.symbol for a in usr_assets if a.rate} - {'USD'} ), } found = { 'id': set(), 'symbol': set() } @@ -114,7 +114,7 @@ def gen_data(data): break for asset in (cfg.usr_rows + cfg.usr_columns): - if asset.amount: + if asset.rate: """ User-supplied rate overrides rate from source data. """ @@ -122,8 +122,8 @@ def gen_data(data): yield ( _id, { 'symbol': asset.symbol, 'id': _id, - 'price_usd': str(Decimal(1/asset.amount)), - 'price_btc': str(Decimal(1/asset.amount/btcusd)), + 'price_usd': str(Decimal(1/asset.rate)), + 'price_btc': str(Decimal(1/asset.rate/btcusd)), 'last_updated': int(now), }) @@ -280,47 +280,62 @@ def main(cfg_parm,cfg_in_parm): def make_cfg(cmd_args,cfg_in): def get_rows_from_cfg(add_data=None): - def create_row(e): - return asset_tuple(e.split('-')[0].upper(),e) def gen(): for n,(k,v) in enumerate(cfg_in.cfg['assets'].items()): yield(k) if add_data and k in add_data: v += tuple(add_data[k]) for e in v: - yield(create_row(e)) + yield parse_asset_id(e,True) return tuple(gen()) - def parse_asset_tuple(s): - sym,id = (s.split('-')[0],s) if '-' in s else (s,None) - return asset_tuple( sym.upper(), id.lower() if id else None ) - - def parse_asset_triplet(s,reverse_ok=False): - ss = s.split(':') - return asset_triplet( - *parse_asset_tuple(s if len(ss) == 1 else ss[0]), - ( - None if len(ss) == 1 else - 1 / Decimal(ss[1][:-1]) if reverse_ok and ss[1].lower().endswith('r') else - Decimal(ss[1]) - )) + def parse_asset_id(s,require_label=False): + sym,label = (*s.split('-',1),None)[:2] + if require_label and not label: + die(1,f'{s!r}: asset label is missing') + return asset_tuple( sym.upper(), (s.lower() if label else None) ) def parse_usr_asset_arg(s): - return tuple(parse_asset_triplet(ss,reverse_ok=True) for ss in s.split(',')) if s else () + """ + asset_id[:rate] + """ + def parse_parm(s): + ss = s.split(':') + assert len(ss) in (1,2), f'{s}: malformed argument' + asset_id,rate = (*ss,None)[:2] + parsed_id = parse_asset_id(asset_id) + + return asset_data( + symbol = parsed_id.symbol, + id = parsed_id.id, + amount = None, + rate = ( + None if rate is None else + 1 / Decimal(rate[:-1]) if rate.lower().endswith('r') else + Decimal(rate) )) + + return tuple(parse_parm(s2) for s2 in s.split(',')) if s else () def parse_query_arg(s): + """ + asset_id:amount[:to_asset_id[:to_amount]] + """ + def parse_query_asset(asset_id,amount): + parsed_id = parse_asset_id(asset_id) + return asset_data( + symbol = parsed_id.symbol, + id = parsed_id.id, + amount = None if amount is None else Decimal(amount), + rate = None ) + ss = s.split(':') - if len(ss) == 2: - return query_tuple( - asset = parse_asset_triplet(s), - to_asset = None ) - elif len(ss) in (3,4): - return query_tuple( - asset = parse_asset_triplet(':'.join(ss[:2])), - to_asset = parse_asset_triplet(':'.join(ss[2:])), - ) - else: - die(1,f'{s}: malformed argument') + assert len(ss) in (2,3,4), f'{s}: malformed argument' + asset_id,amount,to_asset_id,to_amount = (*ss,None,None)[:4] + + return query_tuple( + asset = parse_query_asset(asset_id,amount), + to_asset = parse_query_asset(to_asset_id,to_amount) if to_asset_id else None + ) def gen_uniq(obj_list,key,preload=None): found = set([getattr(obj,key) for obj in preload if hasattr(obj,key)] if preload else ()) @@ -339,7 +354,7 @@ def make_cfg(cmd_args,cfg_in): def get_portfolio_assets(ret=()): if cfg_in.portfolio and opt.portfolio: - ret = tuple( asset_tuple(e.split('-')[0].upper(),e) for e in cfg_in.portfolio ) + ret = (parse_asset_id(e,True) for e in cfg_in.portfolio) return ( 'portfolio', tuple(e for e in ret if (not opt.btc) or e.symbol == 'BTC') ) def get_portfolio(): @@ -357,7 +372,7 @@ def make_cfg(cmd_args,cfg_in): def create_rows(): rows = ( ('trade_pair',) + query if (query and query.to_asset) else - ('bitcoin',parse_asset_tuple('btc-bitcoin')) if opt.btc else + ('bitcoin',parse_asset_id('btc-bitcoin')) if opt.btc else get_rows_from_cfg( add_data={'fiat':['usd-us-dollar']} if opt.add_columns else None ) ) @@ -385,7 +400,7 @@ def make_cfg(cmd_args,cfg_in): 'portfolio' ]) query_tuple = namedtuple('query',['asset','to_asset']) - asset_triplet = namedtuple('asset_triplet',['symbol','id','amount']) + asset_data = namedtuple('asset_data',['symbol','id','amount','rate']) asset_tuple = namedtuple('asset_tuple',['symbol','id']) usr_rows = parse_usr_asset_arg(opt.add_rows) diff --git a/mmgen_node_tools/main_ticker.py b/mmgen_node_tools/main_ticker.py index d4a5533..e843475 100755 --- a/mmgen_node_tools/main_ticker.py +++ b/mmgen_node_tools/main_ticker.py @@ -67,22 +67,28 @@ 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. -ASSETS consist of either a symbol (e.g. ‘xmr’) or full ID consisting of -symbol plus label (e.g. ‘xmr-monero’). In cases where the symbol is -ambiguous, the full ID must be used. Examples: +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 +symbol is ambiguous, the full ID must be used. Examples: chf - specify asset by symbol chf-swiss-franc-token - same as above, but use full ID instead of symbol -ASSET SPECIFIERS consist of an ASSET followed by an optional colon and USD -rate. If the asset is not in the source data (see --list-ids), the label -part of the ID may be arbitrarily chosen by the user. When the letter ‘r’ -is appended to the USD rate, the rate is reversed, i.e. treated as ‘USD per -asset’ instead of ‘asset per USD’. Asset specifier examples: +ASSET SPECIFIERS have the following format: - inr:79.5 - INR is not in the source data, so supply USD rate - inr-indian-rupee:79.5 - same as above, but add an arbitrary label - omr-omani-rial:2.59r - OMR is pegged to USD with fixed value of 2.59 USD + ASSET[:RATE] + +If the asset referred to by ASSET is not in the source data (see --list-ids), +an arbitrarily chosen label may be used. RATE is the USD exchange rate of +the asset. When RATE is postfixed with the letter ‘r’, its meaning is +reversed, i.e. interpreted as ‘ASSET/USD’ instead of ‘USD/ASSET’. Asset +specifier examples: + + inr:79.5 - INR is not in the source data, so supply rate of + 79.5 INR to the Dollar (USD/INR) + inr:0.01257r - same as above, but use reverse rate (INR/USD) + inr-indian-rupee:79.5 - same as first example, but add an arbitrary label + omr-omani-rial:2.59r - Omani Rial is pegged to the Dollar at 2.59 USD A TRADE_SPECIFIER is a single argument in the format: @@ -137,7 +143,7 @@ $ mmnode-ticker # Display BTC price only: $ mmnode-ticker --btc -# Wide display, add EUR and OMR columns, OMRUSD rate, extra precision and +# Wide display, add EUR and OMR columns, OMR/USD rate, extra precision and # proxy: $ mmnode-ticker -w -c eur,omr-omani-rial:2.59r -e2 -x http://vpnhost:8118 diff --git a/test/test_py_d/ts_misc.py b/test/test_py_d/ts_misc.py index 9815560..7295da3 100755 --- a/test/test_py_d/ts_misc.py +++ b/test/test_py_d/ts_misc.py @@ -280,6 +280,6 @@ class TestSuiteScripts(TestSuiteBase): r'EUR \(EURO TOKEN\) = 1.0186 USD ' + r'OMR \(OMANI RIAL\) = 2.5900 USD', 'USD EUR OMR BTC CHG_7d CHG_24h UPDATED', - 'BITCOIN', + r'BITCOIN 23,250.77 22,826.6890 8,977.1328 1.00000000 \+11.15 \+0.89 10 minutes ago', 'OMANI RIAL 2.59 2.5428 1.0000 0.00011139 -- -- just now' ])