import pandas as pd
import os

PATH_UBUNTU = "/var/www/html/flask_project/"
pd.set_option('display.max_rows', None)

symbol = "SPX"
estrategia = "Vertical"
desplazamiento = -5

# Ejemplo:
desde = "2025-04-28"  # Fecha inicial en formato 'YYYY-MM-DD'
lista_hasta = ["2025-05-01"]  # Fechas 'hastas' en formato 'YYYY-MM-DD'

# Archivo base para generar la lista de archivos por horarios
elArchivo = f"bola8/makekos/{symbol}/{symbol}_{estrategia}_strikes_0000.csv"

############################################################
# 1) Generar lista de archivos de incrementos de 5 min
############################################################
def generar_lista_archivos(base_archivo, start_hour=10, start_minute=5, end_hour=15):
    archivos = []
    prefix, _ = base_archivo.rsplit('_', 1)
    for hour in range(start_hour, end_hour + 1):
        for minute in range(0, 60, 5):
            if hour == start_hour and minute < start_minute:
                continue
            if hour == end_hour and minute > 0:
                break
            time_str = f"{hour:02}{minute:02}"
            archivo = f"{prefix}_{time_str}.csv"
            archivos.append(archivo)
    return archivos

############################################################
# 2) Funciones para calcular el crédito y Ganancia_Dia
############################################################
def calcular_credito_y_underlying_desde_archivo_csv(
    archivo_option_chain, strike1, strike2, option_type, time
):
    """
    Devuelve (credit, under_price_time)

    - credit EN PUNTOS (ej: 1.20) => significa $120 totales si multiplicamos * 100.
    - under_price_time es el subyacente en 'time' (no es el de cierre).
    """
    df = pd.read_csv(archivo_option_chain)
    df["timestamp"] = pd.to_datetime(df["timestamp"])
    df = df[df["timestamp"] >= time]
    if df.empty:
        return "No data found after the specified time", None

    df = df[df["strike"].isin([strike1, strike2])]
    if option_type == "PUT":
        df = df[["strike", "bid_put", "ask_put", "underlying_price"]]
    else:  # CALL
        df = df[["strike", "bid_call", "ask_call", "underlying_price"]]

    if df.empty:
        return "Strikes not found in the filtered data", None

    try:
        s1 = df[df["strike"] == strike1].iloc[0]
        s2 = df[df["strike"] == strike2].iloc[0]
    except:
        return 0, None

    if option_type == "PUT":
        s1_avg = (s1["bid_put"] + s1["ask_put"]) / 2
        s2_avg = (s2["bid_put"] + s2["ask_put"]) / 2
    else:  # CALL
        s1_avg = (s1["bid_call"] + s1["ask_call"]) / 2
        s2_avg = (s2["bid_call"] + s2["ask_call"]) / 2

    # credit en puntos, p.ej 1.20 => $120 si *100
    credit = s1_avg - s2_avg
    under_price = s1["underlying_price"]
    return credit, under_price

def obtener_ultimo_underlying_price(archivo_option_chain):
    try:
        df = pd.read_csv(archivo_option_chain)
        df["timestamp"] = pd.to_datetime(df["timestamp"])
        df.sort_values(by="timestamp", inplace=True)
        if "underlying_price" in df.columns:
            return df["underlying_price"].iloc[-1]
        return None
    except:
        return None

