diff --git a/gamestonk_terminal/discovery/fidelity_model.py b/gamestonk_terminal/discovery/fidelity_model.py index 4d0c625584b..73fdf1ffa99 100644 --- a/gamestonk_terminal/discovery/fidelity_model.py +++ b/gamestonk_terminal/discovery/fidelity_model.py @@ -42,7 +42,10 @@ def get_orders() -> Tuple[str, DataFrame]: if not an_order: l_orders_vals.append("") else: - l_orders_vals.append(an_order.contents[1]) + try: + l_orders_vals.append(an_order.contents[1]) + except IndexError: + l_orders_vals.append("0") elif (idx + 1) % 5 == 0: s_orders = str(an_order) l_orders_vals.append( diff --git a/gamestonk_terminal/forex/fx_view.py b/gamestonk_terminal/forex/fx_view.py index 0ac34599671..864acf2ade5 100644 --- a/gamestonk_terminal/forex/fx_view.py +++ b/gamestonk_terminal/forex/fx_view.py @@ -233,7 +233,7 @@ def create_order(accountID, instrument, other_args: List[str]): "--price", dest="price", action="store", - type=float, + type=check_non_negative, required=True, help="The price to set for the limit order. ", ) @@ -245,7 +245,6 @@ def create_order(accountID, instrument, other_args: List[str]): ns_parser.price = round(ns_parser.price, 3) else: ns_parser.price = round(ns_parser.price, 5) - check_non_negative(ns_parser.price) data = { "order": { diff --git a/gamestonk_terminal/options/chains_view.py b/gamestonk_terminal/options/chains_view.py index b87b57460b6..8a1afdefdd7 100644 --- a/gamestonk_terminal/options/chains_view.py +++ b/gamestonk_terminal/options/chains_view.py @@ -56,7 +56,7 @@ def process_chains(response: requests.models.Response) -> pd.DataFrame: Parameters ---------- response: requests.models.Response - This is the respnose from tradier api. + This is the response from tradier api. Returns ------- diff --git a/gamestonk_terminal/options/volume_helper.py b/gamestonk_terminal/options/volume_helper.py new file mode 100644 index 00000000000..4a0f40d03c5 --- /dev/null +++ b/gamestonk_terminal/options/volume_helper.py @@ -0,0 +1,63 @@ +"""Functions for analyzing options data""" +__docformat__ = "numpy" +from typing import Union +import pandas as pd +import numpy as np + + +def get_loss_at_strike( + strike: Union[int, float], chain: pd.DataFrame +) -> Union[int, float]: + """ + Function to get the loss at the given expiry + Parameters + ---------- + strike: Union[int,float] + Value to calculate total loss at + chain: Dataframe: + Dataframe containing at least strike and openInterest + + Returns + ------- + loss: Union[float,int] + Total loss + """ + + itm_calls = chain[chain.index < strike][["OI_call"]] + itm_calls["loss"] = (strike - itm_calls.index) * itm_calls["OI_call"] + call_loss = itm_calls["loss"].sum() + # The *-1 below is due to a sign change for plotting in the _view code + itm_puts = chain[chain.index > strike][["OI_put"]] + itm_puts["loss"] = (itm_puts.index - strike) * itm_puts["OI_put"] * -1 + put_loss = itm_puts.loss.sum() + loss = call_loss + put_loss + return loss + + +def get_max_pain(chain: pd.DataFrame) -> Union[int, float]: + """ + Returns the max pain for a given call/put dataframe + Parameters + ---------- + chain: DataFrame + Dataframe to calculate value from + + Returns + ------- + max_pain : + Max pain value + """ + + strikes = np.array(chain.index) + if ("OI_call" not in chain.columns) or ("OI_put" not in chain.columns): + print("Incorrect columns. Unable to parse max pain") + return np.nan + + loss = [] + for price_at_exp in strikes: + loss.append(get_loss_at_strike(price_at_exp, chain)) + + chain["loss"] = loss + max_pain = chain["loss"].idxmin() + + return max_pain diff --git a/gamestonk_terminal/options/volume_view.py b/gamestonk_terminal/options/volume_view.py index 4d32126c682..9558690ff3c 100644 --- a/gamestonk_terminal/options/volume_view.py +++ b/gamestonk_terminal/options/volume_view.py @@ -16,6 +16,7 @@ from gamestonk_terminal.helper_funcs import ( ) from gamestonk_terminal import config_plot as cfgPlot from gamestonk_terminal import feature_flags as gtff +from gamestonk_terminal.options.volume_helper import get_max_pain def plot_volume_open_interest( @@ -250,9 +251,6 @@ def get_calls_puts_maxpain( df_calls["volume"] = df_calls["volume"] df_calls["oi+v"] = df_calls["openInterest"] + df_calls["volume"] df_calls["spot"] = round(last_adj_close_price, 2) - df_calls["dv"] = last_adj_close_price - df_calls.index - df_calls["dv"] = df_calls["dv"].apply(lambda x: max(0, x)) - df_calls["dv"] = abs(df_calls["dv"] * df_calls["volume"]) if not op_puts.empty: # Process Puts Data @@ -266,15 +264,14 @@ def get_calls_puts_maxpain( df_puts["openInterest"] = -df_puts["openInterest"] df_puts["oi+v"] = df_puts["openInterest"] + df_puts["volume"] df_puts["spot"] = round(last_adj_close_price, 2) - df_puts["dv"] = df_puts.index - last_adj_close_price - df_puts["dv"] = df_puts["dv"].apply(lambda x: max(0, x)) - df_puts["dv"] = abs(df_puts["dv"] * df_puts["volume"]) if not op_calls.empty and not op_puts.empty: # Get max pain df_opt = pd.merge(df_calls, df_puts, left_index=True, right_index=True) - df_opt["dv"] = round(df_opt["dv_x"] + df_opt["dv_y"], 2) - max_pain = df_opt["dv"].idxmax() + df_opt = df_opt[["openInterest_x", "openInterest_y"]].rename( + columns={"openInterest_x": "OI_call", "openInterest_y": "OI_put"} + ) + max_pain = get_max_pain(df_opt) return df_calls, df_puts, max_pain