My Mia stopped responding my question on the chat, so I'm just simply posting my request here:

rewrite my code here so it can be run on quantconnect, the trade will be placed once all criteria met (recommend) will be a long put calendar. Also write a screener for potential canddiate that is a recommend:

 

"""
DISCLAIMER:

This software is provided solely for educational and research purposes. 
It is not intended to provide investment advice, and no investment recommendations are made herein. 
The developers are not financial advisors and accept no responsibility for any financial decisions or losses resulting from the use of this software. 
Always consult a professional financial advisor before making any investment decisions.
"""


import FreeSimpleGUI as sg
import yfinance as yf
from datetime import datetime, timedelta
from scipy.interpolate import interp1d
import numpy as np
import threading


def filter_dates(dates):
   today = datetime.today().date()
   cutoff_date = today + timedelta(days=45)
   
   sorted_dates = sorted(datetime.strptime(date, "%Y-%m-%d").date() for date in dates)

   arr = []
   for i, date in enumerate(sorted_dates):
       if date >= cutoff_date:
           arr = [d.strftime("%Y-%m-%d") for d in sorted_dates[:i+1]]  
           break
   
   if len(arr) > 0:
       if arr[0] == today.strftime("%Y-%m-%d"):
           return arr[1:]
       return arr

   raise ValueError("No date 45 days or more in the future found.")


def yang_zhang(price_data, window=30, trading_periods=252, return_last_only=True):
   log_ho = (price_data['High'] / price_data['Open']).apply(np.log)
   log_lo = (price_data['Low'] / price_data['Open']).apply(np.log)
   log_co = (price_data['Close'] / price_data['Open']).apply(np.log)
   
   log_oc = (price_data['Open'] / price_data['Close'].shift(1)).apply(np.log)
   log_oc_sq = log_oc**2
   
   log_cc = (price_data['Close'] / price_data['Close'].shift(1)).apply(np.log)
   log_cc_sq = log_cc**2
   
   rs = log_ho * (log_ho - log_co) + log_lo * (log_lo - log_co)
   
   close_vol = log_cc_sq.rolling(
       window=window,
       center=False
   ).sum() * (1.0 / (window - 1.0))

   open_vol = log_oc_sq.rolling(
       window=window,
       center=False
   ).sum() * (1.0 / (window - 1.0))

   window_rs = rs.rolling(
       window=window,
       center=False
   ).sum() * (1.0 / (window - 1.0))

   k = 0.34 / (1.34 + ((window + 1) / (window - 1)) )
   result = (open_vol + k * close_vol + (1 - k) * window_rs).apply(np.sqrt) * np.sqrt(trading_periods)

   if return_last_only:
       return result.iloc[-1]
   else:
       return result.dropna()
   

def build_term_structure(days, ivs):
   days = np.array(days)
   ivs = np.array(ivs)

   sort_idx = days.argsort()
   days = days[sort_idx]
   ivs = ivs[sort_idx]


   spline = interp1d(days, ivs, kind='linear', fill_value="extrapolate")

   def term_spline(dte):
       if dte < days[0]:  
           return ivs[0]
       elif dte > days[-1]:
           return ivs[-1]
       else:  
           return float(spline(dte))

   return term_spline

def get_current_price(ticker):
   todays_data = ticker.history(period='1d')
   return todays_data['Close'][0]

