class Coin: """Coin class, it holds loaded coin""" def __init__(self, symbol: str, load_from_api: bool = False): self.client = CoinGeckoAPI() if load_from_api: self._coin_list = self.client.get_coins_list() else: self._coin_list = read_file_data("coingecko_coins.json") self.coin_symbol, self.symbol = self._validate_coin(symbol) if self.coin_symbol: self.coin: Dict[Any, Any] = self._get_coin_info() def __str__(self): return f"{self.coin_symbol}" def _validate_coin( self, search_coin: str) -> Tuple[Optional[Any], Optional[Any]]: """Validate if given coin symbol or id exists in list of available coins on CoinGecko. If yes it returns coin id. [Source: CoinGecko] Parameters ---------- symbol: str Either coin symbol or coin id Returns ------- Tuple[str, str] - str with coin - str with symbol """ coin = None symbol = None for dct in self._coin_list: if search_coin.lower() in [ dct["id"], dct["symbol"], ]: coin = dct.get("id") symbol = dct.get("symbol") return coin, symbol raise ValueError( f"Could not find coin with the given id: {search_coin}\n") def coin_list(self) -> list: """List all available coins [Source: CoinGecko] Returns ------- list list of all available coin ids """ return [token.get("id") for token in self._coin_list] def _get_coin_info(self) -> dict: """Helper method which fetch the coin information by id from CoinGecko API like: (name, price, market, ... including exchange tickers) [Source: CoinGecko] Returns ------- dict Coin information """ params = dict(localization="false", tickers="false", sparkline=True) return self.client.get_coin_by_id(self.coin_symbol, **params) def _get_links(self) -> Dict: """Helper method that extracts links from coin [Source: CoinGecko] Returns ------- dict Links related to coin """ return self.coin.get("links", {}) @property def get_repositories(self) -> Optional[Any]: """Get list of all repositories for given coin [Source: CoinGecko] Returns ------- list Repositories related to coin """ return self._get_links().get("repos_url") @property def get_developers_data(self) -> pd.DataFrame: """Get coin development data from GitHub or BitBucket like: number of pull requests, contributor etc [Source: CoinGecko] Returns ------- pandas.DataFrame Developers Data Columns: Metric, Value """ dev = self.coin.get("developer_data", {}) useless_keys = ( "code_additions_deletions_4_weeks", "last_4_weeks_commit_activity_series", ) remove_keys(useless_keys, dev) df = pd.Series(dev).to_frame().reset_index() df.columns = ["Metric", "Value"] df["Metric"] = df["Metric"].apply( lambda x: replace_underscores_in_column_names(x) if isinstance(x, str) else x) return df[df["Value"].notna()] @property def get_blockchain_explorers(self) -> Union[pd.DataFrame, Any]: """Get list of URLs to blockchain explorers for given coin. [Source: CoinGecko] Returns ------- pandas.DataFrame Blockchain Explorers Columns: Metric, Value """ blockchain = self._get_links().get("blockchain_site") if blockchain: dct = filter_list(blockchain) df = pd.Series(dct).to_frame().reset_index() df.columns = ["Metric", "Value"] df["Metric"] = df["Metric"].apply( lambda x: replace_underscores_in_column_names(x) if isinstance(x, str) else x) return df[df["Value"].notna()] return None @property def get_social_media(self) -> pd.DataFrame: """Get list of URLs to social media like twitter, facebook, reddit... [Source: CoinGecko] Returns ------- pandas.DataFrame Urls to social media Columns: Metric, Value """ social_dct = {} links = self._get_links() for (channel) in CHANNELS.keys(): # pylint: disable=consider-iterating-dictionary) if channel in links: value = links.get(channel, "") if channel == "twitter_screen_name": value = "https://twitter.com/" + value elif channel == "bitcointalk_thread_identifier" and value is not None: value = f"https://bitcointalk.org/index.php?topic={value}" social_dct[channel] = value social_dct["discord"] = find_discord(links.get("chat_url")) dct = rename_columns_in_dct(social_dct, CHANNELS) df = pd.Series(dct).to_frame().reset_index() df.columns = ["Metric", "Value"] df["Metric"] = df["Metric"].apply( lambda x: replace_underscores_in_column_names(x) if isinstance(x, str) else x) return df[df["Value"].notna()] @property def get_websites(self) -> pd.DataFrame: """Get list of URLs to websites like homepage of coin, forum. [Source: CoinGecko] Returns ------- pandas.DataFrame Urls to website, homepage, forum Columns: Metric, Value """ websites_dct = {} links = self._get_links() sites = ["homepage", "official_forum_url", "announcement_url"] for site in sites: websites_dct[site] = filter_list(links.get(site)) df = pd.Series(websites_dct).to_frame().reset_index() df.columns = ["Metric", "Value"] df["Value"] = df["Value"].apply(lambda x: ",".join(x)) df["Metric"] = df["Metric"].apply( lambda x: replace_underscores_in_column_names(x) if isinstance(x, str) else x) return df[df["Value"].notna()] @property def get_categories(self) -> Union[Dict[Any, Any], List[Any]]: """Coins categories. [Source: CoinGecko] Returns ------- list/dict Coin categories """ return self.coin.get("categories", {}) def _get_base_market_data_info(self) -> dict: """Helper method that fetches all the base market/price information about given coin. [Source: CoinGecko] Returns ------- dict All market related information for given coin """ market_dct = {} market_data = self.coin.get("market_data", {}) for stat in [ "total_supply", "max_supply", "circulating_supply", "price_change_percentage_24h", "price_change_percentage_7d", "price_change_percentage_30d", ]: market_dct[stat] = market_data.get(stat) prices = create_dictionary_with_prefixes(["current_price"], market_data, DENOMINATION) market_dct.update(prices) return market_dct @property def get_base_info(self) -> pd.DataFrame: """Get all the base information about given coin. [Source: CoinGecko] Returns ------- pandas.DataFrame Base information about coin """ regx = r'<a href="(.+?)">|</a>' results = {} for attr in BASE_INFO: info_obj = self.coin.get(attr, {}) if attr == "description": info_obj = info_obj.get("en") info_obj = re.sub(regx, "", info_obj) info_obj = re.sub(r"\r\n\r\n", " ", info_obj) results[attr] = info_obj results.update(self._get_base_market_data_info()) df = pd.Series(results).to_frame().reset_index() df.columns = ["Metric", "Value"] df["Metric"] = df["Metric"].apply( lambda x: replace_underscores_in_column_names(x) if isinstance(x, str) else x) return df[df["Value"].notna()] @property def get_market_data(self) -> pd.DataFrame: """Get all the base market information about given coin. [Source: CoinGecko] Returns ------- pandas.DataFrame Base market information about coin Metric,Value """ market_data = self.coin.get("market_data", {}) market_columns_denominated = [ "market_cap", "fully_diluted_valuation", "total_volume", "high_24h", "low_24h", ] denominated_data = create_dictionary_with_prefixes( market_columns_denominated, market_data, DENOMINATION) market_single_columns = [ "market_cap_rank", "total_supply", "max_supply", "circulating_supply", "price_change_percentage_24h", "price_change_percentage_7d", "price_change_percentage_30d", "price_change_percentage_60d", "price_change_percentage_1y", "market_cap_change_24h", ] single_stats = {} for col in market_single_columns: single_stats[col] = market_data.get(col) single_stats.update(denominated_data) try: single_stats["circulating_supply_to_total_supply_ratio"] = ( single_stats["circulating_supply"] / single_stats["total_supply"]) except (ZeroDivisionError, TypeError) as e: console.print(e) df = pd.Series(single_stats).to_frame().reset_index() df.columns = ["Metric", "Value"] df["Metric"] = df["Metric"].apply( lambda x: replace_underscores_in_column_names(x) if isinstance(x, str) else x) return df[df["Value"].notna()] def get_all_time_high(self, currency: str = "usd") -> pd.DataFrame: """Get all time high data for given coin. [Source: CoinGecko] Returns ------- pandas.DataFrame All time high price data Metric,Value """ market_data = self.coin.get("market_data", {}) if market_data == {}: return pd.DataFrame() ath_columns = [ "current_price", "ath", "ath_date", "ath_change_percentage", ] results = {} for column in ath_columns: results[column] = market_data[column].get(currency) df = pd.Series(results).to_frame().reset_index() df.columns = ["Metric", "Value"] df["Metric"] = df["Metric"].apply( lambda x: replace_underscores_in_column_names(x) if isinstance(x, str) else x) df["Metric"] = df["Metric"].apply( lambda x: x.replace("Ath", "All Time High")) df["Metric"] = df["Metric"] + f" {currency.upper()}" return df[df["Value"].notna()] def get_all_time_low(self, currency: str = "usd") -> pd.DataFrame: """Get all time low data for given coin. [Source: CoinGecko] Returns ------- pandas.DataFrame All time low price data Metric,Value """ market_data = self.coin.get("market_data", {}) if market_data == {}: return pd.DataFrame() ath_columns = [ "current_price", "atl", "atl_date", "atl_change_percentage", ] results = {} for column in ath_columns: results[column] = market_data[column].get(currency) df = pd.Series(results).to_frame().reset_index() df.columns = ["Metric", "Value"] df["Metric"] = df["Metric"].apply( lambda x: replace_underscores_in_column_names(x) if isinstance(x, str) else x) df["Metric"] = df["Metric"].apply( lambda x: x.replace("Atl", "All Time Low")) df["Metric"] = df["Metric"] + f" {currency.upper()}" return df[df["Value"].notna()] @property def get_scores(self) -> pd.DataFrame: """Get different kind of scores for given coin. [Source: CoinGecko] Returns ------- pandas.DataFrame Social, community, sentiment scores for coin Metric,Value """ score_columns = [ "coingecko_rank", "coingecko_score", "developer_score", "community_score", "liquidity_score", "sentiment_votes_up_percentage", "sentiment_votes_down_percentage", "public_interest_score", "community_data", "public_interest_stats", ] single_stats = {col: self.coin.get(col) for col in score_columns[:-2]} nested_stats = {} for col in score_columns[-2:]: _dct = self.coin.get(col, {}) for k, _ in _dct.items(): nested_stats[k] = _dct.get(k, {}) single_stats.update(nested_stats) df = pd.Series(single_stats).reset_index() df.replace({0: ""}, inplace=True) df = df.fillna("") df.columns = ["Metric", "Value"] # pylint: disable=unsupported-assignment-operation df["Metric"] = df["Metric"].apply( lambda x: replace_underscores_in_column_names(x) if isinstance(x, str) else x) return df[df["Value"].notna()] def get_coin_market_chart(self, vs_currency: str = "usd", days: int = 30, **kwargs: Any) -> pd.DataFrame: """Get prices for given coin. [Source: CoinGecko] Parameters ---------- vs_currency: str currency vs which display data days: int number of days to display the data kwargs Returns ------- pandas.DataFrame Prices for given coin Columns: time, price, currency """ prices = self.client.get_coin_market_chart_by_id( self.coin_symbol, vs_currency, days, **kwargs) prices = prices["prices"] df = pd.DataFrame(data=prices, columns=["time", "price"]) df["time"] = pd.to_datetime(df.time, unit="ms") df = df.set_index("time") df["currency"] = vs_currency return df def get_ohlc(self, vs_currency: str = "usd", days: int = 90) -> pd.DataFrame: """Get Open, High, Low, Close prices for given coin. [Source: CoinGecko] Parameters ---------- vs_currency: str currency vs which display data days: int number of days to display the data on from (1/7/14/30/90/180/365, max) Returns ------- pandas.DataFrame OHLC data for coin Columns: time, price, currency """ prices = self.client.get_coin_ohlc_by_id(self.coin_symbol, vs_currency, days) df = pd.DataFrame(data=prices, columns=["time", "open", "high", "low", "close"]) df["time"] = pd.to_datetime(df.time, unit="ms") df = df.set_index("time") df["currency"] = vs_currency return df
class Coin: """Coin class, it holds loaded coin""" def __init__(self, symbol): self.client = CoinGeckoAPI() self._coin_list = self.client.get_coins_list() self.coin_symbol = self._validate_coin(symbol) if self.coin_symbol: self.coin = self._get_coin_info() def __str__(self): return f"{self.coin_symbol}" def _validate_coin(self, symbol): """Validate if given coin symbol or id exists in list of available coins on CoinGecko. If yes it returns coin id. Parameters ---------- symbol: str Either coin symbol or coin id Returns ------- id of the coin on CoinGecko service. """ coin = None for dct in self._coin_list: if symbol.lower() in list(dct.values()): coin = dct.get("id") if not coin: raise ValueError( f"Could not find coin with the given id: {symbol}\n") return coin def coin_list(self): """ Returns ------- list of all available coin ids """ return [token.get("id") for token in self._coin_list] def _get_coin_info(self): """Helper method which fetch the coin information by id from CoinGecko API like: (name, price, market, ... including exchange tickers) Returns ------- dict """ params = dict(localization="false", tickers="false", sparkline=True) return self.client.get_coin_by_id(self.coin_symbol, **params) def _get_links(self): """Helper method that extracts links from coin Returns ------- dict """ return self.coin.get("links") @property def repositories(self): """Get list of all repositories for given coin Returns ------- list with repositories """ return self._get_links().get("repos_url") @property def developers_data(self): """Get coin development data from GitHub or BitBucket like: number of pull requests, contributor etc Returns ------- pandas.DataFrame Metric, Value """ dev = self.coin.get("developer_data") useless_keys = ( "code_additions_deletions_4_weeks", "last_4_weeks_commit_activity_series", ) remove_keys(useless_keys, dev) df = pd.Series(dev).to_frame().reset_index() df.columns = ["Metric", "Value"] return df @property def blockchain_explorers(self): """Get list of URLs to blockchain explorers for given coin: Returns ------- pandas.DataFrame Metric, Value """ blockchain = self._get_links().get("blockchain_site") if blockchain: dct = filter_list(blockchain) df = pd.Series(dct).to_frame().reset_index() df.columns = ["Metric", "Value"] return df return None @property def social_media(self): """Get list of URLs to social media like twitter, facebook, reddit... Returns ------- pandas.DataFrame Metric, Value """ social_dct = {} links = self._get_links() for (channel) in CHANNELS.keys(): # pylint: disable=consider-iterating-dictionary) if channel in links: value = links.get(channel) if channel == "twitter_screen_name": value = "https://twitter.com/" + value elif channel == "bitcointalk_thread_identifier" and value is not None: value = f"https://bitcointalk.org/index.php?topic={value}" social_dct[channel] = value social_dct["discord"] = find_discord(links.get("chat_url")) dct = rename_columns_in_dct(social_dct, CHANNELS) df = pd.Series(dct).to_frame().reset_index() df.columns = ["Metric", "Value"] return df @property def websites(self): """Get list of URLs to websites like homepage of coin, forum, Returns ------- pandas.DataFrame Metric, Value """ websites_dct = {} links = self._get_links() sites = ["homepage", "official_forum_url", "announcement_url"] for site in sites: websites_dct[site] = filter_list(links.get(site)) df = pd.Series(websites_dct).to_frame().reset_index() df.columns = ["Metric", "Value"] df["Value"] = df["Value"].apply(lambda x: ",".join(x)) return df @property def categories(self): """Coins categories Returns ------- list/dict """ return self.coin.get("categories") def _get_base_market_data_info(self): """Helper method that fetches all the base market/price information about given coin Returns ------- dict """ market_dct = {} market_data = self.coin.get("market_data") for stat in [ "total_supply", "max_supply", "circulating_supply", "price_change_percentage_24h", "price_change_percentage_7d", "price_change_percentage_30d", ]: market_dct[stat] = market_data.get(stat) prices = create_dictionary_with_prefixes(["current_price"], market_data, DENOMINATION) market_dct.update(prices) return market_dct @property def base_info(self): """Get all the base information about given coin Returns ------- pandas.DataFrame """ results = {} for attr in BASE_INFO: info_obj = self.coin.get(attr) if attr == "description": info_obj = info_obj.get("en") results[attr] = info_obj results.update(self._get_base_market_data_info()) return pd.Series(results).to_frame().reset_index() @property def market_data(self): """Get all the base market information about given coin Returns ------- pandas.DataFrame Metric,Value """ market_data = self.coin.get("market_data") market_columns_denominated = [ "market_cap", "fully_diluted_valuation", "total_volume", "high_24h", "low_24h", ] denominated_data = create_dictionary_with_prefixes( market_columns_denominated, market_data, DENOMINATION) market_single_columns = [ "market_cap_rank", "total_supply", "max_supply", "circulating_supply", "price_change_percentage_24h", "price_change_percentage_7d", "price_change_percentage_30d", "price_change_percentage_60d", "price_change_percentage_1y", "market_cap_change_24h", ] single_stats = {} for col in market_single_columns: single_stats[col] = market_data.get(col) single_stats.update(denominated_data) try: single_stats["circulating_supply_to_total_supply_ratio"] = ( single_stats["circulating_supply"] / single_stats["total_supply"]) except (ZeroDivisionError, TypeError) as e: print(e) df = pd.Series(single_stats).to_frame().reset_index() df.columns = ["Metric", "Value"] return df @property def all_time_high(self): """Get all time high data for given coin Returns ------- pandas.DataFrame Metric,Value """ market_data = self.coin.get("market_data") ath_columns = [ "current_price", "ath", "ath_date", "ath_change_percentage", ] results = create_dictionary_with_prefixes(ath_columns, market_data, DENOMINATION) df = pd.Series(results).to_frame().reset_index() df.columns = ["Metric", "Value"] return df @property def all_time_low(self): """Get all time low data for given coin Returns ------- pandas.DataFrame Metric,Value """ market_data = self.coin.get("market_data") ath_columns = [ "current_price", "atl", "atl_date", "atl_change_percentage", ] results = create_dictionary_with_prefixes(ath_columns, market_data, DENOMINATION) df = pd.Series(results).to_frame().reset_index() df.columns = ["Metric", "Value"] return df @property def scores(self): """Get different kind of scores for given coin Returns ------- pandas.DataFrame Metric,Value """ score_columns = [ "coingecko_rank", "coingecko_score", "developer_score", "community_score", "liquidity_score", "sentiment_votes_up_percentage", "sentiment_votes_down_percentage", "public_interest_score", "community_data", "public_interest_stats", ] single_stats = {col: self.coin.get(col) for col in score_columns[:-2]} nested_stats = {} for col in score_columns[-2:]: _dct = self.coin.get(col) for k, _ in _dct.items(): nested_stats[k] = _dct.get(k) single_stats.update(nested_stats) df = pd.Series(single_stats).reset_index() df.replace({0: ""}, inplace=True) df = df.fillna("") df.columns = ["Metric", "Value"] return df def get_coin_market_chart(self, vs_currency="usd", days=30, **kwargs): """Get prices for given coin Parameters ---------- vs_currency: str currency vs which display data days: int number of days to display the data kwargs Returns ------- pandas.DataFrame time, price, currency """ prices = self.client.get_coin_market_chart_by_id( self.coin_symbol, vs_currency, days, **kwargs) prices = prices["prices"] df = pd.DataFrame(data=prices, columns=["time", "price"]) df["time"] = pd.to_datetime(df.time, unit="ms") df = df.set_index("time") df["currency"] = vs_currency return df def get_ohlc(self, vs_currency="usd", days=90): """Get Open, High, Low, Close prices for given coin Parameters ---------- vs_currency: str currency vs which display data days: int number of days to display the data on from (1/7/14/30/90/180/365, max) Returns ------- pandas.DataFrame time, price, currency """ prices = self.client.get_coin_ohlc_by_id(self.coin_symbol, vs_currency, days) df = pd.DataFrame(data=prices, columns=["time", "open", "high", "low", "close"]) df["time"] = pd.to_datetime(df.time, unit="ms") df = df.set_index("time") df["currency"] = vs_currency return df