mirror of
https://github.com/8go/bitcoin-stock-to-flow.git
synced 2021-05-12 18:52:14 +03:00
added --tor option for TOR socks5 proxy
Now you can use Tor Onion routing Formatting with black
This commit is contained in:
203
s2f.py
203
s2f.py
@@ -4,56 +4,66 @@
|
||||
# Ignore long lines
|
||||
# pylama:format=pep8:linters=pep8:ignore=E501
|
||||
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import traceback
|
||||
import argparse
|
||||
import datetime
|
||||
import json
|
||||
import urllib.request
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user