Add fibonacci level indicator. Improve TA menu in general. (#572)

* Customize `fib` to allow user entry of min/max dates

* Add docs to overlap.  Update VWAP plot to be just last day of intraday data

* Volatility update.  Default load to 2020-01-01

* Momentum update

* Volume update (ad was incorrect)

* Update READme

* main readme

* Edit ad plot

* Update README.md

* Update fib plot + menu spacings

* Fix mypy error with start_date
This commit is contained in:
jmaslek
2021-07-27 19:08:27 -04:00
committed by GitHub
parent a8417d66ea
commit ceb506597e
9 changed files with 694 additions and 304 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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 <a name="view"></a>
@@ -111,10 +116,11 @@ usage: sma [-l L_LENGTH] [-o N_OFFSET]
## vwap <a name="vwap"></a>
VWAP is available for intraday data. This plots the most recent day only.
```
usage: vwap [-o N_OFFSET]
```
![vwap](https://user-images.githubusercontent.com/25267873/108602302-361d1c00-7399-11eb-87de-6026a2987ae0.png)
![vwap](https://user-images.githubusercontent.com/18151143/127217340-0f38bafd-fc16-4be4-a80a-6b89913559f5.png)
# MOMENTUM <a name="MOMENTUM"></a>
@@ -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]
```
![ad](https://user-images.githubusercontent.com/25267873/108603504-1f2df800-73a0-11eb-8d04-bcfd044601c1.png)
![ad](https://user-images.githubusercontent.com/18151143/127217265-73415705-3321-478f-b5a0-3ae1487c74ac.png)
## obv <a name="obv"></a>
```
usage: obv [-o N_OFFSET]
```
![obv](https://user-images.githubusercontent.com/25267873/108603503-1dfccb00-73a0-11eb-8da5-e5e5419a94ac.png)
![obv](https://user-images.githubusercontent.com/18151143/127217286-d73c1079-1b84-4da9-a5d4-39f4eb2d6b1b.png)
# CUSTOM <a name="CUSTOM"></a>
## fib <a name="fib"></a>
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.
![Fib1](https://user-images.githubusercontent.com/18151143/127217240-0b4cd88b-8fd3-484f-941e-b02a0efe08dd.png)

View File

@@ -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")

View File

@@ -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")

View File

@@ -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")

View File

@@ -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 = ""

View File

@@ -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("")

View File

@@ -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("")