Files
OpenBB/openbb_terminal/common/behavioural_analysis/reddit_view.py
LOne2three 58391c1edf Hotfix/reddit spacc (#5067)
* Change logic in print_rich_table and display_spacc_community

* changed comment

* Changed logic in print_rich_table

* Got rid of whitespace

* changed comments

* changed formatting

* changed formatting

* changed formatting

* Fixed linting

* sort imports

* added TypeError to exception block and moved print_reddit_post to after the ticker iteration loop so that tables and tickers would be loaded at the same time

* Changed logic in  display_space_community to print all reddit posts to a single table

* Quick fix wsb command

---------

Co-authored-by: James Maslek <jmaslek11@gmail.com>
2023-05-26 14:42:26 +00:00

342 lines
9.9 KiB
Python

"""Reddit View."""
__docformat__ = "numpy"
import logging
import os
import textwrap
from datetime import datetime
from typing import Dict, Optional, Union
import pandas as pd
import praw
from finvizfinance.screener.ticker import Ticker
from openbb_terminal import OpenBBFigure, rich_config
from openbb_terminal.common.behavioural_analysis import reddit_model
from openbb_terminal.common.behavioural_analysis.reddit_helpers import (
reddit_requirements,
)
from openbb_terminal.core.session.current_user import get_current_user
from openbb_terminal.decorators import check_api_key, log_start_end
from openbb_terminal.helper_funcs import export_data, print_rich_table
from openbb_terminal.rich_config import console
# pylint: disable=R0913,C0302
logger = logging.getLogger(__name__)
@log_start_end(log=logger)
@check_api_key(reddit_requirements)
def print_and_record_reddit_post(
submissions_dict: Dict, submission: praw.models.reddit.submission.Submission
):
"""Print reddit submission.
Parameters
----------
submissions_dict : Dict
Dictionary for storing reddit post information
submission : praw.models.reddit.submission.Submission
Submission to show
"""
# Refactor data
s_datetime = datetime.utcfromtimestamp(submission.created_utc).strftime(
"%Y-%m-%d %H:%M:%S"
)
s_link = f"https://old.reddit.com{submission.permalink}"
s_all_awards = "".join(
f"{award['count']} {award['name']}\n" for award in submission.all_awardings
)
s_all_awards = s_all_awards[:-2]
# Create dictionary with data to construct dataframe allows to save data
submissions_dict[submission.id] = {
"created_utc": s_datetime,
"subreddit": submission.subreddit,
"link_flair_text": submission.link_flair_text,
"title": submission.title,
"score": submission.score,
"link": s_link,
"num_comments": submission.num_comments,
"upvote_ratio": submission.upvote_ratio,
"awards": s_all_awards,
}
# Print post data collected so far
console.print(f"[yellow]{s_datetime}[/yellow] - {submission.title}")
console.print(f"[blue]{s_link}[/blue]\n")
columns = ["Subreddit", "Flair", "Score", "# Comments", "Upvote %", "Awards"]
data = [
submission.subreddit,
submission.link_flair_text,
submission.score,
submission.num_comments,
f"{round(100 * submission.upvote_ratio)}%",
s_all_awards,
]
df = pd.DataFrame([data], columns=columns)
print_rich_table(
df, headers=list(df.columns), show_index=False, title="Reddit Submission"
)
@log_start_end(log=logger)
@check_api_key(reddit_requirements)
def print_reddit_post(sub: tuple):
"""Print reddit submission.
Parameters
----------
sub : tuple
Row from submissions dataframe
"""
sub_list = list(sub[1])
date = sub_list[0]
title = sub_list[3]
link = sub_list[-1]
if rich_config.USE_COLOR and not get_current_user().preferences.USE_INTERACTIVE_DF:
console.print(f"[yellow]{date}[/yellow] - {title}")
console.print(f"[blue]{link}[/blue]\n")
columns = [
"Subreddit",
"Flair",
"Score",
"# Comments",
"Upvote %",
"Awards",
]
print_rich_table(
pd.DataFrame(sub[1][columns]).T,
headers=columns,
show_index=False,
title="Reddit Submission",
)
@log_start_end(log=logger)
@check_api_key(reddit_requirements)
def display_popular_tickers(
limit: int = 10,
post_limit: int = 50,
subreddits: str = "",
export: str = "",
sheet_name: Optional[str] = None,
):
"""Print table showing latest popular tickers. [Source: Reddit].
Parameters
----------
limit : int
Number of top tickers to get
post_limit : int
How many posts to analyze in each subreddit
subreddits : str, optional
String of comma separated subreddits.
export : str
Format to export dataframe
"""
popular_tickers_df = reddit_model.get_popular_tickers(limit, post_limit, subreddits)
if popular_tickers_df.empty:
console.print("No tickers found")
return
print_rich_table(
popular_tickers_df,
headers=list(popular_tickers_df.columns),
show_index=True,
title=f"The following TOP {limit} tickers have been mentioned",
export=bool(export),
)
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"popular",
popular_tickers_df,
sheet_name,
)
@log_start_end(log=logger)
@check_api_key(reddit_requirements)
def display_spac_community(limit: int = 10, popular: bool = False):
"""Print tickers mentioned in r/SPACs [Source: Reddit].
Parameters
----------
limit: int
Number of posts to look through
popular: bool
Search by popular instead of new
"""
subs, d_watchlist_tickers = reddit_model.get_spac_community(limit, popular)
if not subs.empty:
if d_watchlist_tickers:
lt_watchlist_sorted = sorted(
d_watchlist_tickers.items(), key=lambda item: item[1], reverse=True
)
s_watchlist_tickers = ""
n_tickers = 0
tickers = Ticker()
ticker_list = tickers.screener_view()
# validate against a list of all tickers
for t_ticker in lt_watchlist_sorted:
if t_ticker[0] in ticker_list:
if int(t_ticker[1]) > 1:
s_watchlist_tickers += f"{t_ticker[1]} {t_ticker[0]}, "
n_tickers += 1
if n_tickers:
console.print(
"The following stock tickers have been mentioned more than once across the previous posts on "
"r/spaccs: "
)
console.print(s_watchlist_tickers[:-2])
print_rich_table(
pd.DataFrame(subs),
show_index=False,
title="Reddit Submission",
)
@log_start_end(log=logger)
@check_api_key(reddit_requirements)
def display_wsb_community(limit: int = 10, new: bool = False):
"""Print WSB posts.
Parameters
----------
limit : int, optional
Number of posts to look at, by default 10
new : bool, optional
Flag to sort by new instead of hot, by default False
"""
subs = reddit_model.get_wsb_community(limit, new)
if not subs.empty:
# for sub in subs.iterrows():
# print_reddit_post(sub)
print(print_rich_table(subs))
@log_start_end(log=logger)
@check_api_key(reddit_requirements)
def display_due_diligence(
limit: int = 10, n_days: int = 3, show_all_flairs: bool = False
):
"""Print Reddit due diligence data for a given ticker.
Parameters
----------
limit: int
Number of posts to get
n_days: int
Number of days back to get posts
show_all_flairs: bool
Search through all flairs (apart from Yolo and Meme)
"""
subs = reddit_model.get_due_dilligence(limit, n_days, show_all_flairs)
if not subs.empty:
for sub in subs.iterrows():
print_reddit_post(sub)
console.print("")
else:
console.print("No DD posts found\n")
@log_start_end(log=logger)
@check_api_key(reddit_requirements)
def display_redditsent(
symbol: str,
sortby: str = "relevance",
limit: int = 100,
graphic: bool = False,
time_frame: str = "week",
full_search: bool = True,
subreddits: str = "all",
display: bool = False,
export: str = "",
sheet_name: Optional[str] = None,
external_axes: bool = False,
) -> Union[OpenBBFigure, None]:
"""Plot Reddit sentiment about a search term. Prints table showing if display is True.
Parameters
----------
symbol: str
The ticker symbol being search for in Reddit
sortby: str
Type of search
limit: str
Number of posts to get at most
graphic: bool
Displays box and whisker plot
time_frame: str
Time frame for search
full_search: bool
Enable comprehensive search for ticker
subreddits: str
Comma-separated list of subreddits
display: bool
Enable printing of raw sentiment values for each post
sheet_name: str
Optionally specify the name of the sheet the data is exported to.
export: str
Format to export data
external_axes: Optional[List[plt.Axes]]
If supplied, expect 1 external axis
"""
fig = OpenBBFigure()
df, polarity_scores, avg_polarity = reddit_model.get_posts_about(
symbol, limit, sortby, time_frame, full_search, subreddits
)
if df.empty:
return console.print(f"No posts for {symbol} found")
if display:
print_rich_table(df=df, export=bool(export))
if not fig.is_image_export(export):
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"polarity_scores",
df,
sheet_name,
)
console.print(f"Sentiment Analysis for {symbol} is {avg_polarity}\n")
if graphic:
df["Title"] = df["Title"].apply(
lambda x: "<br>".join(textwrap.wrap(str(x), 50))
)
fig = OpenBBFigure(
title=f"Sentiment Score of {symbol}",
xaxis_title="Sentiment Score",
)
fig.add_bar(
x=polarity_scores,
customdata=df["Title"],
hovertemplate="%{customdata}<extra></extra>",
)
fig.update_layout(hovermode="y")
# remove y ticks of graph object because number based index doesn't make sense here
fig.layout.yaxis.tickvals = []
if fig.is_image_export(export):
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"polarity_scores",
df,
sheet_name,
fig,
)
return fig.show(external=external_axes)
return None