mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-11-02 07:23:25 +00:00
* 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
174 lines
5.4 KiB
Python
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
|