diff --git a/fundamental_analysis/fa_menu.py b/fundamental_analysis/fa_menu.py index dec87d40103..bbdf3e0a3ef 100644 --- a/fundamental_analysis/fa_menu.py +++ b/fundamental_analysis/fa_menu.py @@ -14,6 +14,7 @@ from fundamental_analysis import alpha_vantage_api as av_api from fundamental_analysis import financial_modeling_prep_api as fmp_api from fundamental_analysis import finviz_api as fvz_api from fundamental_analysis import market_watch_api as mw_api +from fundamental_analysis import reddit_api as r_api # ----------------------------------------------------------------------------------------------------------------------- @@ -33,6 +34,7 @@ def print_fundamental_analysis(s_ticker, s_start, s_interval): print(" q quit this menu, and shows back to main menu") print(" quit quit to abandon program") print("") + print(" dd gets due diligence from another user's post [Reddit]") print(" warnings company warnings according to Sean Seah book [Market Watch]") print("\nFinviz API") print(" screener screen info about the company") @@ -113,7 +115,7 @@ def fa_menu(s_ticker, s_start, s_interval): # Add list of arguments that the fundamental analysis parser accepts fa_parser = argparse.ArgumentParser(prog='fundamental_analysis', add_help=False) - fa_parser.add_argument('cmd', choices=['info', 'warnings', 'help', 'q', 'quit', 'more', + fa_parser.add_argument('cmd', choices=['info', 'help', 'q', 'quit', 'more', 'warnings', 'dd', 'screener', 'insider', 'news', 'analyst', # Finviz 'income', 'assets', 'liabilities', 'operating', 'investing', 'financing', 'sec']) # MW @@ -146,6 +148,9 @@ def fa_menu(s_ticker, s_start, s_interval): # Abandon the program return True + elif ns_known_args.cmd == 'dd': + r_api.due_diligence(l_args, s_ticker) + elif ns_known_args.cmd == 'warnings': mw_api.sean_seah_warnings(l_args, s_ticker) diff --git a/fundamental_analysis/reddit_api.py b/fundamental_analysis/reddit_api.py new file mode 100644 index 00000000000..4778600c1f0 --- /dev/null +++ b/fundamental_analysis/reddit_api.py @@ -0,0 +1,114 @@ +import argparse +from prettytable import PrettyTable +from datetime import datetime, timedelta +import pandas as pd +from psaw import PushshiftAPI +import praw +from datetime import datetime +from pytz import timezone +from holidays import US as holidaysUS +from stock_market_helper_funcs import * +import re +import finviz +import config_bot as cfg + +# ------------------------------------------------------------------------------------------------------------------- +def due_diligence(l_args, s_ticker): + parser = argparse.ArgumentParser(prog='dd', + description=""" Search for a stock's due diligence [Reddit] """) + parser.add_argument('-l', "--limit", action="store", dest="n_limit", type=check_positive, default=5, + help='Limit of posts with the watchlist word') + parser.add_argument('-d', "--days", action="store", dest="n_days", type=check_positive, default=3, + help="Look for a watchlist created on the past n days") + parser.add_argument('-a', "--all", action="store_true", dest="b_all", default=False, + help=""" Search through all flairs (apart from Yolo and Meme), otherwise we focus on the + flairs: DD, technical analysis, Catalyst, News, Advice, Chart """) + + try: + (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) + + if l_unknown_args: + print(f"The following args couldn't be interpreted: {l_unknown_args}\n") + return + + praw_api = praw.Reddit(client_id=cfg.API_REDDIT_CLIENT_ID, + client_secret=cfg.API_REDDIT_CLIENT_SECRET, + username=cfg.API_REDDIT_USERNAME, + user_agent=cfg.API_REDDIT_USER_AGENT, + password=cfg.API_REDDIT_PASSWORD) + + psaw_api = PushshiftAPI() + + n_ts_after = int((datetime.today() - timedelta(days=ns_parser.n_days)).timestamp()) + l_flair_text = ['DD', 'technical analysis', 'Catalyst', 'News', 'Advice', 'Chart'] + l_sub_reddits = ['pennystocks', 'RobinHoodPennyStocks', 'Daytrading', 'StockMarket', 'stocks', 'investing', 'wallstreetbets'] + + submissions = psaw_api.search_submissions(after=int(n_ts_after), + subreddit=l_sub_reddits, + q=s_ticker, + filter=['id']) + d_submission = {} + n_flair_posts_found = 0 + while True: + submission = next(submissions, None) + if submission: + # Get more information about post using PRAW api + submission = praw_api.submission(id=submission.id) + + # Ensure that the post hasn't been removed in the meanwhile + if not submission.removed_by_category: + + # Either just filter out Yolo, and Meme flairs, or focus on DD, based on b_DD flag + if (submission.link_flair_text in l_flair_text, + submission.link_flair_text not in ['Yolo', 'Meme'])[ns_parser.b_all]: + + # Refactor data + s_datetime = datetime.utcfromtimestamp(submission.created_utc).strftime("%d/%m/%Y %H:%M:%S") + s_link = f"https://www.reddit.com{submission.permalink}" + s_all_awards = "" + for award in submission.all_awardings: + s_all_awards += f"{award['count']} {award['name']}\n" + s_all_awards = s_all_awards[:-2] + + # Create dictionary with data to construct dataframe allows to save data + d_submission[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 + print(f"{s_datetime} - {submission.title}") + print(f"{s_link}") + t_post = PrettyTable(['Subreddit', 'Flair', 'Score', '# Comments', 'Upvote %', "Awards"]) + t_post.add_row([submission.subreddit, submission.link_flair_text, submission.score, + submission.num_comments,f"{round(100*submission.upvote_ratio)}%", s_all_awards]) + print(t_post) + print("\n") + + # If needed, submission.comments could give us the top comments + + # Increment count of valid posts found + n_flair_posts_found += 1 + + # Check if number of wanted posts found has been reached + if n_flair_posts_found > ns_parser.n_limit-1: + break + + # Check if search_submissions didn't get anymore posts + else: + break + + print(f"{('No more posts with specified requirements found.', '')[n_flair_posts_found > ns_parser.n_limit-1]}") + # Create df with found data. Useful for saving all info in excel file. + #df_submissions = pd.DataFrame.from_dict(d_submission, orient='index', columns=list(d_submission[next(iter(d_submission.keys()))].keys())) + #df_submissions.sort_values(by=['created_utc'], inplace=True, ascending=True) + + except: + print("")