import pandas as pd
import os


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


symbol = "RUT"
estrategia = "Vertical"
desplazamiento = -5
desde = "2025-01-01"  # Fecha inicial en formato 'YYYY-MM-DD'
lista_hasta = ['2025-04-21'] # Fechas 'hastas' en formato 'YYYY-MM-DD' , 'YYYY-MM-DD'  

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


# Generar lista de archivos con incrementos de 5 minutos
def generar_lista_archivos(base_archivo, start_hour=10, start_minute=5, end_hour=16):
    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_desde_archivo_csv(archivo_option_chain, strike1, strike2, option_type, time):
    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

    strikes_data = filtered_chain[(filtered_chain['strike'].isin([strike1, strike2]))]

    if option_type == 'PUT':
        strikes_data = strikes_data[["strike", "bid_put", "ask_put", "underlying_price"]]
    elif option_type == 'CALL':
        strikes_data = strikes_data[["strike", "bid_call", "ask_call", "underlying_price"]]

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

    try:
        strike1_data = strikes_data[strikes_data['strike'] == strike1].iloc[0]
        strike2_data = strikes_data[strikes_data['strike'] == strike2].iloc[0]
    except:
        return 0,None


    # strike1_data = strikes_data[strikes_data['strike'] == strike1].iloc[0]
    # strike2_data = strikes_data[strikes_data['strike'] == strike2].iloc[0]

    if option_type == 'PUT':
        strike1_avg = (strike1_data['bid_put'] + strike1_data['ask_put']) / 2
        strike2_avg = (strike2_data['bid_put'] + strike2_data['ask_put']) / 2
    elif option_type == 'CALL':
        strike1_avg = (strike1_data['bid_call'] + strike1_data['ask_call']) / 2
        strike2_avg = (strike2_data['bid_call'] + strike2_data['ask_call']) / 2

    credit_received = strike1_avg - strike2_avg
    underlying_price = strike1_data['underlying_price']

    return credit_received, underlying_price


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

# Función para iterar sobre los días y calcular el crédito para cada vertical


def calcular_precios_verticales(vertical_strikes_df, path_csv_base, desplazamiento, desde, hasta):
    resultados = []
    symbol = vertical_strikes_df['Symbol'].iloc[0]

    # Filtrar el DataFrame de strikes para incluir solo las fechas dentro del rango
    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()

    # Aplicar el desplazamiento a los strikes según el tipo de opción usando .loc
    vertical_strikes_df.loc[:, '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.loc[:, 'Strike2_Desplazado'] = vertical_strikes_df.apply(
        lambda row: row['Strike2'] + desplazamiento if row['Option_Type'] == 'CALL' else row['Strike2'] - desplazamiento, axis=1
    )

    for index, row in vertical_strikes_df.iterrows():
        fecha = pd.to_datetime(row['Day']).strftime('%Y-%m-%d')
        hora = row['Hour']
        strike1 = row['Strike1_Desplazado']
        strike2 = row['Strike2_Desplazado']
        option_type = row['Option_Type']
        if option_type == 'CALL':
            strike_venta = min(strike1, strike2)
            strike_compra = max(strike1, strike2)
        elif option_type == 'PUT':
            strike_venta = max(strike1, strike2)
            strike_compra = min(strike1, strike2)

        specific_time = pd.to_datetime(f"{row['Day']} {hora}")

        # Lista de símbolos que deben llevar el prefijo "$"
        simbolos_con_dolar = {'SPX', 'RUT', 'XSP'}

        # Construcción de la ruta del archivo
        if symbol in simbolos_con_dolar:
            archivo_option_chain = f"{path_csv_base}chains/optionChain_${symbol}_{fecha}.csv"
        else:
            archivo_option_chain = f"{path_csv_base}chains/optionChain_{symbol}_{fecha}.csv"

        try:
            credit_result, underlying_price_specific_time = calcular_credito_y_underlying_desde_archivo_csv(archivo_option_chain, strike1, strike2, option_type, specific_time)
        except FileNotFoundError:
            credit_result = 'File not found'

        try:
            underlying_price_16 = obtener_ultimo_underlying_price(archivo_option_chain)
        except:
            underlying_price_16 = None

        spreadDiff = abs(strike1-strike2)
        if underlying_price_16 is not None and underlying_price_specific_time is not None:
            if option_type == 'CALL':
                if underlying_price_16 > strike_compra:
                    ganancia_dia = (credit_result - spreadDiff) * 100
                elif underlying_price_16 < strike_venta:
                    ganancia_dia = credit_result * 100
                else:
                    valor_itm = (underlying_price_16 - strike_venta) * 100
                    ganancia_dia = credit_result * 100 - valor_itm
            elif option_type == 'PUT':
                if underlying_price_16 < strike_compra:
                    ganancia_dia = (credit_result - spreadDiff) * 100
                elif underlying_price_16 > strike_venta:
                    ganancia_dia = credit_result * 100
                else:
                    valor_itm = (strike_venta - underlying_price_16) * 100
                    ganancia_dia = credit_result * 100 - valor_itm
        else:
            ganancia_dia = 'No calculable'

        resultados.append({
            'Day': fecha,
            'Time': hora,
            'Strike1_Desplazado': strike1,
            'Strike2_Desplazado': strike2,
            'Option_Type': option_type,
            'Credit_Received': credit_result,
            'Underlying_Price_16': underlying_price_16,
            '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: round(x, 2) if pd.notnull(x) else x)

    profit_total = resultados_df['Ganancia_Dia'].sum()
    dias_profit_positivo = resultados_df[resultados_df['Ganancia_Dia'] > 0].shape[0]
    dias_profit_negativo = resultados_df[resultados_df['Ganancia_Dia'] < 0].shape[0]

    return resultados_df, profit_total, dias_profit_positivo, dias_profit_negativo




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

# Iterar sobre cada fecha en `lista_hasta`
for hasta in lista_hasta:
    # Archivo CSV donde se guardarán los resultados para este rango
    output_csv = f"{symbol}_{estrategia}_{desde}_{hasta}_Desp{desplazamiento}.csv"

    # Si el archivo no existe, crear el archivo con encabezados
    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} para rango {desde} a {hasta}")  # 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_verticales, profit_total, dias_profit_positivo, dias_profit_negativo = calcular_precios_verticales(vertical_strikes_df, PATH_UBUNTU, desplazamiento, desde, hasta)

            # 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 para este rango
    print(f"Resultados guardados en '{output_csv}'")

