main_ticker.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. #!/usr/bin/env python3
  2. #
  3. # mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet
  4. # Copyright (C)2013-2022 The MMGen Project <mmgen@tuta.io>
  5. # Licensed under the GNU General Public License, Version 3:
  6. # https://www.gnu.org/licenses
  7. # Public project repositories:
  8. # https://github.com/mmgen/mmgen-wallet https://github.com/mmgen/mmgen-node-tools
  9. # https://gitlab.com/mmgen/mmgen-wallet https://gitlab.com/mmgen/mmgen-node-tools
  10. """
  11. mmnode-ticker: Display price information for cryptocurrency and other assets
  12. """
  13. opts_data = {
  14. 'sets': [
  15. ('widest', True, 'percent_cols', 'd,w,m,y'),
  16. ('widest', True, 'name_labels', True),
  17. ('widest', True, 'thousands_comma', True),
  18. ('widest', True, 'update_time', True),
  19. ('wide', True, 'percent_cols', 'd,w'),
  20. ('wide', True, 'name_labels', True),
  21. ('wide', True, 'thousands_comma', True),
  22. ('wide', True, 'update_time', True),
  23. ],
  24. 'text': {
  25. 'desc': 'Display prices for cryptocurrency and other assets',
  26. 'usage': '[opts] [TRADE_SPECIFIER | ASSET_RANGE]',
  27. 'options': """
  28. -h, --help Print this help message
  29. --, --longhelp Print help message for long options (common options)
  30. -a, --asset-limit=N Retrieve data for top ‘N’ cryptocurrencies by market
  31. cap (default: {al}). To retrieve all available data,
  32. specify a value of zero.
  33. -A, --adjust=P Adjust prices by percentage ‘P’. In ‘trading’ mode,
  34. spot and adjusted prices are shown in separate columns.
  35. -b, --btc Fetch and display data for Bitcoin only
  36. -c, --add-columns=LIST Add columns for asset specifiers in LIST (comma-
  37. separated, see ASSET SPECIFIERS below). Can also be
  38. used to supply a USD exchange rate for missing assets.
  39. -C, --cached-data Use cached data from previous network query instead of
  40. live data from server
  41. -d, --download=D Retrieve and cache asset data ‘D’ from network (valid
  42. options: {ds})
  43. -D, --cachedir=D Read and write cached JSON data to directory ‘D’
  44. instead of ‘~/{dfl_cachedir}’
  45. -e, --add-precision=N Add ‘N’ digits of precision to columns
  46. -E, --elapsed Show elapsed time in UPDATED column (see --update-time)
  47. -F, --portfolio Display portfolio data
  48. -l, --list-ids List IDs of all available assets
  49. -n, --name-labels Label rows with asset names rather than symbols
  50. -p, --percent-cols=C Add daily, weekly, monthly, or yearly percentage change
  51. columns ‘C’ (specify with comma-separated letters
  52. {pc})
  53. -P, --pager Pipe the output to a pager
  54. -q, --quiet Produce quieter output
  55. -r, --add-rows=LIST Add rows for asset specifiers in LIST (comma-separated,
  56. see ASSET SPECIFIERS below). Can also be used to supply
  57. a USD exchange rate for missing assets.
  58. -s, --sort=P Sort output according to parameter P. Valid parameters
  59. are {sp_codes}. See SORT PARAMETERS below.
  60. To reverse the sort, prefix the parameter with ‘r’.
  61. -t, --testing Print command(s) to be executed to stdout and exit
  62. -T, --thousands-comma Use comma as a thousands separator
  63. -u, --update-time Include UPDATED (last update time) column
  64. -U, --pchg-unit=A Use asset ‘A’ as unit of reference for percentage
  65. change columns (default: USD)
  66. -v, --verbose Be more verbose
  67. -w, --wide Display most optional columns (same as -unT -p d,w)
  68. -W, --widest Display all optional columns (same as -unT -p d,w,m,y)
  69. -x, --proxy=P Connect via proxy ‘P’. Set to the empty string to
  70. completely disable or ‘none’ to allow override from
  71. environment. Consult the curl manpage for --proxy usage.
  72. -X, --proxy2=P Alternate proxy for non-crypto financial data. Defaults
  73. to value of --proxy
  74. """,
  75. 'notes': """
  76. The script has three display modes: ‘overview’, enabled when no arguments are
  77. given on the command line; ‘trading’, when a TRADE_SPECIFIER argument (see
  78. below) is given; and ‘market cap’, when an ASSET_RANGE (see below) is given.
  79. Overview mode displays prices of all configured assets, and optionally the
  80. user’s portfolio; trading mode displays the price of a given quantity of an
  81. asset in relation to other assets, optionally comparing an offered price to
  82. the spot price; and market cap mode lists a range of crypto assets selected
  83. by current market cap.
  84. The ASSET_RANGE argument can be either an integer N, in which case the top
  85. N assets by market cap will be displayed, or a hyphen-separated range N-M,
  86. in which case assets from N to M by market cap will be displayed.
  87. ASSETS consist of either a symbol (e.g. ‘xmr’) or full ID (see --list-ids)
  88. consisting of symbol plus label (e.g. ‘xmr-monero’). In cases where the
  89. symbol is ambiguous, the full ID must be used. For Yahoo Finance assets
  90. the symbol and ID are identical:
  91. Examples:
  92. ltc - specify asset by symbol
  93. ltc-litecoin - same as above, but use full ID instead of symbol
  94. ^dji - Dow Jones Industrial Average (Yahoo)
  95. gc=f - gold futures (Yahoo)
  96. ASSET SPECIFIERS have the following format:
  97. ASSET[:RATE[:RATE_ASSET]]
  98. If the asset referred to by ASSET is not in the source data (see --list-ids),
  99. an arbitrarily chosen label may be used. RATE is the exchange rate of the
  100. asset in relation to RATE_ASSET, if present, otherwise USD. When RATE is
  101. postfixed with the letter ‘r’, its meaning is reversed, i.e. interpreted as
  102. ‘ASSET/RATE_ASSET’ instead of ‘RATE_ASSET/ASSET’. Asset specifier examples:
  103. inr:79.5 - INR is not in the source data, so supply rate of
  104. 79.5 INR to the Dollar (USD/INR)
  105. inr:0.01257r - same as above, but use reverse rate (INR/USD)
  106. inr-indian-rupee:79.5 - same as first example, but add an arbitrary label
  107. omr-omani-rial:2.59r - Omani Rial is pegged to the Dollar at 2.59 USD
  108. bgn-bulgarian-lev:0.5113r:eurusd=x
  109. - Bulgarian Lev is pegged to the Euro at 0.5113 EUR
  110. A TRADE_SPECIFIER is a single argument in the format:
  111. ASSET:AMOUNT[:TO_ASSET[:TO_AMOUNT]]
  112. Examples:
  113. xmr:17.34 - price of 17.34 XMR in all configured assets
  114. xmr-monero:17.34 - same as above, but with full ID
  115. xmr:17.34:eurusd=x - price of 17.34 XMR in EUR only
  116. xmr:17.34:eurusd=x:2800 - commission on an offer of 17.34 XMR for 2800 EUR
  117. TO_AMOUNT, if included, is used to calculate the percentage difference or
  118. commission on an offer compared to the spot price.
  119. If either ASSET or TO_ASSET refer to assets not present in the source data,
  120. a USD rate for the missing asset(s) must be supplied via the --add-columns
  121. or --add-rows options.
  122. SORT PARAMETERS:
  123. {sp_fmt}
  124. PROXY NOTE
  125. The remote server used to obtain the crypto price data, {cc.api_host},
  126. blocks Tor behind a Captcha wall, so a Tor proxy cannot be used directly.
  127. If you’re concerned about privacy, connect via a VPN, or better yet, VPN over
  128. Tor. Then set up an HTTP proxy (e.g. Privoxy) on the VPN’ed host and set the
  129. ‘proxy’ option in the config file or --proxy on the command line accordingly.
  130. Or run the script directly on the VPN’ed host with ’proxy’ or --proxy set to
  131. the null string.
  132. Alternatively, you may download the JSON source data in a Tor-proxied browser
  133. from {cc.api_url}, save it as ‘ticker.json’ in your
  134. configured cache directory and run the script with the --cached-data option.
  135. Financial data is obtained from {fi.desc}, which currently allows Tor.
  136. RATE LIMITING NOTE
  137. To protect user privacy, filtering and processing of cryptocurrency data is
  138. performed client side so that the remote server does not know which assets
  139. are being examined. This is done by fetching data for the top {al} crypto
  140. assets by market cap (configurable via the --asset-limit option) with each
  141. invocation of the script. A rate limit of {cc.ratelimit} seconds between calls is thus
  142. imposed to prevent abuse of the remote server. When the --btc option is in
  143. effect, this limit is reduced to {cc.btc_ratelimit} seconds. To bypass the rate limit
  144. entirely, use --cached-data.
  145. Note that financial data obtained from {fi.api_host} is filtered in the
  146. request, which has privacy implications. The rate limit for financial data
  147. is {fi.ratelimit} seconds.
  148. EXAMPLES
  149. # Basic display in ‘overview’ mode:
  150. $ mmnode-ticker
  151. # Display BTC price only:
  152. $ mmnode-ticker --btc
  153. # Wide display, add EUR and OMR columns, OMR/USD rate, extra precision and
  154. # proxy:
  155. $ mmnode-ticker -w -c eurusd=x,omr-omani-rial:2.59r -e2 -x http://vpnhost:8118
  156. # Wide display, elapsed update time, add EUR, BGN columns and BGN/EUR rate:
  157. $ mmnode-ticker -wE -c eurusd=x,bgn-bulgarian-lev:0.5113r:eurusd=x
  158. # Widest display with all percentage change columns, use cached data from
  159. # previous network query, show portfolio (see above), pipe output to pager,
  160. # add DOGE row:
  161. $ mmnode-ticker -WCFP -r doge
  162. # Display 17.234 XMR priced in all configured assets (‘trading’ mode):
  163. $ mmnode-ticker xmr:17.234
  164. # Same as above, but add INR price at specified USDINR rate:
  165. $ mmnode-ticker -c inr:79.5 xmr:17.234
  166. # Same as above, but view INR price only at specified rate, adding label:
  167. $ mmnode-ticker -c inr-indian-rupee:79.5 xmr:17.234:inr
  168. # Calculate commission on an offer of 2700 USD for 0.123 BTC, compared to
  169. # current spot price:
  170. $ mmnode-ticker usd:2700:btc:0.123
  171. # Calculate commission on an offer of 200000 INR for 0.1 BTC, compared to
  172. # current spot price, at specified USDINR rate:
  173. $ mmnode-ticker -n -c inr-indian-rupee:79.5 inr:200000:btc:0.1
  174. # Display top 20 crypto assets by market cap, adding a Euro column:
  175. $ mmnode-ticker -c eurusd=x 20
  176. # Same as above, specifying assets using a range:
  177. $ mmnode-ticker -c eurusd=x 1-20
  178. CONFIGURED ASSETS:
  179. {assets}
  180. Customize output by editing the file
  181. ~/{cfg}
  182. To add a portfolio, edit the file
  183. ~/{pf_cfg}
  184. """},
  185. 'code': {
  186. 'options': lambda s: s.format(
  187. dfl_cachedir = os.path.relpath(dfl_cachedir, start=homedir),
  188. ds = fmt_dict(DataSource.get_sources(), fmt='equal_compact'),
  189. al = DataSource.coinpaprika.dfl_asset_limit,
  190. sp_codes = fmt_list(sort_params, fmt='fancy'),
  191. pc = fmt_list(Ticker.percent_cols, fmt='fancy')),
  192. 'notes': lambda s: s.format(
  193. assets = fmt_list(assets_list_gen(cfg_in), fmt='col', indent=' '),
  194. cfg = os.path.relpath(cfg_in.cfg_file, start=homedir),
  195. pf_cfg = os.path.relpath(cfg_in.portfolio_file, start=homedir),
  196. al = DataSource.coinpaprika.dfl_asset_limit,
  197. cc = src_cls['cc'](),
  198. sp_fmt = '\n '.join(f'‘{k}’ - {v.desc}' for k, v in sort_params.items()),
  199. fi = src_cls['fi']())
  200. }
  201. }
  202. import os
  203. from mmgen.util import fmt_list, fmt_dict
  204. from mmgen.cfg import Config
  205. from . import Ticker
  206. gcfg = Config(opts_data=opts_data, caller_post_init=True)
  207. src_cls, cfg_in = Ticker.make_cfg(gcfg)
  208. from .Ticker import dfl_cachedir, homedir, DataSource, assets_list_gen, sort_params
  209. gcfg._post_init()
  210. Ticker.main()