diff --git a/gamestonk_terminal/README.md b/gamestonk_terminal/README.md
index 77e5200e1d9..a6038db8fa7 100644
--- a/gamestonk_terminal/README.md
+++ b/gamestonk_terminal/README.md
@@ -219,9 +219,10 @@ Command | Description | Sources
[volatility](https://github.com/twopirllc/pandas-ta/tree/master/pandas_ta/volatility) |
`bbands` |bollinger bands | [Wikipedia](https://en.wikipedia.org/wiki/Bollinger_Bands), [Investopedia](https://www.investopedia.com/terms/b/bollingerbands.asp)
[volume](https://github.com/twopirllc/pandas-ta/tree/master/pandas_ta/volume) |
-`ad` |chaikin accumulation/distribution line values | [Wikipedia](https://en.wikipedia.org/wiki/Accumulation/distribution_index), [Investopedia](https://www.investopedia.com/terms/a/accumulationdistribution.asp)
+`ad` |accumulation/distribution line values | [Wikipedia](https://en.wikipedia.org/wiki/Accumulation/distribution_index), [Investopedia](https://www.investopedia.com/terms/a/accumulationdistribution.asp)
`obv` |on balance volume | [Wikipedia](https://en.wikipedia.org/wiki/On-balance_volume), [Investopedia](https://www.investopedia.com/terms/o/onbalancevolume.asp)
-
+custom|
+`fib` | Fibonocci levels | [Investopedia](https://www.investopedia.com/terms/f/fibonacciretracement.asp)
## Due Diligence [ยป](due_diligence/README.md)
diff --git a/gamestonk_terminal/main_helper.py b/gamestonk_terminal/main_helper.py
index 687de8f4356..6e0bc770a88 100644
--- a/gamestonk_terminal/main_helper.py
+++ b/gamestonk_terminal/main_helper.py
@@ -42,7 +42,13 @@ from gamestonk_terminal import thought_of_the_day as thought
from gamestonk_terminal.technical_analysis import trendline_api as trend
-def clear(other_args: List[str], s_ticker, s_start, s_interval, df_stock):
+def clear(
+ other_args: List[str],
+ s_ticker: str,
+ s_start,
+ s_interval: str,
+ df_stock: pd.DataFrame,
+):
"""Clears loaded stock and returns empty variables
Parameters
@@ -89,7 +95,13 @@ def clear(other_args: List[str], s_ticker, s_start, s_interval, df_stock):
return s_ticker, s_start, s_interval, df_stock
-def load(other_args: List[str], s_ticker, s_start, s_interval, df_stock):
+def load(
+ other_args: List[str],
+ s_ticker: str,
+ s_start,
+ s_interval: str,
+ df_stock: pd.DataFrame,
+):
"""Load selected ticker
Parameters
@@ -136,7 +148,7 @@ def load(other_args: List[str], s_ticker, s_start, s_interval, df_stock):
"-s",
"--start",
type=valid_date,
- default="2019-01-01",
+ default=(datetime.now() - timedelta(days=366)).strftime("%Y-%m-%d"),
dest="s_start_date",
help="The starting date (format YYYY-MM-DD) of the stock",
)
@@ -601,7 +613,7 @@ def quote(other_args: List[str], s_ticker: str):
return
-def view(other_args: List[str], s_ticker: str, s_interval, df_stock):
+def view(other_args: List[str], s_ticker: str, s_interval: str, df_stock: pd.DataFrame):
"""Plot loaded ticker
Parameters
diff --git a/gamestonk_terminal/technical_analysis/README.md b/gamestonk_terminal/technical_analysis/README.md
index aa5ca8a0fe6..9eb21bd0891 100644
--- a/gamestonk_terminal/technical_analysis/README.md
+++ b/gamestonk_terminal/technical_analysis/README.md
@@ -41,10 +41,15 @@ This menu aims to perform a technical analysis on a pre-loaded ticker chart, and
[VOLUME](#VOLUME)
* [ad](#ad)
- - chaikin accumulation/distribution line values
+ - Accumulation/distribution line values
* [obv](#obv)
- on balance volume
+[CUSTOM](#CUSTOM)
+ * [fib](#fib)
+ - Shows fibonocci levels
+
+
**S/O to https://github.com/twopirllc/pandas-ta** _Owing to this library, it is fairly easy to add other technical indicators. So, let us know if there's any other that you would like._
## view
@@ -111,10 +116,11 @@ usage: sma [-l L_LENGTH] [-o N_OFFSET]
## vwap
+VWAP is available for intraday data. This plots the most recent day only.
```
usage: vwap [-o N_OFFSET]
```
-
+
# MOMENTUM
@@ -178,11 +184,29 @@ usage: bbands [-h] [-l N_LENGTH] [-s N_STD] [-m S_MAMODE] [-o N_OFFSET]
```
usage: ad [-o N_OFFSET] [--open]
```
-
+
## obv
```
usage: obv [-o N_OFFSET]
```
-
+
+
+# CUSTOM
+
+## fib
+Shows fibonocci levels
+```python
+usage: fib [-p PERIOD] [--start] [--end]
+```
+* -p/--period: Number of days to lookback for retracement. Default = 120.
+* --start: Allows for custom selection of min point.
+* --end : Allows for custom selection of max point.
+
+The fibonocci retracement works by looking at a minimum and maximum point. Between these values, there is typically support/resistance at
+23.5 %, 38.2%, 50% and 61.8%. Those values follow the golden ratio from the fibonocci sequence.
+
+The `--start` and `--end` flags allow the user to select dates for the min and max points as your retracement levels. Both flags are required if using.
+
+
diff --git a/gamestonk_terminal/technical_analysis/custom_indicators_view.py b/gamestonk_terminal/technical_analysis/custom_indicators_view.py
new file mode 100644
index 00000000000..a849e20d618
--- /dev/null
+++ b/gamestonk_terminal/technical_analysis/custom_indicators_view.py
@@ -0,0 +1,153 @@
+"""Custom TA indicators"""
+__docformat__ = "numpy"
+
+import argparse
+from typing import List
+import pandas as pd
+import matplotlib.pyplot as plt
+from tabulate import tabulate
+
+from gamestonk_terminal.helper_funcs import (
+ parse_known_args_and_warn,
+ plot_autoscale,
+ valid_date,
+)
+
+from gamestonk_terminal import config_plot as cfp
+from gamestonk_terminal import feature_flags as gtff
+
+
+def fibinocci_retracement(other_args: List[str], data: pd.DataFrame, ticker: str):
+ """Calculate fibinocci retracement levels
+
+ Parameters
+ ----------
+ other_args:List[str]
+ Argparse arguments
+ data: pd.DataFrame
+ Stock data
+ ticker:str
+ Stock ticker
+ """
+
+ parser = argparse.ArgumentParser(
+ add_help=False,
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+ prog="fib",
+ description="Calculates the fibinocci retracement levels",
+ )
+ parser.add_argument(
+ "-p",
+ "--period",
+ dest="period",
+ type=int,
+ help="Days to lookback for retracement",
+ default=120,
+ )
+
+ parser.add_argument(
+ "--start",
+ dest="start",
+ type=valid_date,
+ help="Starting date to select",
+ required="--end" in other_args,
+ )
+
+ parser.add_argument(
+ "--end",
+ dest="end",
+ type=valid_date,
+ help="Ending date to select",
+ required="--start" in other_args,
+ )
+
+ try:
+ ns_parser = parse_known_args_and_warn(parser, other_args)
+ if not ns_parser:
+ return
+
+ if ns_parser.start and ns_parser.end:
+
+ if ns_parser.start not in data.index:
+ date0 = data.index[
+ data.index.get_loc(ns_parser.start, method="nearest")
+ ]
+ print(f"Start date not in data. Using nearest: {date0}")
+ else:
+ date0 = ns_parser.start
+ if ns_parser.end not in data.index:
+ date1 = data.index[data.index.get_loc(ns_parser.end, method="nearest")]
+ print(f"End date not in data. Using nearest: {date1}")
+ else:
+ date1 = ns_parser.end
+
+ data0 = data.loc[date0, "Adj Close"]
+ data1 = data.loc[date1, "Adj Close"]
+
+ min_pr = min(data0, data1)
+ max_pr = max(data0, data1)
+
+ if min_pr == data0:
+ min_date = date0
+ max_date = date1
+ else:
+ min_date = date1
+ max_date = date0
+
+ else:
+ data_to_use = data.iloc[-ns_parser.period :]["Adj Close"]
+
+ min_pr = data_to_use.min()
+ min_date = data_to_use.idxmin()
+ max_pr = data_to_use.max()
+ max_date = data_to_use.idxmax()
+
+ fib_levels = [0, 0.235, 0.382, 0.5, 0.618, 1]
+ price_dif = max_pr - min_pr
+
+ levels = [round(max_pr - price_dif * f_lev, 2) for f_lev in fib_levels]
+
+ df = pd.DataFrame()
+ df["Level"] = fib_levels
+ df["Level"] = df["Level"].apply(lambda x: str(x * 100) + "%")
+ df["Price"] = levels
+
+ fig, ax = plt.subplots(figsize=(plot_autoscale()), dpi=cfp.PLOT_DPI)
+
+ ax.plot(data["Adj Close"], "b")
+ ax.plot([min_date, max_date], [min_pr, max_pr], c="k")
+
+ for i in levels:
+ ax.axhline(y=i, c="g", alpha=0.5)
+
+ for i in range(5):
+ ax.fill_between(data.index, levels[i], levels[i + 1], alpha=0.6)
+
+ ax.set_ylabel("Price")
+ ax.set_title(f"Fibonacci Support for {ticker.upper()}")
+ ax.set_xlim(data.index[0], data.index[-1])
+
+ ax1 = ax.twinx()
+ ax1.set_ylim(ax.get_ylim())
+ ax1.set_yticks(levels)
+ ax1.set_yticklabels(fib_levels)
+
+ plt.gcf().autofmt_xdate()
+ fig.tight_layout(pad=1)
+
+ if gtff.USE_ION:
+ plt.ion()
+ plt.show()
+
+ print(
+ tabulate(
+ df,
+ headers=["Fib Level", "Price"],
+ showindex=False,
+ tablefmt="fancy_grid",
+ )
+ )
+ print("")
+
+ except Exception as e:
+ print(e, "\n")
diff --git a/gamestonk_terminal/technical_analysis/momentum.py b/gamestonk_terminal/technical_analysis/momentum.py
index 7fc6107fce6..65e003ff915 100644
--- a/gamestonk_terminal/technical_analysis/momentum.py
+++ b/gamestonk_terminal/technical_analysis/momentum.py
@@ -1,7 +1,14 @@
+"""Momentum Technical Analysis"""
+__docformat__ = "numpy"
+
import argparse
+from typing import List
+
import matplotlib.pyplot as plt
import pandas_ta as ta
+import pandas as pd
from pandas.plotting import register_matplotlib_converters
+
from gamestonk_terminal.helper_funcs import (
check_positive,
parse_known_args_and_warn,
@@ -13,7 +20,21 @@ from gamestonk_terminal import feature_flags as gtff
register_matplotlib_converters()
-def cci(l_args, s_ticker, s_interval, df_stock):
+def cci(other_args: List[str], s_ticker: str, s_interval: str, df_stock: pd.DataFrame):
+ """Commodity channel index
+
+ 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,
@@ -56,7 +77,7 @@ def cci(l_args, s_ticker, s_interval, df_stock):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -82,46 +103,63 @@ def cci(l_args, s_ticker, s_interval, df_stock):
offset=ns_parser.n_offset,
).dropna()
- plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
- plt.subplot(211)
- plt.title(f"Commodity Channel Index (CCI) on {s_ticker}")
+ fig, axes = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI)
+ ax = axes[0]
+ ax.set_title(f"{s_ticker} CCI")
if s_interval == "1440min":
- plt.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2)
+ ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2)
else:
- plt.plot(df_stock.index, df_stock["Close"].values, "k", lw=2)
- plt.xlim(df_stock.index[0], df_stock.index[-1])
- plt.ylabel("Share Price ($)")
- plt.grid(b=True, which="major", color="#666666", linestyle="-")
- plt.minorticks_on()
- plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
- plt.subplot(212)
- plt.plot(df_ta.index, df_ta.values, "b", lw=2)
- plt.xlim(df_stock.index[0], df_stock.index[-1])
- plt.axhspan(100, plt.gca().get_ylim()[1], facecolor="r", alpha=0.2)
- plt.axhspan(plt.gca().get_ylim()[0], -100, facecolor="g", alpha=0.2)
- plt.axhline(100, linewidth=3, color="r", ls="--")
- plt.axhline(-100, linewidth=3, color="g", ls="--")
- plt.xlabel("Time")
- plt.grid(b=True, which="major", color="#666666", linestyle="-")
- plt.minorticks_on()
- plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
- plt.gca().twinx()
- plt.ylim(plt.gca().get_ylim())
- plt.yticks([0.2, 0.8], ("OVERSOLD", "OVERBOUGHT"))
+ ax.plot(df_stock.index, df_stock["Close"].values, "k", lw=2)
+ 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)
+ ax2.set_xlim(df_stock.index[0], df_stock.index[-1])
+ ax2.axhspan(100, plt.gca().get_ylim()[1], facecolor="r", alpha=0.2)
+ ax2.axhspan(plt.gca().get_ylim()[0], -100, facecolor="g", alpha=0.2)
+ ax2.axhline(100, linewidth=3, color="r", ls="--")
+ ax2.axhline(-100, linewidth=3, color="g", ls="--")
+ ax2.grid(b=True, which="major", color="#666666", linestyle="-")
+ ax2.minorticks_on()
+ ax2.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
+
+ ax3 = ax2.twinx()
+ ax3.set_ylim(ax2.get_ylim())
+ ax3.set_yticks([-100, 100])
+ ax3.set_yticklabels(["OVERSOLD", "OVERBOUGHT"])
if gtff.USE_ION:
plt.ion()
+ plt.gcf().autofmt_xdate()
+ fig.tight_layout(pad=1)
+
plt.show()
print("")
except Exception as e:
- print(e)
- print("")
+ print(e, "\n")
-def macd(l_args, s_ticker, s_interval, df_stock):
+def macd(other_args: List[str], s_ticker: str, s_interval: str, df_stock: pd.DataFrame):
+ """Moving average convergence divergence
+
+ 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,
@@ -176,7 +214,7 @@ def macd(l_args, s_ticker, s_interval, df_stock):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -200,47 +238,63 @@ def macd(l_args, s_ticker, s_interval, df_stock):
offset=ns_parser.n_offset,
).dropna()
- plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
- plt.subplot(211)
- plt.title(f"Moving Average Convergence Divergence (MACD) on {s_ticker}")
+ fig, axes = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI)
+ ax = axes[0]
+ ax.set_title(f"{s_ticker} MACD")
if s_interval == "1440min":
- plt.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2)
+ ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2)
else:
- plt.plot(df_stock.index, df_stock["Close"].values, "k", lw=2)
- plt.xlim(df_stock.index[0], df_stock.index[-1])
- plt.ylabel("Share Price ($)")
- plt.grid(b=True, which="major", color="#666666", linestyle="-")
- plt.minorticks_on()
- plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
- plt.subplot(212)
- plt.plot(df_ta.index, df_ta.iloc[:, 0].values, "b", lw=2)
- plt.plot(df_ta.index, df_ta.iloc[:, 2].values, "r", lw=2)
- plt.bar(df_ta.index, df_ta.iloc[:, 1].values, color="g")
- plt.legend(
+ ax.plot(df_stock.index, df_stock["Close"].values, "k", lw=2)
+ 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.iloc[:, 0].values, "b", lw=2)
+ ax2.plot(df_ta.index, df_ta.iloc[:, 2].values, "r", lw=2)
+ ax2.bar(df_ta.index, df_ta.iloc[:, 1].values, color="g")
+ ax2.legend(
[
f"MACD Line {df_ta.columns[0]}",
f"Signal Line {df_ta.columns[2]}",
f"Histogram {df_ta.columns[1]}",
- ]
+ ],
+ loc="upper left",
)
- plt.xlim(df_stock.index[0], df_stock.index[-1])
- plt.grid(b=True, which="major", color="#666666", linestyle="-")
- plt.minorticks_on()
- plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
- plt.xlabel("Time")
+ 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.show()
print("")
except Exception as e:
- print(e)
- print("")
+ print(e, "\n")
-def rsi(l_args, s_ticker, s_interval, df_stock):
+def rsi(other_args: List[str], s_ticker: str, s_interval: str, df_stock: pd.DataFrame):
+ """Relative strength index
+
+ 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,
@@ -292,7 +346,7 @@ def rsi(l_args, s_ticker, s_interval, df_stock):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -316,47 +370,65 @@ def rsi(l_args, s_ticker, s_interval, df_stock):
offset=ns_parser.n_offset,
).dropna()
- plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
- plt.subplot(211)
+ fig, axes = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI)
+ ax = axes[0]
if s_interval == "1440min":
- plt.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2)
+ ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2)
else:
- plt.plot(df_stock.index, df_stock["Close"].values, "k", lw=2)
- plt.title(f"Relative Strength Index (RSI) on {s_ticker}")
- plt.xlim(df_stock.index[0], df_stock.index[-1])
- plt.ylabel("Share Price ($)")
- plt.grid(b=True, which="major", color="#666666", linestyle="-")
- plt.minorticks_on()
- plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
- plt.subplot(212)
- plt.plot(df_ta.index, df_ta.values, "b", lw=2)
- plt.xlim(df_stock.index[0], df_stock.index[-1])
- plt.axhspan(70, 100, facecolor="r", alpha=0.2)
- plt.axhspan(0, 30, facecolor="g", alpha=0.2)
- plt.axhline(70, linewidth=3, color="r", ls="--")
- plt.axhline(30, linewidth=3, color="g", ls="--")
- plt.xlabel("Time")
- plt.grid(b=True, which="major", color="#666666", linestyle="-")
- plt.minorticks_on()
- plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
- plt.ylim([0, 100])
- plt.gca().twinx()
- plt.ylim(plt.gca().get_ylim())
- plt.yticks([0.15, 0.85], ("OVERSOLD", "OVERBOUGHT"))
+ ax.plot(df_stock.index, df_stock["Close"].values, "k", lw=2)
+ ax.set_title(f" {s_ticker} RSI{ns_parser.n_length} ")
+ 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)
+ ax2.set_xlim(df_stock.index[0], df_stock.index[-1])
+ ax2.axhspan(70, 100, facecolor="r", alpha=0.2)
+ ax2.axhspan(0, 30, facecolor="g", alpha=0.2)
+ ax2.axhline(70, linewidth=3, color="r", ls="--")
+ ax2.axhline(30, linewidth=3, color="g", ls="--")
+ ax2.grid(b=True, which="major", color="#666666", linestyle="-")
+ ax2.minorticks_on()
+ ax2.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
+ ax2.set_ylim([0, 100])
+ ax3 = ax2.twinx()
+ ax3.set_ylim(ax2.get_ylim())
+ ax3.set_yticks([30, 70])
+ ax3.set_yticklabels(["OVERSOLD", "OVERBOUGHT"])
if gtff.USE_ION:
plt.ion()
+ plt.gcf().autofmt_xdate()
+ fig.tight_layout(pad=1)
+
plt.show()
print("")
except Exception as e:
- print(e)
- print("")
+ print(e, "\n")
-def stoch(l_args, s_ticker, s_interval, df_stock):
+def stoch(
+ other_args: List[str], s_ticker: str, s_interval: str, df_stock: pd.DataFrame
+):
+ """Stochastic oscillator
+
+ 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,
@@ -408,7 +480,7 @@ def stoch(l_args, s_ticker, s_interval, df_stock):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -436,43 +508,51 @@ def stoch(l_args, s_ticker, s_interval, df_stock):
offset=ns_parser.n_offset,
).dropna()
- plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
- plt.subplot(211)
+ fig, axes = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI)
+ ax = axes[0]
if s_interval == "1440min":
- plt.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2)
+ ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2)
else:
- plt.plot(df_stock.index, df_stock["Close"].values, "k", lw=2)
- plt.title(f"Stochastic Relative Strength Index (STOCH RSI) on {s_ticker}")
- plt.xlim(df_stock.index[0], df_stock.index[-1])
- plt.ylabel("Share Price ($)")
- plt.grid(b=True, which="major", color="#666666", linestyle="-")
- plt.minorticks_on()
- plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
- plt.subplot(212)
- plt.plot(df_ta.index, df_ta.iloc[:, 0].values, "k", lw=2)
- plt.plot(df_ta.index, df_ta.iloc[:, 1].values, "b", lw=2, ls="--")
- plt.xlim(df_stock.index[0], df_stock.index[-1])
- plt.axhspan(80, 100, facecolor="r", alpha=0.2)
- plt.axhspan(0, 20, facecolor="g", alpha=0.2)
- plt.axhline(80, linewidth=3, color="r", ls="--")
- plt.axhline(20, linewidth=3, color="g", ls="--")
- plt.legend([f"%K {df_ta.columns[0]}", f"%D {df_ta.columns[1]}"])
- plt.xlabel("Time")
- plt.grid(b=True, which="major", color="#666666", linestyle="-")
- plt.minorticks_on()
- plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
- plt.ylim([0, 100])
- plt.gca().twinx()
- plt.ylim(plt.gca().get_ylim())
- plt.yticks([0.1, 0.9], ("OVERSOLD", "OVERBOUGHT"))
+ ax.plot(df_stock.index, df_stock["Close"].values, "k", lw=2)
+ ax.set_title(f"Stochastic Relative Strength Index (STOCH RSI) on {s_ticker}")
+ ax.set_xlim(df_stock.index[0], df_stock.index[-1])
+ ax.set_xticklabels([])
+ 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.iloc[:, 0].values, "k", lw=2)
+ ax2.plot(df_ta.index, df_ta.iloc[:, 1].values, "b", lw=2, ls="--")
+ ax2.set_xlim(df_stock.index[0], df_stock.index[-1])
+
+ ax2.axhspan(80, 100, facecolor="r", alpha=0.2)
+ ax2.axhspan(0, 20, facecolor="g", alpha=0.2)
+ ax2.axhline(80, linewidth=3, color="r", ls="--")
+ ax2.axhline(20, linewidth=3, color="g", ls="--")
+
+ ax2.grid(b=True, which="major", color="#666666", linestyle="-")
+ ax2.minorticks_on()
+ ax2.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
+ ax2.set_ylim([0, 100])
+
+ ax3 = ax2.twinx()
+ ax3.set_ylim(ax2.get_ylim())
+ ax3.set_yticks([20, 80])
+ ax3.set_yticklabels(["OVERSOLD", "OVERBOUGHT"])
+ ax2.legend(
+ [f"%K {df_ta.columns[0]}", f"%D {df_ta.columns[1]}"], loc="lower left"
+ )
if gtff.USE_ION:
plt.ion()
+ plt.gcf().autofmt_xdate()
+ fig.tight_layout(pad=1)
plt.show()
print("")
except Exception as e:
- print(e)
- print("")
+ print(e, "\n")
diff --git a/gamestonk_terminal/technical_analysis/overlap.py b/gamestonk_terminal/technical_analysis/overlap.py
index bfc52c08c49..dd1e8eb28f5 100644
--- a/gamestonk_terminal/technical_analysis/overlap.py
+++ b/gamestonk_terminal/technical_analysis/overlap.py
@@ -1,7 +1,15 @@
+"""Overlap Technical Analysis"""
+___docformat__ = "numpy"
+
import argparse
+from typing import List
+
import matplotlib.pyplot as plt
+import pandas as pd
import pandas_ta as ta
from pandas.plotting import register_matplotlib_converters
+import mplfinance as mpf
+
from gamestonk_terminal.helper_funcs import (
check_positive,
parse_known_args_and_warn,
@@ -13,7 +21,21 @@ from gamestonk_terminal import feature_flags as gtff
register_matplotlib_converters()
-def ema(l_args, s_ticker, s_interval, df_stock):
+def ema(other_args: List[str], s_ticker: str, s_interval: str, df_stock: pd.DataFrame):
+ """Plots exponential moving average (EMA) over stock
+
+ 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,
@@ -50,7 +72,7 @@ def ema(l_args, s_ticker, s_interval, df_stock):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -70,8 +92,9 @@ def ema(l_args, s_ticker, s_interval, df_stock):
offset=ns_parser.n_offset,
).dropna()
- _, _ = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
- plt.title(f"{ns_parser.n_length} EMA on {s_ticker}")
+ fig, _ = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
+ plt.title(f"{ns_parser.n_length} Day EMA on {s_ticker}")
+
if s_interval == "1440min":
plt.plot(
df_stock["Adj Close"].index,
@@ -86,17 +109,19 @@ def ema(l_args, s_ticker, s_interval, df_stock):
else:
plt.plot(df_stock["Close"].index, df_stock["Close"].values, "k", lw=3)
plt.xlim(df_stock["Close"].index[0], df_stock["Close"].index[-1])
+
plt.xlabel("Time")
- plt.ylabel(f"Share Price of {s_ticker} ($)")
+ 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"{ns_parser.n_length} EMA")
+ l_legend.append(f"EMA {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()
@@ -105,15 +130,30 @@ def ema(l_args, s_ticker, s_interval, df_stock):
if gtff.USE_ION:
plt.ion()
+ plt.gcf().autofmt_xdate()
+ fig.tight_layout(pad=1)
+
plt.show()
print("")
except Exception as e:
- print(e)
- print("")
+ print(e, "\n")
-def sma(l_args, s_ticker, s_interval, df_stock):
+def sma(other_args: List[str], s_ticker: str, s_interval: str, df_stock: pd.DataFrame):
+ """Plots simple moving average (SMA) over stock
+
+ 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,
@@ -148,11 +188,11 @@ def sma(l_args, s_ticker, s_interval, df_stock):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
- plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
+ fig, _ = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
if s_interval == "1440min":
plt.plot(df_stock.index, df_stock["Adj Close"].values, color="k")
else:
@@ -171,11 +211,12 @@ def sma(l_args, s_ticker, s_interval, df_stock):
df_stock["Close"], length=length, offset=ns_parser.n_offset
).dropna()
plt.plot(df_ta.index, df_ta.values)
- l_legend.append(f"{length} SMA")
+ l_legend.append(f"SMA{length} ")
+
plt.title(f"SMA on {s_ticker}")
plt.xlim(df_stock.index[0], df_stock.index[-1])
plt.xlabel("Time")
- plt.ylabel("Share Price ($)")
+ plt.ylabel(f"{s_ticker} Price ($)")
plt.legend(l_legend)
plt.grid(b=True, which="major", color="#666666", linestyle="-")
plt.minorticks_on()
@@ -184,15 +225,30 @@ def sma(l_args, s_ticker, s_interval, df_stock):
if gtff.USE_ION:
plt.ion()
+ plt.gcf().autofmt_xdate()
+ fig.tight_layout(pad=1)
+
plt.show()
print("")
except Exception as e:
- print(e)
- print("")
+ print(e, "\n")
-def vwap(l_args, s_ticker, s_interval, df_stock):
+def vwap(other_args: List[str], s_ticker: str, s_interval: str, df_stock: pd.DataFrame):
+ """Plots volume weighted average price (VWAP)
+
+ 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,
@@ -214,63 +270,41 @@ def vwap(l_args, s_ticker, s_interval, df_stock):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
# Daily
if s_interval == "1440min":
- df_ta = ta.vwap(
- high=df_stock["High"],
- low=df_stock["Low"],
- close=df_stock["Adj Close"],
- volume=df_stock["Volume"],
- offset=ns_parser.n_offset,
- )
+ print("VWAP should be used with intraday data. \n")
+ return
- # Intraday
- else:
- df_ta = ta.vwap(
- high=df_stock["High"],
- low=df_stock["Low"],
- close=df_stock["Close"],
- volume=df_stock["Volume"],
- offset=ns_parser.n_offset,
- )
+ df_stock.index = df_stock.index.tz_localize(None)
+ df_stock["Day"] = [idx.date() for idx in df_stock.index]
- _, axPrice = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
- if s_interval == "1440min":
- plt.plot(df_stock.index, df_stock["Adj Close"].values, color="k")
- else:
- plt.plot(df_stock.index, df_stock["Close"].values, color="k")
- plt.plot(df_ta.index, df_ta.values)
- plt.title(f"VWAP on {s_ticker}")
- plt.xlim(df_stock.index[0], df_stock.index[-1])
- plt.xlabel("Time")
- plt.ylabel("Share Price ($)")
- plt.legend([s_ticker, "VWAP"])
- _ = axPrice.twinx()
+ day_df = df_stock[df_stock.Day == df_stock.Day[-1]]
- if s_interval == "1440min":
- plt.bar(
- df_stock.index,
- df_stock["Volume"].values,
- color="k",
- alpha=0.8,
- width=0.3,
- )
- else:
- plt.bar(
- df_stock.index,
- df_stock["Volume"].values,
- color="k",
- alpha=0.8,
- width=0.3,
- )
- plt.ylabel("Volume")
- plt.grid(b=True, which="major", color="#666666", linestyle="-")
- plt.minorticks_on()
- plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
+ df_vwap = ta.vwap(
+ high=day_df["High"],
+ low=day_df["Low"],
+ close=day_df["Close"],
+ volume=day_df["Volume"],
+ )
+
+ mc = mpf.make_marketcolors(
+ up="green", down="red", edge="black", wick="black", volume="in", ohlc="i"
+ )
+
+ s = mpf.make_mpf_style(marketcolors=mc, gridstyle=":", y_on_right=True)
+ apdict = mpf.make_addplot(df_vwap, color="k")
+ mpf.plot(
+ day_df,
+ style=s,
+ type="candle",
+ addplot=apdict,
+ volume=True,
+ title=f"\n{s_ticker} {s_interval} VWAP",
+ )
if gtff.USE_ION:
plt.ion()
@@ -279,5 +313,4 @@ def vwap(l_args, s_ticker, s_interval, df_stock):
print("")
except Exception as e:
- print(e)
- print("")
+ print(e, "\n")
diff --git a/gamestonk_terminal/technical_analysis/ta_controller.py b/gamestonk_terminal/technical_analysis/ta_controller.py
index 6554a1dd278..3190cd791fe 100644
--- a/gamestonk_terminal/technical_analysis/ta_controller.py
+++ b/gamestonk_terminal/technical_analysis/ta_controller.py
@@ -21,6 +21,7 @@ from gamestonk_terminal.technical_analysis import finbrain_view
from gamestonk_terminal.technical_analysis import tradingview_view
from gamestonk_terminal.technical_analysis import finviz_view
from gamestonk_terminal.technical_analysis import finnhub_view
+from gamestonk_terminal.technical_analysis import custom_indicators_view
class TechnicalAnalysisController:
@@ -49,6 +50,7 @@ class TechnicalAnalysisController:
"bbands",
"ad",
"obv",
+ "fib",
]
def __init__(
@@ -112,8 +114,10 @@ class TechnicalAnalysisController:
print("volatility:")
print(" bbands bollinger bands")
print("volume:")
- print(" ad chaikin accumulation/distribution line values")
+ print(" ad accumulation/distribution line values")
print(" obv on balance volume")
+ print("custom:")
+ print(" fib fibonocci retracement")
print("")
def switch(self, an_input: str):
@@ -229,6 +233,12 @@ class TechnicalAnalysisController:
"""Process obv command"""
ta_volume.obv(other_args, self.ticker, self.interval, self.stock)
+ def call_fib(self, other_args: List[str]):
+ """Process fib command"""
+ custom_indicators_view.fibinocci_retracement(
+ other_args, self.stock, self.ticker
+ )
+
def menu(
ticker: str, start: datetime, interval: str, stock: pd.DataFrame, context: str = ""
diff --git a/gamestonk_terminal/technical_analysis/volatility.py b/gamestonk_terminal/technical_analysis/volatility.py
index 4d1e0eafdb4..27197a2a129 100644
--- a/gamestonk_terminal/technical_analysis/volatility.py
+++ b/gamestonk_terminal/technical_analysis/volatility.py
@@ -1,7 +1,14 @@
+"""Volatility Technical Indicators"""
+__docformat__ = "numpy"
+
import argparse
+from typing import List
+
import matplotlib.pyplot as plt
import pandas_ta as ta
from pandas.plotting import register_matplotlib_converters
+import pandas as pd
+
from gamestonk_terminal.helper_funcs import (
check_positive,
parse_known_args_and_warn,
@@ -13,7 +20,23 @@ from gamestonk_terminal import feature_flags as gtff
register_matplotlib_converters()
-def bbands(l_args, s_ticker, s_interval, df_stock):
+def bbands(
+ other_args: List[str], s_ticker: str, s_interval: str, df_stock: pd.DataFrame
+):
+ """Plot Bollinger Bands
+
+ Parameters
+ ----------
+ other_args: List[str]
+ Argparse arguments
+ s_ticker: str
+ Ticker
+ s_interval: str
+ Interval
+ df_stock: pd.DataFrame
+ Stock dataframe
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
@@ -64,7 +87,7 @@ def bbands(l_args, s_ticker, s_interval, df_stock):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -88,33 +111,37 @@ def bbands(l_args, s_ticker, s_interval, df_stock):
offset=ns_parser.n_offset,
).dropna()
- plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
+ fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
if s_ticker == "1440min":
- plt.plot(df_stock.index, df_stock["Adj Close"].values, color="k", lw=3)
+ ax.plot(df_stock.index, df_stock["Adj Close"].values, color="k", lw=3)
else:
- plt.plot(df_stock.index, df_stock["Close"].values, color="k", lw=3)
+ ax.plot(df_stock.index, df_stock["Close"].values, color="k", lw=3)
plt.plot(df_ta.index, df_ta.iloc[:, 0].values, "r", lw=2)
- plt.plot(df_ta.index, df_ta.iloc[:, 1].values, "b", lw=1.5, ls="--")
- plt.plot(df_ta.index, df_ta.iloc[:, 2].values, "g", lw=2)
- plt.title(f"Bollinger Band (BBands) on {s_ticker}")
- plt.xlim(df_stock.index[0], df_stock.index[-1])
- plt.xlabel("Time")
- plt.ylabel("Share Price ($)")
+ 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, "g", lw=2)
+ ax.set_title(f"{s_ticker} Bollinger Bands")
+ ax.set_xlim(df_stock.index[0], df_stock.index[-1])
+ ax.set_xlabel("Time")
+ ax.set_ylabel("Share Price ($)")
+
plt.legend([s_ticker, df_ta.columns[0], df_ta.columns[1], df_ta.columns[2]])
- plt.gca().fill_between(
+ ax.fill_between(
df_ta.index,
df_ta.iloc[:, 0].values,
df_ta.iloc[:, 2].values,
alpha=0.1,
color="b",
)
- plt.grid(b=True, which="major", color="#666666", linestyle="-")
+ ax.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("")
diff --git a/gamestonk_terminal/technical_analysis/volume.py b/gamestonk_terminal/technical_analysis/volume.py
index 441790225dc..ff44f326049 100644
--- a/gamestonk_terminal/technical_analysis/volume.py
+++ b/gamestonk_terminal/technical_analysis/volume.py
@@ -1,6 +1,14 @@
+"""Volume Technical Analysis"""
+__docformat__ = "numpy"
+
import argparse
+from typing import List
+from datetime import timedelta
+
import matplotlib.pyplot as plt
import pandas_ta as ta
+import pandas as pd
+
from pandas.plotting import register_matplotlib_converters
from gamestonk_terminal.helper_funcs import (
check_positive,
@@ -13,7 +21,21 @@ from gamestonk_terminal import feature_flags as gtff
register_matplotlib_converters()
-def ad(l_args, s_ticker, s_interval, df_stock):
+def ad(other_args: List[str], s_ticker: str, s_interval: str, df_stock: pd.DataFrame):
+ """Accumulation Dictribution Line
+
+ Parameters
+ ----------
+ other_args: List[str]
+ Argparse arguments
+ s_ticker: str
+ Ticker
+ s_interval: str
+ Stock data interval
+ df_stock: pd.DataFrame
+ Dataframe of stock prices
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
@@ -50,107 +72,115 @@ def ad(l_args, s_ticker, s_interval, df_stock):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
- # Daily
- if s_interval == "1440min":
- # Use open stock values
- if ns_parser.b_use_open:
- df_ta = ta.ad(
- high=df_stock["High"],
- low=df_stock["Low"],
- close=df_stock["Adj Close"],
- volume=df_stock["Volume"],
- offset=ns_parser.n_offset,
- open_=df_stock["Open"],
- ).dropna()
- # Do not use open stock values
- else:
- df_ta = ta.ad(
- high=df_stock["High"],
- low=df_stock["Low"],
- close=df_stock["Adj Close"],
- volume=df_stock["Volume"],
- offset=ns_parser.n_offset,
- ).dropna()
+ bar_colors = [
+ "r" if x[1].Open < x[1].Close else "g" for x in df_stock.iterrows()
+ ]
- # Intraday
+ if s_interval == "1440min":
+ bar_width = timedelta(days=1)
else:
- # Use open stock values
- if ns_parser.b_use_open:
- df_ta = ta.ad(
- high=df_stock["High"],
- low=df_stock["Low"],
- close=df_stock["Close"],
- volume=df_stock["Volume"],
- offset=ns_parser.n_offset,
- open_=df_stock["Open"],
- ).dropna()
- # Do not use open stock values
- else:
- df_ta = ta.ad(
- high=df_stock["High"],
- low=df_stock["Low"],
- close=df_stock["Close"],
- volume=df_stock["Volume"],
- offset=ns_parser.n_offset,
- ).dropna()
+ bar_width = timedelta(minutes=int(s_interval.split("m")[0]))
- plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
- axPrice = plt.subplot(211)
- if s_interval == "1440min":
- plt.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2)
+ if ns_parser.b_use_open:
+ df_ta = ta.ad(
+ high=df_stock["High"],
+ low=df_stock["Low"],
+ close=df_stock["Adj Close"],
+ volume=df_stock["Volume"],
+ offset=ns_parser.n_offset,
+ open_=df_stock["Open"],
+ ).dropna()
+ # Do not use open stock values
else:
- plt.plot(df_stock.index, df_stock["Close"].values, "k", lw=2)
- plt.title(f"Accumulation/Distribution Line (AD) on {s_ticker}")
- plt.xlim(df_stock.index[0], df_stock.index[-1])
- plt.ylabel("Share Price ($)")
- plt.grid(b=True, which="major", color="#666666", linestyle="-")
- plt.minorticks_on()
- plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
- _ = axPrice.twinx()
+ # Note this should always be Close not Adj Close
+ df_ta = ta.ad(
+ high=df_stock["High"],
+ low=df_stock["Low"],
+ close=df_stock["Close"],
+ volume=df_stock["Volume"],
+ offset=ns_parser.n_offset,
+ ).dropna()
+
+ fig, axes = plt.subplots(
+ 3,
+ 1,
+ gridspec_kw={"height_ratios": [2, 1, 1]},
+ figsize=plot_autoscale(),
+ dpi=PLOT_DPI,
+ )
+ ax = axes[0]
if s_interval == "1440min":
- plt.bar(
+ ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2)
+ else:
+ ax.plot(df_stock.index, df_stock["Close"].values, "k", lw=2)
+ ax.set_title(f"{s_ticker} AD")
+ 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.set_ylabel("Volume")
+ if s_interval == "1440min":
+ ax2.bar(
df_stock.index,
df_stock["Volume"].values,
- color="k",
+ color=bar_colors,
alpha=0.8,
width=0.3,
)
else:
- plt.bar(
+ ax2.bar(
df_stock.index,
df_stock["Volume"].values,
- color="k",
+ color=bar_colors,
alpha=0.8,
- width=0.3,
+ width=bar_width,
)
- plt.subplot(212)
- plt.plot(df_ta.index, df_ta.values, "b", lw=1)
- plt.xlim(df_stock.index[0], df_stock.index[-1])
- plt.axhline(0, linewidth=2, color="k", ls="--")
- plt.legend(["Chaikin Oscillator"])
- plt.xlabel("Time")
- plt.grid(b=True, which="major", color="#666666", linestyle="-")
- plt.minorticks_on()
- plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
+ ax2.set_xlim(df_stock.index[0], df_stock.index[-1])
+
+ ax3 = axes[2]
+ ax3.plot(df_ta.index, df_ta.values, "b", lw=1)
+ ax3.set_xlim(df_stock.index[0], df_stock.index[-1])
+ ax3.axhline(0, linewidth=2, color="k", ls="--")
+ ax3.set_ylabel("A/D")
+ ax3.set_xlabel("Time")
+ ax3.grid(b=True, which="major", color="#666666", linestyle="-")
+ ax3.minorticks_on()
+ ax3.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)
- print("")
- return
+ print(e, "\n")
-def obv(l_args, s_ticker, s_interval, df_stock):
- """Technical Analysis with On-Balance Volume indicator"""
+def obv(other_args: List[str], s_ticker: str, s_interval: str, df_stock: pd.DataFrame):
+ """On Balance Volume
+
+ Parameters
+ ----------
+ other_args: List[str]
+ Argparse arguments
+ s_ticker: str
+ Ticker
+ s_interval: str
+ Stock data interval
+ df_stock: pd.DataFrame
+ Dataframe of stock prices
+ """
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
@@ -176,10 +206,19 @@ def obv(l_args, s_ticker, s_interval, df_stock):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
+ bar_colors = [
+ "r" if x[1].Open < x[1].Close else "g" for x in df_stock.iterrows()
+ ]
+
+ if s_interval == "1440min":
+ bar_width = timedelta(days=1)
+ else:
+ bar_width = timedelta(minutes=int(s_interval.split("m")[0]))
+
# Daily
if s_interval == "1440min":
df_ta = ta.obv(
@@ -196,47 +235,58 @@ def obv(l_args, s_ticker, s_interval, df_stock):
offset=ns_parser.n_offset,
).dropna()
- plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
- axPrice = plt.subplot(211)
+ fig, axes = plt.subplots(
+ 3,
+ 1,
+ gridspec_kw={"height_ratios": [2, 1, 1]},
+ figsize=plot_autoscale(),
+ dpi=PLOT_DPI,
+ )
+ ax = axes[0]
if s_interval == "1440min":
- plt.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2)
+ ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2)
else:
- plt.plot(df_stock.index, df_stock["Close"].values, "k", lw=2)
- plt.title(f"On-Balance Volume (OBV) on {s_ticker}")
- plt.xlim(df_stock.index[0], df_stock.index[-1])
- plt.ylabel("Share Price ($)")
- plt.grid(b=True, which="major", color="#666666", linestyle="-")
- plt.minorticks_on()
- plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
- _ = axPrice.twinx()
+ ax.plot(df_stock.index, df_stock["Close"].values, "k", lw=2)
+
+ ax.set_title(f"{s_ticker} OBV")
+ 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.set_xlim(df_stock.index[0], df_stock.index[-1])
+
if s_interval == "1440min":
- plt.bar(
+ ax2.bar(
df_stock.index,
df_stock["Volume"].values,
- color="k",
+ color=bar_colors,
alpha=0.8,
- width=0.3,
+ width=bar_width,
)
else:
- plt.bar(
+ ax2.bar(
df_stock.index,
df_stock["Volume"].values,
- color="k",
+ color=bar_colors,
alpha=0.8,
- width=0.3,
+ width=bar_width,
)
- plt.subplot(212)
- plt.plot(df_ta.index, df_ta.values, "b", lw=1)
- plt.xlim(df_stock.index[0], df_stock.index[-1])
- plt.legend(["OBV"])
- plt.xlabel("Time")
- plt.grid(b=True, which="major", color="#666666", linestyle="-")
- plt.minorticks_on()
- plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
+ ax3 = axes[2]
+ ax3.plot(df_ta.index, df_ta.values, "b", lw=1)
+ ax3.set_xlim(df_stock.index[0], df_stock.index[-1])
+ ax3.set_xlabel("Time")
+ ax3.grid(b=True, which="major", color="#666666", linestyle="-")
+ ax3.minorticks_on()
+ ax3.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("")