diff options
author | jp <plutakuba@gmail.com> | 2021-09-05 18:15:35 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-05 17:15:35 +0100 |
commit | 28e3970912b3f81b59ca2de5d77e6034c7e581c1 (patch) | |
tree | 932154039fabd19d3ff6ddaf83df6429275b17f9 | |
parent | a78f3463d4a1ad853c9ac1205bbb5e8380f03b96 (diff) |
Refactoring crypto menu 2nd part (#724)
* Add separate view for finbrain for crypto curreny sentiment analysis
* Move json with symbols to separate directory, little refactoring, update readme
* Add screenshot of finbrain for PolkaDot
* Remove not used methods, remove binance_view, binance_model from discovery menu (It's not needed, as we use all_coins view for finding coins from all sources
* Refactoring Due Diligence menu. Changing views, moving argparsers to controller
* Refactor cryptomenu. Overview, Discovery, DD menu - move argparsers to controllers, add typing hints, change names of views/models, adjust tests
* Adjust tests
* Move finbrain and find/coins method to controller
* Move report argparser into controller. Adjust tests
* Adjust docstrings
* Add helper method to take care about retry/wait for coingecko scraping
* Fix failing test
* Adjust newlines, docstrings, cmd descriptions
* Add use tabulate df flag for all crypto views
* Add status code for coingecko
* Add note, that some coingecko commands can fail
Co-authored-by: Jakub Pluta <jakub.pluta@cdq.com>
36 files changed, 10390 insertions, 4594 deletions
diff --git a/gamestonk_terminal/cryptocurrency/coinpaprika_helpers.py b/gamestonk_terminal/cryptocurrency/coinpaprika_helpers.py index b2efd22364a..fbd2b882f2b 100644 --- a/gamestonk_terminal/cryptocurrency/coinpaprika_helpers.py +++ b/gamestonk_terminal/cryptocurrency/coinpaprika_helpers.py @@ -30,11 +30,13 @@ class PaprikaSession: "search": "/search", } - def __init__(self, max_retries=5): + def __init__(self, max_retries: int = 5): self.session = requests.Session() self.session.mount(self.PAPRIKA_BASE_URL, HTTPAdapter(max_retries=max_retries)) - def make_request(self, endpoint: str, payload: Optional[Any] = None, **kwargs): + def make_request( + self, endpoint: str, payload: Optional[Any] = None, **kwargs: Any + ) -> dict: """Helper method that handles request for coinpaprika api. It prepares URL for given endpoint and payload if it's part of requests @@ -50,8 +52,8 @@ class PaprikaSession: Returns ------- dict with response data - """ + url = f"{self.PAPRIKA_BASE_URL}{endpoint}" if payload is None: payload = {} diff --git a/gamestonk_terminal/cryptocurrency/crypto_controller.py b/gamestonk_terminal/cryptocurrency/crypto_controller.py index 4a76eec2858..851dbbac310 100644 --- a/gamestonk_terminal/cryptocurrency/crypto_controller.py +++ b/gamestonk_terminal/cryptocurrency/crypto_controller.py @@ -7,8 +7,13 @@ import os import matplotlib.pyplot as plt import pandas as pd from prompt_toolkit.completion import NestedCompleter +from binance.client import Client from gamestonk_terminal import feature_flags as gtff -from gamestonk_terminal.helper_funcs import get_flair +from gamestonk_terminal.helper_funcs import ( + get_flair, + parse_known_args_and_warn, + check_positive, +) from gamestonk_terminal.menu import session from gamestonk_terminal.cryptocurrency.technical_analysis import ta_controller from gamestonk_terminal.cryptocurrency.overview import overview_controller @@ -24,9 +29,19 @@ from gamestonk_terminal.cryptocurrency.discovery import ( from gamestonk_terminal.cryptocurrency.due_diligence import ( finbrain_crypto_view, ) +from gamestonk_terminal.cryptocurrency.due_diligence.finbrain_crypto_view import COINS -from gamestonk_terminal.cryptocurrency.cryptocurrency_helpers import load, find +from gamestonk_terminal.cryptocurrency.cryptocurrency_helpers import ( + load, + find, + load_ta_data, + plot_chart, +) from gamestonk_terminal.cryptocurrency.report import report_controller +from gamestonk_terminal.cryptocurrency.due_diligence.binance_model import ( + show_available_pairs_for_given_symbol, +) +import gamestonk_terminal.config_terminal as cfg class CryptoController: @@ -100,6 +115,8 @@ What do you want to do? else "\nSource: ?\n" ) help_text += """ +Note: Some of CoinGecko commands can fail. Team is working on fix. + load load a specific cryptocurrency for analysis chart view a candle chart for a specific cryptocurrency find alternate way to search for coins @@ -160,18 +177,185 @@ What do you want to do? def call_load(self, other_args): """Process load command""" try: - self.current_coin, self.source = load( - coin=self.current_coin, other_args=other_args + parser = argparse.ArgumentParser( + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + prog="load", + description="Load crypto currency to perform analysis on. " + "Available data sources are CoinGecko, CoinPaprika, and Binance" + "By default main source used for analysis is CoinGecko (cg). To change it use --source flag", ) + + parser.add_argument( + "-c", + "--coin", + help="Coin to get", + dest="coin", + type=str, + required="-h" not in other_args, + ) + + parser.add_argument( + "-s", + "--source", + help="Source of data", + dest="source", + choices=("cp", "cg", "bin"), + default="cg", + required=False, + ) + + try: + if other_args: + if not other_args[0][0] == "-": + other_args.insert(0, "-c") + + ns_parser = parse_known_args_and_warn(parser, other_args) + + if not ns_parser: + self.current_coin, self.source = self.current_coin, None + return + + source = ns_parser.source + + for arg in ["--source", source]: + if arg in other_args: + other_args.remove(arg) + + self.current_coin, self.source = load( + coin=ns_parser.coin, source=ns_parser.source + ) + + except Exception as e: + print(e, "\n") + self.current_coin, self.source = self.current_coin, None + except TypeError: print("Couldn't load data\n") def call_chart(self, other_args): """Process chart command""" if self.current_coin: - getattr(self.DD_VIEWS_MAPPING[self.source], "chart")( - self.current_coin, other_args + parser = argparse.ArgumentParser( + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + prog="chart", + description="""Loads data for technical analysis. You can specify currency vs which you want + to show chart and also number of days to get data for. + By default currency: usd and days: 30. + E.g. if you loaded in previous step Ethereum and you want to see it's price vs btc + in last 90 days range use `ta --vs btc --days 90`""", ) + + if self.source == "cp": + parser.add_argument( + "--vs", + default="usd", + dest="vs", + help="Currency to display vs coin", + choices=["usd", "btc", "BTC", "USD"], + type=str, + ) + + parser.add_argument( + "-d", + "--days", + default=30, + dest="days", + help="Number of days to get data for", + type=check_positive, + ) + + if self.source == "cg": + parser.add_argument( + "--vs", default="usd", dest="vs", help="Currency to display vs coin" + ) + + parser.add_argument( + "-d", + "--days", + default=30, + dest="days", + help="Number of days to get data for", + ) + + if self.source == "bin": + client = Client(cfg.API_BINANCE_KEY, cfg.API_BINANCE_SECRET) + interval_map = { + "1day": client.KLINE_INTERVAL_1DAY, + "3day": client.KLINE_INTERVAL_3DAY, + "1hour": client.KLINE_INTERVAL_1HOUR, + "2hour": client.KLINE_INTERVAL_2HOUR, + "4hour": client.KLINE_INTERVAL_4HOUR, + "6hour": client.KLINE_INTERVAL_6HOUR, + "8hour": client.KLINE_INTERVAL_8HOUR, + "12hour": client.KLINE_INTERVAL_12HOUR, + "1week": client.KLINE_INTERVAL_1WEEK, + "1min": client.KLINE_INTERVAL_1MINUTE, + "3min": client.KLINE_INTERVAL_3MINUTE, + "5min": client.KLINE_INTERVAL_5MINUTE, + "15min": client.KLINE_INTERVAL_15MINUTE, + "30min": client.KLINE_INTERVAL_30MINUTE, + "1month": client.KLINE_INTERVAL_1MONTH, + } + + _, quotes = show_available_pairs_for_given_symbol(self.current_coin) + + parser.add_argument( + "--vs", + help="Quote currency (what to view coin vs)", + dest="vs", + type=str, + default="USDT", + choices=quotes, + ) + + parser.add_argument( + "-i", + "--interval", + help="Interval to get data", + choices=list(interval_map.keys()), + dest="interval", + default="1day", + type=str, + ) + + parser.add_argument( + "-l", + "--limit", + dest="limit", + default=100, + help="Number to get", + type=check_positive, + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + + if not ns_parser: + return + + if self.source == "bin": + limit = ns_parser.limit + interval = ns_parser.interval + days = 0 + else: + limit = 0 + interval = "1day" + days = ns_parser.days + + plot_chart( + coin=self.current_coin, + limit=limit, + interval=interval, + days=days, + currency=ns_parser.vs, + source=self.source, + ) + + except Exception as e: + print(e, "\n") + else: print( "No coin selected. Use 'load' to load the coin you want to look at.\n" @@ -181,9 +365,125 @@ What do you want to do? """Process ta command""" # TODO: Play with this to get correct usage if self.current_coin: - self.current_df, self.current_currency = getattr( - self.DD_VIEWS_MAPPING[self.source], "load_ta_data" - )(self.current_coin, other_args) + parser = argparse.ArgumentParser( + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + prog="ta", + description="""Loads data for technical analysis. You can specify currency vs which you want + to show chart and also number of days to get data for. + By default currency: usd and days: 30. + E.g. if you loaded in previous step Ethereum and you want to see it's price vs btc + in last 90 days range use `ta --vs btc --days 90`""", + ) + + if self.source == "cp": + parser.add_argument( + "--vs", + default="usd", + dest="vs", + help="Currency to display vs coin", + choices=["usd", "btc", "BTC", "USD"], + type=str, + ) + + parser.add_argument( + "-d", + "--days", + default=30, + dest="days", + help="Number of days to get data for", + type=check_positive, + ) + + if self.source == "cg": + parser.add_argument( + "--vs", default="usd", dest="vs", help="Currency to display vs coin" + ) + + parser.add_argument( + "-d", + "--days", + default=30, + dest="days", + help="Number of days to get data for", + ) + + if self.source == "bin": + client = Client(cfg.API_BINANCE_KEY, cfg.API_BINANCE_SECRET) + interval_map = { + "1day": client.KLINE_INTERVAL_1DAY, + "3day": client.KLINE_INTERVAL_3DAY, + "1hour": client.KLINE_INTERVAL_1HOUR, + "2hour": client.KLINE_INTERVAL_2HOUR, + "4hour": client.KLINE_INTERVAL_4HOUR, + "6hour": client.KLINE_INTERVAL_6HOUR, + "8hour": client.KLINE_INTERVAL_8HOUR, + "12hour": client.KLINE_INTERVAL_12HOUR, + "1week": client.KLINE_INTERVAL_1WEEK, + "1min": client.KLINE_INTERVAL_1MINUTE, + "3min": client.KLINE_INTERVAL_3MINUTE, + "5min": client.KLINE_INTERVAL_5MINUTE, + "15min": client.KLINE_INTERVAL_15MINUTE, + "30min": client.KLINE_INTERVAL_30MINUTE, + "1month": client.KLINE_INTERVAL_1MONTH, + } + + _, quotes = show_available_pairs_for_given_symbol(self.current_coin) + parser.add_argument( + "--vs", + help="Quote currency (what to view coin vs)", + dest="vs", + type=str, + default="USDT", + choices=quotes, + ) + + parser.add_argument( + "-i", + "--interval", + help="Interval to get data", + choices=list(interval_map.keys()), + dest="interval", + default="1day", + type=str, + ) + + parser.add_argument( + "-l", + "--limit", + dest="limit", + default=100, + help="Number to get", + type=check_positive, + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + + if not ns_parser: + return + + if self.source == "bin": + limit = ns_parser.limit + interval = ns_parser.interval + days = 0 + else: + limit = 0 + interval = "1day" + days = ns_parser.days + + self.current_df, self.current_currency = load_ta_data( + coin=self.current_coin, + source=self.source, + currency=ns_parser.vs, + days=days, + limit=limit, + interval=interval, + ) + + except Exception as e: + print(e, "\n") + if self.current_currency != "" and not self.current_df.empty: try: quit = ta_controller.menu( @@ -225,7 +525,44 @@ What do you want to do? def call_finbrain(self, other_args): """Process finbrain command""" - finbrain_crypto_view.crypto_sentiment_analysis(other_args=other_args) + parser = argparse.ArgumentParser( + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + prog="finbrain", + description="""Display sentiment analysis from FinBrain for chosen Cryptocurrencies""", + ) + + parser.add_argument( + "-c", + "--coin", + default="BTC", + type=str, + dest="coin", + help="Symbol of coin to load data for, ~100 symbols are available", + choices=COINS, + ) + + 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 + + finbrain_crypto_view.display_crypto_sentiment_analysis( + coin=ns_parser.coin, export=ns_parser.export + ) + + except Exception as e: + print(e, "\n") def call_dd(self, _): """Process dd command""" @@ -251,7 +588,87 @@ What do you want to do? def call_find(self, other_args): """Process find command""" - find(other_args=other_args) + parser = argparse.ArgumentParser( + prog="find", + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + description=""" + Find similar coin by coin name,symbol or id. If you don't remember exact name or id of the Coin at CoinGecko, + Binance or CoinPaprika you can use this command to display coins with similar name, symbol or id + to your search query. + Example of usage: coin name is something like "polka". So I can try: find -c polka -k name -t 25 + It will search for coin that has similar name to polka and display top 25 matches. + -c, --coin stands for coin - you provide here your search query + -k, --key it's a searching key. You can search by symbol, id or name of coin + -t, --top it displays top N number of records.""", + ) + + parser.add_argument( + "-c", + "--coin", + help="Symbol Name or Id of Coin", + dest="coin", + required="-h" not in other_args, + type=str, + ) + + parser.add_argument( + "-k", + "--key", + dest="key", + help="Specify by which column you would like to search: symbol, name, id", |