def compute_recommendation(ticker):
   try:
       ticker = ticker.strip().upper()
       if not ticker:
           return "No stock symbol provided."
       
       try:
           stock = yf.Ticker(ticker)
           if len(stock.options) == 0:
               raise KeyError()
       except KeyError:
           return f"Error: No options found for stock symbol '{ticker}'."
       
       exp_dates = list(stock.options)
       try:
           exp_dates = filter_dates(exp_dates)
       except:
           return "Error: Not enough option data."
       
       options_chains = {}
       for exp_date in exp_dates:
           options_chains[exp_date] = stock.option_chain(exp_date)
       
       try:
           underlying_price = get_current_price(stock)
           if underlying_price is None:
               raise ValueError("No market price found.")
       except Exception:
           return "Error: Unable to retrieve underlying stock price."
       
       atm_iv = {}
       straddle = None 
       i = 0
       for exp_date, chain in options_chains.items():
           calls = chain.calls
           puts = chain.puts

           if calls.empty or puts.empty:
               continue

           call_diffs = (calls['strike'] - underlying_price).abs()
           call_idx = call_diffs.idxmin()
           call_iv = calls.loc[call_idx, 'impliedVolatility']

           put_diffs = (puts['strike'] - underlying_price).abs()
           put_idx = put_diffs.idxmin()
           put_iv = puts.loc[put_idx, 'impliedVolatility']

           atm_iv_value = (call_iv + put_iv) / 2.0
           atm_iv[exp_date] = atm_iv_value

           if i == 0:
               call_bid = calls.loc[call_idx, 'bid']
               call_ask = calls.loc[call_idx, 'ask']
               put_bid = puts.loc[put_idx, 'bid']
               put_ask = puts.loc[put_idx, 'ask']
               
               if call_bid is not None and call_ask is not None:
                   call_mid = (call_bid + call_ask) / 2.0
               else:
                   call_mid = None

               if put_bid is not None and put_ask is not None:
                   put_mid = (put_bid + put_ask) / 2.0
               else:
                   put_mid = None

               if call_mid is not None and put_mid is not None:
                   straddle = (call_mid + put_mid)

           i += 1
       
       if not atm_iv:
           return "Error: Could not determine ATM IV for any expiration dates."
       
       today = datetime.today().date()
       dtes = []
       ivs = []
       for exp_date, iv in atm_iv.items():
           exp_date_obj = datetime.strptime(exp_date, "%Y-%m-%d").date()
           days_to_expiry = (exp_date_obj - today).days
           dtes.append(days_to_expiry)
           ivs.append(iv)
       
       term_spline = build_term_structure(dtes, ivs)
       
       ts_slope_0_45 = (term_spline(45) - term_spline(dtes[0])) / (45-dtes[0])
       
       price_history = stock.history(period='3mo')
       iv30_rv30 = term_spline(30) / yang_zhang(price_history)

       avg_volume = price_history['Volume'].rolling(30).mean().dropna().iloc[-1]

       expected_move = str(round(straddle / underlying_price * 100,2)) + "%" if straddle else None

       return {'avg_volume': avg_volume >= 1500000, 'iv30_rv30': iv30_rv30 >= 1.25, 'ts_slope_0_45': ts_slope_0_45 <= -0.00406, 'expected_move': expected_move} #Check that they are in our desired range (see video)
   except Exception as e:
       raise Exception(f'Error occured processing')
       

   

def main_gui():
   main_layout = [
       [sg.Text("Enter Stock Symbol:"), sg.Input(key="stock", size=(20, 1), focus=True)],
       [sg.Button("Submit", bind_return_key=True), sg.Button("Exit")],
       [sg.Text("", key="recommendation", size=(50, 1))]
   ]
   
   window = sg.Window("Earnings Position Checker", main_layout)
   
   while True:
       event, values = window.read()
       if event in (sg.WINDOW_CLOSED, "Exit"):
           break

       if event == "Submit":
           window["recommendation"].update("")
           stock = values.get("stock", "")

           loading_layout = [[sg.Text("Loading...", key="loading", justification="center")]]
           loading_window = sg.Window("Loading", loading_layout, modal=True, finalize=True, size=(275, 200))

           result_holder = {}

           def worker():
               try:
                   result = compute_recommendation(stock)
                   result_holder['result'] = result
               except Exception as e:
                   result_holder['error'] = str(e)

           thread = threading.Thread(target=worker, daemon=True)
           thread.start()

           while thread.is_alive():
               event_load, _ = loading_window.read(timeout=100)
               if event_load == sg.WINDOW_CLOSED:
                   break
           thread.join(timeout=1)

           if 'error' in result_holder:
               loading_window.close()
               window["recommendation"].update(f"Error: {result_holder['error']}")
           elif 'result' in result_holder:
               loading_window.close()
               result = result_holder['result']

               avg_volume_bool    = result['avg_volume']
               iv30_rv30_bool     = result['iv30_rv30']
               ts_slope_bool      = result['ts_slope_0_45']
               expected_move      = result['expected_move']
               
               if avg_volume_bool and iv30_rv30_bool and ts_slope_bool:
                   title = "Recommended"
                   title_color = "#006600"
               elif ts_slope_bool and ((avg_volume_bool and not iv30_rv30_bool) or (iv30_rv30_bool and not avg_volume_bool)):
                   title = "Consider"
                   title_color = "#ff9900"
               else:
                   title = "Avoid"
                   title_color = "#800000"
               
               result_layout = [
                   [sg.Text(title, text_color=title_color, font=("Helvetica", 16))],
                   [sg.Text(f"avg_volume: {'PASS' if avg_volume_bool else 'FAIL'}", text_color="#006600" if avg_volume_bool else "#800000")],
                   [sg.Text(f"iv30_rv30: {'PASS' if iv30_rv30_bool else 'FAIL'}", text_color="#006600" if iv30_rv30_bool else "#800000")],
                   [sg.Text(f"ts_slope_0_45: {'PASS' if ts_slope_bool else 'FAIL'}", text_color="#006600" if ts_slope_bool else "#800000")],
                   [sg.Text(f"Expected Move: {expected_move}", text_color="blue")],
                   [sg.Button("OK")]
               ]
               
               result_window = sg.Window("Recommendation", result_layout, modal=True, finalize=True, size=(275, 200))
               while True:
                   event_result, _ = result_window.read(timeout=100)
                   if event_result in (sg.WINDOW_CLOSED, "OK"):
                       break
               result_window.close()
   
   window.close()

def gui():
   main_gui()

if __name__ == "__main__":
   gui()