Rewrote main.py
This commit is contained in:
BIN
__pycache__/utils.cpython-313.pyc
Normal file
BIN
__pycache__/utils.cpython-313.pyc
Normal file
Binary file not shown.
35
main.py
35
main.py
@@ -1,23 +1,20 @@
|
|||||||
import sys
|
from utils import load_config, create_mqttc
|
||||||
|
from tastytrade import OAuthSession
|
||||||
|
from loguru import logger
|
||||||
|
from producers.sp500 import get_spx_market, stream_spx_greeks
|
||||||
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import tomllib
|
|
||||||
import paho.mqtt.client as paho
|
|
||||||
import time
|
|
||||||
from utils import load_config, authenticate
|
|
||||||
|
|
||||||
config = load_config()
|
config = load_config()
|
||||||
#client = paho.Client(paho.CallbackAPIVersion.VERSION2)
|
session = OAuthSession(config.tasty_trade.client_secret,config.tasty_trade.refresh_token)
|
||||||
#client.username_pw_set(username=config.mqtt.username,password=config.mqtt.password)
|
logger.info("Tasty Trade session instantiated")
|
||||||
|
|
||||||
#if client.connect("proliant.lan", 1883, 60) != 0:
|
async def main():
|
||||||
#print("Couldn't connect to the mqtt broker")
|
functions = [get_spx_market, stream_spx_greeks]
|
||||||
#sys.exit(1)
|
tasks = []
|
||||||
|
for function in functions:
|
||||||
|
task = asyncio.create_task(function(session))
|
||||||
|
tasks.append(task)
|
||||||
|
for task in tasks:
|
||||||
|
await task
|
||||||
|
|
||||||
|
asyncio.run(main())
|
||||||
#client.publish("SP500", json.dumps({"value":6349}), 0)
|
|
||||||
#time.sleep(0.5)
|
|
||||||
|
|
||||||
|
|
||||||
#client.disconnect()
|
|
||||||
|
|
||||||
authenticate()
|
|
||||||
|
|||||||
BIN
producers/__pycache__/sp500.cpython-313.pyc
Normal file
BIN
producers/__pycache__/sp500.cpython-313.pyc
Normal file
Binary file not shown.
@@ -0,0 +1,57 @@
|
|||||||
|
import asyncio
|
||||||
|
from tastytrade.dxfeed import Quote, Greeks
|
||||||
|
from datetime import date, timedelta
|
||||||
|
from tastytrade import instruments,DXLinkStreamer
|
||||||
|
from loguru import logger
|
||||||
|
from tastytrade.instruments import get_option_chain
|
||||||
|
import json
|
||||||
|
from utils import create_mqttc, load_config, parse_greek_event
|
||||||
|
market_subs_list = ["SPX"] # your subscription list, format per tastytrade docs
|
||||||
|
config = load_config()
|
||||||
|
async def get_spx_market(session):
|
||||||
|
mqttc = create_mqttc(config)
|
||||||
|
async with DXLinkStreamer(session) as streamer:
|
||||||
|
await streamer.subscribe(Quote, market_subs_list)
|
||||||
|
logger.info("Subscribed, streaming quotes... Press Ctrl+C to stop.")
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
quote = await streamer.get_event(Quote)
|
||||||
|
mqttc.publish("SP500",str((quote.ask_price+quote.bid_price)/2))
|
||||||
|
# or process/yield the quote as needed
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
logger.info("Streaming cancelled.")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async def stream_spx_greeks(session, days_out=30):
|
||||||
|
mqttc = create_mqttc(config)
|
||||||
|
# Fetch option chain (blocking → thread)
|
||||||
|
chain = await asyncio.to_thread(get_option_chain, session, "SPX")
|
||||||
|
|
||||||
|
cutoff = date.today() + timedelta(days=days_out)
|
||||||
|
option_symbols = [
|
||||||
|
opt.streamer_symbol
|
||||||
|
for exp_date, opts in chain.items()
|
||||||
|
if exp_date <= cutoff
|
||||||
|
for opt in opts
|
||||||
|
]
|
||||||
|
|
||||||
|
logger.info(f"Subscribing to {len(option_symbols)} SPX option contracts...")
|
||||||
|
|
||||||
|
async with DXLinkStreamer(session) as streamer:
|
||||||
|
# Here we pass the list as a single argument (no unpacking, no loop)
|
||||||
|
await streamer.subscribe(Greeks, option_symbols)
|
||||||
|
|
||||||
|
async for greek_event in streamer.listen(Greeks):
|
||||||
|
logger.info(f"Greek Event: {greek_event}")
|
||||||
|
mqttc.publish("SP500/oc",json.dumps(parse_greek_event(greek_event)))
|
||||||
|
|
||||||
|
def create_IV_histogram(mqttc):
|
||||||
|
mqttc.subscribe([("SP500",0),("SP500/oc",0)])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
5
rss-feed-notif/config.toml
Normal file
5
rss-feed-notif/config.toml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[mqtt]
|
||||||
|
user = "mqttuser"
|
||||||
|
password = "MWkWG42PX8Be5j87Q3Rk"
|
||||||
|
[rss-feeds]
|
||||||
|
nyt-feed = 'https://rss.nytimes.com/services/xml/rss/nyt/World.xml'
|
||||||
0
rss-feed-notif/main.py
Normal file
0
rss-feed-notif/main.py
Normal file
23
rss-feed-notif/rss-feed.py
Normal file
23
rss-feed-notif/rss-feed.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
from typing import List
|
||||||
|
import feedparser
|
||||||
|
import tomllib
|
||||||
|
import json
|
||||||
|
with open("config.toml","rb") as file:
|
||||||
|
config = tomllib.load(file)
|
||||||
|
print(config)
|
||||||
|
|
||||||
|
previous_msgs = set()
|
||||||
|
|
||||||
|
def read_rss_feeds(client):
|
||||||
|
for feed_name,feed_link in config["rss-feeds"].items():
|
||||||
|
feed = feedparser.parse(feed_link)
|
||||||
|
for feed_post in feed.entries:
|
||||||
|
if feed_post.title in previous_msgs:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
previous_msgs.add(feed_post.title)
|
||||||
|
notif_json = {"title":feed_post.title,"body":feed_post.description,"topic":"overlordian-news-192","link":feed_post.link}
|
||||||
|
client.publish("notification-pusher",json.dumps(notif_json),0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
112
utils.py
112
utils.py
@@ -1,5 +1,10 @@
|
|||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
import tomllib
|
import tomllib
|
||||||
|
import tastytrade
|
||||||
|
import re
|
||||||
|
import paho.mqtt.client as mqtt
|
||||||
|
from datetime import datetime
|
||||||
|
from loguru import logger
|
||||||
def dict_to_namedtuple(name, dictionary):
|
def dict_to_namedtuple(name, dictionary):
|
||||||
fields = {}
|
fields = {}
|
||||||
for key, value in dictionary.items():
|
for key, value in dictionary.items():
|
||||||
@@ -15,75 +20,48 @@ def load_config():
|
|||||||
config_dict = tomllib.load(f)
|
config_dict = tomllib.load(f)
|
||||||
config = dict_to_namedtuple("Config", config_dict)
|
config = dict_to_namedtuple("Config", config_dict)
|
||||||
return config
|
return config
|
||||||
import webbrowser
|
|
||||||
import requests
|
|
||||||
import threading
|
|
||||||
from flask import Flask, request
|
|
||||||
|
|
||||||
def authenticate(client_id, client_secret, scopes=None, port=5000):
|
def parse_event_symbol(symbol: str):
|
||||||
"""
|
symbol = symbol.lstrip('.')
|
||||||
Opens the browser for OAuth authorization and returns token data.
|
pattern = r"([A-Z]+)(\d{6})([CP])(\d+)"
|
||||||
|
match = re.match(pattern, symbol)
|
||||||
Args:
|
if not match:
|
||||||
client_id (str): Your Tastytrade client ID
|
return None
|
||||||
client_secret (str): Your Tastytrade client secret
|
underlying, exp_str, opt_type, strike_str = match.groups()
|
||||||
scopes (list[str]): Optional list of scopes (default: None)
|
expiration = datetime.strptime(exp_str, "%y%m%d").date()
|
||||||
port (int): Port for local callback server (default: 5000)
|
strike = int(strike_str) / 10
|
||||||
|
return {
|
||||||
Returns:
|
"underlying": underlying,
|
||||||
dict: Token response JSON (access_token, refresh_token, etc.)
|
"expiration": expiration.isoformat(),
|
||||||
"""
|
"option_type": opt_type,
|
||||||
redirect_uri = f"http://127.0.0.1:{port}/callback"
|
"strike": strike,
|
||||||
auth_url = "https://api.tastytrade.com/oauth/authorize"
|
|
||||||
token_url = "https://api.tastytrade.com/oauth/token"
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
auth_code_container = {}
|
|
||||||
|
|
||||||
@app.route("/callback")
|
|
||||||
def callback():
|
|
||||||
code = request.args.get("code")
|
|
||||||
auth_code_container["code"] = code
|
|
||||||
return "Authorization successful. You may close this window."
|
|
||||||
|
|
||||||
# Start local server in background
|
|
||||||
def run_server():
|
|
||||||
app.run(port=port, debug=False, use_reloader=False)
|
|
||||||
threading.Thread(target=run_server, daemon=True).start()
|
|
||||||
|
|
||||||
# Build auth URL
|
|
||||||
params = {
|
|
||||||
"response_type": "code",
|
|
||||||
"client_id": client_id,
|
|
||||||
"redirect_uri": redirect_uri
|
|
||||||
}
|
}
|
||||||
if scopes:
|
def create_mqttc(config):
|
||||||
params["scope"] = " ".join(scopes)
|
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
|
||||||
|
mqttc.username_pw_set(username=config.mqtt.user,password=config.mqtt.password)
|
||||||
|
mqttc.connect("proliant.lan",port=1883)
|
||||||
|
logger.info("MQTT client instantiated")
|
||||||
|
return mqttc
|
||||||
|
|
||||||
# Open browser
|
def parse_greek_event(greek_event):
|
||||||
webbrowser.open(f"{auth_url}?{requests.compat.urlencode(params)}")
|
# parse symbol details
|
||||||
|
parsed_symbol = parse_event_symbol(greek_event.event_symbol)
|
||||||
|
|
||||||
# Wait for code
|
# combine everything into one dict
|
||||||
print("Waiting for authorization...")
|
event_dict = {
|
||||||
while "code" not in auth_code_container:
|
**parsed_symbol,
|
||||||
pass
|
"event_time": greek_event.event_time,
|
||||||
|
"event_flags": greek_event.event_flags,
|
||||||
# Exchange code for token
|
"index": greek_event.index,
|
||||||
token_resp = requests.post(token_url, data={
|
"time": greek_event.time,
|
||||||
"grant_type": "authorization_code",
|
"sequence": greek_event.sequence,
|
||||||
"code": auth_code_container["code"],
|
"price": float(greek_event.price),
|
||||||
"redirect_uri": redirect_uri,
|
"volatility": float(greek_event.volatility),
|
||||||
"client_id": client_id,
|
"delta": float(greek_event.delta),
|
||||||
"client_secret": client_secret
|
"gamma": float(greek_event.gamma),
|
||||||
})
|
"theta": float(greek_event.theta),
|
||||||
token_resp.raise_for_status()
|
"rho": float(greek_event.rho),
|
||||||
|
"vega": float(greek_event.vega),
|
||||||
return token_resp.json()
|
}
|
||||||
|
|
||||||
# Example usage
|
|
||||||
if __name__ == "__main__":
|
|
||||||
client_id = "YOUR_CLIENT_ID"
|
|
||||||
client_secret = "YOUR_CLIENT_SECRET"
|
|
||||||
token_data = authenticate(client_id, client_secret, scopes=["accounts", "orders"])
|
|
||||||
print(token_data)
|
|
||||||
|
|
||||||
|
return event_dict
|
||||||
|
|||||||
Reference in New Issue
Block a user