diff --git a/gamestonk_terminal/common/technical_analysis/volatility_model.py b/gamestonk_terminal/common/technical_analysis/volatility_model.py index 0a3b9613a5d..c6829998656 100644 --- a/gamestonk_terminal/common/technical_analysis/volatility_model.py +++ b/gamestonk_terminal/common/technical_analysis/volatility_model.py @@ -7,7 +7,7 @@ import pandas_ta as ta def bbands( s_interval: str, df_stock: pd.DataFrame, length: int, n_std: float, mamode: str -): +) -> pd.DataFrame: """Calculate Bollinger Bands Parameters @@ -47,3 +47,37 @@ def bbands( ).dropna() return df_ta + + +def donchian( + df_stock: pd.DataFrame, + upper_length: int, + lower_length: int, +) -> pd.DataFrame: + """Calculate Donchian Channels + + Parameters + ---------- + s_interval : str + Interval of stock data + df_stock : pd.DataFrame + DataFrame of stock data + upper_length : int + Length of window to calculate upper channel + lower_length : int + Length of window to calculate lower channel + + + Returns + ------- + df_ta: pd.DataFrame + Dataframe of upper and lower channels + """ + df_ta = ta.donchian( + high=df_stock["High"], + low=df_stock["Low"], + upper_length=upper_length, + lower_length=lower_length, + ).dropna() + + return df_ta diff --git a/gamestonk_terminal/common/technical_analysis/volatility_view.py b/gamestonk_terminal/common/technical_analysis/volatility_view.py index aa695baba90..868285ff6dd 100644 --- a/gamestonk_terminal/common/technical_analysis/volatility_view.py +++ b/gamestonk_terminal/common/technical_analysis/volatility_view.py @@ -83,3 +83,72 @@ def view_bbands( "bbands", df_ta, ) + + +def view_donchian( + ticker: str, + s_interval: str, + df_stock: pd.DataFrame, + upper_length: int, + lower_length: int, + export: str, +): + """Show donchian channels + + Parameters + ---------- + ticker : str + Ticker + s_interval : str + Interval of stock data + df_stock : pd.DataFrame + Dataframe of stock prices + upper_length : int + Length of window to calculate upper channel + lower_length : int + Length of window to calculate lower channel + export : str + Format of export file + """ + df_ta = volatility_model.donchian(df_stock, upper_length, lower_length) + + fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) + if s_interval == "1440min": + ax.plot(df_stock.index, df_stock["Adj Close"].values, color="k", lw=3) + else: + ax.plot(df_stock.index, df_stock["Close"].values, color="k", lw=3) + ax.plot(df_ta.index, df_ta.iloc[:, 0].values, "b", lw=1.5, label="upper") + ax.plot(df_ta.index, df_ta.iloc[:, 1].values, "b", lw=1.5, ls="--") + ax.plot(df_ta.index, df_ta.iloc[:, 2].values, "b", lw=1.5, label="lower") + ax.set_title(f"{ticker} donchian") + ax.set_xlim(df_stock.index[0], df_stock.index[-1]) + ax.set_xlabel("Time") + ax.set_ylabel("Price ($)") + + ax.legend([ticker, df_ta.columns[0], df_ta.columns[1], df_ta.columns[2]]) + ax.fill_between( + df_ta.index, + df_ta.iloc[:, 0].values, + df_ta.iloc[:, 2].values, + alpha=0.1, + color="b", + ) + ax.grid(b=True, which="major", color="#666666", linestyle="-") + + if gtff.USE_ION: + plt.ion() + + plt.gcf().autofmt_xdate() + fig.tight_layout(pad=1) + + plt.legend() + + plt.show() + print("") + + export_data( + export, + os.path.dirname(os.path.abspath(__file__)).replace("common", "stocks"), + "donchian", + df_ta, + ) diff --git a/gamestonk_terminal/stocks/technical_analysis/ta_controller.py b/gamestonk_terminal/stocks/technical_analysis/ta_controller.py index 4b66b937f3b..25d470c9db4 100644 --- a/gamestonk_terminal/stocks/technical_analysis/ta_controller.py +++ b/gamestonk_terminal/stocks/technical_analysis/ta_controller.py @@ -59,6 +59,7 @@ class TechnicalAnalysisController: "adx", "aroon", "bbands", + "donchian", "ad", "obv", "fib", @@ -124,6 +125,7 @@ Trend: aroon aroon indicator Volatility: bbands bollinger bands + donchian donchian channels Volume: ad accumulation/distribution line values obv on balance volume @@ -1110,6 +1112,64 @@ Custom: except Exception as e: print(e, "\n") + def call_donchian(self, other_args: List[str]): + """Process donchian command""" + parser = argparse.ArgumentParser( + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + prog="donchian", + description=""" + Donchian Channels are three lines generated by moving average + calculations that comprise an indicator formed by upper and lower + bands around a midrange or median band. The upper band marks the + highest price of a security over N periods while the lower band + marks the lowest price of a security over N periods. The area + between the upper and lower bands represents the Donchian Channel. + """, + ) + parser.add_argument( + "-u", + "--length_upper", + action="store", + dest="n_length_upper", + type=check_positive, + default=20, + help="length", + ) + parser.add_argument( + "-l", + "--length_lower", + action="store", + dest="n_length_lower", + type=check_positive, + default=20, + help="length", + ) + parser.add_argument( + "--export", + choices=["csv", "json", "xlsx"], + default="", + type=str, + dest="export", + help="Export dataframe data to csv,json,xlsx file", + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + volatility_view.view_donchian( + ticker=self.ticker, + s_interval=self.interval, + df_stock=self.stock, + upper_length=ns_parser.n_length_upper, + lower_length=ns_parser.n_length_lower, + export=ns_parser.export, + ) + + except Exception as e: + print(e, "\n") + def call_ad(self, other_args: List[str]): """Process ad command""" parser = argparse.ArgumentParser(