General bug fixes (#862)

* Bug fixes

* make all yfinance data non tz aware

* Get rid of namespace input

* candle -> display_candle

* Didier I hope you read this.  pycharm would not have let me miss committing this file

Co-authored-by: James Maslek <james@Jamess-MacBook-Pro.local>
This commit is contained in:
jmaslek
2021-10-26 14:17:41 -04:00
committed by GitHub
parent f390e205ba
commit a28e6c9f6a
5 changed files with 245 additions and 194 deletions

View File

@@ -500,7 +500,7 @@ def display_unitroot(
def display_raw(
df: pd.DataFrame, export: str, sort: str, des: bool, num: int = 20
df: pd.DataFrame, sort: str = "", des: bool = False, num: int = 20, export: str = ""
) -> None:
"""Return raw stock data
@@ -508,14 +508,14 @@ def display_raw(
----------
df : DataFrame
DataFrame with historical information
export : str
Export data as CSV, JSON, XLSX
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(
@@ -525,13 +525,16 @@ def display_raw(
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.head(num),
df.tail(num),
headers=[x.title() if x != "" else "Date" for x in df.columns],
tablefmt="fancy_grid",
showindex=True,

View File

@@ -1,19 +1,22 @@
"""Technical Analysis Trendline Module"""
__docformat__ = "numpy"
from typing import Union
from datetime import datetime
import yfinance as yf
from pandas.core.frame import DataFrame
from scipy.stats import linregress
def load_ticker(ticker: str, start_date: str) -> DataFrame:
def load_ticker(ticker: str, start_date: Union[str, datetime]) -> DataFrame:
"""Loads a ticker data from Yahoo Finance, adds a data index column data_id and Open-Close High/Low columns.
Parameters
----------
ticker : str
The stock ticker.
start_date : str
start_date : Union[str,datetime]
Start date to load stock ticker data formatted YYYY-MM-DD.
Returns

View File

@@ -18,10 +18,12 @@ from gamestonk_terminal.common.quantitative_analysis import (
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal.stocks.stocks_helper import load
from gamestonk_terminal.helper_funcs import (
EXPORT_ONLY_RAW_DATA_ALLOWED,
get_flair,
check_positive,
check_proportion_range,
parse_known_args_and_warn,
try_except,
)
from gamestonk_terminal.menu import session
from gamestonk_terminal.stocks.quantitative_analysis.factors_view import capm_view
@@ -31,7 +33,7 @@ class QaController:
"""Quantitative Analysis Controller class"""
# Command choices
CHOICES = ["?", "cls", "help", "q", "quit", "load", "pick"]
CHOICES = ["?", "cls", "help", "q", "quit", "load", "pick", "raw"]
CHOICES_COMMANDS = [
"summary",
@@ -118,6 +120,7 @@ Rolling Metrics:
skew rolling skewness of distribution of prices
kurtosis rolling kurtosis of distribution of prices
Other:
raw print raw data
decompose decomposition in cyclic-trend, season, and residuals of prices
cusum detects abrupt changes using cumulative sum algorithm of prices
capm capital asset pricing model
@@ -216,6 +219,46 @@ Other:
except Exception as e:
print(e, "\n")
@try_except
def call_raw(self, other_args: List[str]):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
add_help=False,
prog="raw",
description="""
Print raw data to console
""",
)
parser.add_argument(
"-n",
"--num",
help="Number to show",
type=check_positive,
default=20,
dest="num",
)
parser.add_argument(
"-d",
"--descend",
action="store_true",
default=False,
dest="descend",
help="Sort in descending order",
)
ns_parser = parse_known_args_and_warn(
parser, other_args, export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED
)
if not ns_parser:
return
qa_view.display_raw(
self.stock[self.target],
num=ns_parser.num,
sort="",
des=ns_parser.descend,
export=ns_parser.export,
)
def call_summary(self, other_args: List[str]):
"""Process summary command"""
parser = argparse.ArgumentParser(

View File

@@ -30,7 +30,7 @@ from gamestonk_terminal.stocks.government import gov_controller
from gamestonk_terminal.stocks.insider import insider_controller
from gamestonk_terminal.stocks.research import res_controller
from gamestonk_terminal.stocks.screener import screener_controller
from gamestonk_terminal.stocks.stocks_helper import candle, load, quote
from gamestonk_terminal.stocks.stocks_helper import display_candle, load, quote
from gamestonk_terminal.stocks.technical_analysis import ta_controller
from gamestonk_terminal.helper_funcs import (
valid_date,
@@ -220,9 +220,24 @@ Market {('CLOSED', 'OPEN')[b_is_stock_market_open()]}
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="data",
prog="candle",
description="Shows historic data for a stock",
)
parser.add_argument(
"-s",
"--start_date",
dest="s_start",
type=valid_date,
default=(datetime.now() - timedelta(days=366)).strftime("%Y-%m-%d"),
help="Start date for candle data",
)
parser.add_argument(
"--plotly",
dest="plotly",
action="store_true",
default=False,
help="Flag to show interactive plot using plotly.",
)
parser.add_argument(
"--export",
choices=["csv", "json", "xlsx"],
@@ -232,7 +247,6 @@ Market {('CLOSED', 'OPEN')[b_is_stock_market_open()]}
help="Export dataframe data to csv,json,xlsx file",
)
parser.add_argument(
"-s",
"--sort",
choices=[
"AdjClose",
@@ -264,24 +278,39 @@ Market {('CLOSED', 'OPEN')[b_is_stock_market_open()]}
default=False,
help="Shows raw data instead of chart",
)
parser.add_argument(
"-n",
"--num",
type=check_positive,
help="Number to show if raw selected",
dest="num",
default=20,
)
try:
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
if not self.ticker:
print("No ticker loaded. First use `load {ticker}`\n")
return
if ns_parser.raw:
qa_view.display_raw(
self.stock,
ns_parser.export,
ns_parser.sort,
ns_parser.descending,
df=self.stock,
export=ns_parser.export,
sort=ns_parser.sort,
des=ns_parser.descending,
num=ns_parser.num,
)
else:
candle(
self.ticker + "." + self.suffix if self.suffix else self.ticker,
other_args,
display_candle(
s_ticker=self.ticker + "." + self.suffix
if self.suffix
else self.ticker,
s_start=ns_parser.s_start,
plotly=ns_parser.plotly,
)
except Exception as e:

View File

@@ -203,6 +203,8 @@ def load(
print("")
return [s_ticker, s_start, s_interval, df_stock]
df_stock_candidate.index = df_stock_candidate.index.tz_localize(None)
# pylint: disable=no-member
df_stock_candidate.sort_index(ascending=True, inplace=True)
@@ -329,6 +331,8 @@ def load(
print("")
return [s_ticker, s_start, s_interval, df_stock]
df_stock_candidate.index = df_stock_candidate.index.tz_localize(None)
if s_start_dt > ns_parser.s_start_date:
s_start = pytz.utc.localize(s_start_dt)
else:
@@ -403,215 +407,184 @@ def load(
return [s_ticker, s_start, s_interval, df_stock]
def candle(s_ticker: str, other_args: List[str]):
def display_candle(s_ticker: str, s_start: datetime, plotly: bool):
"""Shows candle plot of loaded ticker
Parameters
----------
s_ticker: str
Ticker to display
other_args: str
Argparse arguments
s_start: datetime
Starting date for candle
plotly: bool
Flag to show interactive plotly chart
"""
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="candle",
description="Displays candle chart of loaded ticker",
)
parser.add_argument(
"-s",
"--start_date",
dest="s_start",
type=valid_date,
default=(datetime.now() - timedelta(days=366)).strftime("%Y-%m-%d"),
help="Start date for candle data",
)
parser.add_argument(
"--plotly",
dest="plotly",
action="store_true",
default=False,
help="Flag to show interactive plot using plotly.",
)
# TODO: Add option to customize plot even further
print(type(s_start))
df_stock = trend.load_ticker(s_ticker, s_start)
df_stock["ma20"] = df_stock["Close"].rolling(20).mean().fillna(method="bfill")
df_stock["ma50"] = df_stock["Close"].rolling(50).mean().fillna(method="bfill")
try:
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
if not s_ticker:
print("No ticker loaded. First use `load {ticker}`", "\n")
return
df_stock = trend.find_trendline(df_stock, "OC_High", "high")
df_stock = trend.find_trendline(df_stock, "OC_Low", "low")
if not plotly:
mc = mpf.make_marketcolors(
up="green",
down="red",
edge="black",
wick="black",
volume="in",
ohlc="i",
)
df_stock = trend.load_ticker(s_ticker, ns_parser.s_start)
df_stock["ma20"] = df_stock["Close"].rolling(20).mean().fillna(method="bfill")
df_stock["ma50"] = df_stock["Close"].rolling(50).mean().fillna(method="bfill")
s = mpf.make_mpf_style(marketcolors=mc, gridstyle=":", y_on_right=True)
df_stock = trend.find_trendline(df_stock, "OC_High", "high")
df_stock = trend.find_trendline(df_stock, "OC_Low", "low")
if not ns_parser.plotly:
mc = mpf.make_marketcolors(
up="green",
down="red",
edge="black",
wick="black",
volume="in",
ohlc="i",
ap0 = []
if "OC_High_trend" in df_stock.columns:
ap0.append(
mpf.make_addplot(df_stock["OC_High_trend"], color="g"),
)
s = mpf.make_mpf_style(marketcolors=mc, gridstyle=":", y_on_right=True)
ap0 = []
if "OC_High_trend" in df_stock.columns:
ap0.append(
mpf.make_addplot(df_stock["OC_High_trend"], color="g"),
)
if "OC_Low_trend" in df_stock.columns:
ap0.append(
mpf.make_addplot(df_stock["OC_Low_trend"], color="b"),
)
if gtff.USE_ION:
plt.ion()
mpf.plot(
df_stock,
type="candle",
mav=(20, 50),
volume=True,
title=f"\n{s_ticker} - Starting {ns_parser.s_start.strftime('%Y-%m-%d')}",
addplot=ap0,
xrotation=10,
style=s,
figratio=(10, 7),
figscale=1.10,
figsize=(plot_autoscale()),
update_width_config=dict(
candle_linewidth=1.0, candle_width=0.8, volume_linewidth=1.0
),
)
else:
fig = make_subplots(
rows=2,
cols=1,
shared_xaxes=True,
vertical_spacing=0.06,
subplot_titles=(f"{s_ticker}", "Volume"),
row_width=[0.2, 0.7],
)
fig.add_trace(
go.Candlestick(
x=df_stock.index,
open=df_stock.Open,
high=df_stock.High,
low=df_stock.Low,
close=df_stock.Close,
name="OHLC",
),
row=1,
col=1,
if "OC_Low_trend" in df_stock.columns:
ap0.append(
mpf.make_addplot(df_stock["OC_Low_trend"], color="b"),
)
if gtff.USE_ION:
plt.ion()
mpf.plot(
df_stock,
type="candle",
mav=(20, 50),
volume=True,
title=f"\n{s_ticker} - Starting {s_start.strftime('%Y-%m-%d')}",
addplot=ap0,
xrotation=10,
style=s,
figratio=(10, 7),
figscale=1.10,
figsize=(plot_autoscale()),
update_width_config=dict(
candle_linewidth=1.0, candle_width=0.8, volume_linewidth=1.0
),
)
else:
fig = make_subplots(
rows=2,
cols=1,
shared_xaxes=True,
vertical_spacing=0.06,
subplot_titles=(f"{s_ticker}", "Volume"),
row_width=[0.2, 0.7],
)
fig.add_trace(
go.Candlestick(
x=df_stock.index,
open=df_stock.Open,
high=df_stock.High,
low=df_stock.Low,
close=df_stock.Close,
name="OHLC",
),
row=1,
col=1,
)
fig.add_trace(
go.Scatter(
x=df_stock.index,
y=df_stock["ma20"],
name="MA20",
mode="lines",
line=go.scatter.Line(color="royalblue"),
),
row=1,
col=1,
)
fig.add_trace(
go.Scatter(
x=df_stock.index,
y=df_stock["ma50"],
name="MA50",
mode="lines",
line=go.scatter.Line(color="black"),
),
row=1,
col=1,
)
if "OC_High_trend" in df_stock.columns:
fig.add_trace(
go.Scatter(
x=df_stock.index,
y=df_stock["ma20"],
name="MA20",
y=df_stock["OC_High_trend"],
name="High Trend",
mode="lines",
line=go.scatter.Line(color="royalblue"),
line=go.scatter.Line(color="red"),
),
row=1,
col=1,
)
if "OC_Low_trend" in df_stock.columns:
fig.add_trace(
go.Scatter(
x=df_stock.index,
y=df_stock["ma50"],
name="MA50",
y=df_stock["OC_Low_trend"],
name="Low Trend",
mode="lines",
line=go.scatter.Line(color="black"),
line=go.scatter.Line(color="green"),
),
row=1,
col=1,
)
if "OC_High_trend" in df_stock.columns:
fig.add_trace(
go.Scatter(
x=df_stock.index,
y=df_stock["OC_High_trend"],
name="High Trend",
mode="lines",
line=go.scatter.Line(color="red"),
),
row=1,
col=1,
)
if "OC_Low_trend" in df_stock.columns:
fig.add_trace(
go.Scatter(
x=df_stock.index,
y=df_stock["OC_Low_trend"],
name="Low Trend",
mode="lines",
line=go.scatter.Line(color="green"),
),
row=1,
col=1,
)
fig.add_trace(
go.Bar(
x=df_stock.index,
y=df_stock.Volume,
name="Volume",
marker_color="black",
fig.add_trace(
go.Bar(
x=df_stock.index,
y=df_stock.Volume,
name="Volume",
marker_color="black",
),
row=2,
col=1,
)
fig.update_layout(
yaxis_title="Stock Price ($)",
xaxis=dict(
rangeselector=dict(
buttons=list(
[
dict(
count=1,
label="1m",
step="month",
stepmode="backward",
),
dict(
count=3,
label="3m",
step="month",
stepmode="backward",
),
dict(count=1, label="YTD", step="year", stepmode="todate"),
dict(
count=1,
label="1y",
step="year",
stepmode="backward",
),
dict(step="all"),
]
)
),
row=2,
col=1,
)
fig.update_layout(
yaxis_title="Stock Price ($)",
xaxis=dict(
rangeselector=dict(
buttons=list(
[
dict(
count=1,
label="1m",
step="month",
stepmode="backward",
),
dict(
count=3,
label="3m",
step="month",
stepmode="backward",
),
dict(
count=1, label="YTD", step="year", stepmode="todate"
),
dict(
count=1,
label="1y",
step="year",
stepmode="backward",
),
dict(step="all"),
]
)
),
rangeslider=dict(visible=False),
type="date",
),
)
rangeslider=dict(visible=False),
type="date",
),
)
fig.show()
print("")
except Exception as e:
print(e, "\n")
fig.show()
print("")
def quote(other_args: List[str], s_ticker: str):