mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-29 05:21:48 +00:00
Co-authored-by: jmaslek <jmaslek11@gmail.com> Co-authored-by: Chavithra <chavithra@gmail.com> Co-authored-by: Theodore Aptekarev <aptekarev@gmail.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> Co-authored-by: Didier Rodrigues Lopes <dro.lopes@campus.fct.unl.pt> * improve user experience phase 1 * add difflib replacement * implement auto-complete on discovery menu * auoto-complete, difflib,jump through menus with cd * Updating tests : terminal * improve navigation on gst * add q command to terminal.py * usage instructions * Updating tests : terminal * fix cd command * vars updated * show menu when user is going through menus * allow user to forget the intiail / on scripting * terminal to accept text file with configuration * refactor -n to -l and clean code * add all commands to the tests_stocks_disc * remove fds from disc since we have search on stocks/ and stocks/sia * hopefully fix tests * skip test * fix completer type and calling menu after command for stocks/disc * show help menu when moving forward/backwards in menus * skip test * skip test - bug fix * add reset, help and quit to choices * improve stocks/disc controller * refactor sia menu * UX improvements for sia menu * improve ux design * refactor ca controller * fix infinite loop * improve ux on dps controller * Add capability of going back from a menu going into a menu * Ux economy (#1056) * First round of UX improvements on economy menu * Do fred menu + sample tests file * revert to > on menu * rename jobs file to .gst * remove cd option * improve return * final refactoring of disc_controller * fix ca,dps,sia,disc,stocks and terminal controllers * work on ba_controller menu * fix reset and try_except * UX on screener controller * fix for full reset name * Ux etfs (#1059) * Refactor ETF menu for new UX * Add couple more examples to test * r->reset * Clean up switch * gov menu refactored * fix reset issue * 80% of refactoring options and pricing/payoff menu is done * improve payoff controller * minor fix * fix: refactor pred and ta stocks controller * fix: refactor fa(and fmp) controllers * fix: refactored dd controller (still missing .gst tests) * fix infinite loop bug * refactor options controller * add tests for payoff and pricing * fix reset for options * UX Upgrade for Crypto controller(s) (#1049) * refactor crypto controller * refactor crypto/defi controller * added simple test and fixes not returning queue in commands * Clean up unused functions / iex load (#1047) * Clean up unused functions and adjust iex load function to not depend on dates * Had an incorrect tab on s_start definition * wrong default arg * regenerate pytest yml * Comment out parametrization * Tests : Stocks > Discovery (#1050) * Updating tests : stocks/discovery/ark * Updating tests : stocks/discovery/fidelity * Updating tests : stocks/discovery/fidelity * Updating tests : stocks/discovery/fidelity * Updating tests : stocks/discovery/seeking_alpha * Updating tests : stocks/discovery/seeking_alpha * Updating tests : stocks/discovery/shortinterest * Updating tests : stocks/discovery/shortinterest * Updating tests : stocks/discovery/seeking_alpha * Updating tests : stocks/discovery/shortinterest * Updating tests : stocks/discovery/disc_controller * Updating tests : stocks/dd * Updating tests : stocks/fa * Updating tests : stocks/discovery/financedatabase * Updating tests : stocks/discovery/finnhub * Updating tests : stocks/discovery/geekofwallstreet * Updating tests : stocks/discovery/marketbeat * Updating tests : stocks/discovery/nasdaq * Updating tests : stocks / discovery / yahoofinance * Updating tests : black * Updating tests : unused import * Updating tests : stocks/discovery/ark * Tests : Stocks > Doc + Helpers + Government (#1051) * Updating tests : stocks/government/controller * Updating tests : stocks/government * Updating tests : conftest * Updating tests : stocks > government * Updating tests : stocks/government * Updating tests : docs * Tests : Stocks > Insider (#1054) * Updating tests : stocks > helper * Updating tests : doc * Updating tests : clean stocks > fa > av * Updating tests : stocks/insider/controller * Updating tests : stocks/insider/business insider * Updating tests : stocks/insider/finviz * Updating tests : stocks/insider/openinsider * Updating tests : stocks/insider/controller * Updating tests : black * Updating tests : stocks/insider/controller * Tests : Stocks > Backtesting + Behavioural Analysis (#1057) * Updating tests : add __init__ files * Updating tests : stocsk/behavioural_analysis * Updating tests : black * Updating tests : stocks/backtesting * Updating tests : stocks/backtesting * fix: converted top to limit arguments * fix: refactor disc controller, updated docs * fix: refactor dd_controller and docs * fix: refactor nft controller and docs * fix: pass test temporarily, onchain controller refactor, docs * fix: overview controller refactor, fix quit command * fix: linting issues * fix: refacot ta controller * fix: refactor pred controller * fix: linting * fix: crypto controller * fix: added tests, updated all controlers * fix: menu print renamed from stocks to crypto controller, added tests * fix: fix faster function execution * Fix annoying pylint C0201 error * fix: renamed commands to long format * DISC Cleanup (#1058) * Get rid/cleanup of marketbeat functions * Get rid of last unused disc function + fix related tests * fix test * Dividend History Chart (#1053) * Dividend History Chart * changed to default number 10 * changed divs flag default to false * updating the expected result for test_fa_controller. * else statement * fix: added load on dd * fix: added autocompletion in all commands with argument choices * fix: linting * Workflows + Stocks > Insider (#1061) * Updating code : stocks/insider remove unused file * Updating workflows : tests - set mypy==0.910 * fix: linting * Fixing Linting (#1062) * Updating code : fixing linting mypy message = Too many arguments for <lambda> * Updating workflows : allow newest mypy version * Updating code : apply black * Updating code : black * fix: updated predict controller help to match stocks * Ux: portfolio (#1063) * First step of portfolio UX * Add all broker controllers to UX stuff * UX Improvement for PO Co-authored-by: Didier Rodrigues Lopes <dro.lopes@campus.fct.unl.pt> * UX Improvement for resources (#1064) Co-authored-by: Didier Rodrigues Lopes <dro.lopes@campus.fct.unl.pt> * UX: stock/bt (#1065) * UX: stocks>qa (#1068) * fix mypy lambda * skip tests for now * remove unused paths.py * rename tests/simulator to tests/e2e * refactor options/screener menu * UX : move `gst` files location * fix stocks_controller * UX upgrade of the Forex menu (#1048) * Add basic forex menu test * Add forex routes to terminal paths * Remove commands from paths because they're not menus * WIP Refactor forex controller * refactor crypto controller * Remove commented code * Improve user output with printed text * Add "help" back to the list of choices * Enable the command queue for the forex controller * refactor crypto/defi controller * Fix candle chart blocking the terminal * Black * Return help and reset to the list of known args * added simple test and fixes not returning queue in commands * Add currency codes loading to the av_model * Return the queue in edge cases (when commands don't process) * Split select into to and from to enable autocompletion * Style text output * Stop printing help after the execution of every command * Update test scenarios * Black * fix: converted top to limit arguments * fix: refactor disc controller, updated docs * Delete oanda the old view file that was moved into the oanda menu * fix: refactor dd_controller and docs * fix: refactor nft controller and docs * fix: pass test temporarily, onchain controller refactor, docs * fix: overview controller refactor, fix quit command * fix: linting issues * fix: refacot ta controller * fix: refactor pred controller * fix: linting * fix: crypto controller * fix: added tests, updated all controlers * fix: menu print renamed from stocks to crypto controller, added tests * fix: fix faster function execution * Implement basic UX improvement of the oanda controller * Update the forex controller * Fix annoying pylint C0201 error * Add latest convention changes to the forex controller * fix: renamed commands to long format * fix: added load on dd * Merge the latest updates of the controller design * fix: added autocompletion in all commands with argument choices * fix: linting * fix: linting * fix: updated predict controller help to match stocks * Update the forex menu e2e test scripts * Add check_non_negative_float helper * Update the controller with the latest changes to the convention * Update the currency pair loading mechanism * Move data models logic to the models file * Update update oanda views to be interact with the models * Upgrade oanda controller * Remove raw stocks ba and eda code from the forex menu * Update "help wanted" banner for ba and eda in forex menu * Remove remainders of stocks ba and eda from forex context * Improve typing, docstrings and error messages * Remove stocks ba and eda code that was merged from other ux branches * Add fixes that prevented incorrect argument handling * Remove -argument from the candles call If there is an expected agr `-g` and you put an incorrect argument `-argument` the difflib will interpret `argument` as `g` Co-authored-by: jose-donato <zmcdonato@gmail.com> Co-authored-by: Didier Rodrigues Lopes <dro.lopes@campus.fct.unl.pt> * fix reset for menus that require ticker * UX improvement on research menu * skip insider controller test * initial refactoring of insider_controller * improve insider controller ux part 2 * finish refactoring ins controller ux menu * fix bug of when commands in queue have args * skip test * comment test stuff * UX: stocks>qa (#1071) * refactor return self.queue * fix return None * minor fix * minor tabulate fix * Get rid of leading '/' in terminal and add some newlines on quits. (#1074) * Get rid of leading '/' in terminal and add some newlines on quits. * print crypto help on menu entry * looks like a format issue here... * newlines on quit * remove unnecessary line break * fix pylint issue * refactor * refactor * allow portfolio optimization to quit context * add exit at end of scripts * improve dd_controller * test ux in stocks/dd menu * Ux upgrade for reports context (#1075) * Refactor reports and upgrade them with the latest controller convention * Add test scenarios for the reports context * test ux stocks/ta * ux branch scripts/ta * improvement on main param * Upgrades for the UX upgrade for the fa and fa/fmp menus (#1076) * Change --num to --limit * Remove inconsistent/unreliable functions from the choices list * Improve docstring compliance with numpy doc format * Fix hardcoded class id in dcf scrapper * Fix annoying pylint error in discordbot that was blocking the hook * Add test scenarios for the fa and fa/fmp menus * Fix forgotten replacement of --num to --limit * Fix tests * Return some excluded commands to the choices list * Fix dd report to reflect the updates * Fix set function not returning the queue * Update gst test files * fix exit on ca from another submenu * fix changes of options/screener * fix dps controller * fix fa when running out of AV calls * Fix TVL plot locking interpreter during defi test * Add exception handling for broken coingecko scrapper * skip fa/av test that fails * fix dps tests Co-authored-by: Chavithra PARANA <chavithra@gmail.com> Co-authored-by: jmaslek <jmaslek11@gmail.com> Co-authored-by: jose-donato <zmcdonato@gmail.com> Co-authored-by: jose-donato <43375532+jose-donato@users.noreply.github.com> Co-authored-by: Theodore Aptekarev <aptekarev@gmail.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com>
553 lines
14 KiB
Python
553 lines
14 KiB
Python
"""Quantitative Analysis View"""
|
|
__docformat__ = "numpy"
|
|
|
|
import os
|
|
import warnings
|
|
from typing import Any
|
|
|
|
import matplotlib.pyplot as plt
|
|
import numpy as np
|
|
import pandas as pd
|
|
import seaborn as sns
|
|
import statsmodels.api as sm
|
|
from colorama import Fore, Style
|
|
from detecta import detect_cusum
|
|
from matplotlib import gridspec
|
|
from pandas.plotting import register_matplotlib_converters
|
|
from scipy import stats
|
|
from statsmodels.graphics.gofplots import qqplot
|
|
from tabulate import tabulate
|
|
|
|
from gamestonk_terminal import feature_flags as gtff
|
|
from gamestonk_terminal.common.quantitative_analysis import qa_model
|
|
from gamestonk_terminal.config_plot import PLOT_DPI
|
|
from gamestonk_terminal.helper_funcs import export_data, plot_autoscale
|
|
|
|
register_matplotlib_converters()
|
|
|
|
# TODO : Since these are common/ they should be independent of 'stock' info.
|
|
# df_stock should be replaced with a generic df and a column variable
|
|
|
|
|
|
def color_red(val: Any) -> str:
|
|
"""Adds red to dataframe value"""
|
|
return Fore.RED + str(val) + Style.RESET_ALL
|
|
|
|
|
|
def display_summary(df: pd.DataFrame, export: str):
|
|
"""Show summary statistics
|
|
|
|
Parameters
|
|
----------
|
|
df_stock : pd.DataFrame
|
|
DataFrame to get statistics of
|
|
export : str
|
|
Format to export data
|
|
"""
|
|
summary = qa_model.get_summary(df)
|
|
|
|
print(
|
|
tabulate(
|
|
summary, headers=summary.columns, tablefmt="fancy_grid", floatfmt=".3f"
|
|
),
|
|
"\n",
|
|
)
|
|
export_data(
|
|
export,
|
|
os.path.dirname(os.path.abspath(__file__)).replace("common", "stocks"),
|
|
"summary",
|
|
summary,
|
|
)
|
|
|
|
|
|
def display_hist(
|
|
name: str,
|
|
df: pd.DataFrame,
|
|
target: str,
|
|
bins: int,
|
|
):
|
|
"""Generate of histogram of data
|
|
|
|
Parameters
|
|
----------
|
|
name : str
|
|
Name of dataset
|
|
df : pd.DataFrame
|
|
Dataframe to look at
|
|
target : str
|
|
Data column to get histogram of
|
|
bins : int
|
|
Number of bins in histogram
|
|
"""
|
|
fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
|
data = df[target]
|
|
start = df.index[0]
|
|
|
|
sns.histplot(data, bins=bins, kde=True, ax=ax, stat="proportion")
|
|
sns.rugplot(data, c="r", ax=ax)
|
|
|
|
ax.set_title(f"Histogram of {name} {target} from {start.strftime('%Y-%m-%d')}")
|
|
ax.set_xlabel("Share Price")
|
|
ax.grid(True)
|
|
|
|
if gtff.USE_ION:
|
|
plt.ion()
|
|
fig.tight_layout()
|
|
plt.show()
|
|
print("")
|
|
|
|
|
|
def display_cdf(
|
|
name: str,
|
|
df: pd.DataFrame,
|
|
target: str,
|
|
export: str = "",
|
|
):
|
|
"""Plot Cumulative Distribution Function
|
|
|
|
Parameters
|
|
----------
|
|
name : str
|
|
Name of dataset
|
|
df : pd.DataFrame
|
|
Dataframe to look at
|
|
target : str
|
|
Data column
|
|
export : str
|
|
Format to export data
|
|
"""
|
|
plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
|
data = df[target]
|
|
start = df.index[0]
|
|
|
|
cdf = data.value_counts().sort_index().div(len(data)).cumsum()
|
|
cdf.plot(lw=2)
|
|
plt.title(
|
|
f"Cumulative Distribution Function of {name} {target} from {start.strftime('%Y-%m-%d')}"
|
|
)
|
|
plt.ylabel("Probability")
|
|
plt.xlabel(target)
|
|
minVal = data.values.min()
|
|
q25 = np.quantile(data.values, 0.25)
|
|
medianVal = np.quantile(data.values, 0.5)
|
|
q75 = np.quantile(data.values, 0.75)
|
|
labels = [
|
|
(minVal, q25),
|
|
(0.25, 0.25),
|
|
"r",
|
|
(q25, q25),
|
|
(0, 0.25),
|
|
"r",
|
|
(minVal, medianVal),
|
|
(0.5, 0.5),
|
|
"r",
|
|
(medianVal, medianVal),
|
|
(0, 0.5),
|
|
"r",
|
|
(minVal, q75),
|
|
(0.75, 0.75),
|
|
"r",
|
|
(q75, q75),
|
|
(0, 0.75),
|
|
"r",
|
|
]
|
|
plt.plot(*labels, ls="--")
|
|
plt.text(minVal + (q25 - minVal) / 2, 0.27, "Q1", color="r", fontweight="bold")
|
|
plt.text(
|
|
minVal + (medianVal - minVal) / 2,
|
|
0.52,
|
|
"Median",
|
|
color="r",
|
|
fontweight="bold",
|
|
)
|
|
plt.text(minVal + (q75 - minVal) / 2, 0.77, "Q3", color="r", fontweight="bold")
|
|
plt.xlim(cdf.index[0], cdf.index[-1])
|
|
plt.grid(True)
|
|
|
|
if gtff.USE_ION:
|
|
plt.ion()
|
|
|
|
plt.show()
|
|
print("")
|
|
export_data(
|
|
export,
|
|
os.path.dirname(os.path.abspath(__file__)).replace("common", "stocks"),
|
|
"cdf",
|
|
pd.DataFrame(cdf),
|
|
)
|
|
|
|
|
|
def display_bw(
|
|
name: str,
|
|
df: pd.DataFrame,
|
|
target: str,
|
|
yearly: bool,
|
|
):
|
|
"""Show box and whisker plots
|
|
|
|
Parameters
|
|
----------
|
|
name : str
|
|
Name of dataset
|
|
df : pd.DataFrame
|
|
Dataframe to look at
|
|
target : str
|
|
Data column to look at
|
|
yearly : bool
|
|
Flag to indicate yearly accumulation
|
|
"""
|
|
plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
|
data = df[target]
|
|
start = df.index[0]
|
|
sns.set(style="whitegrid")
|
|
if yearly:
|
|
box_plot = sns.boxplot(x=data.index.year, y=data)
|
|
else:
|
|
box_plot = sns.boxplot(x=data.index.month, y=data)
|
|
|
|
box_plot.set(
|
|
xlabel=["Month", "Year"][yearly],
|
|
ylabel=target,
|
|
title=f"{['Month','Year'][yearly]} BoxPlot of {name} {target} from {start.strftime('%Y-%m-%d')}",
|
|
)
|
|
l_months = [
|
|
"Jan",
|
|
"Feb",
|
|
"Mar",
|
|
"Apr",
|
|
"May",
|
|
"Jun",
|
|
"Jul",
|
|
"Aug",
|
|
"Sep",
|
|
"Oct",
|
|
"Nov",
|
|
"Dec",
|
|
]
|
|
l_ticks = list()
|
|
if not yearly:
|
|
for val in box_plot.get_xticklabels():
|
|
l_ticks.append(l_months[int(val.get_text()) - 1])
|
|
box_plot.set_xticklabels(l_ticks)
|
|
|
|
if gtff.USE_ION:
|
|
plt.ion()
|
|
|
|
plt.show()
|
|
print("")
|
|
|
|
|
|
def display_acf(name: str, df: pd.DataFrame, target: str, lags: int):
|
|
"""Show Auto and Partial Auto Correlation of returns and change in returns
|
|
|
|
Parameters
|
|
----------
|
|
name : str
|
|
Name of dataset
|
|
df : pd.DataFrame
|
|
Dataframe to look at
|
|
target : str
|
|
Data column to look at
|
|
lags : int
|
|
Max number of lags to look at
|
|
"""
|
|
df = df[target]
|
|
start = df.index[0]
|
|
fig = plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI, constrained_layout=True)
|
|
spec = gridspec.GridSpec(ncols=2, nrows=2, figure=fig)
|
|
|
|
# Diff Auto-correlation function for original time series
|
|
ax_acf = fig.add_subplot(spec[0, 0])
|
|
sm.graphics.tsa.plot_acf(np.diff(np.diff(df.values)), lags=lags, ax=ax_acf)
|
|
plt.title(f"{name} Returns Auto-Correlation from {start.strftime('%Y-%m-%d')}")
|
|
# Diff Partial auto-correlation function for original time series
|
|
ax_pacf = fig.add_subplot(spec[0, 1])
|
|
sm.graphics.tsa.plot_pacf(np.diff(np.diff(df.values)), lags=lags, ax=ax_pacf)
|
|
plt.title(
|
|
f"{name} Returns Partial Auto-Correlation from {start.strftime('%Y-%m-%d')}"
|
|
)
|
|
|
|
# Diff Diff Auto-correlation function for original time series
|
|
ax_acf = fig.add_subplot(spec[1, 0])
|
|
sm.graphics.tsa.plot_acf(np.diff(np.diff(df.values)), lags=lags, ax=ax_acf)
|
|
plt.title(
|
|
f"Change in {name} Returns Auto-Correlation from {start.strftime('%Y-%m-%d')}"
|
|
)
|
|
# Diff Diff Partial auto-correlation function for original time series
|
|
ax_pacf = fig.add_subplot(spec[1, 1])
|
|
sm.graphics.tsa.plot_pacf(np.diff(np.diff(df.values)), lags=lags, ax=ax_pacf)
|
|
plt.title(
|
|
f"Change in {name}) Returns Partial Auto-Correlation from {start.strftime('%Y-%m-%d')}"
|
|
)
|
|
|
|
if gtff.USE_ION:
|
|
plt.ion()
|
|
|
|
plt.show()
|
|
print("")
|
|
|
|
|
|
def display_cusum(df: pd.DataFrame, target: str, threshold: float, drift: float):
|
|
"""Cumulative sum algorithm (CUSUM) to detect abrupt changes in data
|
|
|
|
Parameters
|
|
----------
|
|
df : pd.DataFrame
|
|
Dataframe
|
|
target : str
|
|
Column of data to look at
|
|
threshold : float
|
|
Threshold value
|
|
drift : float
|
|
Drift parameter
|
|
"""
|
|
detect_cusum(df[target].values, threshold, drift, True, True)
|
|
if gtff.USE_ION:
|
|
plt.ion()
|
|
plt.show()
|
|
print("")
|
|
|
|
|
|
def display_seasonal(
|
|
name: str,
|
|
df: pd.DataFrame,
|
|
target: str,
|
|
multiplicative: bool = False,
|
|
export: str = "",
|
|
):
|
|
"""Display seasonal decomposition data
|
|
|
|
Parameters
|
|
----------
|
|
name : str
|
|
Name of dataset
|
|
df : pd.DataFrame
|
|
DataFrame
|
|
target : str
|
|
Column of data to look at
|
|
multiplicative : bool
|
|
Boolean to indicate multiplication instead of addition
|
|
export : str
|
|
Format to export trend and cycle df
|
|
"""
|
|
data = df[target]
|
|
fig = plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI, constrained_layout=True)
|
|
spec = gridspec.GridSpec(ncols=4, nrows=5, figure=fig)
|
|
fig.add_subplot(spec[0, :])
|
|
plt.plot(data.index, data.values)
|
|
plt.title(name + " (Time-Series)")
|
|
|
|
result, cycle, trend = qa_model.get_seasonal_decomposition(data, multiplicative)
|
|
|
|
# Multiplicative model
|
|
fig.add_subplot(spec[1, :4])
|
|
plt.plot(result.trend, lw=2, c="purple")
|
|
plt.xlim([data.index[0], data.index[-1]])
|
|
plt.title("Cyclic-Trend")
|
|
|
|
fig.add_subplot(spec[2, 0:2])
|
|
plt.plot(trend, lw=2, c="tab:blue")
|
|
plt.xlim([data.index[0], data.index[-1]])
|
|
plt.title("Trend component")
|
|
|
|
fig.add_subplot(spec[2, 2:])
|
|
plt.plot(cycle, lw=2, c="green")
|
|
plt.xlim([data.index[0], data.index[-1]])
|
|
plt.title("Cycle component")
|
|
|
|
fig.add_subplot(spec[3, :])
|
|
plt.plot(result.seasonal, lw=2, c="orange")
|
|
plt.xlim([data.index[0], data.index[-1]])
|
|
plt.title("Seasonal effect")
|
|
|
|
fig.add_subplot(spec[4, :])
|
|
plt.plot(result.resid, lw=2, c="red")
|
|
plt.xlim([data.index[0], data.index[-1]])
|
|
plt.title("Residuals")
|
|
|
|
if gtff.USE_ION:
|
|
plt.ion()
|
|
|
|
plt.show()
|
|
print("")
|
|
|
|
# From # https://otexts.com/fpp2/seasonal-strength.html
|
|
|
|
print("Time-Series Level is " + str(round(data.mean(), 2)))
|
|
|
|
Ft = max(0, 1 - np.var(result.resid)) / np.var(result.trend + result.resid)
|
|
print(f"Strength of Trend: {Ft:.4f}")
|
|
|
|
Fs = max(
|
|
0,
|
|
1 - np.var(result.resid) / np.var(result.seasonal + result.resid),
|
|
)
|
|
print(f"Strength of Seasonality: {Fs:.4f}\n")
|
|
|
|
export_data(
|
|
export,
|
|
os.path.dirname(os.path.abspath(__file__)).replace("common", "stocks"),
|
|
"summary",
|
|
cycle.join(trend),
|
|
)
|
|
|
|
|
|
def display_normality(df: pd.DataFrame, target: str, export: str = ""):
|
|
"""View normality statistics
|
|
|
|
Parameters
|
|
----------
|
|
df : pd.DataFrame
|
|
DataFrame
|
|
target : str
|
|
Column in data to look at
|
|
export : str
|
|
Format to export data
|
|
"""
|
|
data = df[target]
|
|
normal = qa_model.get_normality(data)
|
|
stats1 = normal.copy().T
|
|
print(stats1)
|
|
stats1.loc[:, stats1.iloc[1, :] > 0.05] = stats1.loc[
|
|
:, stats1.iloc[1, :] > 0.05
|
|
].apply(lambda x: color_red(x[0]), axis=1)
|
|
if gtff.USE_TABULATE_DF:
|
|
print(
|
|
tabulate(
|
|
stats1,
|
|
showindex=True,
|
|
headers=normal.columns,
|
|
tablefmt="fancy_grid",
|
|
floatfmt=".4f",
|
|
),
|
|
"\n",
|
|
)
|
|
else:
|
|
print(normal.round(4).to_string(), "\n")
|
|
|
|
export_data(
|
|
export,
|
|
os.path.dirname(os.path.abspath(__file__)).replace("common", "stocks"),
|
|
"normality",
|
|
normal,
|
|
)
|
|
|
|
|
|
def display_qqplot(name: str, df: pd.DataFrame, target: str):
|
|
"""Show QQ plot for data against normal quantiles
|
|
|
|
Parameters
|
|
----------
|
|
name : str
|
|
Stock ticker
|
|
df : pd.DataFrame
|
|
Dataframe
|
|
target : str
|
|
Column in data to look at
|
|
"""
|
|
# Statsmodels has a UserWarning for marker kwarg-- which we dont use
|
|
warnings.filterwarnings(category=UserWarning, action="ignore")
|
|
data = df[target]
|
|
fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
|
qqplot(data, stats.distributions.norm, fit=True, line="45", ax=ax)
|
|
ax.set_title(f"Q-Q plot for {name} {target}")
|
|
ax.set_ylabel("Sample quantiles")
|
|
ax.set_xlabel("Theoretical quantiles")
|
|
ax.grid(True)
|
|
|
|
if gtff.USE_ION:
|
|
plt.ion()
|
|
fig.tight_layout(pad=1)
|
|
plt.show()
|
|
print("")
|
|
|
|
|
|
def display_unitroot(
|
|
df: pd.DataFrame, target: str, fuller_reg: str, kpss_reg: str, export: str = ""
|
|
):
|
|
"""Show unit root test calculations
|
|
|
|
Parameters
|
|
----------
|
|
df : pd.DataFrame
|
|
DataFrame
|
|
target : str
|
|
Column of data to look at
|
|
fuller_reg : str
|
|
Type of regression of ADF test
|
|
kpss_reg : str
|
|
Type of regression for KPSS test
|
|
export : str
|
|
Format for exporting data
|
|
"""
|
|
df = df[target]
|
|
data = qa_model.get_unitroot(df, fuller_reg, kpss_reg)
|
|
if gtff.USE_TABULATE_DF:
|
|
print(
|
|
tabulate(
|
|
data,
|
|
showindex=True,
|
|
headers=data.columns,
|
|
tablefmt="fancy_grid",
|
|
floatfmt=".4f",
|
|
),
|
|
"\n",
|
|
)
|
|
else:
|
|
print(data.round(4).to_string(), "\n")
|
|
|
|
export_data(
|
|
export,
|
|
os.path.dirname(os.path.abspath(__file__)).replace("common", "stocks"),
|
|
"unitroot",
|
|
data,
|
|
)
|
|
|
|
|
|
def display_raw(
|
|
df: pd.DataFrame, sort: str = "", des: bool = False, num: int = 20, export: str = ""
|
|
) -> None:
|
|
"""Return raw stock data
|
|
|
|
Parameters
|
|
----------
|
|
df : DataFrame
|
|
DataFrame with historical information
|
|
sort : str
|
|
The column to sort by
|
|
des : bool
|
|
Whether to sort descending
|
|
num : int
|
|
Number of rows to show
|
|
export : str
|
|
Export data as CSV, JSON, XLSX
|
|
"""
|
|
|
|
export_data(
|
|
export,
|
|
os.path.dirname(os.path.abspath(__file__)),
|
|
"history",
|
|
df,
|
|
)
|
|
|
|
if isinstance(df, pd.Series):
|
|
df = pd.DataFrame(df)
|
|
|
|
if sort:
|
|
df = df.sort_values(by=sort, ascending=des)
|
|
|
|
if gtff.USE_TABULATE_DF:
|
|
print(
|
|
tabulate(
|
|
df.tail(num),
|
|
headers=[x.title() if x != "" else "Date" for x in df.columns],
|
|
tablefmt="fancy_grid",
|
|
showindex=True,
|
|
floatfmt=".2f",
|
|
)
|
|
)
|
|
else:
|
|
print(df.to_string(index=False))
|
|
|
|
print("")
|