add options flow to discord bot
This commit is contained in:
parent
afc9ad884a
commit
1001cf4381
@ -1,27 +1,31 @@
|
||||
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}")
|
||||
|
||||
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"""
|
||||
@ -56,7 +60,7 @@ def format_number(num, decimal=False):
|
||||
return f"{num:,.0f}" # Format smaller numbers with commas
|
||||
|
||||
def dark_pool_flow():
|
||||
|
||||
|
||||
try:
|
||||
with open(f"json/discord/dark_pool.json", "r") as file:
|
||||
seen_list = orjson.loads(file.read())
|
||||
@ -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()
|
||||
Loading…
x
Reference in New Issue
Block a user