import MetaTrader5 as mt5
from MetaTrader5 import *
import numpy as np
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score  # Import r2_score
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.regularizers import l2
from sklearn.model_selection import KFold
import time
import random
import pandas as pd
from datetime import datetime, timedelta
# display data on the MetaTrader 5 package

 

# connect to the trade account without specifying a password and a server

account=xxx#input("Enter you account number: ")
clave_secreta="xxxxxxxxxxxxxxx"#input("Enter you password: ")
server_account="xxxxxxx"#input("Enter the server for the account: ")

delay_1=900#input("Please enter the delay of days from where to get the ticks (better more data than epochs): ")
cerrar1=60
Seleccion_tmf="1d"#input("Please select time frame to forecast: 1 hour (press: 1), 2hours (2), 4 hours (4) or 1 day (1d), (3d), (4d), (1w): ")

epoch =100# input("Please input the number of epoch to use (for example 75,100 or 150): ")
selection="EURUSD"#input("Please enter symbol as in your broker: ")
k_reg=0.001#input("Please input the kernel regulizer you whant to have (for example 0.01): ")

k_reg=float(k_reg)


#############################################################
# Obtains actual time and date
now_inicio_script = time.time()
###########################################################
symbols=selection

if Seleccion_tmf== "1":
    tmf = mt5.TIMEFRAME_H1
    seconds = 60*60
    delay=delay_1
    cerrar=cerrar1*60
    temporalidad="1 hora"
if Seleccion_tmf== "2":
    tmf = mt5.TIMEFRAME_H2
    seconds = 60*60*2
    delay=delay_1
    cerrar=cerrar1*60*2
    temporalidad="2 horas"
if Seleccion_tmf== "3":
    tmf = mt5.TIMEFRAME_H3
    seconds = 60*60*3
    delay=delay_1
    cerrar=cerrar1*60*3
    temporalidad="3 horas"
if Seleccion_tmf== "4":
    tmf = mt5.TIMEFRAME_H4
    seconds = 60*60*4
    delay=delay_1
    cerrar=cerrar1*60*4
    temporalidad="4 horas"
if Seleccion_tmf== "1d":
    tmf = mt5.TIMEFRAME_D1
    seconds = 60*60*24
    delay=delay_1
    cerrar=cerrar1*60*24
    temporalidad="1 dia"
if Seleccion_tmf== "3d":
    tmf = mt5.TIMEFRAME_D1
    seconds = 60*60*24*3
    delay=delay_1
    cerrar=cerrar1*60*24*3
    temporalidad="3 dias"
if Seleccion_tmf== "4d":
    tmf = mt5.TIMEFRAME_D1
    seconds = 60*60*24*4
    delay=delay_1
    cerrar=cerrar1*60*24*4
    temporalidad="4 dias"
if Seleccion_tmf== "1w":
    tmf = mt5.TIMEFRAME_W1
    seconds = 60*60*24*7
    delay=delay_1
    cerrar=cerrar1*60*24*7
    temporalidad="1_week"
print(temporalidad)

print(symbols)
# Initialize an empty list to store results
df = pd.DataFrame()

df = df.drop(index=df.index)

df2 = pd.DataFrame()
# Empty DataFrame
df2 = df2.drop(index=df2.index)

# Create an empty dictionary to store DataFrames
dfs = pd.DataFrame()
# Empty the DataFrame
dfs = dfs.drop(index=dfs.index)

simbolito=symbols
print("Symbol: ", simbolito)

symbol = simbolito
timeframe = temporalidad

# import the 'pandas' module for displaying data obtained in the tabular form
import pandas as pd
pd.set_option('display.max_columns', 500) # number of columns to be displayed
pd.set_option('display.width', 1500)      # max table width to display
# import pytz module for working with time zone
import pytz

# set time zone to UTC
timezone = pytz.timezone("Etc/UTC")

# Obtener la fecha y hora actual
now=None
now = datetime.now()

# Print actual date and time in legible format
print("Fecha y hora actual:", now)


formatted_now=None
formatted_now = now.strftime("%Y-%m-%d %H:%M:%S")
print("Fecha y hora formateadas:", formatted_now)

# Minus n days
date_n_days_ago =None
date_n_days_ago = now - timedelta(days=int(delay))

# Print date from n days ago
print("Fecha y hora hace n días:", date_n_days_ago)

formated_n_time=date_n_days_ago.strftime("%Y-%m-%d %H:%M:%S")
print("Fecha y hora n days ago",formated_n_time)