############################################################
# 3) Función para calcular Ganancia_Dia por cada fila
############################################################
def calcular_precios_verticales(vertical_strikes_df, path_base, desplazamiento, desde, hasta):
    if vertical_strikes_df.empty:
        return pd.DataFrame(), 0, 0, 0

    vertical_strikes_df["Day"] = pd.to_datetime(vertical_strikes_df["Day"])
    vertical_strikes_df = vertical_strikes_df[
        (vertical_strikes_df["Day"] >= pd.to_datetime(desde))
        & (vertical_strikes_df["Day"] <= pd.to_datetime(hasta))
    ].copy()

    if vertical_strikes_df.empty:
        return pd.DataFrame(), 0, 0, 0

    symbol = vertical_strikes_df["Symbol"].iloc[0]

    # Aplicar desplazamiento
    vertical_strikes_df["Strike1_Desplazado"] = vertical_strikes_df.apply(
        lambda row: row["Strike1"] + desplazamiento
        if row["Option_Type"] == "CALL"
        else row["Strike1"] - desplazamiento,
        axis=1,
    )
    vertical_strikes_df["Strike2_Desplazado"] = vertical_strikes_df.apply(
        lambda row: row["Strike2"] + desplazamiento
        if row["Option_Type"] == "CALL"
        else row["Strike2"] - desplazamiento,
        axis=1,
    )

    registros = []
    for _, fila in vertical_strikes_df.iterrows():
        day_str = pd.to_datetime(fila["Day"]).strftime("%Y-%m-%d")
        hour_str = fila["Hour"]
        s1 = fila["Strike1_Desplazado"]
        s2 = fila["Strike2_Desplazado"]
        opt_type = fila["Option_Type"]

        # Identificamos strikes de venta/compra
        if opt_type == "CALL":
            strike_venta = min(s1, s2)
            strike_compra = max(s1, s2)
        else:  # PUT
            strike_venta = max(s1, s2)
            strike_compra = min(s1, s2)

        if symbol in ["RUT", "XSP", "SPX"]:
            chain_file = path_base + f"chains/optionChain_${symbol}_{day_str}.csv"
        else:
            chain_file = path_base + f"chains/optionChain_{symbol}_{day_str}.csv"

        t_especifico = pd.to_datetime(f"{day_str} {hour_str}")
        try:
            # credit => en puntos, ej 1.20
            credit_points, under_price_time = calcular_credito_y_underlying_desde_archivo_csv(
                chain_file, s1, s2, opt_type, t_especifico
            )
        except FileNotFoundError:
            credit_points = "File not found"
            under_price_time = None

        # Precio de cierre
        try:
            underlying_price_16 = obtener_ultimo_underlying_price(chain_file)
        except:
            underlying_price_16 = None

        ganancia = None
        if (
            isinstance(credit_points, (int, float))
            and isinstance(under_price_time, (int, float))
            and (underlying_price_16 is not None)
        ):
            spread = abs(s1 - s2)  # en puntos
            if opt_type == "CALL":
                if underlying_price_16 > strike_compra:
                    # Subyacente > strike_compra => pierdes spread - credit
                    ganancia = (credit_points - spread) * 100
                elif underlying_price_16 < strike_venta:
                    # Subyacente < strike_venta => OTM => credit * 100
                    ganancia = credit_points * 100
                else:
                    # Entre strikes
                    valor_itm_points = (underlying_price_16 - strike_venta)
                    ganancia = (credit_points - valor_itm_points) * 100

            else:  # PUT
                if underlying_price_16 < strike_compra:
                    # Subyacente < strike_compra => pierdes spread - credit
                    ganancia = (credit_points - spread) * 100
                elif underlying_price_16 > strike_venta:
                    # Subyacente > strike_venta => credit total
                    ganancia = credit_points * 100
                else:
                    # Entre strikes => credit_points*100 - intrínseco
                    valor_itm_points = (strike_venta - underlying_price_16)
                    ganancia = (credit_points - valor_itm_points) * 100

        registros.append({"Day": day_str, "Hour": hour_str, "Ganancia_Dia": ganancia})

    df_out = pd.DataFrame(registros)
    if df_out.empty:
        return df_out, 0, 0, 0

    # Convertimos a numérico y redondeamos
    df_out["Ganancia_Dia"] = pd.to_numeric(df_out["Ganancia_Dia"], errors="coerce")
    df_out["Ganancia_Dia"] = df_out["Ganancia_Dia"].round(2)

    tot = df_out["Ganancia_Dia"].sum(skipna=True)
    dpos = df_out[df_out["Ganancia_Dia"] > 0].shape[0]
    dneg = df_out[df_out["Ganancia_Dia"] < 0].shape[0]

    return df_out, tot, dpos, dneg




