mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-28 04:52:07 +00:00
* Handle no adj close * Added fixes for bad data handling * Finished switching model layout * Fixed all the bugs * Big fixes * Handle a lot more bugs * A couple more enhancements * Fixed issue Co-authored-by: Henrique Joaquim <h.joaquim@campus.fct.unl.pt> Co-authored-by: James Maslek <jmaslek11@gmail.com>
358 lines
9.7 KiB
Python
358 lines
9.7 KiB
Python
"""Volatility Technical Indicators View"""
|
|
__docformat__ = "numpy"
|
|
|
|
import logging
|
|
import os
|
|
from typing import Optional, List
|
|
|
|
import matplotlib.pyplot as plt
|
|
import pandas as pd
|
|
|
|
from openbb_terminal.config_terminal import theme
|
|
from openbb_terminal.common.technical_analysis import volatility_model
|
|
from openbb_terminal.config_plot import PLOT_DPI
|
|
from openbb_terminal.decorators import log_start_end
|
|
from openbb_terminal.helper_funcs import (
|
|
export_data,
|
|
plot_autoscale,
|
|
reindex_dates,
|
|
is_valid_axes_count,
|
|
)
|
|
from openbb_terminal.common.technical_analysis import ta_helpers
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@log_start_end(log=logger)
|
|
def display_bbands(
|
|
data: pd.DataFrame,
|
|
symbol: str = "",
|
|
window: int = 15,
|
|
n_std: float = 2,
|
|
mamode: str = "sma",
|
|
export: str = "",
|
|
external_axes: Optional[List[plt.Axes]] = None,
|
|
):
|
|
"""Show bollinger bands
|
|
|
|
Parameters
|
|
----------
|
|
data : pd.DataFrame
|
|
Dataframe of ohlc prices
|
|
symbol : str
|
|
Ticker symbol
|
|
window : int
|
|
Length of window to calculate BB
|
|
n_std : float
|
|
Number of standard deviations to show
|
|
mamode : str
|
|
Method of calculating average
|
|
export : str
|
|
Format of export file
|
|
external_axes : Optional[List[plt.Axes]], optional
|
|
External axes (1 axis is expected in the list), by default None
|
|
"""
|
|
df_ta = volatility_model.bbands(data, window, n_std, mamode)
|
|
plot_data = pd.merge(data, df_ta, how="outer", left_index=True, right_index=True)
|
|
plot_data = reindex_dates(plot_data)
|
|
|
|
# This plot has 1 axis
|
|
if not external_axes:
|
|
_, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
|
elif is_valid_axes_count(external_axes, 1):
|
|
(ax,) = external_axes
|
|
else:
|
|
return
|
|
|
|
close_col = ta_helpers.check_columns(data, high=False, low=False)
|
|
if close_col is None:
|
|
return
|
|
ax.plot(
|
|
plot_data.index,
|
|
plot_data[close_col].values,
|
|
)
|
|
ax.plot(
|
|
plot_data.index,
|
|
plot_data[df_ta.columns[0]].values,
|
|
theme.down_color,
|
|
linewidth=0.7,
|
|
)
|
|
ax.plot(plot_data.index, plot_data[df_ta.columns[1]].values, ls="--", linewidth=0.7)
|
|
ax.plot(
|
|
plot_data.index,
|
|
plot_data[df_ta.columns[2]].values,
|
|
theme.up_color,
|
|
linewidth=0.7,
|
|
)
|
|
ax.set_title(f"{symbol} Bollinger Bands")
|
|
ax.set_xlim(plot_data.index[0], plot_data.index[-1])
|
|
ax.set_ylabel("Share Price ($)")
|
|
ax.legend([symbol, df_ta.columns[0], df_ta.columns[1], df_ta.columns[2]])
|
|
ax.fill_between(
|
|
df_ta.index, df_ta.iloc[:, 0].values, df_ta.iloc[:, 2].values, alpha=0.1
|
|
)
|
|
theme.style_primary_axis(
|
|
ax,
|
|
data_index=plot_data.index.to_list(),
|
|
tick_labels=plot_data["date"].to_list(),
|
|
)
|
|
|
|
if external_axes is None:
|
|
theme.visualize_output()
|
|
|
|
export_data(
|
|
export,
|
|
os.path.dirname(os.path.abspath(__file__)).replace("common", "stocks"),
|
|
"bbands",
|
|
df_ta,
|
|
)
|
|
|
|
|
|
@log_start_end(log=logger)
|
|
def display_donchian(
|
|
data: pd.DataFrame,
|
|
symbol: str = "",
|
|
upper_length: int = 20,
|
|
lower_length: int = 20,
|
|
export: str = "",
|
|
external_axes: Optional[List[plt.Axes]] = None,
|
|
):
|
|
"""Show donchian channels
|
|
|
|
Parameters
|
|
----------
|
|
data : pd.DataFrame
|
|
Dataframe of ohlc prices
|
|
symbol : str
|
|
Ticker symbol
|
|
upper_length : int
|
|
Length of window to calculate upper channel
|
|
lower_length : int
|
|
Length of window to calculate lower channel
|
|
export : str
|
|
Format of export file
|
|
external_axes : Optional[List[plt.Axes]], optional
|
|
External axes (1 axis is expected in the list), by default None
|
|
"""
|
|
df_ta = volatility_model.donchian(data, upper_length, lower_length)
|
|
plot_data = pd.merge(data, df_ta, how="outer", left_index=True, right_index=True)
|
|
plot_data = reindex_dates(plot_data)
|
|
|
|
# This plot has 1 axis
|
|
if external_axes is None:
|
|
_, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
|
elif is_valid_axes_count(external_axes, 1):
|
|
(ax,) = external_axes
|
|
else:
|
|
return
|
|
|
|
close_col = ta_helpers.check_columns(data)
|
|
if close_col is None:
|
|
return
|
|
ax.plot(plot_data.index, plot_data[close_col].values)
|
|
ax.plot(
|
|
plot_data.index,
|
|
plot_data[df_ta.columns[0]].values,
|
|
linewidth=0.7,
|
|
label="Upper",
|
|
)
|
|
ax.plot(plot_data.index, plot_data[df_ta.columns[1]].values, linewidth=0.7, ls="--")
|
|
ax.plot(
|
|
plot_data.index,
|
|
plot_data[df_ta.columns[2]].values,
|
|
linewidth=0.7,
|
|
label="Lower",
|
|
)
|
|
ax.fill_between(
|
|
plot_data.index,
|
|
plot_data[df_ta.columns[0]].values,
|
|
plot_data[df_ta.columns[2]].values,
|
|
alpha=0.1,
|
|
)
|
|
ax.set_title(f"{symbol} donchian")
|
|
ax.set_xlim(plot_data.index[0], plot_data.index[-1])
|
|
ax.set_ylabel("Price ($)")
|
|
ax.legend([symbol, df_ta.columns[0], df_ta.columns[1], df_ta.columns[2]])
|
|
theme.style_primary_axis(
|
|
ax,
|
|
data_index=plot_data.index.to_list(),
|
|
tick_labels=plot_data["date"].to_list(),
|
|
)
|
|
|
|
if external_axes is None:
|
|
theme.visualize_output()
|
|
|
|
export_data(
|
|
export,
|
|
os.path.dirname(os.path.abspath(__file__)).replace("common", "stocks"),
|
|
"donchian",
|
|
df_ta,
|
|
)
|
|
|
|
|
|
@log_start_end(log=logger)
|
|
def view_kc(
|
|
data: pd.DataFrame,
|
|
window: int = 20,
|
|
scalar: float = 2,
|
|
mamode: str = "ema",
|
|
offset: int = 0,
|
|
symbol: str = "",
|
|
export: str = "",
|
|
external_axes: Optional[List[plt.Axes]] = None,
|
|
):
|
|
"""View Keltner Channels Indicator
|
|
|
|
Parameters
|
|
----------
|
|
|
|
data: pd.DataFrame
|
|
Dataframe of ohlc prices
|
|
window: int
|
|
Length of window
|
|
scalar: float
|
|
Scalar value
|
|
mamode: str
|
|
Type of filter
|
|
offset: int
|
|
Offset value
|
|
symbol: str
|
|
Ticker symbol
|
|
export: str
|
|
Format to export data
|
|
external_axes: Optional[List[plt.Axes]], optional
|
|
External axes (2 axes are expected in the list), by default None
|
|
"""
|
|
df_ta = volatility_model.kc(
|
|
data,
|
|
window,
|
|
scalar,
|
|
mamode,
|
|
offset,
|
|
)
|
|
plot_data = pd.merge(data, df_ta, how="outer", left_index=True, right_index=True)
|
|
plot_data = reindex_dates(plot_data)
|
|
|
|
# This plot has 1 axis
|
|
if external_axes is None:
|
|
_, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
|
elif is_valid_axes_count(external_axes, 1):
|
|
(ax,) = external_axes
|
|
else:
|
|
return
|
|
|
|
close_col = ta_helpers.check_columns(data)
|
|
if close_col is None:
|
|
return
|
|
ax.plot(plot_data.index, plot_data[close_col].values)
|
|
ax.plot(
|
|
plot_data.index,
|
|
plot_data[df_ta.columns[0]].values,
|
|
linewidth=0.7,
|
|
label="Upper",
|
|
)
|
|
ax.plot(plot_data.index, plot_data[df_ta.columns[1]].values, linewidth=0.7, ls="--")
|
|
ax.plot(
|
|
plot_data.index,
|
|
plot_data[df_ta.columns[2]].values,
|
|
linewidth=0.7,
|
|
label="Lower",
|
|
)
|
|
ax.fill_between(
|
|
plot_data.index,
|
|
plot_data[df_ta.columns[0]].values,
|
|
plot_data[df_ta.columns[2]].values,
|
|
alpha=0.1,
|
|
)
|
|
ax.set_title(f"{symbol} Keltner Channels")
|
|
ax.set_xlim(plot_data.index[0], plot_data.index[-1])
|
|
ax.set_ylabel("Price")
|
|
ax.legend([symbol, df_ta.columns[0], df_ta.columns[1], df_ta.columns[2]])
|
|
theme.style_primary_axis(
|
|
ax,
|
|
data_index=plot_data.index.to_list(),
|
|
tick_labels=plot_data["date"].to_list(),
|
|
)
|
|
|
|
if external_axes is None:
|
|
theme.visualize_output()
|
|
|
|
export_data(
|
|
export,
|
|
os.path.dirname(os.path.abspath(__file__)).replace("common", "stocks"),
|
|
"kc",
|
|
df_ta,
|
|
)
|
|
|
|
|
|
@log_start_end(log=logger)
|
|
def display_atr(
|
|
data: pd.DataFrame,
|
|
symbol: str = "",
|
|
window: int = 14,
|
|
mamode: str = "sma",
|
|
offset: int = 0,
|
|
export: str = "",
|
|
external_axes: Optional[List[plt.Axes]] = None,
|
|
):
|
|
"""Show ATR
|
|
|
|
Parameters
|
|
----------
|
|
data : pd.DataFrame
|
|
Dataframe of ohlc prices
|
|
symbol : str
|
|
Ticker symbol
|
|
window : int
|
|
Length of window to calculate upper channel
|
|
export : str
|
|
Format of export file
|
|
external_axes : Optional[List[plt.Axes]], optional
|
|
External axes (1 axis is expected in the list), by default None
|
|
"""
|
|
df_ta = volatility_model.atr(data, window=window, mamode=mamode, offset=offset)
|
|
|
|
# This plot has 2 axes
|
|
if external_axes is None:
|
|
_, axes = plt.subplots(
|
|
2, 1, figsize=plot_autoscale(), sharex=True, dpi=PLOT_DPI
|
|
)
|
|
(ax1, ax2) = axes
|
|
elif is_valid_axes_count(external_axes, 2):
|
|
(ax1, ax2) = external_axes
|
|
else:
|
|
return
|
|
|
|
plot_data = pd.merge(data, df_ta, how="outer", left_index=True, right_index=True)
|
|
plot_data = reindex_dates(plot_data)
|
|
|
|
ax1.plot(plot_data.index, plot_data.iloc[:, 1].values, color=theme.get_colors()[0])
|
|
ax1.set_title(f"{symbol} ATR")
|
|
ax1.set_xlim(plot_data.index[0], plot_data.index[-1])
|
|
ax1.set_ylabel("Share Price ($)")
|
|
theme.style_primary_axis(
|
|
ax=ax1,
|
|
data_index=plot_data.index.to_list(),
|
|
tick_labels=plot_data["date"].to_list(),
|
|
)
|
|
|
|
ax2.plot(
|
|
plot_data.index, plot_data[df_ta.columns[0]].values, color=theme.get_colors()[1]
|
|
)
|
|
ax2.set_xlim(plot_data.index[0], plot_data.index[-1])
|
|
ax2.set_ylabel("ATR")
|
|
theme.style_primary_axis(
|
|
ax=ax2,
|
|
data_index=plot_data.index.to_list(),
|
|
tick_labels=plot_data["date"].to_list(),
|
|
)
|
|
if external_axes is None:
|
|
theme.visualize_output()
|
|
|
|
export_data(
|
|
export,
|
|
os.path.dirname(os.path.abspath(__file__)).replace("common", "stocks"),
|
|
"atr",
|
|
df_ta,
|
|
)
|