# También puedes formatear la salida según tus preferencias
formated_date_n_days_ago = date_n_days_ago.strftime("%Y,%m,%d")
formated_date_n_days_ago_y = date_n_days_ago.strftime("%Y")
formated_date_n_days_ago_m = date_n_days_ago.strftime("%m")
formated_date_n_days_ago_d = date_n_days_ago.strftime("%d")
print("Fecha y hora formateadas hace n días:", formated_date_n_days_ago)

# create 'datetime' object in UTC time zone to avoid the implementation of a local time zone offset
utc_from = datetime(int(formated_date_n_days_ago_y),int(formated_date_n_days_ago_m),int(formated_date_n_days_ago_d), tzinfo=timezone)

# this is the complete path to the data csv
path_csv = 'xxxxxxxxxxxx/MQL5/Files/'

rates=pd.DataFrame()
# Empty DataFrame
rates = rates.drop(index=rates.index)

import os

file_path = path_csv + 'ticks_data.csv'

if os.path.exists(file_path):
    rates = pd.read_csv(file_path, encoding='utf-16le')
else:
    print(f"Error: File not found - {file_path}")
    quit()
#rates = pd.read_csv(path_csv+str(symbol)+'_TickData.csv')



#rates = mt5.copy_ticks_from(symbol, utc_from, 1000000000, mt5.COPY_TICKS_ALL)
print(rates)

# create DataFrame out of the obtained data
rates_frame=pd.DataFrame()
# Vaciar el DataFrame
rates_frame = rates_frame.drop(index=rates_frame.index)
rates_frame = pd.DataFrame(rates)
rates = rates.drop(index=rates.index)
print(rates_frame)
#rename columns
rates_frame.rename(columns={0: 'Time', 1: 'bid', 2 : 'ask',3:'spread'}, inplace=True)

# Step 2: Convert the 'Time' column to pandas datetime format
rates_frame['Time'] = pd.to_datetime(rates_frame['Time'], format='%Y.%m.%d %H:%M', errors='coerce')
# Verificar si hay fechas nulas después de la conversión
if rates_frame['Time'].isnull().any():
    print("Hay fechas inválidas en la columna 'timestamp'.")

# Asumiendo que tu DataFrame rates_frame tiene una columna 'timestamp'
# Convierte la columna 'timestamp' a tipo datetime
#rates_frame['timestamp'] = pd.to_datetime(rates_frame['timestamp'])

# Seleccionar el rango de fechas que deseas
fecha_inicio = formated_n_time #'2023-01-01'
fecha_fin =formatted_now #'2023-12-31'
print("start date",fecha_fin)
print("end date",fecha_fin)

# Filtrar el DataFrame para obtener solo las filas dentro del rango de fechas
rates_frame_filtrado = rates_frame[(rates_frame['Time'] >= fecha_inicio) & (rates_frame['Time'] <= fecha_fin)]

# Imprimir el DataFrame filtrado
print(rates_frame_filtrado)




# Step 4: Sort the DataFrame by the 'Time' column
rates_frame_filtrado = rates_frame_filtrado.sort_values(by='Time')

# Display the sorted DataFrame with 'Time_seconds'
print(rates_frame_filtrado['Time'])

# convert time in seconds into the datetime format

#rates_frame_filtrado['time']=pd.to_datetime(rates_frame_filtrado['Time'], unit='s')
rates_frame_filtrado['close']=(rates_frame_filtrado['Ask']+rates_frame_filtrado['Bid'])/2

# display data
print("\nDisplay dataframe with data")
print(rates_frame_filtrado) 


# Create a target variable (e.g., predict the next n closing prices)
############################################################################################
rates_frame_filtrado['target'] = rates_frame_filtrado['close']
rates_frame_filtrado['time'] =rates_frame_filtrado['Time']
rates_frame_filtrado['time_target'] = rates_frame_filtrado['time'].sub(pd.Timestamp("1970-01-01")) // pd.Timedelta('1s')
rates_frame_filtrado['time_target_seconds'] = rates_frame_filtrado['time'].sub(pd.Timestamp("1970-01-01")) // pd.Timedelta('1s')
print("tabla rates_frame_filtrado añadiendo",rates_frame_filtrado)
time_ticks=None
time_ticks=int(((rates_frame_filtrado['time_target'].iloc[-1]-rates_frame_filtrado['time_target'].iloc[0])))/int(len(rates_frame_filtrado))
time_ticks=(round(time_ticks,2))

