

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.preprocessing import RobustScaler
plt.style.use("bmh")
import ta
from datetime import timedelta
import sys
import tensorflow as tf
from keras.models import Sequential
from keras.layers import LSTM, Dense, Dropout
import myenv

"""
Function to predict values for each sequence from neural network. Function inspired from marcosan93 from https://github.com/marcosan93/Price-Forecaster
and he is in keras documentation to valide predict data
Input -- periodB int to back period 
      -- predictPeriod number in days/interval to predict 
      df --- dataframe with scaled data 
      model --- train network
Return -- predictions dataframe
"""
def getPredictInterval(periodB, predictPeriod):
    # Init
    resultDf = pd.DataFrame(index=df.index, columns=[df.columns[0]])

    for i in range(1, len(df)-periodB, predictPeriod):
        #Get one row
        x = df[-i - periodB:-i]
        # reverse scall to original interval
        revertRow = invertScaler.inverse_transform(model.predict(np.array(x).reshape(1, periodB, data)))[0]
        intervalClose = pd.DataFrame(revertRow, index=pd.date_range(start=x.index[-1]+timedelta(days=1), periods=len(revertRow), freq="B"), columns=[x.columns[0]])
        # add predict price to interval in result dataframe
        resultDf.update(intervalClose)
        
    return resultDf


model = tf.keras.models.load_model(myenv.MODEL_PREDICT_SAVE)
df = pd.read_csv(myenv.SOURCE_DATASET)
invertScaler = RobustScaler()
invertScaler.fit(df[['Close']])

df = pd.read_pickle(myenv.PREPARED_DATASET) 

periodB  = myenv.PERIODB
predictPeriod = myenv.PREDICT_PERIOD
data = df.shape[1]

# Back transform close price for rmse calculate
actual = pd.DataFrame(invertScaler.inverse_transform(df[["Close"]]), index=df.index, columns=[df.columns[0]])
# Get predict values for each interval
predictions = getPredictInterval(periodB, predictPeriod)

#Calculate RMSE for calculate mistake
rmse = float(np.sqrt(((actual.Close - predictions.Close)**2).mean()))
print("RMSE:", rmse)
    
# Draw graph with predicted and actual values
plt.figure(figsize=(16,6))
plt.plot(predictions, label='Predikované zatváracie hodnoty')
plt.plot(actual, label='Skutočné zatváracie hodnoty')
plt.title(f"Predikované a aktuálne zatváracie hodnoty finálnej siete dataset3 ")
plt.ylabel("Cena v USD")
plt.legend()
plt.show()

# Get future interval predict prices from neural model and reverse scall to original interval
predictInterval = model.predict(np.array(df.tail(periodB)).reshape(1, periodB, data))
predictInterval = invertScaler.inverse_transform(predictInterval)[0]

# Prepare from interrval data for graph = interval to dataframe
predictDf = pd.DataFrame(predictInterval, index=pd.date_range(start=df.index[-1]+timedelta(days=1), periods=len(predictInterval), freq="B"), columns=[df.columns[0]])

# Transforming the actual values to their original price
actual = pd.DataFrame(invertScaler.inverse_transform(df[["Close"]].tail(periodB)), index=df.Close.tail(periodB).index, columns=[df.columns[0]]).append(predictDf.head(1))

# Draw graph with predicted values in future
plt.figure(figsize=(16,6))
plt.plot(actual, label="Skutočné zatváracie hodnoty")
plt.plot(predictDf, label="Predikované zatváracie hodnoty")
plt.ylabel("Cena")
plt.xlabel("Dátum")
#plt.title(f"Predpoveď pre ďalších {len(predictInterval)} dní")
plt.title(f"Predpoveď vývoju cien Bitcoinu 4.1.2020-14.1.2020")
plt.legend()
plt.show()

# Printing the predicted prices in output
print(predictDf)