mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 12:40:35 +00:00
Screener controller big improvements (#1007)
* massively improve screener controller * Add limit of stocks to display
This commit is contained in:
@@ -14,99 +14,6 @@ presets_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "presets
|
||||
|
||||
# pylint: disable=C0302
|
||||
|
||||
|
||||
def get_screener_data(
|
||||
preset_loaded: str, data_type: str, signal: str, limit: int, ascend: bool
|
||||
):
|
||||
"""Screener Overview
|
||||
|
||||
Parameters
|
||||
----------
|
||||
preset_loaded : str
|
||||
Loaded preset filter
|
||||
data_type : str
|
||||
Data type between: overview, valuation, financial, ownership, performance, technical
|
||||
signal : str
|
||||
Signal to use to filter data
|
||||
limit : int
|
||||
Limit of stocks filtered with presets to print
|
||||
ascend : bool
|
||||
Ascended order of stocks filtered to print
|
||||
|
||||
Returns
|
||||
----------
|
||||
pd.DataFrame
|
||||
Dataframe with loaded filtered stocks
|
||||
"""
|
||||
preset_filter = configparser.RawConfigParser()
|
||||
preset_filter.optionxform = str # type: ignore
|
||||
preset_filter.read(presets_path + preset_loaded + ".ini")
|
||||
|
||||
d_general = preset_filter["General"]
|
||||
d_filters = {
|
||||
**preset_filter["Descriptive"],
|
||||
**preset_filter["Fundamental"],
|
||||
**preset_filter["Technical"],
|
||||
}
|
||||
|
||||
for section in ["General", "Descriptive", "Fundamental", "Technical"]:
|
||||
for key, val in {**preset_filter[section]}.items():
|
||||
if key not in d_check_screener:
|
||||
print(f"The screener variable {section}.{key} shouldn't exist!\n")
|
||||
return pd.DataFrame()
|
||||
|
||||
if val not in d_check_screener[key]:
|
||||
print(
|
||||
f"Invalid [{section}] {key}={val}. "
|
||||
f"Choose one of the following options:\n{', '.join(d_check_screener[key])}.\n"
|
||||
)
|
||||
return pd.DataFrame()
|
||||
|
||||
d_filters = {k: v for k, v in d_filters.items() if v}
|
||||
|
||||
if data_type == "overview":
|
||||
screen = overview.Overview()
|
||||
elif data_type == "valuation":
|
||||
screen = valuation.Valuation()
|
||||
elif data_type == "financial":
|
||||
screen = financial.Financial()
|
||||
elif data_type == "ownership":
|
||||
screen = ownership.Ownership()
|
||||
elif data_type == "performance":
|
||||
screen = performance.Performance()
|
||||
elif data_type == "technical":
|
||||
screen = technical.Technical()
|
||||
else:
|
||||
print("Invalid selected screener type")
|
||||
return pd.DataFrame()
|
||||
|
||||
if signal:
|
||||
screen.set_filter(signal=d_signals[signal])
|
||||
else:
|
||||
if "Signal" in d_general:
|
||||
screen.set_filter(filters_dict=d_filters, signal=d_general["Signal"])
|
||||
else:
|
||||
screen.set_filter(filters_dict=d_filters)
|
||||
|
||||
if "Order" in d_general:
|
||||
if limit > 0:
|
||||
df_screen = screen.ScreenerView(
|
||||
order=d_general["Order"],
|
||||
limit=limit,
|
||||
ascend=ascend,
|
||||
)
|
||||
else:
|
||||
df_screen = screen.ScreenerView(order=d_general["Order"], ascend=ascend)
|
||||
|
||||
else:
|
||||
if limit > 0:
|
||||
df_screen = screen.ScreenerView(limit=limit, ascend=ascend)
|
||||
else:
|
||||
df_screen = screen.ScreenerView(ascend=ascend)
|
||||
|
||||
return df_screen
|
||||
|
||||
|
||||
d_signals = {
|
||||
"top_gainers": "Top Gainers",
|
||||
"top_losers": "Top Losers",
|
||||
@@ -143,6 +50,135 @@ d_signals = {
|
||||
"head_shoulders_inverse": "Head & Shoulders Inverse",
|
||||
}
|
||||
|
||||
|
||||
def get_screener_data(preset_loaded: str, data_type: str, limit: int, ascend: bool):
|
||||
"""Screener Overview
|
||||
|
||||
Parameters
|
||||
----------
|
||||
preset_loaded : str
|
||||
Loaded preset filter
|
||||
data_type : str
|
||||
Data type between: overview, valuation, financial, ownership, performance, technical
|
||||
limit : int
|
||||
Limit of stocks filtered with presets to print
|
||||
ascend : bool
|
||||
Ascended order of stocks filtered to print
|
||||
|
||||
Returns
|
||||
----------
|
||||
pd.DataFrame
|
||||
Dataframe with loaded filtered stocks
|
||||
"""
|
||||
if data_type == "overview":
|
||||
screen = overview.Overview()
|
||||
elif data_type == "valuation":
|
||||
screen = valuation.Valuation()
|
||||
elif data_type == "financial":
|
||||
screen = financial.Financial()
|
||||
elif data_type == "ownership":
|
||||
screen = ownership.Ownership()
|
||||
elif data_type == "performance":
|
||||
screen = performance.Performance()
|
||||
elif data_type == "technical":
|
||||
screen = technical.Technical()
|
||||
else:
|
||||
print("Invalid selected screener type")
|
||||
return pd.DataFrame()
|
||||
|
||||
if preset_loaded in list(d_signals.keys()):
|
||||
screen.set_filter(signal=d_signals[preset_loaded])
|
||||
|
||||
if limit > 0:
|
||||
df_screen = screen.ScreenerView(limit=limit, ascend=ascend)
|
||||
else:
|
||||
df_screen = screen.ScreenerView(ascend=ascend)
|
||||
|
||||
else:
|
||||
preset_filter = configparser.RawConfigParser()
|
||||
preset_filter.optionxform = str # type: ignore
|
||||
preset_filter.read(presets_path + preset_loaded + ".ini")
|
||||
|
||||
d_general = preset_filter["General"]
|
||||
d_filters = {
|
||||
**preset_filter["Descriptive"],
|
||||
**preset_filter["Fundamental"],
|
||||
**preset_filter["Technical"],
|
||||
}
|
||||
|
||||
for section in ["General", "Descriptive", "Fundamental", "Technical"]:
|
||||
for key, val in {**preset_filter[section]}.items():
|
||||
if key not in d_check_screener:
|
||||
print(f"The screener variable {section}.{key} shouldn't exist!\n")
|
||||
return pd.DataFrame()
|
||||
|
||||
if val not in d_check_screener[key]:
|
||||
print(
|
||||
f"Invalid [{section}] {key}={val}. "
|
||||
f"Choose one of the following options:\n{', '.join(d_check_screener[key])}.\n"
|
||||
)
|
||||
return pd.DataFrame()
|
||||
|
||||
d_filters = {k: v for k, v in d_filters.items() if v}
|
||||
|
||||
screen.set_filter(filters_dict=d_filters)
|
||||
|
||||
if "Order" in d_general:
|
||||
if limit > 0:
|
||||
df_screen = screen.ScreenerView(
|
||||
order=d_general["Order"],
|
||||
limit=limit,
|
||||
ascend=ascend,
|
||||
)
|
||||
else:
|
||||
df_screen = screen.ScreenerView(order=d_general["Order"], ascend=ascend)
|
||||
|
||||
else:
|
||||
if limit > 0:
|
||||
df_screen = screen.ScreenerView(limit=limit, ascend=ascend)
|
||||
else:
|
||||
df_screen = screen.ScreenerView(ascend=ascend)
|
||||
|
||||
return df_screen
|
||||
|
||||
|
||||
d_signals_desc = {
|
||||
"top_gainers": "stocks with the highest %% price gain today",
|
||||
"top_losers": "stocks with the highest %% price loss today",
|
||||
"new_high": "stocks making 52-week high today",
|
||||
"new_low": "stocks making 52-week low today",
|
||||
"most_volatile": "stocks with the highest widest high/low trading range today",
|
||||
"most_active": "stocks with the highest trading volume today",
|
||||
"unusual_volume": "stocks with unusually high volume today - the highest relative volume ratio",
|
||||
"overbought": "stock is becoming overvalued and may experience a pullback.",
|
||||
"oversold": "oversold stocks may represent a buying opportunity for investors",
|
||||
"downgrades": "stocks downgraded by analysts today",
|
||||
"upgrades": "stocks upgraded by analysts today",
|
||||
"earnings_before": "companies reporting earnings today, before market open",
|
||||
"earnings_after": "companies reporting earnings today, after market close",
|
||||
"recent_insider_buying": "stocks with recent insider buying activity",
|
||||
"recent_insider_selling": "stocks with recent insider selling activity",
|
||||
"major_news": "stocks with the highest news coverage today",
|
||||
"horizontal_sr": "horizontal channel of price range between support and resistance trendlines",
|
||||
"tl_resistance": "once a rising trendline is broken",
|
||||
"tl_support": "once a falling trendline is broken",
|
||||
"wedge_up": "upward trendline support and upward trendline resistance (reversal)",
|
||||
"wedge_down": "downward trendline support and downward trendline resistance (reversal)",
|
||||
"wedge": "upward trendline support, downward trendline resistance (contiunation)",
|
||||
"triangle_ascending": "upward trendline support and horizontal trendline resistance",
|
||||
"triangle_descending": "horizontal trendline support and downward trendline resistance",
|
||||
"channel_up": "both support and resistance trendlines slope upward",
|
||||
"channel_down": "both support and resistance trendlines slope downward",
|
||||
"channel": "both support and resistance trendlines are horizontal",
|
||||
"double_top": "stock with 'M' shape that indicates a bearish reversal in trend",
|
||||
"double_bottom": "stock with 'W' shape that indicates a bullish reversal in trend",
|
||||
"multiple_top": "same as double_top hitting more highs",
|
||||
"multiple_bottom": "same as double_bottom hitting more lows",
|
||||
"head_shoulders": "chart formation that predicts a bullish-to-bearish trend reversal",
|
||||
"head_shoulders_inverse": "chart formation that predicts a bearish-to-bullish trend reversal",
|
||||
}
|
||||
|
||||
|
||||
d_check_screener = {
|
||||
"Order": [
|
||||
"Any",
|
||||
|
||||
@@ -4,19 +4,126 @@ __docformat__ = "numpy"
|
||||
import argparse
|
||||
from typing import List
|
||||
import os
|
||||
from datetime import datetime
|
||||
import difflib
|
||||
from tabulate import tabulate
|
||||
import pandas as pd
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
parse_known_args_and_warn,
|
||||
check_positive,
|
||||
try_except,
|
||||
export_data,
|
||||
)
|
||||
from gamestonk_terminal.stocks.screener.finviz_model import (
|
||||
d_signals,
|
||||
presets_path,
|
||||
get_screener_data,
|
||||
)
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
|
||||
d_cols_to_sort = {
|
||||
"overview": [
|
||||
"Ticker",
|
||||
"Company",
|
||||
"Sector",
|
||||
"Industry",
|
||||
"Country",
|
||||
"Market Cap",
|
||||
"P/E",
|
||||
"Price",
|
||||
"Change",
|
||||
"Volume",
|
||||
],
|
||||
"valuation": [
|
||||
"Ticker",
|
||||
"Market Cap",
|
||||
"P/E",
|
||||
"Fwd P/E",
|
||||
"PEG",
|
||||
"P/S",
|
||||
"P/B",
|
||||
"P/C",
|
||||
"P/FCF",
|
||||
"EPS this Y",
|
||||
"EPS next Y",
|
||||
"EPS past 5Y",
|
||||
"EPS next 5Y",
|
||||
"Sales past 5Y",
|
||||
"Price",
|
||||
"Change",
|
||||
"Volume",
|
||||
],
|
||||
"financial": [
|
||||
"Ticker",
|
||||
"Market Cap",
|
||||
"Dividend",
|
||||
"ROA",
|
||||
"ROE",
|
||||
"ROI",
|
||||
"Curr R",
|
||||
"Quick R",
|
||||
"LTDebt/Eq",
|
||||
"Debt/Eq",
|
||||
"Gross M",
|
||||
"Oper M",
|
||||
"Profit M",
|
||||
"Earnings",
|
||||
"Price",
|
||||
"Change",
|
||||
"Volume",
|
||||
],
|
||||
"ownership": [
|
||||
"Ticker",
|
||||
"Market Cap",
|
||||
"Outstanding",
|
||||
"Float",
|
||||
"Insider Own",
|
||||
"Insider Trans",
|
||||
"Inst Own",
|
||||
"Inst Trans",
|
||||
"Float Short",
|
||||
"Short Ratio",
|
||||
"Avg Volume",
|
||||
"Price",
|
||||
"Change",
|
||||
"Volume",
|
||||
],
|
||||
"performance": [
|
||||
"Ticker",
|
||||
"Perf Week",
|
||||
"Perf Month",
|
||||
"Perf Quart",
|
||||
"Perf Half",
|
||||
"Perf Year",
|
||||
"Perf YTD",
|
||||
"Volatility W",
|
||||
"Volatility M",
|
||||
"Recom",
|
||||
"Avg Volume",
|
||||
"Rel Volume",
|
||||
"Price",
|
||||
"Change",
|
||||
"Volume",
|
||||
],
|
||||
"technical": [
|
||||
"Ticker",
|
||||
"Beta",
|
||||
"ATR",
|
||||
"SMA20",
|
||||
"SMA50",
|
||||
"SMA200",
|
||||
"52W High",
|
||||
"52W Low",
|
||||
"RSI",
|
||||
"Price",
|
||||
"Change",
|
||||
"from Open",
|
||||
"Gap",
|
||||
"Volume",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@try_except
|
||||
def screener(other_args: List[str], loaded_preset: str, data_type: str) -> List[str]:
|
||||
"""Screener
|
||||
|
||||
@@ -56,17 +163,8 @@ def screener(other_args: List[str], loaded_preset: str, data_type: str) -> List[
|
||||
preset.split(".")[0]
|
||||
for preset in os.listdir(presets_path)
|
||||
if preset[-4:] == ".ini"
|
||||
],
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--signal",
|
||||
action="store",
|
||||
dest="signal",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Signal",
|
||||
choices=list(d_signals.keys()),
|
||||
]
|
||||
+ list(d_signals.keys()),
|
||||
)
|
||||
parser.add_argument(
|
||||
"-l",
|
||||
@@ -74,7 +172,7 @@ def screener(other_args: List[str], loaded_preset: str, data_type: str) -> List[
|
||||
action="store",
|
||||
dest="limit",
|
||||
type=check_positive,
|
||||
default=0,
|
||||
default=10,
|
||||
help="Limit of stocks to print",
|
||||
)
|
||||
parser.add_argument(
|
||||
@@ -86,147 +184,91 @@ def screener(other_args: List[str], loaded_preset: str, data_type: str) -> List[
|
||||
help="Set order to Ascend, the default is Descend",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-e",
|
||||
"-s",
|
||||
"--sort",
|
||||
action="store",
|
||||
dest="sort",
|
||||
default="",
|
||||
nargs="+",
|
||||
help=f"Sort elements of the table. Use {', '.join(d_cols_to_sort[data_type])}",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--export",
|
||||
action="store_true",
|
||||
dest="exportFile",
|
||||
help="Save list as a text file",
|
||||
choices=["csv", "json", "xlsx"],
|
||||
default="",
|
||||
dest="export",
|
||||
help="Export dataframe data to csv,json,xlsx file",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return []
|
||||
|
||||
df_screen = get_screener_data(
|
||||
ns_parser.preset,
|
||||
data_type,
|
||||
0,
|
||||
ns_parser.ascend,
|
||||
)
|
||||
|
||||
if isinstance(df_screen, pd.DataFrame):
|
||||
if df_screen.empty:
|
||||
return []
|
||||
|
||||
df_screen = get_screener_data(
|
||||
ns_parser.preset,
|
||||
df_screen = df_screen.dropna(axis="columns", how="all")
|
||||
|
||||
if ns_parser.sort:
|
||||
if " ".join(ns_parser.sort) in d_cols_to_sort[data_type]:
|
||||
df_screen = df_screen.sort_values(
|
||||
by=[" ".join(ns_parser.sort)],
|
||||
ascending=ns_parser.ascend,
|
||||
na_position="last",
|
||||
)
|
||||
else:
|
||||
similar_cmd = difflib.get_close_matches(
|
||||
" ".join(ns_parser.sort),
|
||||
d_cols_to_sort[data_type],
|
||||
n=1,
|
||||
cutoff=0.7,
|
||||
)
|
||||
if similar_cmd:
|
||||
print(
|
||||
f"Replacing '{' '.join(ns_parser.sort)}' by '{similar_cmd[0]}' so table can be sorted."
|
||||
)
|
||||
df_screen = df_screen.sort_values(
|
||||
by=[similar_cmd[0]],
|
||||
ascending=ns_parser.ascend,
|
||||
na_position="last",
|
||||
)
|
||||
else:
|
||||
print(
|
||||
f"Wrong sort column provided! Provide one of these: {', '.join(d_cols_to_sort[data_type])}"
|
||||
)
|
||||
|
||||
df_screen = df_screen.fillna("")
|
||||
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(
|
||||
tabulate(
|
||||
df_screen.head(n=ns_parser.limit),
|
||||
headers=df_screen.columns,
|
||||
floatfmt=".2f",
|
||||
showindex=False,
|
||||
tablefmt="fancy_grid",
|
||||
),
|
||||
)
|
||||
else:
|
||||
print(df_screen.head(n=ns_parser.limit).to_string())
|
||||
print("")
|
||||
|
||||
export_data(
|
||||
ns_parser.export,
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
data_type,
|
||||
ns_parser.signal,
|
||||
ns_parser.limit,
|
||||
ns_parser.ascend,
|
||||
df_screen,
|
||||
)
|
||||
|
||||
if isinstance(df_screen, pd.DataFrame):
|
||||
if df_screen.empty:
|
||||
return []
|
||||
return list(df_screen.head(n=ns_parser.limit)["Ticker"].values)
|
||||
|
||||
print(df_screen.to_string())
|
||||
print("")
|
||||
if ns_parser.exportFile:
|
||||
now = datetime.now()
|
||||
if not os.path.exists("reports/screener"):
|
||||
os.makedirs("reports/screener")
|
||||
with open(
|
||||
f"reports/screener/{ns_parser.signal}-{now.strftime('%Y-%m-%d_%H:%M:%S')}",
|
||||
"w",
|
||||
) as file:
|
||||
file.write(df_screen.to_string(index=False) + "\n")
|
||||
|
||||
return list(df_screen["Ticker"].values)
|
||||
|
||||
print("")
|
||||
return []
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
return []
|
||||
|
||||
|
||||
def view_signals(other_args: List[str]):
|
||||
"""View list of available signals
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
Command line arguments to be processed with argparse
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="signals",
|
||||
description="""
|
||||
Prints list of available signals. [Source: Finviz]
|
||||
""",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
print("top_gainers stocks with the highest %% price gain today")
|
||||
print("top_losers stocks with the highest %% price loss today.")
|
||||
print("new_high stocks making 52-week high today")
|
||||
print("new_low stocks making 52-week low today")
|
||||
print(
|
||||
"most_volatile stocks with the highest widest high/low trading range today"
|
||||
)
|
||||
print("most_active stocks with the highest trading volume today")
|
||||
print(
|
||||
"unusual_volume stocks with unusually high volume today - the highest relative volume ratio"
|
||||
)
|
||||
print(
|
||||
"overbought stock is becoming overvalued and may experience a pullback."
|
||||
)
|
||||
print(
|
||||
"oversold oversold stocks may represent a buying opportunity for investors."
|
||||
)
|
||||
print("downgrades stocks downgraded by analysts today")
|
||||
print("upgrades stocks upgraded by analysts today.")
|
||||
print(
|
||||
"earnings_before companies reporting earnings today, before market open"
|
||||
)
|
||||
print(
|
||||
"earnings_after companies reporting earnings today, after market close"
|
||||
)
|
||||
print("recent_insider_buying stocks with recent insider buying activity")
|
||||
print("recent_insider_selling stocks with recent insider selling activity")
|
||||
print("major_news stocks with the highest news coverage today")
|
||||
print(
|
||||
"horizontal_sr horizontal channel of price range between support and resistance trendlines"
|
||||
)
|
||||
print("tl_resistance once a rising trendline is broken")
|
||||
print("tl_support once a falling trendline is broken")
|
||||
print(
|
||||
"wedge_up upward trendline support and upward trendline resistance (reversal)"
|
||||
)
|
||||
print(
|
||||
"wedge_down downward trendline support and downward trendline resistance (reversal)"
|
||||
)
|
||||
print(
|
||||
"wedge upward trendline support, downward trendline resistance (contiunation)"
|
||||
)
|
||||
print(
|
||||
"triangle_ascending upward trendline support and horizontal trendline resistance"
|
||||
)
|
||||
print(
|
||||
"triangle_descending horizontal trendline support and downward trendline resistance"
|
||||
)
|
||||
print(
|
||||
"channel_up both support and resistance trendlines slope upward"
|
||||
)
|
||||
print(
|
||||
"channel_down both support and resistance trendlines slope downward"
|
||||
)
|
||||
print(
|
||||
"channel both support and resistance trendlines are horizontal"
|
||||
)
|
||||
print(
|
||||
"double_top stock with 'M' shape that indicates a bearish reversal in trend"
|
||||
)
|
||||
print(
|
||||
"double_bottom stock with 'W' shape that indicates a bullish reversal in trend"
|
||||
)
|
||||
print("multiple_top same as double_top hitting more highs")
|
||||
print("multiple_bottom same as double_bottom hitting more lows")
|
||||
print(
|
||||
"head_shoulders chart formation that predicts a bullish-to-bearish trend reversal"
|
||||
)
|
||||
print(
|
||||
"head_shoulders_inverse chart formation that predicts a bearish-to-bullish trend reversal"
|
||||
)
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("")
|
||||
return
|
||||
print("")
|
||||
return []
|
||||
|
||||
@@ -17,7 +17,11 @@ from gamestonk_terminal.helper_funcs import (
|
||||
)
|
||||
from gamestonk_terminal.menu import session
|
||||
from gamestonk_terminal.portfolio.portfolio_optimization import po_controller
|
||||
from gamestonk_terminal.stocks.screener import finviz_view, yahoofinance_view
|
||||
from gamestonk_terminal.stocks.screener import (
|
||||
finviz_view,
|
||||
yahoofinance_view,
|
||||
finviz_model,
|
||||
)
|
||||
|
||||
presets_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "presets/")
|
||||
|
||||
@@ -43,13 +47,12 @@ class ScreenerController:
|
||||
"ownership",
|
||||
"performance",
|
||||
"technical",
|
||||
"signals",
|
||||
"po",
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
"""Constructor"""
|
||||
self.preset = "template"
|
||||
self.preset = "top_gainers"
|
||||
self.screen_tickers = []
|
||||
self.scr_parser = argparse.ArgumentParser(add_help=False, prog="scr")
|
||||
self.scr_parser.add_argument(
|
||||
@@ -65,7 +68,7 @@ class ScreenerController:
|
||||
print(" q quit this menu, and shows back to main menu")
|
||||
print(" quit quit to abandon program")
|
||||
print("")
|
||||
print(" view view available presets")
|
||||
print(" view view available presets (defaults and customs)")
|
||||
print(" set set one of the available presets")
|
||||
print("")
|
||||
print(f"PRESET: {self.preset}")
|
||||
@@ -78,8 +81,6 @@ class ScreenerController:
|
||||
print(" performance performance (e.g. Perf Week, Perf YTD, Volatility M)")
|
||||
print(" technical technical (e.g. Beta, SMA50, 52W Low, RSI, Change)")
|
||||
print("")
|
||||
print(" signals view filter signals (e.g. -s top_gainers)")
|
||||
print("")
|
||||
if self.screen_tickers:
|
||||
print(f"Last screened tickers: {', '.join(self.screen_tickers)}")
|
||||
print("")
|
||||
@@ -142,6 +143,7 @@ class ScreenerController:
|
||||
if preset[-4:] == ".ini"
|
||||
]
|
||||
|
||||
print("\nCustom Presets:")
|
||||
for preset in presets:
|
||||
with open(
|
||||
presets_path + preset + ".ini",
|
||||
@@ -152,8 +154,13 @@ class ScreenerController:
|
||||
if line.strip() == "[General]":
|
||||
break
|
||||
description += line.strip()
|
||||
print(f"\nPRESET: {preset}")
|
||||
print(description.split("Description: ")[1].replace("#", ""))
|
||||
print(
|
||||
f" {preset}{(50-len(preset)) * ' '}{description.split('Description: ')[1].replace('#', '')}"
|
||||
)
|
||||
|
||||
print("\nDefault Presets:")
|
||||
for signame, sigdesc in finviz_model.d_signals_desc.items():
|
||||
print(f" {signame}{(50-len(signame)) * ' '}{sigdesc}")
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
@@ -178,7 +185,8 @@ class ScreenerController:
|
||||
preset.split(".")[0]
|
||||
for preset in os.listdir(presets_path)
|
||||
if preset[-4:] == ".ini"
|
||||
],
|
||||
]
|
||||
+ list(finviz_model.d_signals.keys()),
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -280,10 +288,6 @@ class ScreenerController:
|
||||
"""Process technical command"""
|
||||
self.screen_tickers = finviz_view.screener(other_args, self.preset, "technical")
|
||||
|
||||
def call_signals(self, other_args: List[str]):
|
||||
"""Process signals command"""
|
||||
finviz_view.view_signals(other_args)
|
||||
|
||||
def call_po(self, _):
|
||||
"""Call the portfolio optimization menu with selected tickers"""
|
||||
return po_controller.menu(self.screen_tickers)
|
||||
|
||||
@@ -18,7 +18,7 @@ from gamestonk_terminal.helper_funcs import (
|
||||
plot_autoscale,
|
||||
valid_date,
|
||||
)
|
||||
from gamestonk_terminal.stocks.screener import finviz_view
|
||||
from gamestonk_terminal.stocks.screener import finviz_model
|
||||
|
||||
register_matplotlib_converters()
|
||||
|
||||
@@ -76,40 +76,30 @@ def historical(other_args: List[str], preset_loaded: str) -> List[str]:
|
||||
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 list()
|
||||
|
||||
preset_filter = configparser.RawConfigParser()
|
||||
preset_filter.optionxform = str # type: ignore
|
||||
preset_filter.read(presets_path + 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 preset_loaded in list(finviz_model.d_signals.keys()):
|
||||
screen.set_filter(signal=finviz_model.d_signals[preset_loaded])
|
||||
|
||||
if ns_parser.signal:
|
||||
screen.set_filter(signal=finviz_view.d_signals[ns_parser.signal])
|
||||
else:
|
||||
preset_filter = configparser.RawConfigParser()
|
||||
preset_filter.optionxform = str # type: ignore
|
||||
preset_filter.read(presets_path + 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}
|
||||
|
||||
if d_general["Signal"]:
|
||||
screen.set_filter(filters_dict=d_filters, signal=d_general["Signal"])
|
||||
else:
|
||||
@@ -117,9 +107,8 @@ def historical(other_args: List[str], preset_loaded: str) -> List[str]:
|
||||
|
||||
l_min = []
|
||||
l_leg = []
|
||||
plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
||||
|
||||
l_stocks = screen.ScreenerView(verbose=0)
|
||||
limit_random_stocks = False
|
||||
|
||||
if len(l_stocks) > 10:
|
||||
print(
|
||||
@@ -129,6 +118,9 @@ def historical(other_args: List[str], preset_loaded: str) -> List[str]:
|
||||
random.shuffle(l_stocks)
|
||||
l_stocks = sorted(l_stocks[:10])
|
||||
print(", ".join(l_stocks))
|
||||
limit_random_stocks = True
|
||||
|
||||
plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
||||
|
||||
while l_stocks:
|
||||
l_parsed_stocks = []
|
||||
@@ -164,12 +156,12 @@ def historical(other_args: List[str], preset_loaded: str) -> List[str]:
|
||||
for parsed_stock in l_parsed_stocks:
|
||||
l_stocks.remove(parsed_stock)
|
||||
|
||||
if ns_parser.signal:
|
||||
if limit_random_stocks:
|
||||
plt.title(
|
||||
f"Screener Historical Price using {finviz_view.d_signals[ns_parser.signal]} signal"
|
||||
f"Screener Historical Price using {preset_loaded} on 10 of those stocks"
|
||||
)
|
||||
else:
|
||||
plt.title(f"Screener Historical Price using {preset_loaded} preset")
|
||||
plt.title(f"Screener Historical Price using {preset_loaded}")
|
||||
|
||||
plt.xlabel("Time")
|
||||
plt.ylabel("Share Price ($)")
|
||||
|
||||
Reference in New Issue
Block a user