print("time_1 de ticks",time_ticks)

print("the time_1 measures time get data in seconds ",time_ticks)

number_of_rows= seconds
empty_rows = pd.DataFrame(np.nan, index=range(number_of_rows), columns=rates_frame_filtrado.columns)
rates_frame_filtrado = rates_frame_filtrado._append(empty_rows, ignore_index=True)
rates_frame_filtrado['target'] = rates_frame_filtrado['close'].shift(-seconds)
print("rates_frame_filtrado modified",rates_frame_filtrado)


df2=rates_frame_filtrado[['close','target','time']]

print("rates_frame_filtrado",rates_frame_filtrado)
print("df2",df2)

# Drop NaN values
rates_frame_filtrado=rates_frame_filtrado.dropna()
rates_frame_filtrado = rates_frame_filtrado.drop(index=rates_frame_filtrado.index)
df2 = df2.dropna()
print("rates_frame_filtrado con dropna",rates_frame_filtrado)
print("df2 con dropna",df2)

# Split the data into features (X) and target variable (y)
X=[]
y=[]
X = df2[['close']]
y = df2['target']

# Split the data into training and testing sets
X_train=[]
X_test=[]
y_train=[]
y_test=[]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False)

# Standardize the features
X_train_scaled=[]
X_test_scaled=[]
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# Build a neural network model
model=None
model = Sequential()
model.add(Dense(128, activation='relu', input_shape=(X_train.shape[1],), kernel_regularizer=l2(k_reg)))
model.add(Dense(256, activation='relu', kernel_regularizer=l2(k_reg)))
model.add(Dense(128, activation='relu', kernel_regularizer=l2(k_reg)))
model.add(Dense(64, activation='relu', kernel_regularizer=l2(k_reg)))
model.add(Dense(1, activation='linear'))

# Compile the model[]
model.compile(optimizer='adam', loss='mean_squared_error')

giggs=model.summary()
print(giggs)

time_calc_start = time.time()
# Train the model
history=model.fit(X_train_scaled, y_train, epochs=int(epoch), batch_size=256, validation_split=0.2, verbose=1)
print(history)
fit_time_seconds = time.time() - time_calc_start
print("fit time =",fit_time_seconds," seconds.")
# Use the model to predict the next 4 instances
X_predict=[]
X_predict_scaled=[]

predictions = pd.DataFrame()
predictions=[]
# Vaciar el DataFrame
#predictions = predictions.drop(index=predictions.index)
X_predict = df2.tail(seconds)[['close']]
X_predict_scaled = scaler.transform(X_predict)
predictions = model.predict(X_predict_scaled)

# Print actual and predicted values for the next 4 instances
print("Actual Value for the Last Instances:")
print(df2.tail(1)['close'].values)

print("\nPredicted Value for the Next Instances:")
print(predictions[:, 0])
predictions=pd.DataFrame(predictions)

    ######################################################### ONNX
# python libraries
import MetaTrader5 as mt5
import tensorflow as tf
import numpy as np
import pandas as pd
import tf2onnx
from sklearn.model_selection import train_test_split
from sys import argv
import matplotlib.pyplot as plt 
import pytz

symbol=symbol
x_train=X_train
x_test=X_test
inp_model_name = "model."+str(symbol)+".onnx"
file_path="xxxxxxxxxxxxxxxxxxxx/MQL5/Files/"
data_path=argv[0]
last_index=data_path.rfind("\\")+1
data_path=data_path[0:last_index]
print("data path to save onnx model",data_path)


# and save to MQL5\Files folder to use as file


print("file path to save onnx model",file_path)



# save model to ONNX
output_path = data_path+inp_model_name
onnx_model = tf2onnx.convert.from_keras(model, output_path=output_path)
print(f"saved model to {output_path}")


#####################################################################


#calculate metrics
from sklearn import metrics
from sklearn.metrics import r2_score


# Calculate and print mean squared error
mse = mean_squared_error(y_test, model.predict(X_test_scaled))
print(f"\nMean Squared Error: {mse}")

# Calculate and print mean absolute error
mae = mean_absolute_error(y_test, model.predict(X_test_scaled))
print(f"\nMean Absolute Error: {mae}")

# Calculate and print R2 Score
r2 = r2_score(y_test, model.predict(X_test_scaled))
print(f"\nR2 Score: {r2}")

print("Finished")
#mt5.shutdown
print("##################################################################")

