From a6b2e32400093b74a16b67f725914645ce9041d9 Mon Sep 17 00:00:00 2001 From: 8go Date: Thu, 4 Feb 2021 07:03:53 +0000 Subject: [PATCH] added --tor option for TOR socks5 proxy Now you can use Tor Onion routing Formatting with black --- s2f.py | 201 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 140 insertions(+), 61 deletions(-) diff --git a/s2f.py b/s2f.py index 97691d9..9846b0b 100644 --- a/s2f.py +++ b/s2f.py @@ -4,56 +4,66 @@ # Ignore long lines # pylama:format=pep8:linters=pep8:ignore=E501 +import argparse +import datetime +import logging import os import sys -import logging import traceback -import argparse -import datetime -import json -import urllib.request + +import requests -def infoFromMessari(): +def infoFromMessari(proxies): url = "https://data.messari.io/api/v1/assets/bitcoin/metrics" - req = urllib.request.Request(url) - r = urllib.request.urlopen(req).read() - cont = json.loads(r.decode('utf-8')) - logger.debug("cont {}".format(cont)) - fwd_stock_to_flow = cont['data']['supply']['stock_to_flow'] + cont = requests.get(url, proxies=proxies).json() + logger.debug(f"cont {cont}") + fwd_stock_to_flow = cont["data"]["supply"]["stock_to_flow"] # conservative formula: 0.18 * s2f^3.3 # aggressive formula: exp(-1.84) * s2f^3.36 # conservative gives slightly lower price # conservative formula: 0.18*s2f^3.3 fwd_stock_to_flow_usd = 0.18 * fwd_stock_to_flow ** 3.3 - annual_inflation_percent = cont['data']['supply']['annual_inflation_percent'] - circulating = cont['data']['supply']['circulating'] - logger.debug("Data {} {} {} {}".format(fwd_stock_to_flow, fwd_stock_to_flow_usd, - annual_inflation_percent, circulating)) + annual_inflation_percent = cont["data"]["supply"]["annual_inflation_percent"] + circulating = cont["data"]["supply"]["circulating"] + usd_price = cont["data"]["market_data"]["price_usd"] + logger.debug( + f"Data {fwd_stock_to_flow} {fwd_stock_to_flow_usd} " + f"{annual_inflation_percent} {circulating}" + ) # example output: Data 54.73928728956236 98097.8891323435 # 1.826841468925517 18410936.0981691 - return float(circulating), float(annual_inflation_percent), float( - fwd_stock_to_flow), float(fwd_stock_to_flow_usd) + return ( + float(usd_price), + float(circulating), + float(annual_inflation_percent), + float(fwd_stock_to_flow), + float(fwd_stock_to_flow_usd), + ) -def btcSupplyOnDate(date): +def btcSupplyOnDate(date, proxies): """Provides BTC supply on a given date""" - url = 'https://community-api.coinmetrics.io/v2/assets/btc/metricdata?metrics=SplyCur&start=' + \ - str(date) + '&end=' + str(date) - req = urllib.request.Request(url) - r = urllib.request.urlopen(req).read() - cont = json.loads(r.decode('utf-8')) - supply = cont['metricData']['series'][0]['values'][0] + url = ( + "https://community-api.coinmetrics.io/" + + "v2/assets/btc/metricdata?metrics=SplyCur&start=" + + str(date) + + "&end=" + + str(date) + ) + cont = requests.get(url, proxies=proxies).json() + supply = cont["metricData"]["series"][0]["values"][0] return float(supply) -def infoFromCoinMetrics(period): +def infoFromCoinMetrics(period, proxies): dateYesterday = datetime.date.today() - datetime.timedelta(days=1) datePeriodInit = dateYesterday - datetime.timedelta(days=period) - supplyYesterday = btcSupplyOnDate(dateYesterday) - supplyPeriodAgo = btcSupplyOnDate(datePeriodInit) - stock_to_flow_ratio = supplyPeriodAgo / \ - ((supplyYesterday - supplyPeriodAgo) / period * 365) + supplyYesterday = btcSupplyOnDate(dateYesterday, proxies) + supplyPeriodAgo = btcSupplyOnDate(datePeriodInit, proxies) + stock_to_flow_ratio = supplyPeriodAgo / ( + (supplyYesterday - supplyPeriodAgo) / period * 365 + ) # conservative formula: 0.18*s2f^3.3, see comments above stock_to_flow_usd = 0.18 * stock_to_flow_ratio ** 3.3 return stock_to_flow_ratio, stock_to_flow_usd @@ -66,63 +76,132 @@ def s2f(args): It was 365 days in a past formula, then in June 2020 adjusted to 463 as 463 is the value fitting the curve best """ + if args.tor: + if os.name == "nt": + TOR_PORT = 9150 # Windows + else: + TOR_PORT = 9050 # LINUX + proxies = { + "http": f"socks5://127.0.0.1:{TOR_PORT}", + "https": f"socks5://127.0.0.1:{TOR_PORT}", + } + proxyindicator = " (via Tor)" + else: + proxies = {} + proxyindicator = "" + period = 463 - stock_to_flow_ratio, stock_to_flow_usd = infoFromCoinMetrics(period) - circulating, annual_inflation_percent, fwd_stock_to_flow, fwd_stock_to_flow_usd = infoFromMessari() + stock_to_flow_ratio, stock_to_flow_usd = infoFromCoinMetrics(period, proxies) + ( + usd_price, + circulating, + annual_inflation_percent, + fwd_stock_to_flow, + fwd_stock_to_flow_usd, + ) = infoFromMessari(proxies) if args.verbose: - print("Read about Stock-to-Flow here: {}".format( - "https://medium.com/@100trillionUSD/efficient-market-hypothesis-and-bitcoin-stock-to-flow-model-db17f40e6107")) - print("Compare with Stock-to-Flow data: {}".format( - "https://bitcoin.clarkmoody.com/dashboard/")) print( - "Compare with Stock-to-Flow graph: {}".format("https://digitalik.net/btc/")) + "Read about Stock-to-Flow here: " + "https://medium.com/@100trillionUSD/fficient-market-hypothesis-" + "and-bitcoin-stock-to-flow-model-db17f40e6107" + ) + print( + "Compare with Stock-to-Flow data: " + "https://bitcoin.clarkmoody.com/dashboard/" + ) + print("Compare with Stock-to-Flow graph: https://digitalik.net/btc/") if not args.terse: - print("Data sources: {}".format( - "messari.io and coinmetrics.io")) print( - "Calculated for date: {}".format( - datetime.date.today())) - print( - "Circulating BTC: {:,.0f} BTC".format(circulating)) - print("Annual inflation: {:.2f} %".format( - annual_inflation_percent)) - print("Forward stock-to-flow ratio: {:.2f}".format(fwd_stock_to_flow)) + "Data sources: " + f"messari.io and coinmetrics.io{proxyindicator}" + ) + print(f"Calculated for date: {datetime.date.today()}") + print(f"Circulating BTC: {circulating:,.0f} BTC") + print(f"Annual inflation: {annual_inflation_percent:.2f} %") + if args.terse: + labelForwRatio = "F/" + labelForwPrice = "F$" + labelBckwRatio = "B/" + labelBckwPrice = "B$" + labelCurrPrice = " $" + labelDeviation = "D%" + else: + labelForwRatio = "Forward stock-to-flow ratio: " + labelForwPrice = "Forward stock-to-flow price: " + labelBckwRatio = str(period) + "-day Stock-to-flow ratio: " + labelBckwPrice = str(period) + "-day Stock-to-flow price: " + labelCurrPrice = "Current price: " + labelDeviation = "Deviation of " + str(period) + "-day S2F price: " + print(f"{labelForwRatio} {fwd_stock_to_flow:.2f}") + print(f"{labelForwPrice} {fwd_stock_to_flow_usd:,.0f} USD") + print(f"{labelBckwRatio} {stock_to_flow_ratio:.2f}") + print(f"{labelBckwPrice} {stock_to_flow_usd:,.0f} USD") + print(f"{labelCurrPrice} {usd_price:,.0f} USD") print( - "Forward stock-to-flow price: {:,.0f} USD".format(fwd_stock_to_flow_usd)) - print("{}-day Stock-to-flow ratio: {:.2f}".format(period, stock_to_flow_ratio)) - print("{}-day Stock-to-flow price: {:,.0f} USD".format(period, stock_to_flow_usd)) - print("Current price: {:,.0f} USD".format(usd_price)) - print("Deviation of {}-day S2F price: {:,.2f} %".format(period, - (stock_to_flow_usd - usd_price) / stock_to_flow_usd * 100)) + f"{labelDeviation} " + f"{(stock_to_flow_usd -usd_price) / stock_to_flow_usd * 100:,.2f} %" + ) if __name__ == "__main__": if "DEBUG" in os.environ: logging.basicConfig() # initialize root logger, a must - logging.getLogger().setLevel(logging.DEBUG) # set log level on root logger + logging.getLogger().setLevel(logging.DEBUG) # set root logger log level else: - logging.getLogger().setLevel(logging.INFO) # set log level on root logger + logging.getLogger().setLevel(logging.INFO) # set root logger log level # Construct the argument parser ap = argparse.ArgumentParser( - description="This program prints the Bitcoin Stock-to-Flow ratio and price") + description="This program prints Bitcoin Stock-to-Flow ratio and price" + ) # Add the arguments to the parser - ap.add_argument("-d", "--debug", required=False, - action="store_true", help="Print debug information") - ap.add_argument("-v", "--verbose", required=False, - action="store_true", help="Print verbose output") - ap.add_argument("-t", "--terse", required=False, - action="store_true", help="Print only terse condensed output") + ap.add_argument( + "-d", + "--debug", + required=False, + action="store_true", + help="Print debug information", + ) + ap.add_argument( + "-v", + "--verbose", + required=False, + action="store_true", + help="Print verbose output", + ) + ap.add_argument( + "-t", + "--terse", + required=False, + action="store_true", + help="Print only terse condensed output", + ) + ap.add_argument( + "-o", # onion + "--tor", + required=False, + action="store_true", + help="Use Tor, go through Tor Socks5 proxy", + ) args = ap.parse_args() if args.debug: - logging.getLogger().setLevel(logging.DEBUG) # set log level on root logger + logging.getLogger().setLevel(logging.DEBUG) # set root logger log level logging.getLogger().info("Debug is turned on.") logger = logging.getLogger("s2f") try: s2f(args) + except requests.exceptions.ConnectionError: + if args.tor: + print("ConnectionError. Maybe Tor is not running.", file=sys.stderr) + else: + print( + "ConnectionError. Maybe network connection is not down.", + file=sys.stderr, + ) + sys.exit(1) except Exception: traceback.print_exc(file=sys.stdout) sys.exit(1)