import pandas as pd
import os


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

DESPLAZAMIENTO = -5  # Ajusta este valor según sea necesario (positivo o negativo múltiplo de 5)

# Variables de rango de fechas
desde = "2025-02-01"  # Fecha inicial en formato 'YYYY-MM-DD'
hasta = "2025-03-22"  # Fecha final en formato 'YYYY-MM-DD'

symbol="SPX"
estrategia="Sonar"
# Archivo a cargar
elArchivo = 'bola8/makekos/' + symbol + '/' + symbol +'_' + estrategia + '_strikes_0000.csv'



def obtener_ultimo_underlying_price(archivo_option_chain):
    try:
        # Leer el archivo CSV
        option_chain_df = pd.read_csv(archivo_option_chain)

        # Asegurarse de que 'timestamp' sea de tipo datetime
        option_chain_df['timestamp'] = pd.to_datetime(option_chain_df['timestamp'])

        # Ordenar por timestamp para garantizar el último registro
        option_chain_df = option_chain_df.sort_values(by='timestamp')

        # Obtener el último precio del subyacente
        if 'underlying_price' in option_chain_df.columns:
            ultimo_underlying_price = option_chain_df['underlying_price'].iloc[-1]
            return ultimo_underlying_price
        else:
            return None

    except Exception as e:
        return None
    

# Generar lista de archivos con incrementos de 5 minutos
def generar_lista_archivos(base_archivo, start_hour=10, start_minute=5, end_hour=15):
    archivos = []
    prefix, _ = base_archivo.rsplit('_', 1)  # Separar el prefijo del archivo base
    for hour in range(start_hour, end_hour + 1):
        for minute in range(0, 60, 5):
            # Comenzar en 09:40
            if hour == start_hour and minute < start_minute:
                continue
            # Terminar en 15:00
            if hour == end_hour and minute > 0:
                break
            time_str = f"{hour:02}{minute:02}"  # Formato HHMM
            archivo = f"{prefix}_{time_str}.csv"
            archivos.append(archivo)
    return archivos

# Crear la lista de archivos
lista_archivos = generar_lista_archivos(elArchivo)


# Función para calcular el crédito recibido y el precio subyacente desde un archivo CSV
def calcular_credito_y_underlying_iron_condor(archivo_option_chain, strikes, time):
    """
    Calcula el crédito recibido para un iron condor y obtiene el precio subyacente.
    strikes: Diccionario con los 4 strikes (Call_Strike1, Call_Strike2, Put_Strike1, Put_Strike2).
    time: Tiempo de la operación en formato datetime.
    """

    # print(archivo_option_chain)
    option_chain_df = pd.read_csv(archivo_option_chain)
    option_chain_df['timestamp'] = pd.to_datetime(option_chain_df['timestamp'])
    filtered_chain = option_chain_df[option_chain_df['timestamp'] >= time]

    if filtered_chain.empty:
        return "No data found after the specified time", None, None, None
    
    # Filtrar datos para los strikes
    strikes_data = filtered_chain[
        filtered_chain['strike'].isin([strikes['Call_Strike1'], strikes['Call_Strike2'], strikes['Put_Strike1'], strikes['Put_Strike2']])
    ]
    
    if strikes_data.empty:
        return "Strikes not found in the filtered data", None, None, None
    
    # Calcular los valores promedio (bid + ask) / 2 para cada strike
    strike_values = {}
    for key, strike in strikes.items():
        strike_row = strikes_data[strikes_data['strike'] == strike]
        if key.startswith('Call'):
            strike_values[key] = ((strike_row['bid_call'].iloc[0] + strike_row['ask_call'].iloc[0]) / 2) if not strike_row.empty else None
        elif key.startswith('Put'):
            strike_values[key] = ((strike_row['bid_put'].iloc[0] + strike_row['ask_put'].iloc[0]) / 2) if not strike_row.empty else None
    

    # Calcular el crédito recibido por calls y puts
    credit_calls = strike_values['Call_Strike1'] - strike_values['Call_Strike2']
    credit_puts = strike_values['Put_Strike1'] - strike_values['Put_Strike2']
    
    # Crédito total recibido
    credit_received = credit_calls + credit_puts
    
    # Obtener el precio subyacente
    underlying_price = strikes_data['underlying_price'].iloc[0]
    
    return credit_received, underlying_price, credit_calls, credit_puts

