Merge pull request #319 from DidierRLopes/screener-plot

Add view to screener data
This commit is contained in:
DidierRLopes
2021-04-07 00:26:40 +01:00
committed by GitHub
4 changed files with 216 additions and 0 deletions

View File

@@ -181,6 +181,7 @@
* [x] Add Screener menu with overview, valuation, financial, ownership, performance, technical commands based on filter presets from Finviz (@didier) - [PR #314](https://github.com/DidierRLopes/GamestonkTerminal/pull/314)
* [x] Add README with explanation of how presets are stored and can be added by experienced users. (@didier) - [PR #314](https://github.com/DidierRLopes/GamestonkTerminal/pull/314)
* [x] Add screener signals (e.g. top gainers, new highs, most volatile, oversold, major news, ...) from Finviz (@didier) - [PR #314](https://github.com/DidierRLopes/GamestonkTerminal/pull/314)
* [x] Plot screener historical using Yahoo Finance data (@didier) - [PR #319](https://github.com/DidierRLopes/GamestonkTerminal/pull/319)
**NEXT**

View File

@@ -6,6 +6,8 @@ This menu aims to filter stocks based on pre-specified preset filters, and the u
* view available presets
* [set](#set)
* set one of the available presets
* [historical](#historical)
* view historical price [Yahoo Finance]
* [overview](#overview)
* overview information [Finviz]
* [valuation](#valuation)
@@ -45,6 +47,23 @@ Set preset from under presets folder.
* -p : Filter presets
## historical <a name="historical"></a>
```text
usage: historical [-t {o,h,l,c,a}] [-s {top_gainers,top_losers,...}] [--start START]
```
View historical price of stocks. [Source: Yahoo Finance]
* -t : Type of candle: Default 'a' for adjusted close.
* -s : Signal type. Default: None. When specified (see list available in [signals](#signals)), the preset is disregarded.
* --start : Start time with format "%Y-%m-%d". Default 6 months earlier.
![screener_view](https://user-images.githubusercontent.com/25267873/113784557-8bd13c00-972d-11eb-9776-0e192bb83515.png)
![top_gainers](https://user-images.githubusercontent.com/25267873/113784834-f97d6800-972d-11eb-8112-6c80f4e2cf5e.png)
## overview <a name="overview"></a>
```text

View File

@@ -4,6 +4,7 @@ __docformat__ = "numpy"
import os
import argparse
from typing import List
import matplotlib.pyplot as plt
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal.helper_funcs import get_flair
from gamestonk_terminal.menu import session
@@ -12,6 +13,7 @@ from gamestonk_terminal.helper_funcs import (
parse_known_args_and_warn,
)
from gamestonk_terminal.screener import finviz_view
from gamestonk_terminal.screener import yahoo_finance_view
class ScreenerController:
@@ -24,6 +26,7 @@ class ScreenerController:
"quit",
"view",
"set",
"historical",
"overview",
"valuation",
"financial",
@@ -56,6 +59,7 @@ class ScreenerController:
print("")
print(f"PRESET: {self.preset}")
print("")
print(" historical view historical price")
print(" overview overview information")
print(" valuation valuation information")
print(" financial financial information")
@@ -181,6 +185,10 @@ class ScreenerController:
"""Process overview command"""
self.set_preset(self, other_args)
def call_historical(self, other_args: List[str]):
"""Process historical command"""
yahoo_finance_view.historical(other_args, self.preset)
def call_overview(self, other_args: List[str]):
"""Process overview command"""
finviz_view.screener(other_args, self.preset, "overview")
@@ -230,6 +238,8 @@ def menu():
an_input = input(f"{get_flair()} (scr)> ")
try:
plt.close("all")
process_input = scr_controller.switch(an_input)
if process_input is not None:

View File

@@ -0,0 +1,186 @@
import argparse
from typing import List
from pandas.plotting import register_matplotlib_converters
import matplotlib.pyplot as plt
import datetime
import configparser
import yfinance as yf
from finvizfinance.screener import ticker
from gamestonk_terminal.screener import finviz_view
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal.helper_funcs import (
parse_known_args_and_warn,
plot_autoscale,
valid_date,
)
from gamestonk_terminal.config_plot import PLOT_DPI
register_matplotlib_converters()
d_candle_types = {
"o": "Open",
"h": "High",
"l": "Low",
"c": "Close",
"a": "Adj Close",
}
def check_one_of_ohlca(type_candles: str) -> str:
if (
type_candles == "o"
or type_candles == "h"
or type_candles == "l"
or type_candles == "c"
or type_candles == "a"
):
return type_candles
raise argparse.ArgumentTypeError("The type of candles specified is not recognized")
def historical(other_args: List[str], preset_loaded: str):
"""View historical price of stocks that meet preset
Parameters
----------
other_args : List[str]
Command line arguments to be processed with argparse
ticker : str
Loaded preset filter
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="historical",
description="""Historical price comparison between similar companies [Source: Yahoo Finance]
""",
)
parser.add_argument(
"--start",
type=valid_date,
default=datetime.datetime.now() - datetime.timedelta(days=6 * 30),
dest="start",
help="The starting date (format YYYY-MM-DD) of the historical price to plot",
)
parser.add_argument(
"-t",
"--type",
action="store",
dest="type_candle",
type=check_one_of_ohlca,
default="a", # in case it's adjusted close
help=("type of candles: o-open, h-high, l-low, c-close, a-adjusted close."),
)
parser.add_argument(
"-s",
"--signal",
action="store",
dest="signal",
type=str,
default=None,
help="Signal",
choices=list(finviz_view.d_signals.keys()),
)
try:
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
preset_filter = configparser.RawConfigParser()
preset_filter.optionxform = str # type: ignore
preset_filter.read(
"gamestonk_terminal/screener/presets/" + preset_loaded + ".ini"
)
d_general = preset_filter["General"]
d_filters = {
**preset_filter["Descriptive"],
**preset_filter["Fundamental"],
**preset_filter["Technical"],
}
d_filters = {k: v for k, v in d_filters.items() if v}
screen = ticker.Ticker()
if ns_parser.signal:
screen.set_filter(signal=finviz_view.d_signals[ns_parser.signal])
else:
if d_general["Signal"]:
screen.set_filter(filters_dict=d_filters, signal=d_general["Signal"])
else:
screen.set_filter(filters_dict=d_filters)
l_min = list()
l_leg = list()
plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
l_stocks = screen.ScreenerView(verbose=0)
if len(l_stocks) > 10:
print(
"We limit stocks shown to 10, as after this the plot becomes too noisy. "
"Also, we ran out of different colors."
)
l_stocks = l_stocks[:10]
while l_stocks:
l_parsed_stocks = list()
for symbol in l_stocks:
try:
df_similar_stock = yf.download(
symbol,
start=datetime.datetime.strftime(ns_parser.start, "%Y-%m-%d"),
progress=False,
threads=False,
)
if not df_similar_stock.empty:
plt.plot(
df_similar_stock.index,
df_similar_stock[
d_candle_types[ns_parser.type_candle]
].values,
)
l_min.append(df_similar_stock.index[0])
l_leg.append(symbol)
l_parsed_stocks.append(symbol)
except Exception as e:
print("")
print(e)
print(
"Disregard previous error, which is due to API Rate limits from Yahoo Finance."
)
print(
f"Because we like '{symbol}', and we won't leave without getting data from it."
)
for parsed_stock in l_parsed_stocks:
l_stocks.remove(parsed_stock)
if ns_parser.signal:
plt.title(
f"Screener Historical Price using {finviz_view.d_signals[ns_parser.signal]} signal"
)
else:
plt.title(f"Screener Historical Price using {preset_loaded} preset")
plt.xlabel("Time")
plt.ylabel("Share Price ($)")
plt.legend(l_leg)
plt.grid(b=True, which="major", color="#666666", linestyle="-")
plt.minorticks_on()
plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
# ensures that the historical data starts from same datapoint
plt.xlim([max(l_min), df_similar_stock.index[-1]])
if gtff.USE_ION:
plt.ion()
plt.show()
print("")
except SystemExit:
print("Similar companies need to be provided", "\n")
except Exception as e:
print(e, "\n")