import sys import time from typing import List from tabulate import tabulate from . import calc from .comparison import clone_context, compare_fair_values from .db import default_sql_query from .payoffs import PayoffContext def _prompt_with_default(prompt: str, default: str) -> str: value = input(prompt) return default if not value else value def _print_table(title: str, headers: List[str], rows: List[List[object]]) -> None: print() print(title) print(tabulate(rows, headers=headers, tablefmt="github")) def get_caso_string(airbag: int, sigma: int, relief: int, twinwin: int, onestar: int) -> str: componenti = [] if airbag == 1: componenti.append("Airbag") if sigma == 1: componenti.append("Sigma") if relief == 1: componenti.append("Relief") if twinwin == 1: componenti.append("TwinWin") if onestar == 1: componenti.append("OneStar") return " + ".join(componenti) if componenti else "Standard" def restart_or_exit(): print() print("Premere Invio per finire o R per riavviare il programma...") restart = input() if restart and restart.upper() == "R": main() else: sys.exit(0) def main(): version = "2.2 - [12/06/2025]" print(f"Pricer v.{version}") fs_db = default_sql_query() isin = _prompt_with_default("Inserire ISIN (default IT0006767633): ", "IT0006767633") check_isin = fs_db.check_isin(isin) if check_isin is not None: check_value = check_isin[0] if check_isin else None if check_value == "KO": print(f"ISIN {isin} non processabile!") print("Certificati nel pricer devono avere le seguenti caratteristiche : ") print("- Categoria: Coupon,StepUp,Bonus (con Barriera Discreta)") print("- Status: In Quotazione") print("- Direction: Long") print("- Basket Type : Worst") print("- Currency : EUR") print("- CedolaVariabile : FALSE") print("- Darwin : FALSE") print("- Domino : FALSE") print("- Magnet : FALSE") restart_or_exit() prezzi_eod = _prompt_with_default( "Num. Prezzi EOD per calcolo matrice correlazione e volatilita (default 252): ", "252" ) num_prezzi_eod = int(prezzi_eod) corr_matrix = calc.correl_certificates(isin, num_prezzi_eod, True) volatility = calc.volatility_certificates(isin, num_prezzi_eod, True) is_dividend = _prompt_with_default("Considerare i dividendi ? s/n (default s): ", "s") num_sims = int(_prompt_with_default("Inserire # simulazioni montecarlo (default = 10000) : ", "10000")) t_montecarlo_choice = time.perf_counter() details_ul_model = fs_db.get_details_ul(isin) nomi_sottostanti = [r.sottostante for r in details_ul_model] corr_rows = calc.array_to_table(corr_matrix, nomi_sottostanti) _print_table(f"Matrix Correl {isin}", nomi_sottostanti, corr_rows) details_ctf_model = fs_db.get_details_ctf(isin) details_event_model = fs_db.get_details_event(isin) details_event_exdate_model = fs_db.get_details_event_exdate(isin) ctf = details_ctf_model[0] tasso_interesse = ctf.tasso_interesse days_to_maturity = ctf.days_to_maturity pdi_style = ctf.pdi_style pdi_strike = ctf.pdi_strike pdi_barrier = round(ctf.pdi_barrier, 4) capital_value = ctf.capital_value nominal_amount = ctf.nominal_amount bid = ctf.bid ask = ctf.ask last_date_price = ctf.last_date_price coupon_in_memory = ctf.coupon_in_memory prot_min_val = ctf.prot_min_val airbag = ctf.air_bag fattore_airbag = ctf.fattore_airbag one_star = ctf.one_star trigger_onestar = round(ctf.trigger_onestar, 4) twin_win = ctf.twin_win sigma = ctf.sigma relief = ctf.relief domino = ctf.domino category = ctf.category cap = ctf.cap leva = ctf.leva prices_ul = [r.spot_price_normalized for r in details_ul_model] dividends = [r.dividend for r in details_ul_model] if is_dividend != "s": dividends = [0.0 for _ in dividends] num_sottostanti = len(details_ul_model) days_to_obs = [r.days_to_obs for r in details_event_model] days_to_ex_date = [r.days_to_ex_date for r in details_event_exdate_model] days_to_obs_y_fract = [r.days_to_obs_y_fract for r in details_event_model] coupon_values = [r.coupon_value for r in details_event_model] coupon_triggers = [r.coupon_trigger for r in details_event_model] autocall_values = [r.autocall_value for r in details_event_model] autocall_triggers = [r.autocall_trigger for r in details_event_model] memory_flags = [r.memory for r in details_event_model] num_eventi = len(details_event_model) input_ul_rows = [] for i in range(num_sottostanti): input_ul_rows.append( [ nomi_sottostanti[i], round(prices_ul[i], 4), round(dividends[i], 4), round(volatility[i], 4), ] ) _print_table( f"Dati Input Sottostanti {isin}", ["Sottostante", "Price", "Dividend", "Volatility"], input_ul_rows, ) input_ctf_rows = [ [ round(tasso_interesse, 4), days_to_maturity, pdi_style, pdi_barrier, round(capital_value * nominal_amount, 5), round(coupon_in_memory, 5), round(prot_min_val, 3), ] ] _print_table( f"Dati Input Certificato {isin}", [ "TassoInteresse", "DaysToMaturity", "PDI Style", "PDI Barrier", "Capital Value", "Coupon In Memoria", "Prot Min Val %", ], input_ctf_rows, ) input_flag_rows = [ [ airbag, round(fattore_airbag, 3), one_star, trigger_onestar, twin_win, sigma, relief, ] ] _print_table( f"Dati Input Flags {isin}", [ "AirBag", "Fattore Airbag", "OneStar", "TriggerOnestar", "TwinWin", "Sigma", "Relief", ], input_flag_rows, ) input_event_rows = [] for i in range(num_eventi): input_event_rows.append( [ days_to_obs[i], round(days_to_obs_y_fract[i], 4), round(coupon_values[i] * nominal_amount, 6), round(coupon_triggers[i], 6), round(autocall_values[i] * nominal_amount, 6), round(autocall_triggers[i], 6), memory_flags[i], ] ) _print_table( f"Dati Input Eventi {isin}", [ "DaysToObs.", "DaysToObsYFract", "Cpn. Value", "Cpn. Trigger", "Autoc. Value", "Autoc. Trigger", "Memory", ], input_event_rows, ) print("Elaborazione Fair value in corso...") context_original = PayoffContext( days_to_maturity=days_to_maturity, r=tasso_interesse, capital_value=capital_value, prot_min_val=prot_min_val, pdi_barrier=pdi_barrier, pdi_style=pdi_style, coupon_in_memory=coupon_in_memory, days_to_obs_y_fract=days_to_obs_y_fract, coupon_triggers=coupon_triggers, coupon_values=coupon_values, autocall_triggers=autocall_triggers, autocall_values=autocall_values, memory_flags=memory_flags, caso=get_caso_string(airbag, sigma, relief, twin_win, one_star), pdi_strike=pdi_strike, fattore_airbag=fattore_airbag, trigger_one_star=trigger_onestar, cap=cap, days_to_obs=days_to_obs, airbag=airbag, sigma=sigma, relief=relief, twin_win=twin_win, one_star=one_star, leva=leva, volatility=volatility, prices_ul=prices_ul, nominal_amount=nominal_amount, ) context_for_compare = clone_context(context_original) fvalues = calc.fair_value_array( prices_ul, corr_matrix, num_sottostanti, num_sims, tasso_interesse, days_to_maturity, dividends, volatility, days_to_obs, days_to_obs_y_fract, coupon_values, coupon_triggers, autocall_values, autocall_triggers, memory_flags, coupon_in_memory, pdi_style, pdi_strike, pdi_barrier, capital_value, prot_min_val, airbag, sigma, twin_win, relief, fattore_airbag, one_star, trigger_onestar, cap, leva, ).fair_value_array fv = [int(value * nominal_amount / 100) for value in fvalues] t_engine_choice = time.perf_counter() print(f"Tempo fino alla scelta del motore: {t_engine_choice - t_montecarlo_choice:.2f} sec") compare_fair_values( num_sims, prices_ul, corr_matrix, num_sottostanti, days_to_maturity, tasso_interesse, dividends, context_for_compare, nominal_amount, isin, ask, bid, last_date_price, category, ) t_expected_done = time.perf_counter() print(f"Tempo fino al valore atteso: {t_expected_done - t_engine_choice:.2f} sec") print("----------------------------------------") if len(days_to_ex_date) > len(days_to_obs): last_obs = days_to_obs[-1] last_ex = days_to_ex_date[-1] if last_obs < last_ex: print("ATTENZIONE: POSSIBILE SOTTOSTIMA DEL FAIR VALUE") print("\n Il calcolo del fair value presume che il coupon sia gia stato pagato,") print(" ma in realta non e ancora maturato (la Ex-Date non e ancora stata raggiunta).") print(" Il titolo incorpora ancora quel coupon nel suo prezzo, ma il pricer lo ha gia scontato.") print("\n Inoltre, se erano presenti coupon in memoria, questi sono stati azzerati nel calcolo,") print(" come se il pagamento fosse gia avvenuto.") print(" In realta il diritto al pagamento non e ancora stato acquisito.") print(" Questo comporta una POSSIBILE SOTTOSTIMA SIGNIFICATIVA del FAIR VALUE.") print("\n SUGGERIMENTO: verificare manualmente l'ultimo evento osservato") print(" e valutare l'impatto potenziale sul fair value atteso.") restart_or_exit()