add options flow to discord bot

This commit is contained in:
MuslemRahimi 2025-04-11 14:27:50 +02:00
parent afc9ad884a
commit 1001cf4381

View File

@ -1,26 +1,30 @@
import requests
import time
import orjson
from datetime import datetime, timedelta, timezone
from datetime import datetime, timedelta, timezone, date
import pytz
import os
from dotenv import load_dotenv
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)
WEBHOOK_URL = os.getenv("DISCORD_DARK_POOL_WEBHOOK")
DARK_POOL_WEBHOOK_URL = os.getenv("DISCORD_DARK_POOL_WEBHOOK")
OPTIONS_FLOW_WEBHOOK_URL = os.getenv("DISCORD_OPTIONS_FLOW_WEBHOOK")
def save_json(data):
directory = "json/discord"
try:
os.makedirs(directory, exist_ok=True)
with open(directory+"/dark_pool.json", 'wb') as file:
file.write(orjson.dumps(data))
except Exception as e:
print(f"An error occurred while saving data: {e}")
def format_number(num, decimal=False):
@ -118,7 +122,7 @@ def dark_pool_flow():
"embeds": [embed]
}
response = requests.post(WEBHOOK_URL, json=payload)
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']})
@ -133,5 +137,126 @@ def dark_pool_flow():
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 - <t:{message_timestamp}:R> - 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}")
if __name__ == "__main__":
options_flow()
dark_pool_flow()