# Función para calcular ganancia o pérdida del día
def calcular_ganancia_perdida_dia(credit_result, underlying_price_16, strikes):
    """
    Calcula la ganancia o pérdida del día para un Iron Condor.
    """
    if underlying_price_16 is None or credit_result is None:
        return 'No calculable'

    # Calcular diferencias entre strikes
    diferencia_strikes_put = strikes['Put_Strike1'] - strikes['Put_Strike2']
    diferencia_strikes_call = strikes['Call_Strike2'] - strikes['Call_Strike1']

    # Caso 1: Precio completamente fuera del rango (pérdida máxima)
    if underlying_price_16 < strikes['Put_Strike2'] or underlying_price_16 > strikes['Call_Strike2']:
        return (credit_result - max(diferencia_strikes_put, diferencia_strikes_call)) * 100

    # Caso 2: Precio completamente dentro del rango (ganancia máxima)
    if strikes['Put_Strike1'] <= underlying_price_16 <= strikes['Call_Strike1']:
        return credit_result * 100

    # Caso 3: Precio parcialmente ITM en la pierna PUT
    if strikes['Put_Strike2'] <= underlying_price_16 < strikes['Put_Strike1']:
        perdida_put = strikes['Put_Strike1'] - underlying_price_16
        return (credit_result - min(perdida_put, diferencia_strikes_put)) * 100

    # Caso 4: Precio parcialmente ITM en la pierna CALL
    if strikes['Call_Strike1'] < underlying_price_16 <= strikes['Call_Strike2']:
        perdida_call = underlying_price_16 - strikes['Call_Strike1']
        return (credit_result - min(perdida_call, diferencia_strikes_call)) * 100

    return 'No calculable'

# Función principal para manejar iron condor con desplazamiento
def calcular_precios_iron_condor(vertical_strikes_df, path_csv_base, desplazamiento):
    resultados = []
    symbol= vertical_strikes_df['Symbol'].iloc[0]

    for index, row in vertical_strikes_df.iterrows():
        fecha = pd.to_datetime(row['Day']).strftime('%Y-%m-%d')
        hora = row['Hour']
        
        # Ajustar los strikes con el desplazamiento
        strikes = {
            'Call_Strike1': row['Call_Strike1'] + desplazamiento,
            'Call_Strike2': row['Call_Strike2'] + desplazamiento,
            'Put_Strike1': row['Put_Strike1'] - desplazamiento,
            'Put_Strike2': row['Put_Strike2'] - desplazamiento
        }
        
        # Formatear los strikes en el formato XXXX/XXXX XXXX/XXXX
        strikes_formateados = f"{strikes['Call_Strike1']}/{strikes['Call_Strike2']} {strikes['Put_Strike1']}/{strikes['Put_Strike2']}"
        
        specific_time = pd.to_datetime(f"{row['Day']} {hora}")


        if symbol in ["RUT", "XSP", "SPX"]:
            archivo_option_chain = path_csv_base + "chains/optionChain_$" + symbol + '_' + fecha + ".csv"
        else:
            archivo_option_chain = path_csv_base + "chains/optionChain_" + symbol + '_' + fecha + ".csv"
        
        
        try:
            credit_result, _, credit_calls, credit_puts = calcular_credito_y_underlying_iron_condor(archivo_option_chain, strikes, specific_time)
        except FileNotFoundError:
            credit_result = 'File not found'
            credit_calls, credit_puts = None, None
        
        # specific_time_16 = pd.to_datetime(f"{row['Day']} 16:00:00")
        # try:
        #     credit_result_16, underlying_price_16, _, _ = calcular_credito_y_underlying_iron_condor(archivo_option_chain, strikes, specific_time_16)

        #     # if isinstance(credit_result_16, (int, float)) and credit_result_16 > 5.0:
        #     #     credit_result_16 = 5.0
        # except FileNotFoundError:
        #     credit_result_16 = 'File not found'
        #     underlying_price_16 = None


        try:
            underlying_price_16 = obtener_ultimo_underlying_price(archivo_option_chain)

        except FileNotFoundError:
            underlying_price_16 = None
        # Calcular ganancia o pérdida del día
        ganancia_dia = calcular_ganancia_perdida_dia(credit_result, underlying_price_16, strikes)
        
        resultados.append({
            'Day': fecha,
            'Time': hora,
            'Strikes': strikes_formateados,
            'Underlying_Price_16': underlying_price_16,
            'Credit_Received': credit_result,
            'Credit_Calls': credit_calls,
            'Credit_Puts': credit_puts,
            'Ganancia_Dia': ganancia_dia
        })
    
    resultados_df = pd.DataFrame(resultados)
    resultados_df['Ganancia_Dia'] = pd.to_numeric(resultados_df['Ganancia_Dia'], errors='coerce')
    resultados_df['Ganancia_Dia'] = resultados_df['Ganancia_Dia'].map(lambda x: f"{x:.2f}" if pd.notnull(x) else x)
    profit_total = resultados_df['Ganancia_Dia'].astype(float).sum()

    dias_profit_positivo = resultados_df[resultados_df['Ganancia_Dia'].astype(float) > 0].shape[0]
    dias_profit_negativo = resultados_df[resultados_df['Ganancia_Dia'].astype(float) < 0].shape[0]

    return resultados_df, profit_total, dias_profit_positivo, dias_profit_negativo


