def test_get_historical_greeks_invalid_status(mocker): mock_response = requests.Response() mock_response.status_code = 400 mocker.patch(target="requests.get", new=mocker.Mock(return_value=mock_response)) result = tradier_model.last_price(ticker="PM") assert result is None
def test_last_price(recorder): result = tradier_model.last_price(ticker="AAPL") recorder.capture(result)
def plot_volume_open_interest( ticker: str, expiry: str, min_sp: float, max_sp: float, min_vol: float, export: str = "", ): """Plot volume and open interest Parameters ---------- ticker: str Stock ticker expiry: str Option expiration min_sp: float Min strike price max_sp: float Max strike price min_vol: float Min volume to consider export: str Format for exporting data """ current_price = tradier_model.last_price(ticker) options = tradier_model.get_option_chains(ticker, expiry) calls = options[options.option_type == "call"][ ["strike", "volume", "open_interest"] ] puts = options[options.option_type == "put"][["strike", "volume", "open_interest"]] # Process Calls Data df_calls = calls.pivot_table( index="strike", values=["volume", "open_interest"], aggfunc="sum" ).reindex() df_calls["strike"] = df_calls.index df_calls["type"] = "calls" df_calls["open_interest"] = df_calls["open_interest"] df_calls["volume"] = df_calls["volume"] df_calls["oi+v"] = df_calls["open_interest"] + df_calls["volume"] df_calls["spot"] = round(current_price, 2) df_puts = puts.pivot_table( index="strike", values=["volume", "open_interest"], aggfunc="sum" ).reindex() df_puts["strike"] = df_puts.index df_puts["type"] = "puts" df_puts["open_interest"] = df_puts["open_interest"] df_puts["volume"] = -df_puts["volume"] df_puts["open_interest"] = -df_puts["open_interest"] df_puts["oi+v"] = df_puts["open_interest"] + df_puts["volume"] df_puts["spot"] = round(current_price, 2) call_oi = calls.set_index("strike")["open_interest"] / 1000 put_oi = puts.set_index("strike")["open_interest"] / 1000 df_opt = pd.merge(call_oi, put_oi, left_index=True, right_index=True) df_opt = df_opt.rename( columns={"open_interest_x": "OI_call", "open_interest_y": "OI_put"} ) max_pain = op_helpers.calculate_max_pain(df_opt) if min_vol == -1 and min_sp == -1 and max_sp == -1: # If no argument provided, we use the percentile 50 to get 50% of upper volume data volume_percentile_threshold = 50 min_vol_calls = np.percentile(df_calls["oi+v"], volume_percentile_threshold) min_vol_puts = np.percentile(df_puts["oi+v"], volume_percentile_threshold) df_calls = df_calls[df_calls["oi+v"] > min_vol_calls] df_puts = df_puts[df_puts["oi+v"] < min_vol_puts] else: if min_vol > -1: df_calls = df_calls[df_calls["oi+v"] > min_vol] df_puts = df_puts[df_puts["oi+v"] < -min_vol] if min_sp > -1: df_calls = df_calls[df_calls["strike"] > min_sp] df_puts = df_puts[df_puts["strike"] > min_sp] if max_sp > -1: df_calls = df_calls[df_calls["strike"] < max_sp] df_puts = df_puts[df_puts["strike"] < max_sp] if df_calls.empty and df_puts.empty: console.print( "The filtering applied is too strong, there is no data available for such conditions.\n" ) return # Initialize the matplotlib figure _, ax = plt.subplots(figsize=plot_autoscale(), dpi=cfp.PLOT_DPI) # make x axis symmetric axis_origin = max(abs(max(df_puts["oi+v"])), abs(max(df_calls["oi+v"]))) ax.set_xlim(-axis_origin, +axis_origin) sns.set_style(style="darkgrid") g = sns.barplot( x="oi+v", y="strike", data=df_calls, label="Calls: Open Interest", color="lightgreen", orient="h", ) g = sns.barplot( x="volume", y="strike", data=df_calls, label="Calls: Volume", color="green", orient="h", ) g = sns.barplot( x="oi+v", y="strike", data=df_puts, label="Puts: Open Interest", color="pink", orient="h", ) g = sns.barplot( x="volume", y="strike", data=df_puts, label="Puts: Volume", color="red", orient="h", ) # draw spot line s = [float(strike.get_text()) for strike in ax.get_yticklabels()] spot_index = bisect_left(s, current_price) # find where the spot is on the graph spot_line = ax.axhline(spot_index, ls="--", color="dodgerblue", alpha=0.3) # draw max pain line max_pain_index = bisect_left(s, max_pain) max_pain_line = ax.axhline(max_pain_index, ls="-", color="black", alpha=0.3) max_pain_line.set_linewidth(3) # format ticklabels without - for puts g.set_xticks(g.get_xticks()) xlabels = [f"{x:,.0f}".replace("-", "") for x in g.get_xticks()] g.set_xticklabels(xlabels) plt.title( f"{ticker} volumes for {expiry} (open interest displayed only during market hours)" ) ax.invert_yaxis() _ = ax.legend() handles, _ = ax.get_legend_handles_labels() handles.append(spot_line) handles.append(max_pain_line) # create legend labels + add to graph labels = [ "Calls open interest", "Calls volume ", "Puts open interest", "Puts volume", "Current stock price", f"Max pain = {max_pain}", ] plt.legend(handles=handles[:], labels=labels) sns.despine(left=True, bottom=True) if gtff.USE_ION: plt.ion() plt.show() export_data( export, os.path.dirname(os.path.abspath(__file__)), "voi_tr", options, ) console.print("")
def plot_vol( ticker: str, expiry: str, min_sp: float, max_sp: float, calls_only: bool, puts_only: bool, export: str = "", ): """Plot volume Parameters ---------- ticker: str Ticker expiry: str Expiry date for options min_sp: float Min strike to consider max_sp: float Max strike to consider calls_only: bool Show calls only puts_only: bool Show puts only export: str Format to export file """ options = tradier_model.get_option_chains(ticker, expiry) current_price = tradier_model.last_price(ticker) if min_sp == -1: min_strike = 0.75 * current_price else: min_strike = min_sp if max_sp == -1: max_strike = 1.25 * current_price else: max_strike = max_sp if calls_only and puts_only: console.print("Both flags selected, please select one", "\n") return calls = options[options.option_type == "call"][["strike", "volume"]] puts = options[options.option_type == "put"][["strike", "volume"]] call_v = calls.set_index("strike")["volume"] / 1000 put_v = puts.set_index("strike")["volume"] / 1000 plt.style.use("classic") fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=cfp.PLOT_DPI) if not calls_only: put_v.plot( x="strike", y="volume", label="Puts", ax=ax, marker="o", ls="-", c="r", ) if not puts_only: call_v.plot( x="strike", y="volume", label="Calls", ax=ax, marker="o", ls="-", c="g", ) ax.axvline(current_price, lw=2, c="k", ls="--", label="Current Price", alpha=0.7) ax.grid("on") ax.set_xlabel("Strike Price") ax.set_ylabel("Volume (1k) ") ax.set_xlim(min_strike, max_strike) if gtff.USE_ION: plt.ion() ax.set_title(f"Volume for {ticker.upper()} expiring {expiry}") plt.legend(loc=0) fig.tight_layout(pad=1) plt.show() export_data( export, os.path.dirname(os.path.abspath(__file__)), "vol_tr", options, ) console.print("")
def plot_vol( ticker: str, expiry: str, min_sp: float, max_sp: float, calls_only: bool, puts_only: bool, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Plot volume Parameters ---------- ticker: str Ticker expiry: str Expiry date for options min_sp: float Min strike to consider max_sp: float Max strike to consider calls_only: bool Show calls only puts_only: bool Show puts only export: str Format to export file external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None """ options = tradier_model.get_option_chains(ticker, expiry) current_price = tradier_model.last_price(ticker) if min_sp == -1: min_strike = 0.75 * current_price else: min_strike = min_sp if max_sp == -1: max_strike = 1.25 * current_price else: max_strike = max_sp if calls_only and puts_only: console.print("Both flags selected, please select one", "\n") return calls = options[options.option_type == "call"][["strike", "volume"]] puts = options[options.option_type == "put"][["strike", "volume"]] call_v = calls.set_index("strike")["volume"] / 1000 put_v = puts.set_index("strike")["volume"] / 1000 if external_axes is None: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=cfp.PLOT_DPI) else: ax = external_axes[0] if not calls_only: put_v.plot( x="strike", y="volume", label="Puts", ax=ax, marker="o", ls="-", c="r", ) if not puts_only: call_v.plot( x="strike", y="volume", label="Calls", ax=ax, marker="o", ls="-", c="g", ) ax.axvline(current_price, lw=2, c="k", ls="--", label="Current Price", alpha=0.7) ax.grid("on") ax.set_xlabel("Strike Price") ax.set_ylabel("Volume (1k) ") ax.set_xlim(min_strike, max_strike) ax.set_title(f"Volume for {ticker.upper()} expiring {expiry}") theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), "vol_tr", options, ) console.print("")
def plot_oi( ticker: str, expiry: str, min_sp: float, max_sp: float, calls_only: bool, puts_only: bool, export: str = "", external_axes: Optional[List[plt.Axes]] = None, ): """Plot open interest Parameters ---------- ticker: str Ticker expiry: str Expiry date for options min_sp: float Min strike to consider max_sp: float Max strike to consider calls_only: bool Show calls only puts_only: bool Show puts only export: str Format to export file external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None """ options = tradier_model.get_option_chains(ticker, expiry) current_price = tradier_model.last_price(ticker) if min_sp == -1: min_strike = 0.75 * current_price else: min_strike = min_sp if max_sp == -1: max_strike = 1.25 * current_price else: max_strike = max_sp if calls_only and puts_only: console.print("Both flags selected, please select one", "\n") return calls = options[options.option_type == "call"][["strike", "open_interest"]] puts = options[options.option_type == "put"][["strike", "open_interest"]] call_oi = calls.set_index("strike")["open_interest"] / 1000 put_oi = puts.set_index("strike")["open_interest"] / 1000 df_opt = pd.merge(call_oi, put_oi, left_index=True, right_index=True) df_opt = df_opt.rename(columns={ "open_interest_x": "OI_call", "open_interest_y": "OI_put" }) max_pain = op_helpers.calculate_max_pain(df_opt) if external_axes is None: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=cfp.PLOT_DPI) else: if len(external_axes) != 1: logger.error("Expected list of one axis item.") console.print("[red]Expected list of one axis item./n[/red]") return (ax, ) = external_axes if not calls_only: ax.plot(put_oi.index, put_oi.values, "-o", label="Puts") if not puts_only: ax.plot(call_oi.index, call_oi.values, "-o", label="Calls") ax.legend(loc=0) ax.axvline(current_price, lw=2, ls="--", label="Current Price", alpha=0.7) ax.axvline(max_pain, lw=3, label=f"Max Pain: {max_pain}", alpha=0.7) ax.set_xlabel("Strike Price") ax.set_ylabel("Open Interest (1k) ") ax.set_xlim(min_strike, max_strike) ax.set_title(f"Open Interest for {ticker.upper()} expiring {expiry}") theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output() export_data( export, os.path.dirname(os.path.abspath(__file__)), "oi_tr", options, )
def plot_oi( ticker: str, expiry: str, min_sp: float, max_sp: float, calls_only: bool, puts_only: bool, export: str = "", ): """Plot open interest Parameters ---------- ticker: str Ticker expiry: str Expiry date for options min_sp: float Min strike to consider max_sp: float Max strike to consider calls_only: bool Show calls only puts_only: bool Show puts only export: str Format to export file """ options = tradier_model.get_option_chains(ticker, expiry) current_price = tradier_model.last_price(ticker) if min_sp == -1: min_strike = 0.75 * current_price else: min_strike = min_sp if max_sp == -1: max_strike = 1.25 * current_price else: max_strike = max_sp if calls_only and puts_only: print("Both flags selected, please select one", "\n") return calls = options[options.option_type == "call"][["strike", "open_interest"]] puts = options[options.option_type == "put"][["strike", "open_interest"]] call_oi = calls.set_index("strike")["open_interest"] / 1000 put_oi = puts.set_index("strike")["open_interest"] / 1000 df_opt = pd.merge(call_oi, put_oi, left_index=True, right_index=True) df_opt = df_opt.rename(columns={ "open_interest_x": "OI_call", "open_interest_y": "OI_put" }) max_pain = op_helpers.calculate_max_pain(df_opt) plt.style.use("classic") fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=cfp.PLOT_DPI) if not calls_only: put_oi.plot( x="strike", y="open_interest", label="Puts", ax=ax, marker="o", ls="-", c="r", ) if not puts_only: call_oi.plot( x="strike", y="open_interest", label="Calls", ax=ax, marker="o", ls="-", c="g", ) ax.axvline(current_price, lw=2, c="k", ls="--", label="Current Price", alpha=0.7) ax.axvline(max_pain, lw=3, c="k", label=f"Max Pain: {max_pain}", alpha=0.7) ax.grid("on") ax.set_xlabel("Strike Price") ax.set_ylabel("Open Interest (1k) ") ax.set_xlim(min_strike, max_strike) if gtff.USE_ION: plt.ion() ax.set_title(f"Open Interest for {ticker.upper()} expiring {expiry}") plt.legend(loc=0) fig.tight_layout(pad=1) plt.show() export_data( export, os.path.dirname(os.path.abspath(__file__)), "oi_tr", options, ) print("")