From 567aca080a7254fb8779149bc2832940dbd35d84 Mon Sep 17 00:00:00 2001 From: devwolff <62347426+devwolff@users.noreply.github.com> Date: Fri, 13 Aug 2021 21:43:49 +1000 Subject: [PATCH] add centre of gravity & zlma to ta menu (#663) * add centre of gravity & zlma to ta menu * quickfix --- .../common/technical_analysis/momentum.py | 108 ++++++++++++++++ .../common/technical_analysis/overlap.py | 118 ++++++++++++++++++ .../technical_analysis/ta_controller.py | 12 ++ 3 files changed, 238 insertions(+) diff --git a/gamestonk_terminal/common/technical_analysis/momentum.py b/gamestonk_terminal/common/technical_analysis/momentum.py index 46d3e40cca3..1a2167ff571 100644 --- a/gamestonk_terminal/common/technical_analysis/momentum.py +++ b/gamestonk_terminal/common/technical_analysis/momentum.py @@ -4,6 +4,7 @@ __docformat__ = "numpy" import argparse from typing import List +import numpy as np import matplotlib.pyplot as plt import pandas_ta as ta import pandas as pd @@ -691,3 +692,110 @@ def fisher( except Exception as e: print(e, "\n") + + +def cg(other_args: List[str], s_ticker: str, s_interval: str, df_stock: pd.DataFrame): + """Centre of Gravity + + Parameters + ---------- + other_args:List[str] + Argparse arguments + s_ticker: str + Ticker + s_interval: str + Stock time interval + df_stock: pd.DataFrame + Dataframe of prices + """ + + parser = argparse.ArgumentParser( + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + prog="cg", + description=""" + The Center of Gravity indicator, also known as the COD indicator in short, + is a useful feature that enables traders to look into the concurrent price + fluctuations and try to predict the upcoming ones. According to the main + function of the Center of Gravity indicator explained by John Ehlers, traders + who use it will be able to closely speculate the upcoming price change of the asset. + """, + ) + + parser.add_argument( + "-l", + "--length", + action="store", + dest="n_length", + type=check_positive, + default=14, + help="length", + ) + parser.add_argument( + "-o", + "--offset", + action="store", + dest="n_offset", + type=check_positive, + default=0, + help="offset", + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + + # Daily + if s_interval == "1440min": + df_ta = ta.cg( + close=df_stock["Adj Close"], + length=ns_parser.n_length, + offset=ns_parser.n_offset, + ).dropna() + + # Intraday + else: + df_ta = ta.cg( + close=df_stock["Close"], + length=ns_parser.n_length, + offset=ns_parser.n_offset, + ).dropna() + + fig, axes = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI) + ax = axes[0] + ax.set_title(f"{s_ticker} Centre of Gravity") + if s_interval == "1440min": + ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=1) + else: + ax.plot(df_stock.index, df_stock["Close"].values, "k", lw=1) + ax.set_xlim(df_stock.index[0], df_stock.index[-1]) + ax.set_ylabel("Share Price ($)") + ax.grid(b=True, which="major", color="#666666", linestyle="-") + ax.minorticks_on() + ax.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) + ax2 = axes[1] + ax2.plot(df_ta.index, df_ta.values, "b", lw=2, label="CG") + # shift cg 1 bar forward for signal + signal = df_ta.values + signal = np.roll(signal, 1) + ax2.plot(df_ta.index, signal, "g", lw=1, label="Signal") + + ax2.set_xlim(df_stock.index[0], df_stock.index[-1]) + ax2.grid(b=True, which="major", color="#666666", linestyle="-") + ax2.minorticks_on() + ax2.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) + + if gtff.USE_ION: + plt.ion() + + plt.gcf().autofmt_xdate() + fig.tight_layout(pad=1) + + plt.legend() + plt.show() + + print("") + + except Exception as e: + print(e, "\n") diff --git a/gamestonk_terminal/common/technical_analysis/overlap.py b/gamestonk_terminal/common/technical_analysis/overlap.py index dd1e8eb28f5..c56df4e00b3 100644 --- a/gamestonk_terminal/common/technical_analysis/overlap.py +++ b/gamestonk_terminal/common/technical_analysis/overlap.py @@ -314,3 +314,121 @@ def vwap(other_args: List[str], s_ticker: str, s_interval: str, df_stock: pd.Dat except Exception as e: print(e, "\n") + + +def zlma(other_args: List[str], s_ticker: str, s_interval: str, df_stock: pd.DataFrame): + """Plots zero lag moving average (ZLMA) + + Parameters + ---------- + other_args: List[str] + Argparse arguments + s_ticker: str + Ticker + s_interval: str + Data interval + df_stock: pd.DataFrame + Dataframe of dates and prices + """ + + parser = argparse.ArgumentParser( + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + prog="zlma", + description=""" + The zero lag exponential moving average (ZLEMA) indicator + was created by John Ehlers and Ric Way. The idea is do a + regular exponential moving average (EMA) calculation but + on a de-lagged data instead of doing it on the regular data. + Data is de-lagged by removing the data from "lag" days ago + thus removing (or attempting to) the cumulative effect of + the moving average. + """, + ) + + parser.add_argument( + "-l", + "--length", + action="store", + dest="n_length", + type=check_positive, + default=10, + help="length", + ) + parser.add_argument( + "-o", + "--offset", + action="store", + dest="n_offset", + type=check_positive, + default=0, + help="offset", + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + + # Daily + if s_interval == "1440min": + df_ta = ta.zlma( + df_stock["Adj Close"], + length=ns_parser.n_length, + offset=ns_parser.n_offset, + ).dropna() + + # Intraday + else: + df_ta = ta.zlma( + df_stock["Close"], + length=ns_parser.n_length, + offset=ns_parser.n_offset, + ).dropna() + + fig, _ = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) + plt.title(f"{ns_parser.n_length} Day ZLMA on {s_ticker}") + + if s_interval == "1440min": + plt.plot( + df_stock["Adj Close"].index, + df_stock["Adj Close"].values, + "fuchsia", + lw=1, + ) + plt.xlim( + df_stock["Adj Close"].index[0], + df_stock["Adj Close"].index[-1], + ) + else: + plt.plot(df_stock["Close"].index, df_stock["Close"].values, "k", lw=1) + plt.xlim(df_stock["Close"].index[0], df_stock["Close"].index[-1]) + + plt.xlabel("Time") + plt.ylabel(f"{s_ticker} Price($)") + plt.plot(df_ta.index, df_ta.values, c="tab:blue") + l_legend = list() + l_legend.append(s_ticker) + # Pandas series + if len(df_ta.shape) == 1: + l_legend.append(f"ZLMA {ns_parser.n_length}") + # Pandas dataframe + else: + l_legend.append(df_ta.columns.tolist()) + + plt.legend(l_legend) + plt.grid(b=True, which="major", color="#666666", linestyle="-") + plt.minorticks_on() + plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) + + if gtff.USE_ION: + plt.ion() + + plt.gcf().autofmt_xdate() + fig.tight_layout(pad=1) + + plt.show() + print("") + + except Exception as e: + print(e, "\n") diff --git a/gamestonk_terminal/stocks/technical_analysis/ta_controller.py b/gamestonk_terminal/stocks/technical_analysis/ta_controller.py index ca466dd9fe1..bcc99b0d201 100644 --- a/gamestonk_terminal/stocks/technical_analysis/ta_controller.py +++ b/gamestonk_terminal/stocks/technical_analysis/ta_controller.py @@ -45,6 +45,7 @@ class TechnicalAnalysisController: "ema", "sma", "vwap", + "zlma", "cci", "macd", "rsi", @@ -56,6 +57,7 @@ class TechnicalAnalysisController: "ad", "obv", "fib", + "cg", ] def __init__( @@ -109,12 +111,14 @@ class TechnicalAnalysisController: print(" ema exponential moving average") print(" sma simple moving average") print(" vwap volume weighted average price") + print(" zlma zero lag moving average") print("momentum:") print(" cci commodity channel index") print(" macd moving average convergence/divergence") print(" rsi relative strength index") print(" stoch stochastic oscillator") print(" fisher fisher transform") + print(" cg centre of gravity") print("trend:") print(" adx average directional movement index") print(" aroon aroon indicator") @@ -201,6 +205,10 @@ class TechnicalAnalysisController: """Process vwap command""" overlap.vwap(other_args, self.ticker, self.interval, self.stock) + def call_zlma(self, other_args: List[str]): + """Process zlma command""" + overlap.zlma(other_args, self.ticker, self.interval, self.stock) + def call_cci(self, other_args: List[str]): """Process cci command""" momentum.cci(other_args, self.ticker, self.interval, self.stock) @@ -221,6 +229,10 @@ class TechnicalAnalysisController: """Process fisher command""" momentum.fisher(other_args, self.ticker, self.interval, self.stock) + def call_cg(self, other_args: List[str]): + """Process cg command""" + momentum.cg(other_args, self.ticker, self.interval, self.stock) + def call_adx(self, other_args: List[str]): """Process adx command""" trend_indicators.adx(other_args, self.ticker, self.interval, self.stock)