# Crear una lista para almacenar los resultados de cada archivo
resultados_totales = []

# Iterar sobre la lista de archivos generada

# Archivo CSV donde se guardarán los resultados
# output_csv = 'resultados_totales.csv'
output_csv = f"{symbol}_{estrategia}_{desde}_{hasta}_Desp{DESPLAZAMIENTO}.csv"

# Si el archivo no existe, crear el archivo con encabezados
if not os.path.exists(output_csv):
    with open(output_csv, 'w') as f:
        f.write('Hour,Profit_Total,Días_Profit_Positivo,Días_Profit_Negativo,Win_Rate,Desplazamiento\n')

# Iterar sobre la lista de archivos generada
for archivo in lista_archivos:
    print(f"Procesando archivo: {archivo}")  # Mostrar progreso

    try:
        # Cargar archivo con strikes
        vertical_strikes_df = pd.read_csv(PATH_UBUNTU + archivo)

        # Convertir a datetime y filtrar por rango de fechas
        vertical_strikes_df['Day'] = pd.to_datetime(vertical_strikes_df['Day'])
        vertical_strikes_df = vertical_strikes_df[(vertical_strikes_df['Day'] >= desde) & (vertical_strikes_df['Day'] <= hasta)]

        # Llamar a la función con el desplazamiento
        resultados_iron_condor, profit_total, dias_profit_positivo, dias_profit_negativo = calcular_precios_iron_condor(
            vertical_strikes_df, PATH_UBUNTU, desplazamiento=DESPLAZAMIENTO
        )

        # Calcular el número total de días
        total_dias = dias_profit_positivo + dias_profit_negativo

        # Calcular el Win Rate
        if total_dias > 0:
            win_rate = (dias_profit_positivo / total_dias) * 100
        else:
            win_rate = 0.0

        # Extraer la hora del nombre del archivo
        hour = archivo.split('_')[-1].replace('.csv', '')

        # Escribir los resultados en el archivo CSV
        with open(output_csv, 'a') as f:
            f.write(f"{hour},{profit_total:.2f},{dias_profit_positivo},{dias_profit_negativo},{win_rate:.2f},{DESPLAZAMIENTO}\n")

    except FileNotFoundError:
        print(f"Archivo no encontrado: {archivo}")
    except Exception as e:
        print(f"Error procesando archivo {archivo}: {e}")

# Mostrar mensaje final
print(f"Resultados guardados en '{output_csv}'")
