Files
OpenBB/openbb_terminal/common/behavioural_analysis/reddit_helpers.py
Colin Delahunty 1ca7fd9beb Improves the settings/userdata command, and upgrade ruff (#5359)
* Began the fax

* Bumped ruff

* Fixed a BUNCH of ruff errors

* Fixed a lot of ruff errors

* Simplify if statements

* Fixed black

* Updated some stuff

* Updated some stuff

* A lot more ruff fixes

* Added a fix

* Added a fix

* Fixed mypy

* Fixed some stuff

* Reverted one thing

* Small fix

* Small fix

* Small fix

* Added fix

* Added fix

* Update requirements
2023-08-22 20:11:48 +00:00

174 lines
5.4 KiB
Python

"""Reddit Helpers."""
__docformat__ = "numpy"
import logging
import re
import urllib.request
from typing import List
import pandas as pd
import praw
from prawcore.exceptions import ResponseException
from openbb_terminal.core.models import UserModel
from openbb_terminal.rich_config import console
logger = logging.getLogger(__name__)
reddit_requirements = [
"API_REDDIT_CLIENT_ID",
"API_REDDIT_CLIENT_SECRET",
"API_REDDIT_USERNAME",
"API_REDDIT_USER_AGENT",
"API_REDDIT_PASSWORD",
]
def find_tickers(submission: praw.models.reddit.submission.Submission) -> List[str]:
"""Extract potential tickers from reddit submission.
Parameters
----------
submission : praw.models.reddit.submission.Submission
Reddit post to scan
Returns
-------
List[str]
List of potential tickers
"""
ls_text = [submission.selftext, submission.title]
submission.comments.replace_more(limit=0)
for comment in submission.comments.list():
ls_text.append(comment.body)
l_tickers_found = []
for s_text in ls_text:
for s_ticker in set(re.findall(r"([A-Z]{3,5})", s_text)):
l_tickers_found.append(s_ticker.strip())
return l_tickers_found
def get_praw_api(current_user: UserModel) -> praw.Reddit:
"""Get praw api.
Parameters
----------
current_user : UserModel
The user model
Returns
-------
praw.Reddit
Praw api
"""
# See https://github.com/praw-dev/praw/issues/1016 regarding praw arguments
praw_api = praw.Reddit(
client_id=current_user.credentials.API_REDDIT_CLIENT_ID,
client_secret=current_user.credentials.API_REDDIT_CLIENT_SECRET,
username=current_user.credentials.API_REDDIT_USERNAME,
user_agent=current_user.credentials.API_REDDIT_USER_AGENT,
password=current_user.credentials.API_REDDIT_PASSWORD,
check_for_updates=False,
comment_kind="t1",
message_kind="t4",
redditor_kind="t2",
submission_kind="t3",
subreddit_kind="t5",
trophy_kind="t6",
oauth_url="https://oauth.reddit.com",
reddit_url="https://www.reddit.com",
short_url="https://redd.it",
ratelimit_seconds=5,
timeout=16,
)
return praw_api
def has_author(submission_, authors) -> bool:
"""Check if submission has author."""
return (
hasattr(submission_, "author")
and hasattr(submission_.author, "name")
and submission_.author.name not in authors
)
def has_content(submission_) -> bool:
"""Check if submission has text or title."""
return hasattr(submission_, "selftext") or hasattr(submission_, "title")
class RedditResponses:
tickers: dict = {}
authors: List[str] = []
def __init__(self):
pass
def gather(self, praw_api, responses) -> int:
count = 0
for submission in responses:
try:
# Get more information about post using PRAW api
submission_ = praw_api.submission(id=submission["id"])
# Ensure that the post hasn't been removed by moderator in the meanwhile,
# that there is a description and it's not just an image, that the flair is
# meaningful, and that we aren't re-considering same author's content
if (
submission_ is not None
and not submission_.removed_by_category
and has_content(submission_)
and has_author(submission_, self.authors)
):
l_tickers_found = find_tickers(submission_)
if l_tickers_found:
count += len(l_tickers_found)
# Add another author's name to the parsed watchlists
self.authors.append(submission_.author.name)
# Lookup stock tickers within a watchlist
for key in l_tickers_found:
if key in self.tickers:
# Increment stock ticker found
self.tickers[key] += 1
else:
# Initialize stock ticker found
self.tickers[key] = 1
except ResponseException as e:
logger.exception("Invalid response: %s", str(e))
if "received 401 HTTP response" in str(e):
console.print("[red]Invalid API Key[/red]\n")
else:
console.print(f"[red]Invalid response: {str(e)}[/red]\n")
return 0
return count
def validate(
self,
url: str = "https://raw.githubusercontent.com/rreichel3/US-Stock-Symbols/main/all/all_tickers.txt",
) -> None:
"""Validate tickers."""
valids = []
with urllib.request.urlopen(url) as file: # noqa: S310
for line in file:
new_item = line.decode("utf-8").replace("\n", "").strip()
valids.append(new_item)
for key in list(self.tickers.keys()):
if key not in valids:
self.tickers.pop(key)
def to_df(self) -> pd.DataFrame:
popularity = pd.DataFrame.from_dict(self.tickers, orient="index")
popularity.columns = ["Mentions"]
popularity = popularity.sort_values(by=["Mentions"], ascending=False)
return popularity