############################################################
# 4) Lógica principal
############################################################

feriados = ["2025-02-17"]  # Agrega tus fechas aquí
lista_archivos = generar_lista_archivos(elArchivo)

for hasta in lista_hasta:
    out_csv = f"{symbol}_{estrategia}_{desde}_{hasta}_Desp{desplazamiento}_Rachas.csv"
    if os.path.exists(out_csv):
        os.remove(out_csv)

    all_results = pd.DataFrame(columns=["Day", "Hour", "Ganancia_Dia"])

    for archivo in lista_archivos:
        print(f"Procesando archivo: {archivo} para rango {desde} a {hasta}")
        path_completo = os.path.join(PATH_UBUNTU, archivo)
        if not os.path.exists(path_completo):
            print(f"No existe: {path_completo}")
            continue

        df_strikes = pd.read_csv(path_completo)
        df_strikes["Day"] = pd.to_datetime(df_strikes["Day"])

        # Filtrar rango de fechas
        df_strikes = df_strikes[
            (df_strikes["Day"] >= desde) & (df_strikes["Day"] <= hasta)
        ]
        if df_strikes.empty:
            continue

        df_gan, _, _, _ = calcular_precios_verticales(
            df_strikes, PATH_UBUNTU, desplazamiento, desde, hasta
        )

        # Filtrar DF con dropna
        df_gan.dropna(axis="columns", how="all", inplace=True)
        df_gan.dropna(axis="rows", how="all", inplace=True)

        if not df_gan.empty:
            df_gan = df_gan.reindex(columns=all_results.columns, fill_value=pd.NA)
            all_results = pd.concat([all_results, df_gan], ignore_index=True)

    if all_results.empty:
        print(f"Sin datos para {hasta}")
        continue

    # Ordenamos desc
    all_results["Day"] = pd.to_datetime(all_results["Day"])
    
    # Filtrar sábados, domingos y feriados
    all_results = all_results[
        (all_results["Day"].dt.dayofweek < 5) &  # 0=Lunes, 4=Viernes (excluye sábado y domingo)
        (~all_results["Day"].dt.strftime("%Y-%m-%d").isin(feriados))  # Excluye feriados
    ]

    all_results.sort_values(by="Day", ascending=False, inplace=True)

    # Lógica de rachas y creación de CSV, sin cambios
    negative_streak = {}
    horas_unicas = sorted(all_results["Hour"].unique())

    all_days_in_range = pd.date_range(start=desde, end=hasta)
    
    # Excluir sábados, domingos y feriados del rango de días
    day_strs = [
        d.strftime("%Y-%m-%d")
        for d in all_days_in_range
        if d.weekday() < 5 and d.strftime("%Y-%m-%d") not in feriados
    ]

    for hour in horas_unicas:
        df_hour = all_results[all_results["Hour"] == hour].sort_values(
            by="Day", ascending=False
        )
        streak = 0
        stop_racha = False
        day_profits = {ds: 0 for ds in day_strs}

        for _, row in df_hour.iterrows():
            d = row["Day"].strftime("%Y-%m-%d")
            val = row["Ganancia_Dia"]
            if pd.notnull(val):
                day_profits[d] = val
                if not stop_racha:
                    if val < 0:
                        streak += 1
                    else:
                        stop_racha = True
            else:
                day_profits[d] = 0

        negative_streak[hour] = {
            "streak": streak,
            "profits_by_day": day_profits,
        }

        cols = ["Hour", "Streak"] + day_strs[::-1]  # Invertimos el orden de los días
        with open(out_csv, "w") as f:
            f.write(",".join(cols) + "\n")
            for hour in sorted(negative_streak.keys()):
                row = [hour, str(negative_streak[hour]["streak"])]
                for ds in day_strs[::-1]:  # Iteramos en orden inverso
                    pv = negative_streak[hour]["profits_by_day"].get(ds, 0)
                    row.append(str(pv))
                f.write(",".join(row) + "\n")

        print(f"Rachas negativas guardadas en '{out_csv}'")





