import requests import time import orjson import aiohttp import aiofiles from datetime import datetime, timedelta, timezone, date import pytz import os from dotenv import load_dotenv import asyncio import sqlite3 import hashlib import glob load_dotenv() ny_tz = pytz.timezone("America/New_York") today = datetime.utcnow().date() now = datetime.now(timezone.utc) now_ny = datetime.now(ny_tz) N_minutes_ago = now - timedelta(minutes=30) DARK_POOL_WEBHOOK_URL = os.getenv("DISCORD_DARK_POOL_WEBHOOK") OPTIONS_FLOW_WEBHOOK_URL = os.getenv("DISCORD_OPTIONS_FLOW_WEBHOOK") RECENT_EARNINGS_WEBHOOK_URL = os.getenv("DISCORD_RECENT_EARNINGS_WEBHOOK") EXECUTIVE_ORDER_WEBHOOK_URL = os.getenv("DISCORD_EXECUTIVE_ORDER_WEBHOOK") ANALYST_REPORT_WEBHOOK_URL = os.getenv("DISCORD_ANALYST_REPORT_WEBHOOK") BENZINGA_API_KEY = os.getenv('BENZINGA_API_KEY') headers = {"accept": "application/json"} def save_json(data): directory = "json/discord" os.makedirs(directory, exist_ok=True) with open(directory+"/dark_pool.json", 'wb') as file: file.write(orjson.dumps(data)) def format_number(num, decimal=False): """Abbreviate large numbers with B/M suffix and format appropriately""" # Handle scientific notation formats like 5E6 if isinstance(num, str) and ('e' in num.lower() or 'E' in num.lower()): try: num = float(num) except ValueError: return num # Return as is if conversion fails # Convert strings to numbers if needed if isinstance(num, str): try: num = float(num) if num.is_integer(): num = int(num) except ValueError: return num # Return as is if conversion fails # Format based on size if num >= 1_000_000_000: # Billions formatted = num / 1_000_000_000 # Only show decimal places if needed return f"{formatted:.2f}B".rstrip('0').rstrip('.') + 'B' elif num >= 1_000_000: # Millions formatted = num / 1_000_000 # Only show decimal places if needed return f"{formatted:.2f}".rstrip('0').rstrip('.') + 'M' elif decimal and isinstance(num, float) and not num.is_integer(): return f"{num:,.2f}" else: return f"{num:,.0f}" # Format smaller numbers with commas def abbreviate_number(n): """ Abbreviate a number to a readable format. E.g., 1500 -> '1.5K', 2300000 -> '2.3M' """ if n is None: return "N/A" abs_n = abs(n) if abs_n < 1000: return str(n) elif abs_n < 1_000_000: return f"{n/1000:.1f}K" elif abs_n < 1_000_000_000: return f"{n/1_000_000:.1f}M" else: return f"{n/1_000_000_000:.1f}B" def remove_duplicates(elements): seen = set() unique_elements = [] for element in elements: if element['symbol'] not in seen: seen.add(element['symbol']) unique_elements.append(element) return unique_elements def weekday(): today = datetime.today() if today.weekday() >= 5: # 5 = Saturday, 6 = Sunday yesterday = today - timedelta(2) else: yesterday = today - timedelta(1) return yesterday.strftime('%Y-%m-%d') def dark_pool_flow(): try: with open(f"json/discord/dark_pool.json", "r") as file: seen_list = orjson.loads(file.read()) seen_list = [item for item in seen_list if datetime.fromisoformat(item['date']).date() == today] except: seen_list = [] with open(f"json/dark-pool/feed/data.json", "r") as file: res_list = orjson.loads(file.read()) res_list = [item for item in res_list if float(item['premium']) >= 100E6 and datetime.fromisoformat(item['date']).date() == today] if res_list: filtered_recent = [ item for item in res_list if (dt := datetime.fromisoformat(item['date'])) >= N_minutes_ago ] # If there are any recent orders, find the one with the highest premium if filtered_recent: best_order = max(filtered_recent, key=lambda x: x['premium']) result = {k: best_order[k] for k in ['date', 'trackingID', 'price', 'size', 'premium', 'ticker']} else: result = None # Or handle however you like (e.g., empty dict) if seen_list: seen_ids = {item['trackingID'] for item in seen_list} else: seen_ids = {} if result != None and result['trackingID'] not in seen_ids: symbol = result['ticker'] quantity = format_number(result['size']) price = result['price'] amount = format_number(result['premium']) message_timestamp = int((datetime.now() - timedelta(minutes=0)).timestamp()) embed = { "color": 0xC475FD, "thumbnail": {"url": "https://stocknear.com/pwa-64x64.png"}, "title": "Dark Pool Order", "fields": [ {"name": "Symbol", "value": symbol, "inline": True}, {"name": "", "value": "", "inline": True}, {"name": "Quantity", "value": str(quantity), "inline": True}, {"name": "Price", "value": str(price), "inline": True}, {"name": "", "value": "\u200B \u200B", "inline": True}, {"name": "Amount", "value": "$"+amount, "inline": True}, {"name": "", "value": "", "inline": False}, {"name": f"Data by Stocknear - - Delayed by 15 min.", "value": "", "inline": False} ], "footer": {"text": ""} } payload = { "content": "", "embeds": [embed] } response = requests.post(DARK_POOL_WEBHOOK_URL, json=payload) if response.status_code in (200, 204): seen_list.append({'date': result['date'], 'trackingID': result['trackingID']}) with open("json/discord/dark_pool.json","wb") as file: file.write(orjson.dumps(seen_list)) print("Embed sent successfully!") else: print(f"Failed to send embed. Status code: {response.status_code}") print("Response content:", response.text) else: print("Dark pool already sent!") def options_flow(): now_ny = datetime.now(ny_tz) N_minutes_ago = now_ny - timedelta(minutes=5) today = now_ny.date() # Load seen entries try: with open("json/discord/options_flow.json", "rb") as file: seen_list = orjson.loads(file.read()) today_iso = today.isoformat() seen_list = [item for item in seen_list if item['date'] == today_iso] except FileNotFoundError: seen_list = [] except Exception as e: print(f"Error loading seen list: {e}") seen_list = [] # Load current data try: with open("json/options-flow/feed/data.json", "rb") as file: res_list = orjson.loads(file.read()) except Exception as e: print(f"Error loading data.json: {e}") res_list = [] # Process and filter entries filtered = [] for item in res_list: try: # Validate required fields if float(item.get('cost_basis', 0)) < 1E5: continue item_date = datetime.fromisoformat(item['date']).date() if item_date != today: continue item_time = datetime.strptime(item['time'], "%H:%M:%S").time() item_dt = ny_tz.localize(datetime.combine(item_date, item_time)) if item_dt < N_minutes_ago: filtered.append(item) except Exception as e: print(f"Error processing item {item.get('id')}: {e}") continue if not filtered: print("No recent valid entries found") return # Find best order best_order = max(filtered, key=lambda x: float(x['cost_basis'])) result = { k: best_order[k] for k in [ 'date', 'sentiment', 'option_activity_type', 'ticker', 'id', 'strike_price', 'date_expiration', 'size', 'cost_basis', 'execution_estimate', 'volume', 'open_interest', 'put_call' ] } # Check duplicates seen_ids = {item['id'] for item in seen_list} if result['id'] in seen_ids: print("Options Flow data already sent!") return # Prepare message try: symbol = result['ticker'] size = format_number(result['size']) premium = format_number(result['cost_basis']) strike = result['strike_price'] side = result['execution_estimate'] volume = format_number(result['volume']) open_interest = format_number(result['open_interest']) put_call = result['put_call'].replace('Calls', 'Call').replace('Puts', 'Put') option_activity_type = result['option_activity_type'] sentiment = result['sentiment'] date_expiration = datetime.strptime(result['date_expiration'], "%Y-%m-%d").strftime("%d/%m/%Y") message_timestamp = int(now_ny.timestamp()) color = 0x39FF14 if sentiment == 'Bullish' else 0xFF0000 if sentiment == 'Bearish' else 0xFFA500 embed = { "color": color, "thumbnail": {"url": "https://stocknear.com/pwa-64x64.png"}, "description": f"{put_call} {option_activity_type} ({sentiment})", "fields": [ {"name": "Symbol", "value": symbol, "inline": True}, {"name": "Strike", "value": str(strike), "inline": True}, {"name": "Expiration", "value": date_expiration, "inline": True}, {"name": "Call/Put", "value": put_call, "inline": True}, {"name": "Side", "value": str(side), "inline": True}, {"name": "Size", "value": str(size), "inline": True}, {"name": "Premium", "value": f"${premium}", "inline": True}, {"name": "Volume", "value": str(volume), "inline": True}, {"name": "OI", "value": str(open_interest), "inline": True}, {"name": f"Data by Stocknear - - Delayed by 5 min", "value": "", "inline": False} ], "footer": {"text": ""} } payload = {"content": "", "embeds": [embed]} # Send to Discord response = requests.post(OPTIONS_FLOW_WEBHOOK_URL, json=payload) response.raise_for_status() # Update seen list seen_list.append({'date': result['date'], 'id': result['id']}) with open("json/discord/options_flow.json", "wb") as file: file.write(orjson.dumps(seen_list)) print("Embed sent successfully!") except Exception as e: print(f"Error sending message: {e}") def recent_earnings(): try: with open(f"json/discord/recent_earnings.json", "r") as file: seen_list = orjson.loads(file.read()) seen_list = [item for item in seen_list if datetime.fromisoformat(item['date']).date() == today] except: seen_list = [] with open(f"json/dashboard/data.json", 'rb') as file: data = orjson.loads(file.read())['recentEarnings'] res_list = [] for item in data: try: with open(f"json/quote/{item['symbol']}.json","r") as file: quote_data = orjson.loads(file.read()) item['price'] = round(quote_data.get('price',0),2) item['changesPercentage'] = round(quote_data.get('changesPercentage',0),2) item['marketCap'] = quote_data.get('marketCap',0) item['eps'] = round(quote_data.get('eps',0),2) unique_str = f"{item['date']}-{item['symbol']}" item['id'] = hashlib.md5(unique_str.encode()).hexdigest() res_list.append(item) except: pass print(res_list) if res_list: if seen_list: seen_ids = {item['id'] for item in seen_list} else: seen_ids = {} for item in res_list: try: if item != None and item['id'] not in seen_ids and item['marketCap']: symbol = item['symbol'] price = item['price'] changes_percentage = round(item['changesPercentage'],2) revenue = abbreviate_number(item['revenue']) revenue_surprise = abbreviate_number(item.get("revenueSurprise", 0)) eps = item['eps'] eps_surprise = item.get("epsSurprise", 0) revenue_surprise_text = "exceeds" if item["revenueSurprise"] > 0 else "misses" eps_surprise_text = "exceeds" if eps_surprise > 0 else "misses" market_cap = abbreviate_number(item['marketCap']) revenue_yoy_change = (item["revenue"] / item["revenuePrior"] - 1) * 100 revenue_yoy_direction = "decline" if (item["revenue"] / item["revenuePrior"] - 1) < 0 else "growth" eps_yoy_change = (item["eps"] / item["epsPrior"] - 1) * 100 eps_yoy_direction = "decline" if (item["eps"] / item["epsPrior"] - 1) < 0 else "growth" message_timestamp = int((datetime.now() - timedelta(minutes=0)).timestamp()) embed = { "color": 0xC475FD, "thumbnail": {"url": "https://stocknear.com/pwa-64x64.png"}, "title": "Earnings Surprise", "fields": [ {"name": "Symbol", "value": symbol, "inline": True}, {"name": "", "value": "", "inline": True}, {"name": "Market Cap", "value": market_cap, "inline": True}, {"name": "Price", "value": str(price), "inline": True}, {"name": "", "value": "", "inline": True}, {"name": "% Change", "value": str(changes_percentage)+"%", "inline": True}, {"name": "", "value": "", "inline": False}, {"name": f"Revenue of {revenue} {revenue_surprise_text} estimates by {revenue_surprise}, with {revenue_yoy_change:.2f}% YoY {revenue_yoy_direction}.", "value": "", "inline": False}, {"name": f"EPS of {eps} {eps_surprise_text} estimates by {eps_surprise}, with {eps_yoy_change:.2f}% YoY {eps_yoy_direction}.", "value": "", "inline": False}, {"name": f"Data by Stocknear - ", "value": "", "inline": False}, ], "footer": {"text": ""} } payload = { "content": "", "embeds": [embed] } #response = requests.post(RECENT_EARNINGS_WEBHOOK_URL, json=payload) if response.status_code in (200, 204): seen_list.append({'date': item['date'], 'id': item['id'], 'symbol': symbol}) print("Embed sent successfully!") else: print(f"Failed to send embed. Status code: {response.status_code}") print("Response content:", response.text) else: print("Earnings already sent!") except Exception as e: print(e) try: with open("json/discord/recent_earnings.json","wb") as file: file.write(orjson.dumps(seen_list)) except Exception as e: print(e) def executive_order_message(): try: with open(f"json/discord/executive_order.json", "r") as file: seen_list = orjson.loads(file.read()) seen_list = [item for item in seen_list if datetime.fromisoformat(item['date']).date() == today] except: seen_list = [] res_list = [] json_files = glob.glob("json/executive-orders/*.json") for filepath in json_files: try: file_id = os.path.basename(filepath) with open(filepath, "r") as file: # Load the JSON data from the file using orjson data = orjson.loads(file.read()) if datetime.fromisoformat(item['date']).date() == today: data['id'] = file_id.replace(".json","") res_list.append(data) except: pass if res_list: if seen_list: seen_ids = {item['id'] for item in seen_list} else: seen_ids = {} for item in res_list: try: if item['id'] not in seen_ids: title = item['title'] description = item['description'] date = item['date'] date = datetime.strptime(date, "%Y-%m-%d") date = date.strftime("%B %d, %Y") source = f"[Source]({item['link']})" message_timestamp = int((datetime.now() - timedelta(minutes=0)).timestamp()) embed = { "color": 0xFF0000, "thumbnail": {"url": "https://stocknear.com/pwa-64x64.png"}, "title": title, "description": f"Signed on {date}", "fields": [ {"name": "", "value": description, "inline": False}, {"name": "", "value": source, "inline": False}, {"name": f"Data by Stocknear - ", "value": "", "inline": False} ], "footer": {"text": ""} } payload = { "content": "", "embeds": [embed] } response = requests.post(EXECUTIVE_ORDER_WEBHOOK_URL, json=payload) if response.status_code in (200, 204): seen_list.append({'date': item['date'], 'id': item['id']}) with open("json/discord/executive_order.json","wb") as file: file.write(orjson.dumps(seen_list)) print("Embed sent successfully!") else: print(f"Failed to send embed. Status code: {response.status_code}") print("Response content:", response.text) else: print("Executive Order already sent!") except Exception as e: print(e) def analyst_report(): try: with open(f"json/discord/analyst_report.json", "r") as file: seen_list = orjson.loads(file.read()) seen_list = [item for item in seen_list if datetime.fromisoformat(item['date']).date() == today] except: seen_list = [] with open(f"json/dashboard/data.json", 'rb') as file: data = orjson.loads(file.read())['analystReport'] date_obj = datetime.strptime(data['date'], '%b %d, %Y') data['date'] = date_obj.strftime('%Y-%m-%d') if datetime.fromisoformat(data['date']).date() == today: if seen_list: seen_ids = {item['id'] for item in seen_list} else: seen_ids = {} if data['id'] not in seen_ids: symbol = data['symbol'] insight = data['insight'] message_timestamp = int((datetime.now() - timedelta(minutes=0)).timestamp()) with open(f"json/quote/{symbol}.json","r") as file: quote_data = orjson.loads(file.read()) market_cap = abbreviate_number(quote_data.get('marketCap',0)) eps = round(quote_data.get('eps',0),2) changes_percentage = round(quote_data.get('changesPercentage',0),2) summary = ( f"According to {data['numOfAnalyst']} analyst ratings, the average rating for {symbol} stock is '{data['consensusRating']}'. " f"The 12-month stock price forecast is {data['highPriceTarget']}, which is an " f"{'increase' if data['highPriceChange'] > 0 else 'decrease'} of {abs(data['highPriceChange'])}% from the latest price." ) embed = { "color": 0xFFA500, "thumbnail": {"url": "https://stocknear.com/pwa-64x64.png"}, "title": "", "fields": [ {"name": "Symbol", "value": symbol, "inline": True}, {"name": "", "value": "", "inline": True}, {"name": "Market Cap", "value": str(market_cap), "inline": True}, {"name": "EPS", "value": str(eps), "inline": True}, {"name": "", "value": "", "inline": True}, {"name": "% Change", "value": str(changes_percentage)+"%", "inline": True}, {"name": "Analyst Insight Report", "value": insight, "inline": False}, {"name": "", "value": summary, "inline": False}, {"name": f"Data by Stocknear - ", "value": "", "inline": False} ], "footer": {"text": ""} } payload = { "content": "", "embeds": [embed] } response = requests.post(ANALYST_REPORT_WEBHOOK_URL, json=payload) if response.status_code in (200, 204): seen_list.append({'date': data['date'], 'id': data['id']}) with open("json/discord/analyst_report.json","wb") as file: file.write(orjson.dumps(seen_list)) print("Embed sent successfully!") else: print(f"Failed to send embed. Status code: {response.status_code}") print("Response content:", response.text) else: print("Analyst Report already sent!") if __name__ == "__main__": #options_flow() #dark_pool_flow() recent_earnings() #executive_order_message() #analyst_report()