diff --git a/i18n/en.yml b/i18n/en.yml index 2c1c96544fd..93ef5dbbc43 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -251,7 +251,7 @@ en: stocks/ins/stats: insider stats of the company stocks/ins/act: insider activity over time stocks/ins/lins: last insider trading of the company - stocks/ins/lcb: latest cluster boys + stocks/ins/lcb: latest cluster buys stocks/ins/lpsb: latest penny stock buys stocks/ins/lit: latest insider trading (all filings) stocks/ins/lip: latest insider purchases @@ -612,6 +612,7 @@ en: crypto/dd/change: 30d change of supply held on exchange wallets crypto/dd/eb: total balance held on exchanges (in percentage and units) crypto/dd/oi: open interest per exchange + crypto/dd/fundrate: funding rate per exchange crypto/dd/basic: basic information about loaded coin crypto/dd/ps: price and supply related metrics for loaded coin crypto/dd/mkt: all markets for loaded coin diff --git a/openbb_terminal/cryptocurrency/due_diligence/coinglass_model.py b/openbb_terminal/cryptocurrency/due_diligence/coinglass_model.py index b2dbf60b5dd..2b6aabeee90 100644 --- a/openbb_terminal/cryptocurrency/due_diligence/coinglass_model.py +++ b/openbb_terminal/cryptocurrency/due_diligence/coinglass_model.py @@ -16,6 +16,68 @@ api_url = "https://open-api.coinglass.com/api/pro/v1/" INTERVALS = [0, 1, 2, 4] +@log_start_end(log=logger) +def get_funding_rate(symbol: str) -> pd.DataFrame: + """Returns open interest by exchange for a certain symbol + [Source: https://coinglass.github.io/API-Reference/] + + Parameters + ---------- + symbol : str + Crypto Symbol to search open interest futures (e.g., BTC) + + Returns + ------- + pd.DataFrame + funding rate per exchange + """ + + url = api_url + f"futures/funding_rates_chart?symbol={symbol.upper()}&type=C" + + headers = {"coinglassSecret": cfg.API_COINGLASS_KEY} + + response = requests.request("GET", url, headers=headers) + + df = pd.DataFrame() + + if response.status_code == 200: + res_json = json.loads(response.text) + + if res_json["success"]: + if "data" in res_json: + data = res_json["data"] + time = data["dateList"] + time_new = [] + for elem in time: + time_actual = dt.datetime.utcfromtimestamp(elem / 1000) + time_new.append(time_actual) + + df = pd.DataFrame( + data={ + "date": time_new, + "price": data["priceList"], + **data["dataMap"], + } + ) + df = df.set_index("date") + else: + console.print(f"No data found for {symbol}.\n") + else: + if "secret invalid" in res_json["msg"]: + console.print("[red]Invalid API Key[/red]\n") + else: + console.print(res_json["msg"]) + + elif response.status_code == 429: + console.print("[red]Exceeded number of calls per minute[/red]\n") + elif response.status_code == 429: + console.print( + "[red]IP address autobanned for exceeding calls limit multiple times.[/red]\n" + ) + + return df + + @log_start_end(log=logger) def get_open_interest_per_exchange(symbol: str, interval: int) -> pd.DataFrame: """Returns open interest by exchange for a certain symbol @@ -36,7 +98,7 @@ def get_open_interest_per_exchange(symbol: str, interval: int) -> pd.DataFrame: url = ( api_url - + f"futures/openInterest/chart?&symbol={symbol.upper()}&interval={interval}" + + f"futures/openInterest/chart?symbol={symbol.upper()}&interval={interval}" ) headers = {"coinglassSecret": cfg.API_COINGLASS_KEY} diff --git a/openbb_terminal/cryptocurrency/due_diligence/coinglass_view.py b/openbb_terminal/cryptocurrency/due_diligence/coinglass_view.py index 3da9064c84e..42a76e5dc37 100644 --- a/openbb_terminal/cryptocurrency/due_diligence/coinglass_view.py +++ b/openbb_terminal/cryptocurrency/due_diligence/coinglass_view.py @@ -9,6 +9,7 @@ from matplotlib import ticker from openbb_terminal.config_terminal import theme from openbb_terminal import config_plot as cfgPlot from openbb_terminal.cryptocurrency.due_diligence.coinglass_model import ( + get_funding_rate, get_open_interest_per_exchange, ) from openbb_terminal.decorators import check_api_key @@ -24,6 +25,33 @@ from openbb_terminal.rich_config import console logger = logging.getLogger(__name__) +@log_start_end(log=logger) +@check_api_key(["API_COINGLASS_KEY"]) +def display_funding_rate(symbol: str, export: str = "") -> None: + """Displays funding rate by exchange for a certain cryptocurrency + [Source: https://coinglass.github.io/API-Reference/] + + Parameters + ---------- + symbol : str + Crypto symbol to search funding rate (e.g., BTC) + export : str + Export dataframe data to csv,json,xlsx file""" + df = get_funding_rate(symbol) + if df.empty: + return + + plot_data(df, symbol, f"Exchange {symbol} Funding Rate", "Funding Rate [%]") + console.print("") + + export_data( + export, + os.path.dirname(os.path.abspath(__file__)), + "fundrate", + df, + ) + + @log_start_end(log=logger) @check_api_key(["API_COINGLASS_KEY"]) def display_open_interest(symbol: str, interval: int = 0, export: str = "") -> None: @@ -42,7 +70,12 @@ def display_open_interest(symbol: str, interval: int = 0, export: str = "") -> N if df.empty: return - plot_data(df, symbol) + plot_data( + df, + symbol, + f"Exchange {symbol} Futures Open Interest", + "Open futures value [$B]", + ) console.print("") export_data( @@ -57,6 +90,8 @@ def display_open_interest(symbol: str, interval: int = 0, export: str = "") -> N def plot_data( df: pd.DataFrame, symbol: str, + title: str, + ylabel: str, external_axes: Optional[List[plt.Axes]] = None, ): @@ -84,8 +119,8 @@ def plot_data( ticker.FuncFormatter(lambda x, _: lambda_long_number_format(x)) ) ax1.legend(df_without_price.columns, fontsize="x-small", ncol=2) - ax1.set_title(f"Exchange {symbol} Futures Open Interest") - ax1.set_ylabel("Open futures value[$B]") + ax1.set_title(title) + ax1.set_ylabel(ylabel) ax2.plot(df_price.index, df_price) ax2.legend([f"{symbol} price"]) diff --git a/openbb_terminal/cryptocurrency/due_diligence/dd_controller.py b/openbb_terminal/cryptocurrency/due_diligence/dd_controller.py index 523dd750277..3f648177928 100644 --- a/openbb_terminal/cryptocurrency/due_diligence/dd_controller.py +++ b/openbb_terminal/cryptocurrency/due_diligence/dd_controller.py @@ -55,7 +55,7 @@ def check_cg_id(symbol: str): class DueDiligenceController(CryptoBaseController): """Due Diligence Controller class""" - CHOICES_COMMANDS = ["load", "oi", "active", "change", "nonzero", "eb"] + CHOICES_COMMANDS = ["load", "fundrate", "oi", "active", "change", "nonzero", "eb"] SPECIFIC_CHOICES = { "cp": [ @@ -183,6 +183,7 @@ class DueDiligenceController(CryptoBaseController): mt.add_cmd("trades", "Coinbase") mt.add_cmd("ex", "CoinPaprika") mt.add_cmd("oi", "Coinglass") + mt.add_cmd("fundrate", "Coinglass") mt.add_cmd("eb", "Glassnode") mt.add_info("_metrics_") @@ -499,6 +500,30 @@ class DueDiligenceController(CryptoBaseController): export=ns_parser.export, ) + @log_start_end(log=logger) + def call_fundrate(self, other_args): + """Process fundrate command""" + assert isinstance(self.symbol, str) + parser = argparse.ArgumentParser( + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + prog="fundrate", + description=""" + Displays funding rate by exchange for a certain asset + [Source: https://coinglass.github.io/API-Reference/] + """, + ) + + ns_parser = self.parse_known_args_and_warn( + parser, other_args, EXPORT_BOTH_RAW_DATA_AND_FIGURES + ) + + if ns_parser: + coinglass_view.display_funding_rate( + symbol=self.symbol.upper(), + export=ns_parser.export, + ) + @log_start_end(log=logger) def call_info(self, other_args): """Process info command""" diff --git a/scripts/test_crypto_dd.openbb b/scripts/test_crypto_dd.openbb index d823cb822df..3ee8fffc852 100644 --- a/scripts/test_crypto_dd.openbb +++ b/scripts/test_crypto_dd.openbb @@ -1,6 +1,8 @@ crypto load btc dd +fundrate +oi nonzero info market diff --git a/tests/openbb_terminal/cryptocurrency/due_diligence/test_dd_controller.py b/tests/openbb_terminal/cryptocurrency/due_diligence/test_dd_controller.py index 3886c2fa1c3..dd694862ff5 100644 --- a/tests/openbb_terminal/cryptocurrency/due_diligence/test_dd_controller.py +++ b/tests/openbb_terminal/cryptocurrency/due_diligence/test_dd_controller.py @@ -302,6 +302,13 @@ def test_call_func_expect_queue(expected_queue, func, queue, mocker): [], dict(), ), + ( + "call_fundrate", + [], + "coinglass_view.display_funding_rate", + [], + dict(), + ), ( "call_oi", [], diff --git a/tests/openbb_terminal/cryptocurrency/due_diligence/txt/test_dd_controller/test_print_help.txt b/tests/openbb_terminal/cryptocurrency/due_diligence/txt/test_dd_controller/test_print_help.txt index d05a49c5384..7c9da447a36 100644 --- a/tests/openbb_terminal/cryptocurrency/due_diligence/txt/test_dd_controller/test_print_help.txt +++ b/tests/openbb_terminal/cryptocurrency/due_diligence/txt/test_dd_controller/test_print_help.txt @@ -22,6 +22,7 @@ Market: trades last trades [Coinbase] ex all exchanges where loaded coin is listed [CoinPaprika] oi open interest per exchange [Coinglass] + fundrate funding rate per exchange [Coinglass] eb total balance held on exchanges (in percentage and units) [Glassnode] Metrics: mcapdom market cap dominance [Messari] diff --git a/tests/openbb_terminal/stocks/insider/txt/test_insider_controller/test_print_help.txt b/tests/openbb_terminal/stocks/insider/txt/test_insider_controller/test_print_help.txt index 9c71be5d206..a58049a37b1 100644 --- a/tests/openbb_terminal/stocks/insider/txt/test_insider_controller/test_print_help.txt +++ b/tests/openbb_terminal/stocks/insider/txt/test_insider_controller/test_print_help.txt @@ -13,7 +13,7 @@ Ticker: [unvl] lins last insider trading of the company[/unvl] [Finviz] Last Insiders: - lcb latest cluster boys [Open Insider] + lcb latest cluster buys [Open Insider] lpsb latest penny stock buys [Open Insider] lit latest insider trading (all filings) [Open Insider] lip latest insider purchases [Open Insider] diff --git a/website/content/terminal/crypto/dd/fundrate/_index.md b/website/content/terminal/crypto/dd/fundrate/_index.md new file mode 100644 index 00000000000..4fa19d40b9d --- /dev/null +++ b/website/content/terminal/crypto/dd/fundrate/_index.md @@ -0,0 +1,11 @@ +``` +usage: fundrate [-h] [--export EXPORT] +``` + +Displays funding rate by exchange for a certain asset [Source: https://coinglass.github.io/API-Reference/] + +``` +optional arguments: + -h, --help show this help message (default: False) + --export EXPORT Export raw data into csv, json, xlsx and figure into png, jpg, pdf, svg (default: ) +``` diff --git a/website/content/terminal/crypto/dd/oi/_index.md b/website/content/terminal/crypto/dd/oi/_index.md index 97a05fa6b55..5d7aaa269ca 100644 --- a/website/content/terminal/crypto/dd/oi/_index.md +++ b/website/content/terminal/crypto/dd/oi/_index.md @@ -3,7 +3,7 @@ usage: oi [-i {0, 1, 2, 4}] [--export {csv,json,xlsx}] [-h] ``` -Display the open interest per exchange for a certain cryptocurrency. [Source: https://bybt.gitbook.io] +Display the open interest per exchange for a certain cryptocurrency. [Source: https://coinglass.github.io/API-Reference/] Crypto must be loaded (e.g., `load btc`) before running this feature. The total Bitcoin futures open interest across cryptocurrency exchanges, where open interest is calculated as the estimated notional value of all open futures positions, or the aggregate dollar value of outstanding contract specified BTC deliverables. Includes the largest exchanges with trustworthy reporting of exchange volume metrics. diff --git a/website/data/menu/main.yml b/website/data/menu/main.yml index 4b0629a921a..2aa545f703d 100755 --- a/website/data/menu/main.yml +++ b/website/data/menu/main.yml @@ -748,6 +748,8 @@ main: ref: "/terminal/crypto/dd/change" - name: eb ref: "/terminal/crypto/dd/eb" + - name: fundrate + ref: "/terminal/crypto/dd/fundrate" - name: oi ref: "/terminal/crypto/dd/oi" - name: info