# ############################################################
# # 4) Lógica principal
# ############################################################

# lista_archivos = generar_lista_archivos(elArchivo)

# for hasta in lista_hasta:
#     out_csv = f"{symbol}_{estrategia}_{desde}_{hasta}_Desp{desplazamiento}_Rachas.csv"
#     if os.path.exists(out_csv):
#         os.remove(out_csv)

#     all_results = pd.DataFrame(columns=["Day", "Hour", "Ganancia_Dia"])

#     for archivo in lista_archivos:
#         print(f"Procesando archivo: {archivo} para rango {desde} a {hasta}")
#         path_completo = os.path.join(PATH_UBUNTU, archivo)
#         if not os.path.exists(path_completo):
#             print(f"No existe: {path_completo}")
#             continue

#         df_strikes = pd.read_csv(path_completo)
#         df_strikes["Day"] = pd.to_datetime(df_strikes["Day"])
#         df_strikes = df_strikes[
#             (df_strikes["Day"] >= desde) & (df_strikes["Day"] <= hasta)
#         ]
#         if df_strikes.empty:
#             continue

#         df_gan, _, _, _ = calcular_precios_verticales(
#             df_strikes, PATH_UBUNTU, desplazamiento, desde, hasta
#         )

#         # Filtrar DF con dropna
#         df_gan.dropna(axis="columns", how="all", inplace=True)
#         df_gan.dropna(axis="rows", how="all", inplace=True)

#         if not df_gan.empty:
#             df_gan = df_gan.reindex(columns=all_results.columns, fill_value=pd.NA)
#             all_results = pd.concat([all_results, df_gan], ignore_index=True)

#     if all_results.empty:
#         print(f"Sin datos para {hasta}")
#         continue

#     # Ordenamos desc
#     all_results["Day"] = pd.to_datetime(all_results["Day"])
#     all_results.sort_values(by="Day", ascending=False, inplace=True)

#     # Lógica de rachas y creación de CSV, sin cambios
#     negative_streak = {}
#     horas_unicas = sorted(all_results["Hour"].unique())

#     all_days_in_range = pd.date_range(start=desde, end=hasta)
#     day_strs = [d.strftime("%Y-%m-%d") for d in all_days_in_range]

#     for hour in horas_unicas:
#         df_hour = all_results[all_results["Hour"] == hour].sort_values(
#             by="Day", ascending=False
#         )
#         streak = 0
#         stop_racha = False
#         day_profits = {ds: 0 for ds in day_strs}

#         for _, row in df_hour.iterrows():
#             d = row["Day"].strftime("%Y-%m-%d")
#             val = row["Ganancia_Dia"]
#             if pd.notnull(val):
#                 day_profits[d] = val
#                 if not stop_racha:
#                     if val < 0:
#                         streak += 1
#                     else:
#                         stop_racha = True
#             else:
#                 day_profits[d] = 0

#         negative_streak[hour] = {
#             "streak": streak,
#             "profits_by_day": day_profits,
#         }

#         cols = ["Hour", "Streak"] + day_strs[::-1]  # Invertimos el orden de los días
#         with open(out_csv, "w") as f:
#             f.write(",".join(cols) + "\n")
#             for hour in sorted(negative_streak.keys()):
#                 row = [hour, str(negative_streak[hour]["streak"])]
#                 for ds in day_strs[::-1]:  # Iteramos en orden inverso
#                     pv = negative_streak[hour]["profits_by_day"].get(ds, 0)
#                     row.append(str(pv))
#                 f.write(",".join(row) + "\n")

#         print(f"Rachas negativas guardadas en '{out_csv}'")
