diff --git a/gamestonk_terminal/config_terminal.py b/gamestonk_terminal/config_terminal.py index ea2aab6b960..bed32fd3644 100644 --- a/gamestonk_terminal/config_terminal.py +++ b/gamestonk_terminal/config_terminal.py @@ -45,3 +45,6 @@ TRADIER_TOKEN = os.getenv("GT_TRADIER_TOKEN") or "REPLACE_ME" # Selenium Webbrowser drivers can be found at https://selenium-python.readthedocs.io/installation.html WEBDRIVER_TO_USE = "chrome" PATH_TO_SELENIUM_DRIVER = None # Replace with "PATH" + +# https://coinmarketcap.com/api/ +COINMARKETCAP_KEY = os.getenv("GT_CMC_API_KEY") or "REPLACE_ME" diff --git a/gamestonk_terminal/cryptocurrency/README.md b/gamestonk_terminal/cryptocurrency/README.md index fd5ac92c10e..78a1167ffbf 100644 --- a/gamestonk_terminal/cryptocurrency/README.md +++ b/gamestonk_terminal/cryptocurrency/README.md @@ -9,6 +9,7 @@ Current functionality is aimed to be similar to loading a stock ticker. * [load](#load) * [view](#view) +* [top](#top) ## load Load a given coin vs a given currency: @@ -39,3 +40,18 @@ usage: view After loading the above 1 day dogecoin/eur. Running view plots the data: ![doge](https://user-images.githubusercontent.com/18151143/112690617-7832f500-8e52-11eb-84c4-253ab222a918.png) + + +## top +This command displays the top n cryptocurrencies from coinmarketcap.com. The list appears to be sorted by Mar + +```` +top [-n] [-s --sort SORTBY] [--descend] +```` +* -n: Number of coins to look at (after sort). Defaults to 10. +* -s/--sort : Column to sort by. One of {Symbol,CMC_Rank,LastPrice,DayPctChange,MarketCap}. Defaults to sorting by the CMC rank. +* --descend : Flag to change the sorting order. Sorts in ascending order (since default order is the Rank which starts at 1). + +Example usage to get the CMC top 100, then show the top 4 highest Percent Day Change + +![im](https://user-images.githubusercontent.com/18151143/115587223-6bf85700-a29b-11eb-9d96-cb4239b7c2d0.png) diff --git a/gamestonk_terminal/cryptocurrency/coinmarketcap_view.py b/gamestonk_terminal/cryptocurrency/coinmarketcap_view.py new file mode 100644 index 00000000000..a8820889d33 --- /dev/null +++ b/gamestonk_terminal/cryptocurrency/coinmarketcap_view.py @@ -0,0 +1,100 @@ +"""CoinMarketCap API""" +__docformat__ = "numpy" + +import argparse +from typing import List +import pandas as pd +from tabulate import tabulate +from coinmarketcapapi import CoinMarketCapAPI +from gamestonk_terminal.config_terminal import COINMARKETCAP_KEY +from gamestonk_terminal.helper_funcs import parse_known_args_and_warn + +sort_options = ["Symbol", "CMC_Rank", "LastPrice", "DayPctChange", "MarketCap"] + +sort_map = { + "Symbol": "Symbol", + "CMC_Rank": "CMC_Rank", + "LastPrice": "Last Price", + "DayPctChange": "1 Day Pct Change", + "MarketCap": "Market Cap ($B)", +} + + +def get_cmc_top_n(other_args: List[str]): + """ + Shows top n coins from coinmarketcap.com + Parameters + ---------- + other_args: List[str] + Arguments to pass to argparse + + """ + parser = argparse.ArgumentParser( + prog="cmc_top_n", + add_help=False, + description="This gets the top ranked coins from coinmarketcap.com", + ) + + parser.add_argument( + "-n", default=10, dest="n_to_get", type=int, help="number of coins to display" + ) + + parser.add_argument( + "-s", + "--sort", + dest="sortby", + type=str, + help="column to sort data by.", + default="CMC_Rank", + choices=sort_options, + ) + + parser.add_argument( + "--descend", + action="store_false", + help="Flag to sort in descending order (lowest first)", + dest="descend", + default=True, + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + + cmc = CoinMarketCapAPI(COINMARKETCAP_KEY) + ratings = cmc.cryptocurrency_listings_latest().data + + symbol, rank, price, pchange1d, mkt_cap = [], [], [], [], [] + for coin in ratings: + symbol.append(coin["symbol"]) + rank.append(coin["cmc_rank"]) + price.append(coin["quote"]["USD"]["price"]) + pchange1d.append(coin["quote"]["USD"]["percent_change_24h"]) + mkt_cap.append(coin["quote"]["USD"]["market_cap"] / (10 ** 9)) + + df = pd.DataFrame(data=[symbol, rank, price, pchange1d, mkt_cap]).transpose() + df.columns = [ + "Symbol", + "CMC_Rank", + "Last Price", + "1 Day Pct Change", + "Market Cap ($B)", + ] + + df = df.sort_values(by=sort_map[ns_parser.sortby], ascending=ns_parser.descend) + + print( + tabulate( + df.iloc[: ns_parser.n_to_get, :], + headers=df.columns, + showindex=False, + tablefmt="fancy_grid", + floatfmt=".2f", + ) + ) + print("") + + except Exception as e: + print(e) + print("") diff --git a/gamestonk_terminal/cryptocurrency/crypto_controller.py b/gamestonk_terminal/cryptocurrency/crypto_controller.py index 4a1508e11f8..e78323b473b 100644 --- a/gamestonk_terminal/cryptocurrency/crypto_controller.py +++ b/gamestonk_terminal/cryptocurrency/crypto_controller.py @@ -7,12 +7,13 @@ from prompt_toolkit.completion import NestedCompleter from gamestonk_terminal import feature_flags as gtff from gamestonk_terminal.helper_funcs import get_flair from gamestonk_terminal.menu import session -from gamestonk_terminal.cryptocurrency import coin_api +from gamestonk_terminal.cryptocurrency import pycoingecko_view +from gamestonk_terminal.cryptocurrency import coinmarketcap_view as cmc_view class CryptoController: - CHOICES = ["help", "q", "quit", "load", "view"] + CHOICES = ["help", "q", "quit", "load", "view", "top"] def __init__(self): """ CONSTRUCTOR """ @@ -34,6 +35,8 @@ class CryptoController: print(" load load cryptocurrency data") print(" view load and view cryptocurrency data") print("") + print(" top view top coins from coinmarketcap") + print("") def switch(self, an_input: str): """Process and dispatch input @@ -64,16 +67,19 @@ class CryptoController: return True def call_load(self, other_args): - self.current_coin, self.current_df = coin_api.load(other_args) + self.current_coin, self.current_df = pycoingecko_view.load(other_args) def call_view(self, other_args): if self.current_coin: - coin_api.view(self.current_coin, self.current_df, other_args) + pycoingecko_view.view(self.current_coin, self.current_df, other_args) else: print("No coin selected. Use 'load' to load the coin you want to look at.") print("") + def call_top(self, other_args): + cmc_view.get_cmc_top_n(other_args) + def menu(): crypto_controller = CryptoController() diff --git a/gamestonk_terminal/cryptocurrency/coin_api.py b/gamestonk_terminal/cryptocurrency/pycoingecko_view.py similarity index 100% rename from gamestonk_terminal/cryptocurrency/coin_api.py rename to gamestonk_terminal/cryptocurrency/pycoingecko_view.py diff --git a/poetry.lock b/poetry.lock index 582cfdfc228..1c9dc7b56d1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2046,6 +2046,14 @@ toml = "*" [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +[[package]] +name = "python-coinmarketcap" +version = "0.2" +description = "CoinMarketCap Python API Wrapper" +category = "main" +optional = false +python-versions = "*" + [[package]] name = "python-dateutil" version = "2.8.1" @@ -2946,7 +2954,7 @@ prediction = ["fbprophet", "tensorflow", "pmdarima", "transformers", "flair", "t [metadata] lock-version = "1.1" python-versions = "^3.6.8" -content-hash = "2f3963dac96a208dfe5157d593c45f946d9b4c829b16302f2b297250390367cb" +content-hash = "fa7c02ebec2d14a1c42f76f8e1328134975893c5f98afa879f2bc672675d6a7f" [metadata.files] absl-py = [ @@ -4275,6 +4283,11 @@ pytest = [ {file = "pytest-6.2.3-py3-none-any.whl", hash = "sha256:6ad9c7bdf517a808242b998ac20063c41532a570d088d77eec1ee12b0b5574bc"}, {file = "pytest-6.2.3.tar.gz", hash = "sha256:671238a46e4df0f3498d1c3270e5deb9b32d25134c99b7d75370a68cfbe9b634"}, ] +python-coinmarketcap = [ + {file = "python-coinmarketcap-0.2.tar.gz", hash = "sha256:b1e0e8b098fc910a5ec943a06774d5ee3b190e915123366e2f16238ef0a8a433"}, + {file = "python_coinmarketcap-0.2-py2-none-any.whl", hash = "sha256:54c278154ee11ca78837fb73eae8c322a60af93dc0ce75b515fecf895d181cf5"}, + {file = "python_coinmarketcap-0.2-py3-none-any.whl", hash = "sha256:3b69a7a92cd4f2b4726a2982d166c0b587fa4911cf366286f798e1e6f9d94933"}, +] python-dateutil = [ {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, diff --git a/pyproject.toml b/pyproject.toml index 53f0f468699..a3bbf6762c7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,6 +58,7 @@ statsmodels = "^0.12.2" tabulate = "^0.8.9" pyportfolioopt = "^1.4.1" selenium = "^3.141.0" +python-coinmarketcap = "^0.2" [tool.poetry.dev-dependencies] pytest = "^6.2.2" diff --git a/requirements-full.txt b/requirements-full.txt index 39247ebb9c6..1dce549665e 100644 --- a/requirements-full.txt +++ b/requirements-full.txt @@ -146,6 +146,7 @@ pyportfolioopt==1.4.1; python_full_version >= "3.6.1" and python_full_version < pyrsistent==0.14.11 pysocks==1.7.1; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" pystan==2.19.1.1 +python-coinmarketcap==0.2 python-dateutil==2.8.1; python_full_version >= "3.6.1" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6") and (python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0") and (python_version >= "2.7" and python_full_version < "3.0.0" and python_version < "4" or python_version >= "2.7" and python_version < "4" and python_full_version >= "3.3.0") python-dotenv==0.17.0; python_version >= "3" pytrends==4.7.3 diff --git a/requirements-old.txt b/requirements-old.txt index 3dd16fb2a3f..6dcb6d00577 100644 --- a/requirements-old.txt +++ b/requirements-old.txt @@ -93,6 +93,7 @@ pyparsing==2.4.7; python_full_version >= "3.6.0" and python_version >= "3.6" pyportfolioopt==1.4.1 pysocks==1.7.1; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" pystan==2.18 +python-coinmarketcap==0.2 python-dateutil==2.8.1; python_full_version >= "3.6.1" and python_version >= "3.5" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6") and (python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0") and (python_version >= "2.7" and python_full_version < "3.0.0" and python_version < "4" or python_version >= "2.7" and python_version < "4" and python_full_version >= "3.3.0") pytest==6.2.2; python_version >= "3.6" pytrends==4.7.3 diff --git a/requirements-win.txt b/requirements-win.txt index d5b413e1ca6..399b80c6f67 100644 --- a/requirements-win.txt +++ b/requirements-win.txt @@ -95,6 +95,7 @@ pyparsing==2.4.7; python_full_version >= "3.6.0" and python_version >= "3.6" pyportfolioopt==1.4.1 pysocks==1.7.1; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" pystan==2.19.1.1 +python-coinmarketcap==0.2 python-dateutil==2.8.1; python_full_version >= "3.6.1" and python_version >= "3.5" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6") and (python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0") and (python_version >= "2.7" and python_full_version < "3.0.0" and python_version < "4" or python_version >= "2.7" and python_version < "4" and python_full_version >= "3.3.0") pytest==6.2.2; python_version >= "3.6" pytrends==4.7.3 diff --git a/requirements.txt b/requirements.txt index 31e6b0412cc..bf0985ecfa5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -110,6 +110,7 @@ pyparsing==2.4.7; python_version >= "3.6" and python_full_version < "3.0.0" or p pyportfolioopt==1.4.1; python_full_version >= "3.6.1" and python_full_version < "4.0.0" pyrsistent==0.14.11 pysocks==1.7.1; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" +python-coinmarketcap==0.2 python-dateutil==2.8.1; python_full_version >= "3.6.1" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6") and (python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0") python-dotenv==0.17.0; python_version >= "3" pytrends==4.7.3 diff --git a/tests/test_coingecko_crypto.py b/tests/test_coingecko_crypto.py index 5f20e2e04d1..e0eed2eed55 100644 --- a/tests/test_coingecko_crypto.py +++ b/tests/test_coingecko_crypto.py @@ -1,14 +1,14 @@ from unittest import mock, TestCase import json from pycoingecko import CoinGeckoAPI -from gamestonk_terminal.cryptocurrency.coin_api import load +from gamestonk_terminal.cryptocurrency.pycoingecko_view import load # pylint: disable=unused-import class TestCoinGeckoAPI(TestCase): @mock.patch( - "gamestonk_terminal.cryptocurrency.coin_api.CoinGeckoAPI.get_coin_market_chart_by_id" + "gamestonk_terminal.cryptocurrency.pycoingecko_view.CoinGeckoAPI.get_coin_market_chart_by_id" ) def test_coin_api_load(self, mock_load): """