diff --git a/gamestonk_terminal/cryptocurrency/dataframe_helpers.py b/gamestonk_terminal/cryptocurrency/dataframe_helpers.py index 7e9f8b50fe5..638f2104881 100644 --- a/gamestonk_terminal/cryptocurrency/dataframe_helpers.py +++ b/gamestonk_terminal/cryptocurrency/dataframe_helpers.py @@ -2,7 +2,7 @@ __docformat__ = "numpy" import re -from typing import Union, Any +from typing import Union, Any, Optional import textwrap import pandas as pd from gamestonk_terminal.helper_funcs import long_number_format @@ -137,3 +137,46 @@ def prettify_column_names(columns: list) -> list: list with reformatted columns """ return [" ".join(re.findall(".[^A-Z]*", val)).capitalize() for val in columns] + + +def denominate_number( + number: Any, divider: int = 1000000, round_digits: Optional[int] = 4 +) -> float: + """Denominate numbers base on provided divider and round number by provided digit + + Parameters + ---------- + number: Any + value to round + divider: int + divide by value + round_digits: + round number to n digits + Returns + ------- + float: + denominated number + """ + + if round_digits: + return round(float(number) / divider, round_digits) + return round(float(number) / divider) + + +def replace_unicode(x: Any) -> Any: + """Replace unicode characters to ? + + Parameters + ---------- + x: Any + value to replace unicode chars + + Returns + ------- + Any + replaced value + """ + + if isinstance(x, str): + return x.encode("ascii", "replace").decode() + return x diff --git a/gamestonk_terminal/cryptocurrency/defi/defi_controller.py b/gamestonk_terminal/cryptocurrency/defi/defi_controller.py index f7372fa08a9..c2ffb7e1f57 100644 --- a/gamestonk_terminal/cryptocurrency/defi/defi_controller.py +++ b/gamestonk_terminal/cryptocurrency/defi/defi_controller.py @@ -1,6 +1,8 @@ """Defi Controller Module""" __docformat__ = "numpy" +# pylint: disable=C0302 + import argparse from typing import List @@ -11,6 +13,8 @@ from gamestonk_terminal.cryptocurrency.defi import ( coindix_model, terraengineer_model, terraengineer_view, + terramoney_fcd_view, + terramoney_fcd_model, ) from gamestonk_terminal.parent_classes import BaseController from gamestonk_terminal import feature_flags as gtff @@ -18,6 +22,7 @@ from gamestonk_terminal.menu import session from gamestonk_terminal.helper_funcs import ( parse_known_args_and_warn, check_positive, + check_terra_address_format, EXPORT_ONLY_RAW_DATA_ALLOWED, EXPORT_BOTH_RAW_DATA_AND_FIGURES, ) @@ -54,6 +59,12 @@ class DefiController(BaseController): "vaults", "ayr", "aterra", + "sinfo", + "validators", + "govp", + "gacc", + "sratio", + "sreturn", ] PATH = "/crypto/defi/" @@ -75,6 +86,14 @@ class DefiController(BaseController): choices["vaults"]["-k"] = {c: {} for c in coindix_model.VAULT_KINDS} choices["vaults"]["-c"] = {c: {} for c in coindix_model.CHAINS} choices["vaults"]["-p"] = {c: {} for c in coindix_model.PROTOCOLS} + choices["govp"]["-s"] = {c: {} for c in terramoney_fcd_model.GOV_COLUMNS} + choices["govp"]["--status"] = { + c: {} for c in terramoney_fcd_model.GOV_STATUSES + } + choices["validators"]["-s"] = { + c: {} for c in terramoney_fcd_model.VALIDATORS_COLUMNS + } + self.completer = NestedCompleter.from_nested_dict(choices) def print_help(self): @@ -95,12 +114,19 @@ class DefiController(BaseController): swaps Recent swaps done on Uniswap [src][Defi Llama][/src] ldapps Lists dApps - gdapps Display top DeFi dApps grouped by chain - stvl Display historical values of the total sum of TVLs from all dApps - dtvl Display historical total value locked (TVL) by dApp + gdapps Displays top DeFi dApps grouped by chain + stvl Displays historical values of the total sum of TVLs from all dApps + dtvl Displays historical total value locked (TVL) by dApp [src][Terra Engineer][/src] - aterra Displays 30-day history of specified asset in terra address - ayr Displays 30-day history of anchor yield reserve[/cmds] + aterra Displays 30-day history of specified asset in terra address [src][Terra Engineer][/src] + ayr Displays 30-day history of anchor yield reserve [src][Terra Engineer][/src] +[src][Terra FCD][/src] + sinfo Displays staking info for provided terra account address + validators Displays information about terra blockchain validators + govp Displays terra blockchain governance proposals list + gacc Displays terra blockchain account growth history + sratio Displays terra blockchain staking ratio history + sreturn Displays terra blockchain staking returns history[/cmds] """ console.print(text=help_text, menu="Cryptocurrency - Decentralized Finance") @@ -125,7 +151,7 @@ class DefiController(BaseController): parser.add_argument( "--address", dest="address", - type=str, + type=check_terra_address_format, help="Terra address. Valid terra addresses start with 'terra'", required=True, ) @@ -167,6 +193,265 @@ class DefiController(BaseController): if ns_parser: terraengineer_view.display_anchor_yield_reserve(export=ns_parser.export) + def call_sinfo(self, other_args: List[str]): + parser = argparse.ArgumentParser( + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + prog="sinfo", + description=""" + Displays staking info of a certain terra address. + [Source: https://fcd.terra.dev/swagger] + """, + ) + parser.add_argument( + "-a", + "--address", + dest="address", + type=check_terra_address_format, + help="Terra address. Valid terra addresses start with 'terra'", + required="-h" not in other_args, + ) + parser.add_argument( + "-l", + "--limit", + dest="limit", + type=check_positive, + help="Number of delegations", + default=10, + ) + + if other_args and not other_args[0][0] == "-": + other_args.insert(0, "-a") + + ns_parser = parse_known_args_and_warn( + parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED + ) + + if ns_parser: + terramoney_fcd_view.display_account_staking_info( + export=ns_parser.export, address=ns_parser.address, top=ns_parser.limit + ) + + def call_validators(self, other_args: List[str]): + parser = argparse.ArgumentParser( + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + prog="validators", + description=""" + Displays information about terra validators. + [Source: https://fcd.terra.dev/swagger] + """, + ) + parser.add_argument( + "-l", + "--limit", + dest="limit", + type=check_positive, + help="Number of validators to show", + default=10, + ) + parser.add_argument( + "-s", + "--sort", + dest="sortby", + type=str, + help="Sort by given column. Default: votingPower", + default="votingPower", + choices=[ + "validatorName", + "tokensAmount", + "votingPower", + "commissionRate", + "status", + "uptime", + ], + ) + parser.add_argument( + "--descend", + action="store_true", + help="Flag to sort in descending order (lowest first)", + dest="descend", + default=False, + ) + + ns_parser = parse_known_args_and_warn( + parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED + ) + + if ns_parser: + terramoney_fcd_view.display_validators( + export=ns_parser.export, + sortby=ns_parser.sortby, + descend=ns_parser.descend, + top=ns_parser.limit, + ) + + def call_govp(self, other_args: List[str]): + parser = argparse.ArgumentParser( + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + prog="govp", + description=""" + Displays terra blockchain governance proposals list. + [Source: https://fcd.terra.dev/swagger] + """, + ) + parser.add_argument( + "-l", + "--limit", + dest="limit", + type=check_positive, + help="Number of proposals to show", + default=10, + ) + parser.add_argument( + "-s", + "--sort", + dest="sortby", + type=str, + help="Sort by given column. Default: id", + default="id", + choices=terramoney_fcd_model.GOV_COLUMNS, + ) + parser.add_argument( + "--status", + dest="status", + type=str, + help="Status of proposal. Default: all", + default="all", + choices=terramoney_fcd_model.GOV_STATUSES, + ) + parser.add_argument( + "--descend", + action="store_false", + help="Flag to sort in descending order (lowest first)", + dest="descend", + default=False, + ) + + ns_parser = parse_known_args_and_warn( + parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED + ) + + if ns_parser: + terramoney_fcd_view.display_gov_proposals( + status=ns_parser.status, + export=ns_parser.export, + sortby=ns_parser.sortby, + descend=ns_parser.descend, + top=ns_parser.limit, + ) + + def call_gacc(self, other_args: List[str]): + parser = argparse.ArgumentParser( + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + prog="gacc", + description=""" + Displays terra blockchain account growth history. + [Source: https://fcd.terra.dev/swagger] + """, + ) + parser.add_argument( + "-l", + "--limit", + dest="limit", + type=check_positive, + help="Number of days to show", + default=90, + ) + parser.add_argument( + "--cumulative", + action="store_false", + help="Show cumulative or discrete values. For active accounts only discrete value are available", + dest="cumulative", + default=True, + ) + parser.add_argument( + "-k", + "--kind", + dest="kind", + type=str, + help="Total account count or active account count. Default: total", + default="total", + choices=["active", "total"], + ) + parser.add_argument( + "--descend", + action="store_false", + help="Flag to sort in descending order (lowest first)", + dest="descend", + default=False, + ) + + ns_parser = parse_known_args_and_warn( + parser, other_args, EXPORT_BOTH_RAW_DATA_AND_FIGURES + ) + + if ns_parser: + terramoney_fcd_view.display_account_growth( + kind=ns_parser.kind, + export=ns_parser.export, + cumulative=ns_parser.cumulative, + top=ns_parser.limit, + ) + + def call_sratio(self, other_args: List[str]): + parser = argparse.ArgumentParser( + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + prog="sratio", + description=""" + Displays terra blockchain staking ratio history. + [Source: https://fcd.terra.dev/swagger] + """, + ) + parser.add_argument( + "-l", + "--limit", + dest="limit", + type=check_positive, + help="Number of days to show", + default=90, + ) + + ns_parser = parse_known_args_and_warn( + parser, other_args, EXPORT_BOTH_RAW_DATA_AND_FIGURES + ) + + if ns_parser: + terramoney_fcd_view.display_staking_ratio_history( + export=ns_parser.export, top=ns_parser.limit + ) + + def call_sreturn(self, other_args: List[str]): + parser = argparse.ArgumentParser( + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + prog="sreturn", + description=""" + Displays terra blockchain staking returns history. + [Source: https://fcd.terra.dev/swagger] + """, + ) + parser.add_argument( + "-l", + "--limit", + dest="limit", + type=check_positive, + help="Number of days to show", + default=90, + ) + + ns_parser = parse_known_args_and_warn( + parser, other_args, EXPORT_BOTH_RAW_DATA_AND_FIGURES + ) + + if ns_parser: + terramoney_fcd_view.display_staking_returns_history( + export=ns_parser.export, top=ns_parser.limit + ) + def call_dpi(self, other_args: List[str]): """Process dpi command""" parser = argparse.ArgumentParser( diff --git a/gamestonk_terminal/cryptocurrency/defi/terramoney_fcd_model.py b/gamestonk_terminal/cryptocurrency/defi/terramoney_fcd_model.py new file mode 100644 index 00000000000..3fae390733b --- /dev/null +++ b/gamestonk_terminal/cryptocurrency/defi/terramoney_fcd_model.py @@ -0,0 +1,273 @@ +"""Terra Money FCD model""" +__docformat__ = "numpy" + +import textwrap +from typing import Any, Tuple +from datetime import datetime +import requests +import pandas as pd +from gamestonk_terminal.cryptocurrency.dataframe_helpers import ( + denominate_number, + prettify_column_names, + replace_unicode, +) + +GOV_COLUMNS = [ + "submitTime", + "id", + "depositEndTime", + "status", + "type", + "title", + "Yes", + "No", +] +GOV_STATUSES = ["voting", "deposit", "passed", "rejected", "all"] +VALIDATORS_COLUMNS = [ + "validatorName", + "tokensAmount", + "votingPower", + "commissionRate", + "status", + "uptime", +] + + +def _make_request(endpoint: str) -> dict: + """Helper method handles terra fcd api requests. [Source: https://fcd.terra.dev/v1] + + Parameters + ---------- + endpoint: str + endpoint url + Returns + ------- + dict: + dictionary with response data + """ + + url = f"https://fcd.terra.dev/v1/{endpoint}" + response = requests.get( + url, headers={"Accept": "application/json", "User-Agent": "GST"} + ) + if not 200 <= response.status_code < 300: + raise Exception(f"fcd terra api exception: {response.text}") + try: + return response.json() + except Exception as e: + raise ValueError(f"Invalid Response: {response.text}") from e + + +def _adjust_delegation_info(delegation: dict) -> dict: + """Helper method which removes redundant fields from delegation info dictionary, + and denominate value fields. [Source: https://fcd.terra.dev/v1] + + Parameters + ---------- + delegation: + dictionary object with delegation data e.g. + + Returns + ------- + dict + adjusted dictionary with delegation data + """ + + delegation_info = {} + for key, value in delegation.items(): + if key in ["amountDelegated", "totalReward"]: + delegation_info[key] = denominate_number(value) + elif key in ["validatorAddress", "rewards"]: + continue + else: + delegation_info[key] = value + return delegation_info + + +def get_staking_account_info(address: str = "") -> Tuple[pd.DataFrame, str]: + """Get staking info for provided terra account [Source: https://fcd.terra.dev/swagger] + + Parameters + ---------- + address: str + terra blockchain address e.g. terra1jvwelvs7rdk6j3mqdztq5tya99w8lxk6l9hcqg + Returns + ------- + Tuple[pd.DataFrame, str]: + luna delegations and summary report for given address + """ + + response = _make_request(f"staking/{address}") + results: dict[str, Any] = {"myDelegations": []} + + for field in ["availableLuna", "delegationTotal"]: + results[field] = denominate_number(response.get(field, 0)) + + my_delegations = response.get("myDelegations") + if my_delegations: + for delegation in my_delegations: + validator = _adjust_delegation_info(delegation) + results["myDelegations"].append(validator) + + df = pd.DataFrame(results["myDelegations"]) + + try: + df["validatorName"] = df["validatorName"].apply(lambda x: replace_unicode(x)) + df.columns = prettify_column_names(list(df.columns)) + except KeyError: + df = pd.DataFrame() + + results["totalRewards"] = denominate_number( + response.get("rewards", {}).get("total", 0) + ) + + report = f"""Overview: + Address: {address} + Available Luna: {results['availableLuna']} + Delegated Luna: {results['delegationTotal']} + Total Rewards: {results['totalRewards']}\n""" + report += "\nDelegations: " if not df.empty else "\nNo delegations found\n" + + return df, report + + +def get_validators() -> pd.DataFrame: + """Get information about terra validators [Source: https://fcd.terra.dev/swagger] + + Returns + ------- + pd.DataFrame + terra validators details + """ + + response = _make_request("staking")["validators"] + results = [] + for validator in response: + results.append( + { + "accountAddress": validator["accountAddress"], + "validatorName": validator["description"].get("moniker"), + "tokensAmount": denominate_number(validator["tokens"]), + "votingPower": round( + (float(validator["votingPower"].get("weight")) * 100), 2 + ), + "commissionRate": round( + (float(validator["commissionInfo"].get("rate", 0)) * 100), 2 + ), + "status": validator["status"], + "uptime": round((float(validator.get("upTime", 0)) * 100), 2), + } + ) + + return pd.DataFrame(results).sort_values(by="votingPower") + + +def get_proposals(status: str = "") -> pd.DataFrame: + """Get terra blockchain governance proposals list [Source: https://fcd.terra.dev/swagger] + + Parameters + ---------- + status: str + status of proposal, one from list: ['Voting','Deposit','Passed','Rejected'] + + Returns + ------- + pd.DataFrame + Terra blockchain governance proposals list + """ + + statuses = ["Voting", "Deposit", "Passed", "Rejected"] + response = _make_request("gov/proposals")["proposals"] + results = [] + votes_options = ["Yes", "Abstain", "No", "NoWithVeto"] + for proposal in response: + deposit = proposal.pop("deposit") + proposal["depositEndTime"] = deposit.get("depositEndTime") + vote = proposal.pop("vote") + proposal.pop("proposer") + for opt in votes_options: + proposal[opt] = vote["count"].get(opt) + + results.append(proposal) + columns = [ + "id", + "submitTime", + "depositEndTime", + "status", + "type", + "title", + "Yes", + "No", + "Abstain", + "NoWithVeto", + ] + df = pd.DataFrame(results)[columns] + df[["id", "Yes", "No", "Abstain", "NoWithVeto"]] = df[ + ["id", "Yes", "No", "Abstain", "NoWithVeto"] + ].astype(int, errors="ignore") + df["title"] = df["title"].apply( + lambda x: "\n".join(textwrap.wrap(x, width=40)) if isinstance(x, str) else x + ) + + for col in ["submitTime", "depositEndTime"]: + df[col] = df[col].apply(lambda x: pd.to_datetime(x).strftime("%Y-%m-%d %H:%M")) + + if status.title() in statuses: + df = df[df["status"] == status.title()] + return df + + +def get_account_growth(cumulative: bool = True) -> pd.DataFrame: + """Get terra blockchain account growth history [Source: https://fcd.terra.dev/swagger] + + Parameters + ---------- + cumulative: bool + distinguish between periodical and cumulative account growth data + Returns + ------- + pd.DataFrame + historical data of accounts growth + """ + + response = _make_request("dashboard/account_growth") + kind = "cumulative" if cumulative else "periodic" + df = pd.DataFrame(response[kind]) + df["date"] = df["datetime"].apply(lambda x: datetime.fromtimestamp(x / 1000).date()) + df = df[["date", "totalAccountCount", "activeAccountCount"]] + df.columns = ["date", "Total accounts", "Active accounts"] + return df + + +def get_staking_ratio_history(): + """Get terra blockchain staking ratio history [Source: https://fcd.terra.dev/swagger] + + Returns + ------- + pd.DataFrame + historical staking ratio + """ + + response = _make_request("dashboard/staking_ratio") + df = pd.DataFrame(response) + df["date"] = df["datetime"].apply(lambda x: datetime.fromtimestamp(x / 1000).date()) + df["stakingRatio"] = df["stakingRatio"].apply(lambda x: round(float(x) * 100, 2)) + return df[["date", "stakingRatio"]] + + +def get_staking_returns_history(): + """Get terra blockchain staking returns history [Source: https://fcd.terra.dev/v1] + + Returns + ------- + pd.DataFrame + historical staking returns + """ + + response = _make_request("dashboard/staking_return") + df = pd.DataFrame(response) + df["date"] = df["datetime"].apply(lambda x: datetime.fromtimestamp(x / 1000).date()) + df["annualizedReturn"] = df["annualizedReturn"].apply( + lambda x: round(float(x) * 100, 2) + ) + return df[["date", "annualizedReturn"]] diff --git a/gamestonk_terminal/cryptocurrency/defi/terramoney_fcd_view.py b/gamestonk_terminal/cryptocurrency/defi/terramoney_fcd_view.py new file mode 100644 index 00000000000..a8a91ef8c79 --- /dev/null +++ b/gamestonk_terminal/cryptocurrency/defi/terramoney_fcd_view.py @@ -0,0 +1,299 @@ +"""Terra Money FCD view""" +__docformat__ = "numpy" + +import os +import matplotlib.pyplot as plt +from matplotlib import ticker, dates as mdates +from gamestonk_terminal.cryptocurrency.defi import terramoney_fcd_model +from gamestonk_terminal.helper_funcs import ( + export_data, + long_number_format, + plot_autoscale, + rich_table_from_df, +) +from gamestonk_terminal.cryptocurrency.dataframe_helpers import ( + prettify_column_names, + very_long_number_formatter, +) +from gamestonk_terminal import feature_flags as gtff +from gamestonk_terminal.config_plot import PLOT_DPI +from gamestonk_terminal.rich_config import console + + +def display_account_staking_info( + address: str = "", top: int = 10, export: str = "" +) -> None: + """Display staking info for provided terra account address [Source: https://fcd.terra.dev/swagger] + + Parameters + ---------- + address: str + terra blockchain address e.g. terra1jvwelvs7rdk6j3mqdztq5tya99w8lxk6l9hcqg + top: int + Number of records to display + export : str + Export dataframe data to csv,json,xlsx file + """ + + df, report = terramoney_fcd_model.get_staking_account_info(address) + console.print(report) + if not df.empty: + if gtff.USE_TABULATE_DF: + console.print( + rich_table_from_df( + df.head(top), + headers=list(df.columns), + floatfmt=".2f", + show_index=False, + ), + "\n", + ) + else: + console.print(df.to_string, "\n") + + export_data( + export, + os.path.dirname(os.path.abspath(__file__)), + "sinfo", + df, + ) + + +def display_validators( + top: int = 10, sortby: str = "votingPower", descend: bool = False, export: str = "" +) -> None: + """Display information about terra validators [Source: https://fcd.terra.dev/swagger] + + Parameters + ---------- + top: int + Number of records to display + sortby: str + Key by which to sort data + descend: bool + Flag to sort data descending + export : str + Export dataframe data to csv,json,xlsx file + """ + + df = terramoney_fcd_model.get_validators() + df_data = df.copy() + df = df.sort_values(by=sortby, ascending=descend) + df["tokensAmount"] = df["tokensAmount"].apply( + lambda x: very_long_number_formatter(x) + ) + df.columns = [ + x if x not in ["Voting power", "Commission rate", "Uptime"] else f"{x} %" + for x in prettify_column_names(df.columns) + ] + + if gtff.USE_TABULATE_DF: + console.print( + rich_table_from_df( + df.head(top), + headers=list(df.columns), + floatfmt=".2f", + show_index=False, + ), + "\n", + ) + else: + console.print(df.to_string, "\n") + + export_data( + export, + os.path.dirname(os.path.abspath(__file__)), + "validators", + df_data, + ) + + +def display_gov_proposals( + top: int = 10, + status: str = "all", + sortby: str = "id", + descend: bool = False, + export: str = "", +) -> None: + """Display terra blockchain governance proposals list [Source: https://fcd.terra.dev/swagger] + + Parameters + ---------- + top: int + Number of records to display + status: str + status of proposal, one from list: ['Voting','Deposit','Passed','Rejected'] + sortby: str + Key by which to sort data + descend: bool + Flag to sort data descending + export : str + Export dataframe data to csv,json,xlsx file + """ + + df = terramoney_fcd_model.get_proposals(status) + df_data = df.copy() + df = df.sort_values(by=sortby, ascending=descend).head(top) + df.columns = prettify_column_names(df.columns) + + if gtff.USE_TABULATE_DF: + console.print( + rich_table_from_df( + df, + headers=list(df.columns), + floatfmt=".2f", + show_index=False, + ), + "\n", + ) + else: + console.print(df.to_string, "\n") + + export_data( + export, + os.path.dirname(os.path.abspath(__file__)), + "govp", + df_data, + ) + + +def display_account_growth( + kind: str = "total", cumulative: bool = False, top: int = 90, export: str = "" +) -> None: + """Display terra blockchain account growth history [Source: https://fcd.terra.dev/swagger] + + Parameters + ---------- + top: int + Number of records to display + kind: str + display total account count or active account count. One from list [active, total] + cumulative: bool + Flag to show cumulative or discrete values. For active accounts only discrete value are available. + export : str + Export dataframe data to csv,json,xlsx file + """ + + df = terramoney_fcd_model.get_account_growth(cumulative) + if kind not in ["active", "total"]: + kind = "total" + options = {"total": "Total accounts", "active": "Active accounts"} + + opt = options[kind] + label = "Cumulative" if cumulative and opt == "total" else "Daily" + + fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) + + df = df.sort_values("date", ascending=False).head(top) + df = df.set_index("date") + + start, end = df.index[-1], df.index[0] + if cumulative: + ax.plot(df[opt], label=df[opt]) + else: + ax.bar(x=df.index, height=df[opt], label=df[opt]) + + ax.set_ylabel(f"{opt}") + ax.set_xlabel("Date") + dateFmt = mdates.DateFormatter("%m/%d/%Y") + ax.xaxis.set_major_formatter(dateFmt) + + ax.get_yaxis().set_major_formatter( + ticker.FuncFormatter(lambda x, _: long_number_format(x)) + ) + fig.tight_layout(pad=8) + ax.set_title(f"{label} number of {opt.lower()} in period from {start} to {end}") + ax.grid(alpha=0.5) + ax.tick_params(axis="x", labelrotation=45) + if gtff.USE_ION: + plt.ion() + plt.show() + print("") + export_data( + export, + os.path.dirname(os.path.abspath(__file__)), + "gacc", + df, + ) + + +def display_staking_ratio_history(top: int = 90, export: str = "") -> None: + """Display terra blockchain staking ratio history [Source: https://fcd.terra.dev/v1] + + Parameters + ---------- + top: int + Number of records to display + export : str + Export dataframe data to csv,json,xlsx file + """ + + df = terramoney_fcd_model.get_staking_ratio_history() + + fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) + df = df.sort_values("date", ascending=False).head(top) + df = df.set_index("date") + + start, end = df.index[-1], df.index[0] + + ax.plot(df, label=df["stakingRatio"]) + ax.set_ylabel("Staking ratio [%]") + ax.set_xlabel("Date") + dateFmt = mdates.DateFormatter("%m/%d/%Y") + ax.xaxis.set_major_formatter(dateFmt) + + fig.tight_layout(pad=8) + ax.set_title(f"Staking ratio in period from {start} to {end}") + ax.grid(alpha=0.5) + ax.tick_params(axis="x", labelrotation=45) + if gtff.USE_ION: + plt.ion() + plt.show() + print("") + export_data( + export, + os.path.dirname(os.path.abspath(__file__)), + "sratio", + df, + ) + + +def display_staking_returns_history(top: int = 90, export: str = "") -> None: + """Display terra blockchain staking returns history [Source: https://fcd.terra.dev/swagger] + + Parameters + ---------- + top: int + Number of records to display + export : str + Export dataframe data to csv,json,xlsx file + """ + + df = terramoney_fcd_model.get_staking_returns_history() + + fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) + df = df.sort_values("date", ascending=False).head(top) + df = df.set_index("date") + + start, end = df.index[-1], df.index[0] + + ax.plot(df, label=df["annualizedReturn"]) + ax.set_ylabel("Staking returns [%]") + ax.set_xlabel("Date") + dateFmt = mdates.DateFormatter("%m/%d/%Y") + ax.xaxis.set_major_formatter(dateFmt) + + fig.tight_layout(pad=8) + ax.set_title(f"Staking returns in period from {start} to {end}") + ax.grid(alpha=0.5) + ax.tick_params(axis="x", labelrotation=45) + if gtff.USE_ION: + plt.ion() + plt.show() + print("") + export_data( + export, + os.path.dirname(os.path.abspath(__file__)), + "sreturn", + df, + ) diff --git a/gamestonk_terminal/helper_funcs.py b/gamestonk_terminal/helper_funcs.py index b1859e3f157..7cf0b9b37ef 100644 --- a/gamestonk_terminal/helper_funcs.py +++ b/gamestonk_terminal/helper_funcs.py @@ -161,6 +161,27 @@ def check_non_negative(value) -> int: return new_value +def check_terra_address_format(address: str) -> str: + """Validate if terra account address has proper format: ^terra1[a-z0-9]{38}$ + + Parameters + ---------- + address: str + terra blockchain account address + Returns + ------- + str + Terra blockchain address or raise argparse exception + """ + + pattern = re.compile(r"^terra1[a-z0-9]{38}$") + if not pattern.match(address): + raise argparse.ArgumentTypeError( + f"Terra address: {address} has invalid format. Valid format: ^terra1[a-z0-9]{{38}}$" + ) + return address + + def check_non_negative_float(value) -> float: """Argparse type to check non negative int""" new_value = float(value) diff --git a/website/content/cryptocurrency/defi/gacc/_index.md b/website/content/cryptocurrency/defi/gacc/_index.md new file mode 100644 index 00000000000..63d4a80b7ca --- /dev/null +++ b/website/content/cryptocurrency/defi/gacc/_index.md @@ -0,0 +1,17 @@ +``` +usage: gacc [-l LIMIT] [--cumulative] [-k {active,total}] [--descend] [-h] [--export {csv,json,xlsx}] +``` +Displays terra blockchain account growth history. [Source: https://fcd.terra.dev/swagger] + +``` +optional arguments: + -l LIMIT, --limit LIMIT + Number of days to show (default: 90) + --cumulative Show cumulative or discrete values. For active accounts only discrete value are available (default: True) + -k {active,total}, --kind {active,total} + Total account count or active account count. Default: total (default: total) + --descend Flag to sort in descending order (lowest first) (default: False) + -h, --help show this help message (default: False) + --export {csv,json,xlsx} + Export raw data into csv, json, xlsx (default: ) +``` \ No newline at end of file diff --git a/website/content/cryptocurrency/defi/govp/_index.md b/website/content/cryptocurrency/defi/govp/_index.md new file mode 100644 index 00000000000..19873cdb003 --- /dev/null +++ b/website/content/cryptocurrency/defi/govp/_index.md @@ -0,0 +1,17 @@ +``` +usage: govp [-l LIMIT] [-s {submitTime,id,depositEndTime,status,type,title,Yes,No}] [--status {voting,deposit,passed,rejected,all}] [--descend] [-h] [--export {csv,json,xlsx}] +``` +Displays terra blockchain governance proposals list. [Source: https://fcd.terra.dev/swagger] +``` +optional arguments: + -l LIMIT, --limit LIMIT + Number of proposals to show (default: 10) + -s {submitTime,id,depositEndTime,status,type,title,Yes,No}, --sort {submitTime,id,depositEndTime,status,type,title,Yes,No} + Sort by given column. Default: id (default: id) + --status {voting,deposit,passed,rejected,all} + Status of proposal. Default: all (default: all) + --descend Flag to sort in descending order (lowest first) (default: False) + -h, --help show this help message (default: False) + --export {csv,json,xlsx} + Export raw data into csv, json, xlsx (default: ) +``` \ No newline at end of file diff --git a/website/content/cryptocurrency/defi/sinfo/_index.md b/website/content/cryptocurrency/defi/sinfo/_index.md new file mode 100644 index 00000000000..ba16a8c1665 --- /dev/null +++ b/website/content/cryptocurrency/defi/sinfo/_index.md @@ -0,0 +1,15 @@ +``` +usage: sinfo [-a ADDRESS] [-l LIMIT] [-h] [--export {csv,json,xlsx}] +``` +Displays staking info of a certain terra address. [Source: https://fcd.terra.dev/swagger] + +``` +optional arguments: + -a ADDRESS, --address ADDRESS + Terra address. Valid terra addresses start with 'terra' (default: None) + -l LIMIT, --limit LIMIT + Number of delegations (default: 10) + -h, --help show this help message (default: False) + --export {csv,json,xlsx} + Export raw data into csv, json, xlsx (default: ) +``` \ No newline at end of file diff --git a/website/content/cryptocurrency/defi/sratio/_index.md b/website/content/cryptocurrency/defi/sratio/_index.md new file mode 100644 index 00000000000..7eef19dbb16 --- /dev/null +++ b/website/content/cryptocurrency/defi/sratio/_index.md @@ -0,0 +1,12 @@ +``` +usage: sratio [-l LIMIT] [-h] [--export {csv,json,xlsx}] +``` +Displays terra blockchain staking ratio history. [Source: https://fcd.terra.dev/swagger] +``` +optional arguments: + -l LIMIT, --limit LIMIT + Number of days to show (default: 90) + -h, --help show this help message (default: False) + --export {csv,json,xlsx} + Export raw data into csv, json, xlsx (default: ) +``` \ No newline at end of file diff --git a/website/content/cryptocurrency/defi/sreturn/_index.md b/website/content/cryptocurrency/defi/sreturn/_index.md new file mode 100644 index 00000000000..502f568ab44 --- /dev/null +++ b/website/content/cryptocurrency/defi/sreturn/_index.md @@ -0,0 +1,13 @@ +``` +usage: sreturn [-l LIMIT] [-h] [--export {csv,json,xlsx}] +``` +Displays terra blockchain staking returns history. [Source: https://fcd.terra.dev/swagger] + +``` +optional arguments: + -l LIMIT, --limit LIMIT + Number of days to show (default: 90) + -h, --help show this help message (default: False) + --export {csv,json,xlsx} + Export raw data into csv, json, xlsx (default: ) +``` \ No newline at end of file diff --git a/website/content/cryptocurrency/defi/validators/_index.md b/website/content/cryptocurrency/defi/validators/_index.md new file mode 100644 index 00000000000..04182ed24c2 --- /dev/null +++ b/website/content/cryptocurrency/defi/validators/_index.md @@ -0,0 +1,16 @@ +``` +usage: validators [-l LIMIT] [-s {validatorName,tokensAmount,votingPower,commissionRate,status,uptime}] [--descend] [-h] [--export {csv,json,xlsx}] +``` +Displays information about terra validators. [Source: https://fcd.terra.dev/swagger] + +``` +optional arguments: + -l LIMIT, --limit LIMIT + Number of validators to show (default: 10) + -s {validatorName,tokensAmount,votingPower,commissionRate,status,uptime}, --sort {validatorName,tokensAmount,votingPower,commissionRate,status,uptime} + Sort by given column. Default: votingPower (default: votingPower) + --descend Flag to sort in descending order (lowest first) (default: False) + -h, --help show this help message (default: False) + --export {csv,json,xlsx} + Export raw data into csv, json, xlsx (default: ) +``` \ No newline at end of file diff --git a/website/data/menu/main.yml b/website/data/menu/main.yml index 7590ee6c91d..59c7c9ea0a6 100755 --- a/website/data/menu/main.yml +++ b/website/data/menu/main.yml @@ -903,6 +903,18 @@ main: ref: "/cryptocurrency/defi/pools" - name: swaps ref: "/cryptocurrency/defi/swaps" + - name: sinfo + ref: "/cryptocurrency/defi/sinfo" + - name: govp + ref: "/cryptocurrency/defi/govp" + - name: gacc + ref: "/cryptocurrency/defi/gacc" + - name: validators + ref: "/cryptocurrency/defi/validators" + - name: sratio + ref: "/cryptocurrency/defi/sratio" + - name: sreturn + ref: "/cryptocurrency/defi/sreturn" - name: economy ref: "/economy" sub: