From f4dac4dc4221329914bdde787746c8d095754c32 Mon Sep 17 00:00:00 2001 From: jose-donato <43375532+jose-donato@users.noreply.github.com> Date: Sat, 23 Oct 2021 00:08:39 +0100 Subject: [PATCH] Active addresses command (#840) * feat: added active command * fix: added more examples to onchain * fix: lint issues * fix: linting issues * fix: linting issues --- gamestonk_terminal/config_terminal.py | 3 + .../cryptocurrency/crypto_controller.py | 11 +- .../cryptocurrency/defi/defi_controller.py | 2 - .../cryptocurrency/onchain/glassnode_model.py | 49 ++++ .../cryptocurrency/onchain/glassnode_view.py | 63 +++++ .../onchain/onchain_controller.py | 224 +++++++++++++++++- .../report/report_controller.py | 4 +- .../stocks/report/report_controller.py | 4 +- .../cryptocurrency/onchain/active/_index.md | 23 ++ .../cryptocurrency/onchain/whales/_index.md | 3 +- website/data/menu/main.yml | 54 +++-- 11 files changed, 397 insertions(+), 43 deletions(-) create mode 100644 gamestonk_terminal/cryptocurrency/onchain/glassnode_model.py create mode 100644 gamestonk_terminal/cryptocurrency/onchain/glassnode_view.py create mode 100644 website/content/cryptocurrency/onchain/active/_index.md diff --git a/gamestonk_terminal/config_terminal.py b/gamestonk_terminal/config_terminal.py index 13dc477fdfc..93365cce239 100644 --- a/gamestonk_terminal/config_terminal.py +++ b/gamestonk_terminal/config_terminal.py @@ -97,5 +97,8 @@ API_COINBASE_PASS_PHRASE = os.getenv("GT_API_COINBASE_PASS_PHRASE") or "REPLACE_ # https://docs.whale-alert.io/ API_WHALE_ALERT_KEY = os.getenv("GT_API_WHALE_ALERT_KEY") or "REPLACE_ME" +# https://docs.glassnode.com/basic-api/api-key#how-to-get-an-api-key +API_GLASSNODE_KEY = os.getenv("GT_API_GLASSNODE_KEY") or "REPLACE_ME" + # https://github.com/EverexIO/Ethplorer/wiki/Ethplorer-API API_ETHPLORER_KEY = os.getenv("GT_API_ETHPLORER_KEY") or "freekey" diff --git a/gamestonk_terminal/cryptocurrency/crypto_controller.py b/gamestonk_terminal/cryptocurrency/crypto_controller.py index 38f7046cccb..7ce1ba26d9c 100644 --- a/gamestonk_terminal/cryptocurrency/crypto_controller.py +++ b/gamestonk_terminal/cryptocurrency/crypto_controller.py @@ -6,6 +6,7 @@ import argparse import os import matplotlib.pyplot as plt import pandas as pd +from colorama import Style from prompt_toolkit.completion import NestedCompleter from binance.client import Client from gamestonk_terminal import feature_flags as gtff @@ -114,8 +115,7 @@ What do you want to do? if self.source != "" else "\nSource: ?\n" ) - help_text += """ -Note: Some of CoinGecko commands can fail. Team is working on fix. + help_text += f""" load load a specific cryptocurrency for analysis chart view a candle chart for a specific cryptocurrency @@ -124,11 +124,12 @@ Note: Some of CoinGecko commands can fail. Team is working on fix. > disc discover trending cryptocurrencies, e.g.: top gainers, losers, top sentiment > ov overview of the cryptocurrencies, e.g.: market cap, DeFi, latest news, top exchanges, stables +> onchain information on different blockchains, e.g.: eth gas fees, active asset addresses, whale alerts +> defi decentralized finance information, e.g.: dpi, llama, tvl, lending, borrow, funding +> report generate automatic report {Style.DIM if not self.current_coin else ""} > dd due-diligence for loaded coin, e.g.: coin information, social media, market stats > ta technical analysis for loaded coin, e.g.: ema, macd, rsi, adx, bbands, obv -> onchain information on different blockchains, e.g.: eth gas fees -> defi decentralized finance information, e.g.: dpi, llama, tvl, lending, borrow, funding -> report generate automatic report +{Style.RESET_ALL if not self.current_coin else ""} """ print(help_text) diff --git a/gamestonk_terminal/cryptocurrency/defi/defi_controller.py b/gamestonk_terminal/cryptocurrency/defi/defi_controller.py index ebee79c25bd..98bed04018c 100644 --- a/gamestonk_terminal/cryptocurrency/defi/defi_controller.py +++ b/gamestonk_terminal/cryptocurrency/defi/defi_controller.py @@ -21,8 +21,6 @@ from gamestonk_terminal.cryptocurrency.defi import ( substack_view, ) -# pylint: disable=R1732 - class DefiController: """Defi Controller class""" diff --git a/gamestonk_terminal/cryptocurrency/onchain/glassnode_model.py b/gamestonk_terminal/cryptocurrency/onchain/glassnode_model.py new file mode 100644 index 00000000000..8b762a17f79 --- /dev/null +++ b/gamestonk_terminal/cryptocurrency/onchain/glassnode_model.py @@ -0,0 +1,49 @@ +import json +import pandas as pd +import requests +from gamestonk_terminal import config_terminal as cfg + + +def get_active_addresses( + asset: str, interval: str, since: int, until: int +) -> pd.DataFrame: + """Returns active addresses of a certain asset + [Source: https://glassnode.com] + + Parameters + ---------- + asset : str + Asset to search active addresses (e.g., BTC) + since : int + Initial date timestamp (e.g., 1_614_556_800) + until : str + End date timestamp (e.g., 1_614_556_800) + interval : str + Interval frequency (e.g., 24h) + + Returns + ------- + pd.DataFrame + active addresses over time + """ + + url = "https://api.glassnode.com/v1/metrics/addresses/active_count" + + parameters = { + "api_key": cfg.API_GLASSNODE_KEY, + "a": asset, + "i": interval, + "s": str(since), + "u": str(until), + } + + r = requests.get(url, params=parameters) + + if r.status_code == 200: + df = pd.DataFrame(json.loads(r.text)) + df = df.set_index("t") + df.index = pd.to_datetime(df.index, unit="s") + df = df.loc[df.index > "2010-1-1"] + df.reset_index(inplace=True) + return df + return pd.DataFrame() diff --git a/gamestonk_terminal/cryptocurrency/onchain/glassnode_view.py b/gamestonk_terminal/cryptocurrency/onchain/glassnode_view.py new file mode 100644 index 00000000000..b862c595093 --- /dev/null +++ b/gamestonk_terminal/cryptocurrency/onchain/glassnode_view.py @@ -0,0 +1,63 @@ +import os +from matplotlib import pyplot as plt +import pandas as pd +from gamestonk_terminal.cryptocurrency.onchain.glassnode_model import ( + get_active_addresses, +) +from gamestonk_terminal.helper_funcs import export_data, plot_autoscale +from gamestonk_terminal import config_plot as cfgPlot + + +def display_active_addresses( + asset: str, since: int, until: int, interval: str, export: str = "" +) -> None: + """Display active addresses of a certain asset over time + [Source: https://glassnode.org] + + Parameters + ---------- + asset : str + Asset to search active addresses (e.g., BTC) + since : int + Initial date timestamp (e.g., 1_614_556_800) + until : str + End date timestamp (e.g., 1_614_556_800) + interval : str + Interval frequency (e.g., 24h) + export : str + Export dataframe data to csv,json,xlsx file + """ + + df_addresses = get_active_addresses(asset, interval, since, until) + + if df_addresses.empty: + print("Error in glassnode request") + else: + plot_data(df_addresses, asset) + print("") + + export_data( + export, + os.path.dirname(os.path.abspath(__file__)), + "active", + df_addresses, + ) + + +def plot_data(df, asset): + df = df.set_index("t") + df.index = pd.to_datetime(df.index, unit="s") + df = df.loc[df.index > "2010-1-1"] + df.reset_index(inplace=True) + + _, main_ax = plt.subplots(figsize=plot_autoscale(), dpi=cfgPlot.PLOT_DPI) + + main_ax.plot(df["t"], df["v"], linewidth=0.5) + main_ax.set_yscale("log") + main_ax.grid(True) + + main_ax.set_title(f"Active {asset} addresses over time") + main_ax.set_ylabel("Addresses") + main_ax.set_xlabel("Date") + + plt.show() diff --git a/gamestonk_terminal/cryptocurrency/onchain/onchain_controller.py b/gamestonk_terminal/cryptocurrency/onchain/onchain_controller.py index f9a548d1d58..323255b74ff 100644 --- a/gamestonk_terminal/cryptocurrency/onchain/onchain_controller.py +++ b/gamestonk_terminal/cryptocurrency/onchain/onchain_controller.py @@ -1,9 +1,12 @@ """Onchain Controller Module""" __docformat__ = "numpy" +# pylint: disable=C0302 + import os import argparse from typing import List +from datetime import datetime, timedelta from prompt_toolkit.completion import NestedCompleter @@ -14,16 +17,16 @@ from gamestonk_terminal.helper_funcs import ( parse_known_args_and_warn, check_positive, check_int_range, + valid_date, ) from gamestonk_terminal.cryptocurrency.onchain import ( ethgasstation_view, + glassnode_view, whale_alert_view, ethplorer_view, ) -# pylint: disable=R1732 - class OnchainController: """Onchain Controller class""" @@ -62,6 +65,7 @@ class OnchainController: "th", "prices", "address", + "active", ] CHOICES += CHOICES_COMMANDS @@ -159,12 +163,218 @@ class OnchainController: except Exception as e: print(e, "\n") + def call_active(self, other_args: List[str]): + """Process active command""" + + supported_assets = [ + "BTC", + "ETH", + "LTC", + "AAVE", + "ABT", + "AMPL", + "ANT", + "ARMOR", + "BADGER", + "BAL", + "BAND", + "BAT", + "BIX", + "BNT", + "BOND", + "BRD", + "BUSD", + "BZRX", + "CELR", + "CHSB", + "CND", + "COMP", + "CREAM", + "CRO", + "CRV", + "CVC", + "CVP", + "DAI", + "DDX", + "DENT", + "DGX", + "DHT", + "DMG", + "DODO", + "DOUGH", + "DRGN", + "ELF", + "ENG", + "ENJ", + "EURS", + "FET", + "FTT", + "FUN", + "GNO", + "GUSD", + "HEGIC", + "HOT", + "HPT", + "HT", + "HUSD", + "INDEX", + "KCS", + "LAMB", + "LBA", + "LDO", + "LEO", + "LINK", + "LOOM", + "LRC", + "MANA", + "MATIC", + "MCB", + "MCO", + "MFT", + "MIR", + "MKR", + "MLN", + "MTA", + "MTL", + "MX", + "NDX", + "NEXO", + "NFTX", + "NMR", + "Nsure", + "OCEAN", + "OKB", + "OMG", + "PAX", + "PAY", + "PERP", + "PICKLE", + "PNK", + "PNT", + "POLY", + "POWR", + "PPT", + "QASH", + "QKC", + "QNT", + "RDN", + "REN", + "REP", + "RLC", + "ROOK", + "RPL", + "RSR", + "SAI", + "SAN", + "SNT", + "SNX", + "STAKE", + "STORJ", + "sUSD", + "SUSHI", + "TEL", + "TOP", + "UBT", + "UMA", + "UNI", + "USDC", + "USDK", + "USDT", + "UTK", + "VERI", + "WaBi", + "WAX", + "WBTC", + "WETH", + "wNMX", + "WTC", + "YAM", + "YFI", + "ZRX", + ] + + parser = argparse.ArgumentParser( + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + prog="active", + description=""" + Display active blockchain addresses over time + [Source: https://glassnode.org] + """, + ) + + parser.add_argument( + "-a", + "--asset", + dest="asset", + type=str, + help="Asset symbol. Default: BTC", + default="BTC", + choices=supported_assets, + ) + + parser.add_argument( + "-i", + "--interval", + dest="interval", + type=str, + help="Frequency interval. Default: 24h", + default="24h", + choices=["1h", "24h", "10m", "1w", "1month"], + ) + + # max_timestamp = int(datetime.timestamp(datetime.now())) + + parser.add_argument( + "-s", + "--since", + dest="since", + type=valid_date, + help="Initial date. Default: 2020-01-01", + default=(datetime.now() - timedelta(days=365)).strftime("%Y-%m-%d"), + ) + + parser.add_argument( + "-u", + "--until", + dest="until", + type=valid_date, + help="Final date. Default: 2021-01-01", + default=(datetime.now()).strftime("%Y-%m-%d"), + ) + + parser.add_argument( + "--export", + choices=["csv", "json", "xlsx"], + default="", + type=str, + dest="export", + help="Export dataframe data to csv,json,xlsx file", + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + + if not ns_parser: + return + + glassnode_view.display_active_addresses( + asset=ns_parser.asset, + interval=ns_parser.interval, + since=int(datetime.timestamp(ns_parser.since)), + until=int(datetime.timestamp(ns_parser.until)), + export=ns_parser.export, + ) + + except Exception as e: + print(e) + def call_whales(self, other_args: List[str]): """Process whales command""" parser = argparse.ArgumentParser( add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter, - prog="wales", + prog="whales", description=""" Display crypto whales transactions. [Source: https://docs.whale-alert.io/] @@ -845,7 +1055,13 @@ Onchain: q quit this menu, and shows back to main menu quit quit to abandon the program +Eth Gas Station: gwei check current eth gas fees + +Glassnode: + active check active addresses in a certain blockchain + +Whale Alert: whales check crypto wales transactions """ help_text += f"\nEthereum address: {self.address if self.address else '?'}" @@ -854,7 +1070,7 @@ Onchain: ) help_text += """ -Ethereum: +Ethereum [Ethplorer]: address load ethereum address of token, account or transaction top top ERC20 tokens""" diff --git a/gamestonk_terminal/cryptocurrency/report/report_controller.py b/gamestonk_terminal/cryptocurrency/report/report_controller.py index 64e3016cb3c..fd93093383a 100644 --- a/gamestonk_terminal/cryptocurrency/report/report_controller.py +++ b/gamestonk_terminal/cryptocurrency/report/report_controller.py @@ -1,6 +1,8 @@ """Papermill Controller Module""" __docformat__ = "numpy" +# pylint: disable=R1732 + import argparse import os from typing import List @@ -14,8 +16,6 @@ from gamestonk_terminal.helper_funcs import get_flair from gamestonk_terminal import config_terminal from gamestonk_terminal.helper_funcs import parse_known_args_and_warn -# pylint: disable=R1732 - class ReportController: """Report Controller class""" diff --git a/gamestonk_terminal/stocks/report/report_controller.py b/gamestonk_terminal/stocks/report/report_controller.py index 6833fa8aa2c..adfac7dc415 100644 --- a/gamestonk_terminal/stocks/report/report_controller.py +++ b/gamestonk_terminal/stocks/report/report_controller.py @@ -1,6 +1,8 @@ """Papermill Controller Module""" __docformat__ = "numpy" +# pylint: disable=R1732 + import argparse import os from typing import List @@ -16,8 +18,6 @@ from gamestonk_terminal.menu import session from gamestonk_terminal.helper_funcs import get_flair from gamestonk_terminal import config_terminal -# pylint: disable=R1732 - class ReportController: """Report Controller class""" diff --git a/website/content/cryptocurrency/onchain/active/_index.md b/website/content/cryptocurrency/onchain/active/_index.md new file mode 100644 index 00000000000..a466ca5286f --- /dev/null +++ b/website/content/cryptocurrency/onchain/active/_index.md @@ -0,0 +1,23 @@ +``` +usage: active [-a ASSET] + [-s INITIAL_DATE] + [-u END_DATE] + [-i {1h, 24h, 10m, 1w, 1month}] + [--export {csv,json,xlsx}] [-h] +``` + +Display active addresses on a certain blockchain over time [Source: https://glassnode.org] + +The number of unique addresses that were active either as a sender or receiver. Only addresses that were active in successful transactions are counted. + +Supported assets: BTC, ETH, LTC, AAVE, ABT, AMPL, ANT, ARMOR, BADGER, BAL, BAND, BAT, BIX, BNT, BOND, BRD, BUSD, BZRX, CELR, CHSB, CND, COMP, CREAM, CRO, CRV, CVC, CVP, DAI, DDX, DENT, DGX, DHT, DMG, DODO, DOUGH, DRGN, ELF, ENG, ENJ, EURS, FET, FTT, FUN, GNO, GUSD, HEGIC, HOT, HPT, HT, HUSD, INDEX, KCS, LAMB, LBA, LDO, LEO, LINK, LOOM, LRC, MANA, MATIC, MCB, MCO, MFT, MIR, MKR, MLN, MTA, MTL, MX, NDX, NEXO, NFTX, NMR, Nsure, OCEAN, OKB, OMG, PAX, PAY, PERP, PICKLE, PNK, PNT, POLY, POWR, PPT, QASH, QKC, QNT, RDN, REN, REP, RLC, ROOK, RPL, RSR, SAI, SAN, SNT, SNX, STAKE, STORJ, sUSD, SUSHI, TEL, TOP, UBT, UMA, UNI, USDC, USDK, USDT, UTK, VERI, WaBi, WAX, WBTC, WETH, wNMX, WTC, YAM, YFI, ZRX + +``` +optional arguments: + -a ASSET Asset to search for active addresses (default: BTC) + -s DATE --since DATE Start date (default: 1 year before, e.g., 2020-10-22) + -u DATE --until DATE End date (default: current day, e.g., 2021-10-22) + -i INTERV --interval INTERV Interval frequency (default: 24h) + --export {csv,json,xlsx} Export dataframe data to csv,json,xlsx file (default: ) + -h, --help show this help message (default: False) +``` diff --git a/website/content/cryptocurrency/onchain/whales/_index.md b/website/content/cryptocurrency/onchain/whales/_index.md index 9b440fa6fcf..c71bc413432 100644 --- a/website/content/cryptocurrency/onchain/whales/_index.md +++ b/website/content/cryptocurrency/onchain/whales/_index.md @@ -6,13 +6,12 @@ usage: whales [-m MIN] [-t TOP] Display huge value transactions from major blockchains. [Source: https://docs.whale-alert.io/] - ``` optional arguments: -m MIN, --min MIN Minimum value of transactions. (default: 1000000) -t TOP, --top TOP top N number of records (default: 10) -s {date,symbol,blockchain,amount,amount_usd,from,to}, --sort {date,symbol,blockchain,amount,amount_usd,from,to} - Sort by given column. Default: date (default: date) + Sort by given column (default: date) --descend Flag to sort in descending order (lowest first) (default: True) -a, --address Flag to show addresses of transactions (default: False) diff --git a/website/data/menu/main.yml b/website/data/menu/main.yml index a3669abf274..0749762b21d 100755 --- a/website/data/menu/main.yml +++ b/website/data/menu/main.yml @@ -663,32 +663,32 @@ main: - name: portfolio optimization ref: "/portfolio/portfolio_optimization" sub: - - name: select - ref: "/portfolio/portfolio_optimization/select" - - name: add - ref: "/portfolio/portfolio_optimization/add" - - name: rmv - ref: "/portfolio/portfolio_optimization/rmv" - - name: equal - ref: "/portfolio/portfolio_optimization/equal" - - name: mktcap - ref: "/portfolio/portfolio_optimization/mktcap" - - name: dividend - ref: "/portfolio/portfolio_optimization/dividend" - - name: property - ref: "/portfolio/portfolio_optimization/property" - - name: maxhsarpe - ref: "/portfolio/portfolio_optimization/maxsharpe" - - name: minvol - ref: "/portfolio/portfolio_optimization/minvol" - - name: maxquadutil - ref: "/portfolio/portfolio_optimization/maxquadutil" - - name: effret - ref: "/portfolio/portfolio_optimization/effret" - - name: effrisk - ref: "/portfolio/portfolio_optimization/effrisk" - - name: ef - ref: "/portfolio/portfolio_optimization/ef" + - name: select + ref: "/portfolio/portfolio_optimization/select" + - name: add + ref: "/portfolio/portfolio_optimization/add" + - name: rmv + ref: "/portfolio/portfolio_optimization/rmv" + - name: equal + ref: "/portfolio/portfolio_optimization/equal" + - name: mktcap + ref: "/portfolio/portfolio_optimization/mktcap" + - name: dividend + ref: "/portfolio/portfolio_optimization/dividend" + - name: property + ref: "/portfolio/portfolio_optimization/property" + - name: maxhsarpe + ref: "/portfolio/portfolio_optimization/maxsharpe" + - name: minvol + ref: "/portfolio/portfolio_optimization/minvol" + - name: maxquadutil + ref: "/portfolio/portfolio_optimization/maxquadutil" + - name: effret + ref: "/portfolio/portfolio_optimization/effret" + - name: effrisk + ref: "/portfolio/portfolio_optimization/effrisk" + - name: ef + ref: "/portfolio/portfolio_optimization/ef" - name: cryptocurrency ref: "/cryptocurrency" sub: @@ -830,6 +830,8 @@ main: sub: - name: gwei ref: "/cryptocurrency/onchain/gwei" + - name: active + ref: "/cryptocurrency/onchain/active" - name: technical analysis ref: "/cryptocurrency/technical_analysis" sub: