import numpy as np
import os
import csv
import secrets

from datetime import datetime
import calendar
import pprint
import time
import pandas as pd
from ubuntuFiles import PATH_UBUNTU
from flask import jsonify

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from multiprocessing import Pool, cpu_count



def obtener_Dias(estrategiaNumber):
    estrategia_archivo_map = {
        '1': 'IBData0940NoResults.csv',
        '2': 'IBData1030NoResults.csv',
        '3': 'IBData1100NoResults.csv',
        '4': 'IBData1130NoResults.csv',
        '5': 'IBData0932NoResults.csv',
        '6': 'IBData0933NoResults.csv',
        '7': 'ICData0932NoResults.csv',
        '8': 'ICData1030NoResults.csv',
        '9': 'ICData0933NoResults.csv',
        '10': 'ICData1031NoResults.csv',
        
    }
    archivo_csv = PATH_UBUNTU + estrategia_archivo_map[estrategiaNumber]
    df = pd.read_csv(archivo_csv, header=0, dtype=str)
    dfLista = df.columns.tolist()
    solo_Fechas = dfLista[0::4]
    print("todo ok")
    return solo_Fechas


def listaParaGrafico(fecha_str, estrategiaNumber, offset):

    # Obteniendo los strikes de los Iron Condors
    dfCabecera = ""

    if estrategiaNumber == '7' or estrategiaNumber == '8':
        # Convertir la fecha string a un objeto datetime
        fecha_objeto = datetime.strptime(fecha_str, "%m-%d-%Y")
        # Convertir el objeto datetime de nuevo a string en el formato deseado (yyyy/mm/dd)
        fecha_str_ic = fecha_objeto.strftime("%Y-%m-%d")
        preNombreArchivo = "Intraday_"
        # creando el nombre del archivo en base al dia
        if estrategiaNumber == '7':
            archivo_csv_IC = PATH_UBUNTU + preNombreArchivo + "IC0932_" + fecha_str_ic + ".csv"
        if estrategiaNumber == '8':
            archivo_csv_IC = PATH_UBUNTU + preNombreArchivo + "IC1030_" + fecha_str_ic + ".csv"
        print("archivo Intraday: ", archivo_csv_IC)
        dfCabecera = pd.read_csv(archivo_csv_IC, nrows=1, header=None)

    estrategia_archivo_map = {
        '1': 'IBData0940NoResults.csv',
        '2': 'IBData1030NoResults.csv',
        '3': 'IBData1100NoResults.csv',
        '4': 'IBData1130NoResults.csv',
        '5': 'IBData0932NoResults.csv',
        '6': 'IBData0933NoResults.csv',
        '7': 'ICData0932NoResults.csv',
        '8': 'ICData1030NoResults.csv'
    }

    archivo_csv = ""
    archivo_csv = PATH_UBUNTU + estrategia_archivo_map[estrategiaNumber]
    indice_fecha_especifica = 0
    fecha_str = fecha_str.replace("-", "/")
    df = pd.read_csv(archivo_csv, low_memory=False)

    dfLista = df.columns.tolist()
    solo_Fechas = dfLista[0::4]
    if fecha_str in solo_Fechas:
        indice_fecha_especifica = dfLista.index(fecha_str)

    cantidad_filas = df.iloc[:, indice_fecha_especifica].count()
    onlyDF = df.iloc[:cantidad_filas,
                     indice_fecha_especifica:indice_fecha_especifica+4]
    elprimero = onlyDF.iloc[0, 1] - offset
    onlyDF.iloc[:, 0] = onlyDF.iloc[:, 0].apply(
        lambda x: '0' + x if len(x) == 7 else x)
    onlyDF['P/L'] = elprimero - onlyDF.iloc[:, 1]
    onlyDF['P/L%'] = onlyDF.iloc[:, 4] / elprimero
    onlyDF['VIX%'] = onlyDF.iloc[:, 3] / 100

    return onlyDF, dfCabecera




def obtener_Datos(tp, sl, contracts, estrategiaNumber, offset, dollarOrPerc):

    data = []
    estrategia_info = {
        '1': {'archivo_csv': 'IBData0940NoResults.csv', 'HoraComienzo': '09:40:00'},
        '2': {'archivo_csv': 'IBData1030NoResults.csv', 'HoraComienzo': '10:30:00'},
        '3': {'archivo_csv': 'IBData1100NoResults.csv', 'HoraComienzo': '11:00:00'},
        '4': {'archivo_csv': 'IBData1130NoResults.csv', 'HoraComienzo': '11:30:00'},
        '5': {'archivo_csv': 'IBData0932NoResults.csv', 'HoraComienzo': '09:31:00'},
        '6': {'archivo_csv': 'IBData0933NoResults.csv', 'HoraComienzo': '09:31:00'},
        '7': {'archivo_csv': 'ICData0932NoResults.csv', 'HoraComienzo': '09:31:00'},
        '8': {'archivo_csv': 'ICData1030NoResults.csv', 'HoraComienzo': '10:30:00'},
        '9': {'archivo_csv': 'ICData0933NoResults.csv', 'HoraComienzo': '09:31:00'},
        '10': {'archivo_csv': 'ICData1031NoResults.csv', 'HoraComienzo': '10:30:00'},

    }

    estrategia = estrategia_info.get(estrategiaNumber)
    archivo_csv = PATH_UBUNTU + estrategia['archivo_csv']
    HoraComienzo = estrategia['HoraComienzo']

    df = pd.read_csv(archivo_csv, low_memory=False)
    dfLista = df.columns.tolist()
    solo_Fechas = dfLista[0::4]
    columna_indice = 0

    for fecha in solo_Fechas:
        cantidad_filas = df.iloc[:, columna_indice].count()
        onlyDF = df.iloc[0:cantidad_filas, columna_indice:columna_indice+3]

        diaSemana = calendar.day_name[datetime.strptime(
            fecha, "%m/%d/%Y").date().weekday()]  # obtiene el dia de la semana
        holiday = verificarFeriados(fecha)

        elprimero = onlyDF.iloc[0, 1] - offset
        onlyDF['P/L'] = elprimero - onlyDF.iloc[:, 1]
        onlyDF['P/L%'] = onlyDF.iloc[:, 3] / elprimero

        TPTime, SLTime, BadOrGood, credito, TPMinutes, SLMinutes, ProfitOrLossNoContracts, ocurrencias = goodOrBadDay(
            tp, sl, onlyDF, HoraComienzo, dollarOrPerc, offset)
        ProfitOrLoss = f"$ {float(ProfitOrLossNoContracts * contracts):.2f}"

        nuevos_datos = [fecha, diaSemana, holiday, TPTime, TPMinutes,
                        ocurrencias, SLTime, SLMinutes, credito, ProfitOrLoss, "", "", BadOrGood]
        data.append(nuevos_datos)
        columna_indice += 4



    return data


def goodOrBadDay(takeProfit, stopLoss, onlydf1, HoraComienzo, dollarOrPerc, offset):

    # Multiplica los valores por 100 si es en porcentaje
    multiplier = 100 if dollarOrPerc == "D" else 1
    takeProfit *= multiplier
    stopLoss *= multiplier

    # Busca la hora del 1er TP
    if dollarOrPerc == "P":
        fila_indiceTP = (onlydf1.iloc[:, 4] > takeProfit).idxmax()
    else:
        fila_indiceTP = (onlydf1.iloc[:, 3] > takeProfit).idxmax()

    HoraTP = onlydf1.iloc[fila_indiceTP, 0]

    # Busca la hora del 1er SL
    if dollarOrPerc == "P":
        fila_indiceSL = (onlydf1.iloc[:, 4] < stopLoss).idxmax()
    else:
        fila_indiceSL = (onlydf1.iloc[:, 3] < stopLoss).idxmax()

    HoraSL = onlydf1.iloc[fila_indiceSL, 0]

    # Busca el primer precio del IB, osea el credito otorgado
    credito = round(float(onlydf1.iloc[0, 1]), 2)-offset
    credito_formatted = f"$ {float(credito):.2f}"
    # Busca la cantidad de ocurrencias

    if fila_indiceSL == 0:
        fila_indiceSL = 999999

    if fila_indiceTP == 0:
        fila_indiceTP = 999999

    if dollarOrPerc == "P":
        countMayorATakeProfit = (onlydf1.iloc[:, 4] > takeProfit).sum()
        countParcialATakeProfift = (
            onlydf1.iloc[fila_indiceTP:fila_indiceSL, 4] > takeProfit).sum()
    else:
        countMayorATakeProfit = (onlydf1.iloc[:, 3] > takeProfit).sum()
        countParcialATakeProfift = (
            onlydf1.iloc[fila_indiceTP:fila_indiceSL, 3] > takeProfit).sum()

    occurrencias = str(countParcialATakeProfift) + \
        "/" + str(countMayorATakeProfit)

    TPMinutes = calcular_diferencia_horas(HoraTP, HoraComienzo)
    SLMinutes = calcular_diferencia_horas(HoraSL, HoraComienzo)

    if fila_indiceTP < fila_indiceSL:
        BadOrGood = "GOOD"
        if dollarOrPerc == "P":
            ProfitOrLoss = credito * takeProfit
        else:
            ProfitOrLoss = takeProfit
    else:
        BadOrGood = "BAD"
        if dollarOrPerc == "P":
            ProfitOrLoss = credito * stopLoss
        else:
            ProfitOrLoss = stopLoss

    if fila_indiceSL == 999999:
        BadOrGood = "GOOD"
        HoraSL = "-"
        if dollarOrPerc == "P":
            ProfitOrLoss = credito * takeProfit
        else:
            ProfitOrLoss = takeProfit

    if fila_indiceTP == 999999:
        BadOrGood = "BAD"
        HoraTP = "-"
        if dollarOrPerc == "P":
            ProfitOrLoss = credito * stopLoss
        else:
            ProfitOrLoss = stopLoss

    return HoraTP, HoraSL, BadOrGood, credito_formatted, TPMinutes, SLMinutes, ProfitOrLoss, occurrencias


def calcular_diferencia_horas(hora1_str, hora2_str):
    # Convertir las horas a objetos datetime
    hora1 = datetime.strptime(hora1_str, "%H:%M:%S")
    hora2 = datetime.strptime(hora2_str, "%H:%M:%S")
    # Calcular la diferencia entre las horas
    diferencia = hora1 - hora2

    # Obtener la diferencia en horas y minutos
    diferencia_horas = diferencia.seconds // 3600
    diferencia_minutos = (diferencia.seconds // 60) % 60

    # Formatear el resultado en formato "hh:mm"
    diferencia_str = "{:02d}:{:02d}".format(
        diferencia_horas, diferencia_minutos)

    if diferencia_str == "00:00":
        diferencia_str = "-"

    return diferencia_str


def verificarFeriados(fecha_verificar):
    archivo_csv = PATH_UBUNTU + "holidays.csv"
    df1 = pd.read_csv(archivo_csv, header=None)
    # Convertir la primera columna en datetime
    df1[0] = pd.to_datetime(df1[0])

    # Buscar la fecha en la columna de fechas
    mask = df1[0] == fecha_verificar
    if mask.any():
        # Si la fecha está en el DataFrame, obtener el valor de la segunda columna
        valor_columna_2 = df1.loc[mask, 1].values[0]
        return valor_columna_2
    else:
        # Si la fecha no se encuentra, devolver una cadena vacía
        return "No News"


def listaParaGraficoDiario(estrategiaNumber, offset):
    preNombreArchivo = "Intraday_"
    fecha_actual = datetime.now()
    postNombreArchivo = fecha_actual.strftime('%Y-%m-%d')
    archivo_csv = ""

    # creando el nombre del archivo en base al dia
    if estrategiaNumber == '1':
        archivo_csv = PATH_UBUNTU + preNombreArchivo + "IB0940_" + postNombreArchivo + ".csv"
    if estrategiaNumber == '2':
        archivo_csv = PATH_UBUNTU + preNombreArchivo + "IB1030_" + postNombreArchivo + ".csv"
    if estrategiaNumber == '3':
        archivo_csv = PATH_UBUNTU + preNombreArchivo + "IB1100_" + postNombreArchivo + ".csv"
    if estrategiaNumber == '4':
        archivo_csv = PATH_UBUNTU + preNombreArchivo + "IB1130_" + postNombreArchivo + ".csv"
    if estrategiaNumber == '5':
        archivo_csv = PATH_UBUNTU + preNombreArchivo + "IB0932_" + postNombreArchivo + ".csv"
    if estrategiaNumber == '6':
        archivo_csv = PATH_UBUNTU + preNombreArchivo + "IB0933_" + postNombreArchivo + ".csv"
    if estrategiaNumber == '7':
        archivo_csv = PATH_UBUNTU + preNombreArchivo + "IC0932_" + postNombreArchivo + ".csv"
    if estrategiaNumber == '8':
        archivo_csv = PATH_UBUNTU + preNombreArchivo + "IC1030_" + postNombreArchivo + ".csv"

    dfDatos = pd.read_csv(archivo_csv, skiprows=1, header=None)
    dfCabecera = pd.read_csv(archivo_csv, nrows=1, header=None)

    # dfDatos = pd.read_csv(archivo_csv, header=None)
    dfDatos[0] = dfDatos[0].str[-8:]

    elprimero = dfDatos.iloc[0, 1] - float(offset)

    dfDatos.iloc[:, 0] = dfDatos.iloc[:, 0].apply(
        lambda x: '0' + x if len(x) == 7 else x)

    dfDatos['P/L'] = elprimero - dfDatos.iloc[:, 1]
    dfDatos['P/L%'] = dfDatos.iloc[:, 5] / elprimero

    return dfDatos, dfCabecera


def listaComparativa(takeProfit1, takeProfit2, takeProfit3, takeProfit4, stopLoss1, stopLoss2, stopLoss3, stopLoss4, offset, contracts, miniComparative, IBList, dollarOrPercen):

    listaParcial1, listaCreditos1, TPMinutesParcial1, profitOrLoss1 = listaComparativaPorEstrategia(
        IBList[0], takeProfit1, stopLoss1, offset, contracts, miniComparative, dollarOrPercen)
    listaParcial2, listaCreditos2, TPMinutesParcial2, profitOrLoss2 = listaComparativaPorEstrategia(
        IBList[1], takeProfit2, stopLoss2, offset, contracts, miniComparative, dollarOrPercen)
    listaParcial3, listaCreditos3, TPMinutesParcial3, profitOrLoss3 = listaComparativaPorEstrategia(
        IBList[2], takeProfit3, stopLoss3, offset, contracts, miniComparative, dollarOrPercen)
    listaParcial4, listaCreditos4, TPMinutesParcial4, profitOrLoss4 = listaComparativaPorEstrategia(
        IBList[3], takeProfit4, stopLoss4, offset, contracts, miniComparative, dollarOrPercen)

    # para obtener las fechas. Se usa 1130 porque es la que tiene mas data
    archivo_csv = PATH_UBUNTU + 'IBData1130NoResults.csv'
    if miniComparative == 'true':
        df = pd.read_csv(archivo_csv, nrows=1, low_memory=False, usecols=range(100))
    else:
        df = pd.read_csv(archivo_csv, nrows=1, low_memory=False)

    dfLista = df.columns.tolist()
    listaFechas = dfLista[0::4]

    # para obtener los dias de noticias
    listaNews = []
    archivo_csv = PATH_UBUNTU + 'holidays.csv'
    for fecha in listaFechas:
        holiday = verificarFeriados(fecha)
        listaNews.append(holiday)

    return listaFechas, listaNews, listaParcial1, listaParcial2, listaParcial3, listaParcial4, listaCreditos1, listaCreditos2, listaCreditos3, listaCreditos4, TPMinutesParcial1, TPMinutesParcial2, TPMinutesParcial3, TPMinutesParcial4, profitOrLoss1, profitOrLoss2, profitOrLoss3, profitOrLoss4


def listaComparativaPorEstrategia(estrategiaNumber, takeProfit, stopLoss, offset, contracts, miniComparative, dollarOrPercen):
    estrategia_info = {
        '1': {'archivo_csv': 'IBData0940NoResults.csv', 'HoraComienzo': '09:40:00'},
        '2': {'archivo_csv': 'IBData1030NoResults.csv', 'HoraComienzo': '10:30:00'},
        '3': {'archivo_csv': 'IBData1100NoResults.csv', 'HoraComienzo': '11:00:00'},
        '4': {'archivo_csv': 'IBData1130NoResults.csv', 'HoraComienzo': '11:30:00'},
        '5': {'archivo_csv': 'IBData0932NoResults.csv', 'HoraComienzo': '09:31:00'},
        '6': {'archivo_csv': 'IBData0933NoResults.csv', 'HoraComienzo': '09:31:00'},


    }

    estrategia = estrategia_info.get(estrategiaNumber)
    archivo_csv = PATH_UBUNTU + estrategia['archivo_csv']
    HoraComienzo = estrategia['HoraComienzo']

    if miniComparative == 'true':
        df = pd.read_csv(archivo_csv, low_memory=False, usecols=range(100))
    else:
        df = pd.read_csv(archivo_csv, low_memory=False)

    listaparcial = []
    TPMinutesParcial = []
    profitOrLossParcial = []

    dfLista = df.columns.tolist()
    solo_Fechas = dfLista[0::4]
    creditoParcial = (df.iloc[0, 1::4]-offset).astype(int).tolist()

    columna_indice = 0
    for fecha in solo_Fechas:
        cantidad_filas = df.iloc[:, columna_indice].count()
        onlyDF = df.iloc[0:cantidad_filas, columna_indice:columna_indice+3]

        elprimero = onlyDF.iloc[0, 1] - offset
        onlyDF['P/L'] = elprimero - onlyDF.iloc[:, 1]
        onlyDF['P/L%'] = onlyDF.iloc[:, 3] / elprimero

        columna_indice += 4
        if dollarOrPercen == "P":
            indice_fila_TP = onlyDF.index[onlyDF['P/L%'] > takeProfit].min()
        else:
            indice_fila_TP = onlyDF.index[onlyDF['P/L'] > takeProfit].min()

        if np.isnan(indice_fila_TP):
            indice_fila_TP = 99999

        if dollarOrPercen == "P":
            indice_fila_SL = onlyDF.index[onlyDF['P/L%'] < stopLoss].min()
        else:
            indice_fila_SL = onlyDF.index[onlyDF['P/L'] < stopLoss].min()

        if np.isnan(indice_fila_SL):
            indice_fila_SL = 99999

        if indice_fila_TP < indice_fila_SL:
            listaparcial.append("G")
            HoraTP = onlyDF.iloc[indice_fila_TP, 0]
            TPMinutes = calcular_diferencia_horas(HoraTP, HoraComienzo)
            TPMinutesParcial.append(TPMinutes)

            if dollarOrPercen == "P":
                profitOrLoss = elprimero * float(takeProfit) * contracts
            else:
                profitOrLoss = takeProfit * contracts

            profitOrLossParcial.append("{:.2f}".format(profitOrLoss))
        else:
            listaparcial.append("B")
            TPMinutesParcial.append("")

            if dollarOrPercen == "P":
                profitOrLoss = elprimero * float(stopLoss) * contracts
            else:
                profitOrLoss = stopLoss * contracts

            profitOrLossParcial.append("{:.2f}".format(profitOrLoss))

    return listaparcial, creditoParcial, TPMinutesParcial, profitOrLossParcial








# CODIGO OPTIMIZADO POR CHAT GPT PARA LOS MAPAS DE CALOR - FUNCION getTotals y obtenerBestPair

def getTotals(takeProfit, stopLoss, credito_inicial, pl_array, plpct_array, dollarOrPerc):
    """
    Recibe:
        takeProfit, stopLoss: valores numéricos (ya convertidos según corresponda a D ó P).
        credito_inicial: float con el crédito inicial (elprimero - offset).
        pl_array: Series o array con la columna 'P/L' (ya calculada).
        plpct_array: Series o array con la columna 'P/L%' (ya calculada).
        dollarOrPerc: 'D' ó 'P'.

    Devuelve:
        (ProfitOrLoss, goodOrBad)
    """

    # Buscamos en la columna adecuada según sea D ó P
    if dollarOrPerc == "P":
        # plpct_array es la columna 4 en el código original
        # Necesitamos el primer índice donde plpct > TP y donde plpct < SL
        fila_indiceTP = (plpct_array > takeProfit).idxmax()
        fila_indiceSL = (plpct_array < stopLoss).idxmax()
    else:
        # pl_array es la columna 3 en el código original
        fila_indiceTP = (pl_array > takeProfit).idxmax()
        fila_indiceSL = (pl_array < stopLoss).idxmax()

    # Si no se encuentra un True en la serie booleana, idxmax() devolverá el primer índice (0).
    # Para distinguir un "no encontrado", podemos comprobar si en realidad no hubo True.
    # Sin embargo, el código original maneja esto poniendo 999999 si idxmax() sale 0.
    # Replicamos la misma lógica para no cambiar resultados.
    if fila_indiceSL == 0:
        fila_indiceSL = 999999
    if fila_indiceTP == 0:
        fila_indiceTP = 999999

    # Decidir si fue GOOD o BAD
    if fila_indiceTP < fila_indiceSL:
        goodOrBad = "GOOD"
        ProfitOrLoss = (credito_inicial * takeProfit) if (dollarOrPerc == "P") else takeProfit
    else:
        goodOrBad = "BAD"
        ProfitOrLoss = (credito_inicial * stopLoss) if (dollarOrPerc == "P") else stopLoss

    # Si ninguno se activó, el código original obliga a tomar el SL si TP = 999999, y viceversa.
    if fila_indiceSL == 999999:  # no hubo SL
        goodOrBad = "GOOD"
        ProfitOrLoss = (credito_inicial * takeProfit) if (dollarOrPerc == "P") else takeProfit

    if fila_indiceTP == 999999:  # no hubo TP
        goodOrBad = "BAD"
        ProfitOrLoss = (credito_inicial * stopLoss) if (dollarOrPerc == "P") else stopLoss

    return (ProfitOrLoss, goodOrBad)


def obtenerBestPair(
    estrategia, dollarOrPerc, newsDays, resultsIn, contracts, offset,
    sinceDate, untilDate, dayFilter
):
    estrategia_archivo_map = {
        '1': 'IBData0940NoResults.csv',
        '2': 'IBData1030NoResults.csv',
        '3': 'IBData1100NoResults.csv',
        '4': 'IBData1130NoResults.csv',
        '5': 'IBData0932NoResults.csv',
        '6': 'IBData0933NoResults.csv'
    }
    archivo_csv = PATH_UBUNTU + estrategia_archivo_map[estrategia]

    # Listas de TP y SL
    if dollarOrPerc == "P":
        listaTP = [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
        listaSL = [-5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -19]
    else:
        listaTP = [40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260, 280, 300, 320]
        listaSL = [-50, -70, -90, -110, -130, -150, -170, -190, -210, -230, -250, -270, -290, -310, -330]

    # Leemos las "holidays" (o "news days" según tu lógica)
    archivo_holidays = PATH_UBUNTU + "holidays.csv"
    df_holidays = pd.read_csv(archivo_holidays, header=None)
    set_de_fechas_holiday = set(df_holidays.iloc[:, 0].tolist())

    # Rango de fechas
    fecha_begin_obj = datetime.strptime(sinceDate, "%m/%d/%Y")
    fecha_end_obj = datetime.strptime(untilDate, "%m/%d/%Y")

    # Leemos el DataFrame ancho
    df = pd.read_csv(archivo_csv, low_memory=False)
    # Cada fecha está en las columnas 0,4,8,... => extraemos el nombre de columna
    solo_Fechas = df.columns.tolist()[0::4]

    # Prepara una estructura donde guardaremos la data de cada día que pase los filtros
    # para no tener que volver a filtrar en cada TP/SL.
    dias_validos_data = []

    # Recorremos cada "columna principal" asociada a una fecha
    for i, fecha_col_name in enumerate(solo_Fechas):
        fecha_obj = datetime.strptime(fecha_col_name, "%m/%d/%Y")
        # Filtro por rango de fechas
        if not (fecha_begin_obj <= fecha_obj <= fecha_end_obj):
            continue

        # Filtro por día de la semana
        # dayFilter: 0 = todos, 1 = lunes, 2 = martes, ...
        if dayFilter != 0:
            # weekday() => lunes=0, martes=1, ..., domingo=6
            # dayFilter=1 => lunes => weekday()==0
            if fecha_obj.weekday() != (dayFilter - 1):
                continue

        # Filtro por días con o sin noticias (holidays) según "newsDays"
        # Si newsDays = True => solo incluimos días que estén en set_de_fechas_holiday
        # Si newsDays = False => solo incluimos días NO en set_de_fechas_holiday
        esta_en_holiday = (fecha_col_name in set_de_fechas_holiday)
        if not newsDays and esta_en_holiday:
            continue
   

        # Extraemos el "chunk" de 4 columnas de ese día: c, c+1, c+2, c+3
        start_col = i * 4
        end_col = start_col + 3  # se incluye
        # Contamos cuántas filas válidas hay en la primera columna
        # (para no agarrar filas vacías al final)
        filas_validas = df.iloc[:, start_col].count()
        if filas_validas == 0:
            continue

        # Extraemos las filas válidas y las 4 columnas
        day_df = df.iloc[:filas_validas, start_col:(end_col + 1)].copy()
        # day_df tiene ahora 4 columnas (en posiciones 0..3)
        # en tu código original: onlyDF.iloc[:,1] se usa para "elprimero", etc.

        # Calculamos "elprimero" = day_df.iloc[0,1] - offset
        try:
            elprimero = float(day_df.iloc[0, 1]) - offset
        except:
            # Si por alguna razón está vacío o no se puede castear:
            continue

        # Si quieres filtrar por rango de crédito (en el código pones 0..999999)
        # Lo dejamos hardcodeado, aunque no parezca que cambie nada.
        if not (0 < elprimero < 999999):
            continue

        # Creamos las columnas P/L y P/L% dentro de este day_df,
        # tal cual en tu código original
        day_df["P/L"] = elprimero - day_df.iloc[:, 1]
        # OJO con day_df.iloc[:,3]: si no existiera, habría que adaptar. 
        # Asumiendo que la tercera columna (índice 2) es algo que usas en 'P/L%'.
        # Pero en el código que pasaste, pareciera que usabas day_df.iloc[:,3] 
        # (cuarta columna) para el cálculo. Ajusta según sea tu CSV real.
        #
        # En tu código: onlyDF['P/L%'] = onlyDF.iloc[:,3] / elprimero
        # => Significa que la columna 3 original (start_col+3) se divide entre elprimero.
        day_df["P/L%"] = day_df.iloc[:, 3] / elprimero

        # Guardamos en una estructura más ligera (arrays) para agilizar cálculos posteriores
        credito_inicial = round(elprimero, 2)
        pl_array = day_df["P/L"]
        plpct_array = day_df["P/L%"]

        # Añadimos a la lista de días válidos
        dias_validos_data.append({
            "fecha_str": fecha_col_name,
            "credito_inicial": credito_inicial,
            "pl_array": pl_array,
            "plpct_array": plpct_array
        })

    # ------------------------------------------------------------------
    # Una vez que tenemos todos los días filtrados, iteramos sobre (TP, SL)
    # y acumulamos resultados.
    # ------------------------------------------------------------------

    resultsList = []

    # Pre-convertimos TP y SL a valor “real” según si es D ó P (para ahorrar cálculos en bucle)
    # En tu código original multiplicas luego por 0.01 si es P.
    # Podemos hacerlo una sola vez.
    listaTP_convertida = []
    listaSL_convertida = []
    if dollarOrPerc == "P":
        for tp in listaTP:
            listaTP_convertida.append(tp * 0.01)
        for sl in listaSL:
            listaSL_convertida.append(sl * 0.01)
    else:
        # Si es en dólares, se queda igual
        listaTP_convertida = listaTP
        listaSL_convertida = listaSL

    # Para cada combinación de TP / SL, calculamos
    for tp1 in listaTP_convertida:
        for sl1 in listaSL_convertida:
            totalGOODs = 0
            totalBADs = 0
            sumGOODs = 0.0
            sumBADs = 0.0

            dataIB = []

            # Recorremos todos los días válidos
            for day_info in dias_validos_data:
                credito_inicial = day_info["credito_inicial"]
                pl_array = day_info["pl_array"]
                plpct_array = day_info["plpct_array"]

                profitOrLoss, goodOrBad = getTotals(
                    tp1, sl1, credito_inicial,
                    pl_array, plpct_array,
                    dollarOrPerc
                )

                if goodOrBad == "GOOD":
                    totalGOODs += 1
                    sumGOODs += profitOrLoss
                else:
                    totalBADs += 1
                    sumBADs += profitOrLoss

                # profitOrLoss * contracts
                dataIB.append(profitOrLoss * contracts)

            # Al finalizar todos los días, calculamos la métrica que pida `resultsIn`
            if resultsIn == 'EV':
                # expectationValue = ( ratio * aciertosPercent ) - erroresPercent
                # ratio = mediaGOODs / mediaBADs
                expectationValue = 0
                totalDias = totalGOODs + totalBADs
                if totalDias > 0:
                    aciertosPercent = totalGOODs / totalDias
                    erroresPercent = totalBADs / totalDias
                    mediaGOODs = (sumGOODs / totalGOODs) if totalGOODs > 0 else 0
                    mediaBADs = abs(sumBADs / totalBADs) if totalBADs > 0 else 0
                    ratio = (mediaGOODs / mediaBADs) if mediaBADs != 0 else 0
                    expectationValue = (ratio * aciertosPercent) - erroresPercent

                # Guardamos la tupla
                # Ojo que en la versión original guardabas los TP/SL “sin convertir” 
                # en la lista final. Si quieres mantener eso literal, usa 
                # la versión original (tp1, sl1, ...)
                # Si prefieres ver el TP/SL ya en la escala real, dejas tp1, sl1.
                # Aquí asumo que quieres el valor “original” (sin multiplicar), 
                # así que habría que invertir la lógica o simplemente 
                # construir la tupla con el valor no convertido.
                resultsList.append((tp1, sl1, expectationValue))
            else:
                # sum(dataIB)
                resultsList.append((tp1, sl1, sum(dataIB)))

    return resultsList


def obtener_datos_best_pair():
    # Lee el archivo CSV utilizando pandas
    archivo_csv = '/var/www/html/spxbutterflies/resultados.csv'
    try:

        df = pd.read_csv(archivo_csv)
    except FileNotFoundError:
        return jsonify({"error": "Archivo CSV no encontrado"})

    fecha_creacion = os.path.getctime(archivo_csv)
    fecha_formateada = datetime.fromtimestamp(
        fecha_creacion).strftime('%m/%d/%Y')

    # Convierte el DataFrame a un diccionario en formato JSON
    datos = df.to_dict(orient='records')
    # Agregar la fecha de creación al diccionario
    datos = {"fecha_creacion": fecha_formateada, "datos": datos}

    return jsonify(datos)


def registrar_log(user_id):
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    log_data = [user_id, timestamp]
    archivo_csv = '/var/www/html/spxbutterflies/static/data/ingresos.csv'
    # Escribe la información en el archivo CSV
    with open(archivo_csv, 'a', newline='') as csvfile:
        csv_writer = csv.writer(csvfile)
        csv_writer.writerow(log_data)


def send_email(subject, body, username, token, tipoEmail):
    # Configura tu servidor de correo electrónico y credenciales
    email_server = 'smtp.titan.email'
    email_port = 587
    email_username = 'info@spxbutterflies.com'
    email_password = 'Daleriver11$s'

    # Configura el correo electrónico
    sender_name = 'SPX Butterflies'
    sender_email = 'info@spxbutterflies.com'
    receiver_email = username

    message = MIMEMultipart()
    message['From'] = f'{sender_name} <{sender_email}>'
    message['To'] = receiver_email
    message['Subject'] = subject

    if tipoEmail == "ResetPassword":
        reset_password_link = f"https://spxbutterflies.com/reset_password?token={token}"
    if tipoEmail == "FreeTrial":
        #        reset_password_link = f"http://127.0.0.1:5000/validate_email?token={token}&username={username}"
        reset_password_link = f"https://spxbutterflies.com/validate_email?token={token}&username={username}"

    body_with_link = f"{body}\n{reset_password_link}"

    message.attach(MIMEText(body_with_link, 'plain'))

    # Conéctate al servidor de correo electrónico y envía el mensaje
    with smtplib.SMTP(email_server, email_port) as server:
        server.starttls()
        server.login(email_username, email_password)
        server.sendmail(sender_email, receiver_email, message.as_string())


def send_email_general(subject, firstName, lastName, receiptEmail, body):
    # Configura tu servidor de correo electrónico y credenciales
    email_server = 'smtp.titan.email'
    email_port = 587
    email_username = 'info@spxbutterflies.com'
    email_password = 'Daleriver11$s'

    # Configura el correo electrónico
    sender_name = firstName + " " + lastName
    sender_email = email_username
    receiver_email = receiptEmail

    message = MIMEMultipart()
    message['From'] = f'{sender_name} <{sender_email}>'
    message['To'] = receiver_email
    message['Subject'] = subject

    message.attach(MIMEText(body, 'plain'))

    # Conéctate al servidor de correo electrónico y envía el mensaje
    with smtplib.SMTP(email_server, email_port) as server:
        server.starttls()
        server.login(email_username, email_password)
        server.sendmail(sender_email, receiver_email, message.as_string())


def get_alert_data():
    archivo_csv = PATH_UBUNTU + "/alerts/alerts.csv"

    # Leer el contenido del archivo CSV y convertirlo a una lista de diccionarios
    with open(archivo_csv, 'r', newline='') as file:
        csv_reader = csv.DictReader(file)
        csv_data = list(csv_reader)

    # Devolver los datos como JSON
    return jsonify(csv_data)


def get_heatMapResultados():
    archivo_csv = PATH_UBUNTU + "/heatMapCharts/heatMapCharts.csv"

    # Leer el contenido del archivo CSV y convertirlo a una lista de diccionarios
    with open(archivo_csv, 'r', newline='') as file:
        csv_reader = csv.DictReader(file)
        csv_data = list(csv_reader)
    # Devolver los datos como JSON
    return jsonify(csv_data)


def get_boletinResultados():
    archivo_csv = PATH_UBUNTU + "/boletinReporte/boletinReporte.csv"
    # Leer el contenido del archivo CSV y convertirlo a una lista de diccionarios
    with open(archivo_csv, 'r', newline='', encoding='utf-8') as file:
        csv_reader = csv.DictReader(file)
        csv_data = list(csv_reader)
    # Devolver los datos como JSON
    return jsonify(csv_data), 200, {'Content-Type': 'application/json; charset=utf-8'}


def ICminiListaComparativa(takeProfit1, takeProfit2, takeProfit3, takeProfit4, stopLoss1, stopLoss2, stopLoss3, stopLoss4, offset, contracts, dollarOrPercen):

    listaParcial1 = ICminiListaComparativaPorEstrategia("1", takeProfit1, stopLoss1, offset, contracts, dollarOrPercen)
    listaParcial2 = ICminiListaComparativaPorEstrategia("2", takeProfit2, stopLoss2, offset, contracts, dollarOrPercen)
    listaParcial3 = ICminiListaComparativaPorEstrategia("3", takeProfit3, stopLoss3, offset, contracts, dollarOrPercen)
    listaParcial4 = ICminiListaComparativaPorEstrategia("4", takeProfit4, stopLoss4, offset, contracts, dollarOrPercen)

    # para obtener las fechas. Se usa 1130 porque es la que tiene mas data
    archivo_csv = PATH_UBUNTU + 'IBData1130NoResults.csv'
    df = pd.read_csv(archivo_csv, nrows=1, low_memory=False, usecols=range(100))

    dfLista = df.columns.tolist()
    listaFechas = dfLista[0::4]

    # para obtener los dias de noticias
    listaNews = []
    archivo_csv = PATH_UBUNTU + 'holidays.csv'
    for fecha in listaFechas:
        holiday = verificarFeriados(fecha)
        listaNews.append(holiday)

    return listaFechas, listaNews, listaParcial1, listaParcial2, listaParcial3, listaParcial4

def ICminiListaComparativaPorEstrategia(estrategiaNumber, takeProfit, stopLoss, offset, contracts, dollarOrPercen):
    estrategia_info = {
        '1': {'archivo_csv': 'ICData0932NoResults.csv', 'HoraComienzo': '09:31:00'},
        '2': {'archivo_csv': 'ICData1030NoResults.csv', 'HoraComienzo': '10:30:00'},
        '3': {'archivo_csv': 'ICData0933NoResults.csv', 'HoraComienzo': '09:31:00'},
        '4': {'archivo_csv': 'ICData1031NoResults.csv', 'HoraComienzo': '10:30:00'} 

    }

    estrategia = estrategia_info.get(estrategiaNumber)
    archivo_csv = PATH_UBUNTU + estrategia['archivo_csv']
    HoraComienzo = estrategia['HoraComienzo']


    df = pd.read_csv(archivo_csv, low_memory=False, usecols=range(100))

    listaparcial = []

    dfLista = df.columns.tolist()
    solo_Fechas = dfLista[0::4]

    columna_indice = 0
    for fecha in solo_Fechas:
        cantidad_filas = df.iloc[:, columna_indice].count()
        onlyDF = df.iloc[0:cantidad_filas, columna_indice:columna_indice+3]

        elprimero = onlyDF.iloc[0, 1] - offset
        onlyDF['P/L'] = elprimero - onlyDF.iloc[:, 1]
        onlyDF['P/L%'] = onlyDF.iloc[:, 3] / elprimero

        columna_indice += 4
        if dollarOrPercen == "P":
            indice_fila_TP = onlyDF.index[onlyDF['P/L%'] > takeProfit].min()
        else:
            indice_fila_TP = onlyDF.index[onlyDF['P/L'] > takeProfit].min()

        if np.isnan(indice_fila_TP):
            indice_fila_TP = 99999

        if dollarOrPercen == "P":
            indice_fila_SL = onlyDF.index[onlyDF['P/L%'] < stopLoss].min()
        else:
            indice_fila_SL = onlyDF.index[onlyDF['P/L'] < stopLoss].min()

        if np.isnan(indice_fila_SL):
            indice_fila_SL = 99999

        if indice_fila_TP < indice_fila_SL:
            listaparcial.append("G")

        else:
            listaparcial.append("B")


    return listaparcial