# Start writing code here...
from numpy import *
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, LSTM, TimeDistributed, LeakyReLU
from tensorflow import keras
import matplotlib.pyplot as plt
import matplotlib
import os
import pandas as pd
import time
import csv
import requests
from datetime import datetime
ticker = "NVDA"
price = pd.DataFrame()
for i in range(1,2):
    for j in range(1,2):
        # replace the "demo" apikey below with your own key from https://www.alphavantage.co/support/#api-key
        CSV_URL = "https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY_EXTENDED&symbol="+ticker+"&interval=5min&slice=year"+str(i)+"month"+str(j)+"&apikey=XQ8OJYOFJFBN3TA7"
        
        with requests.Session() as s:
            download = s.get(CSV_URL)
            decoded_content = download.content.decode('utf-8')
            cr = csv.reader(decoded_content.splitlines(), delimiter=',')
            my_list = list(cr)
            temp = pd.DataFrame(my_list)
            new_header = temp.iloc[0] #grab the first row for the header
            temp = temp[1:] #take the data less the header row
            temp.columns = new_header #set the header row as the df header
            
        price = price.append(temp, ignore_index=True)
        time.sleep(12) #to satisfy alphavantage data requirements
n_input_data = 1
kept_for_exam = 10000
price = price.iloc[::-1]
price = price.reset_index()
price = price.drop("index", axis=1)
price
def init_network():
    global rnn, timesteps, n_input_data
    rnn = Sequential()
    rnn.add(LSTM(30, batch_input_shape=(None, timesteps, n_input_data), return_sequences=True))
#    rnn.add(LSTM(700, return_sequences=True))
    rnn.add(LSTM(15, return_sequences=True))
#    rnn.add(LSTM(200, return_sequences=True))
    rnn.add(LSTM(5, return_sequences=False))   
#   rnn.add(LSTM(800, return_sequences=True))
#    rnn.add(LSTM(800, return_sequences=True))
    rnn.add(Dense(1, activation=LeakyReLU(0.3)))
    rnn.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])
    
def make_batch(batchsize, timesteps):
    """
    Take as argument: batchsize, timesteps. 
    This function will generate randomly the batches from the available data
    """
    global n_input_data, all_y_in, all_y_ans, kept_for_exam, length
    #Change the inputs here
    all_y_in = array(price["close"])
    all_y_in = all_y_in.reshape([shape(all_y_in)[0], 1])
    closingprice = array(price["close"])
    length = shape(closingprice)[0]
    all_y_ans = zeros(length)
    all_y_ans[:-1] = closingprice[1:]
    length = shape(all_y_ans)[0]
    
    #Generate random samples with timesteps length.
    start_time = random.randint(0, length-kept_for_exam-timesteps+1, size =batchsize)
    yin = zeros([batchsize, timesteps, n_input_data])
    yans = zeros([batchsize, timesteps])
    for i in range(batchsize):
        yin[i,:,:] = all_y_in[start_time[i]:(start_time[i]+timesteps), :]
        yans[i, :] = all_y_ans[start_time[i]:(start_time[i]+timesteps)]
        
    #Normalizing the price and the volume wrt the zeroth price and volume in the time series
    
    for j in range(batchsize):
        basis = yin[j,0,0]
        maximum = yin[j,:,0].max()
        minimum = yin[j,:,0].min()
        yin[j, :, 0] = (yin[j, :, 0]-minimum)/(maximum-minimum)
        yans[j, :] = (yans[j, :]-minimum)/(maximum-minimum)
    #    yin[j, :, 1] = yin[j, :, 1]/yin[j,0,1]
    
    #Reshaping yans for categorical cross entropy
    yans_new = zeros([batchsize, timesteps, 2])
    yans_new[:, :, 0] = (yans[:, :]==0)*1
    yans_new[:, :, 1] = (yans[:, :]==1)*1
    
    #New Addition:
    y_ans = zeros([batchsize, 2])
    y_ans[:,:] = yans_new[:,timesteps-1,:]
    
    #For price prediction
    yans_price = zeros([batchsize, 1])
    yans_price[:,0] = yans[:,-1]
    return [yin, yans_price]
converge =False
while(converge ==False):
    batchsize = 30
    timesteps = 10
    init_network()
    accuracy = 0
    errors = []
    acc = []
    array_for_predacc = []
    array_for_money = []
    k=0
    while(accuracy<0.95):
    #    if(i%10==0):
    #        print(100*i/epochs)
        
        yin, yout = make_batch(batchsize, timesteps)
        temp = rnn.train_on_batch(yin, yout)
        errors.append(temp[0])
        
        predicted = rnn.predict(yin)
        directional_pred = predicted[:,0]>yin[:, timesteps-1, 0]
        directional_answer = yout[:, 0]>yin[:, timesteps-1,0]
        accuracy = sum(directional_answer==directional_pred)/batchsize
        acc.append(accuracy)
        k+=1
        ####################
        #input the testing input
        y_input = zeros([kept_for_exam+timesteps-1, n_input_data])
        y_input[:,:] =  all_y_in[-(kept_for_exam+timesteps-1):, :]
        
        #input the date input
        a = pd.DataFrame(price)
        datea = a.reset_index()
        datea =array(datea)
        
        for i in range(shape(datea)[0]):
            datea[i][1] = datetime.strptime(datea[i][1], '%Y-%m-%d %H:%M:%S').date()
        
        datea = datea[:,0]
        date_exam = datea[-kept_for_exam:]
        
        #input the testing answer
        y_ans = zeros(kept_for_exam)
        y_ans[:] = all_y_ans[-kept_for_exam:]
        
        
        
        length = shape(y_input)[0] #NOTE THAT THIS IS NOT 500
        prediction = []
        for i in range(length-timesteps+1):
            current_y_input = zeros([1, timesteps, n_input_data])
            current_y_input[0,:,:] = y_input[i:i+timesteps, :]
              
            #Normalizing according to the simulation
            maximum = current_y_input[0,:,0].max()
            minimum = current_y_input[0,:,0].min()
            current_y_input[0,:,0] = (current_y_input[0,:,0]-minimum)/(maximum-minimum)
            #current_y_input[0,:,1] = current_y_input[0,:,1]/current_y_input[0,0,1]
            #current_y_input[0,:,2] = current_y_input[0,:,2]/current_y_input[0,0,2]
            
            if(i<(length-timesteps) and date_exam[i]==date_exam[i+1]): #We must buy at the end of the day
                prediction.append(1)
            else:
                temp = (rnn.predict(current_y_input)[0][0]>current_y_input[0][timesteps-1][0])*1 #IF TRUE IT IS PREDICTING THAT THE PRICE IS GOING UP
                prediction.append(temp)
            
        prediction = array(prediction)
        #savetxt(exam_folder+"/prediction.txt", prediction)
        
        exam_number = kept_for_exam
        
        y_ans[1:] = y_ans[1:]>y_ans[:-1]
        accuracy_of_prediction=zeros(exam_number)
        accuracy_of_prediction[:] = (y_ans[:]==prediction[:])*1
        pred_acc = sum(accuracy_of_prediction)/exam_number
        
        #Cutting the input to only the last 500 and store into price array
        pricenew = zeros(exam_number)
        pricenew[:] = y_input[-exam_number:, 0] #Note this is not the actual price, but its ok.and
        
        #output_exam = open("result"+ticker+".txt", "a+")
        #output_exam.write("Accuracy ="+ str(pred_acc) + "\n" +"\n")
        array_for_predacc.append(pred_acc)
        
        for j in range(1): 
            have_share = False
            money = 10000
            shares = 0
            i=j
            lastbuy=0
            Gain = []
            Loss = []
            while(i < exam_number):
                if(prediction[i]==1):
                    if(have_share==False):
                        have_share=True
                        shares += money/pricenew[i]
                        lastbuy = money
                        money = 0
                    
                if(prediction[i]==0):
                    if(have_share==True):
                        have_share = False
                        money += shares*pricenew[i]
                        shares = 0
                        if(money>lastbuy): Gain.append(money-lastbuy)
                        elif(money<lastbuy): Loss.append(lastbuy-money)
        
                i+=1
                
#            output_exam.write("\n######### Day "+ str(j) + " #########\n")
#            output_exam.write("Ending Money: " + str(money+shares*pricenew[kept_for_exam-1]) +"\n")
#            output_exam.write("Gain: "+ str(Gain) +"\n")
#            output_exam.write("Loss: "+ str(Loss) +"\n")
            array_for_money.append(money+shares*pricenew[kept_for_exam-1])
        benchmark = (y_input[-1,0]-y_input[timesteps-1,0])/y_input[timesteps-1,0]    
#        output_exam.write("buy hold=" + str(benchmark))
#        output_exam.close()
        ####################
        
        if(k>100): 
            converge=True
            break
    #    if(i%10==0):
    #        im, (ax0, ax1) = plt.subplots(ncols=2)
    #        ax0.plot(errors)
    #        ax1.plot(acc)
    #        plt.show()
    #        clear_output(wait=True)
    
    if(accuracy>0.95):
        converge=True
        
errors = array(errors)
acc = array(acc)
array_for_money = array(array_for_money)
array_for_predacc = array(array_for_predacc)
    
im, (ax0, ax1) = plt.subplots(ncols=2)
ax0.plot(errors)
ax1.plot(acc)
plt.savefig("graph"+ticker+".png")
im2, (ax2, ax3) = plt.subplots(nrows=2)
ax2.plot(array_for_predacc)
ax3.plot(array_for_money)
ax3.axhline(y=(benchmark+1)*10000)
plt.savefig("test"+ticker+".png")
k
errors = array(errors)
acc = array(acc)
array_for_money = array(array_for_money)
array_for_predacc = array(array_for_predacc)
    
im, (ax0, ax1) = plt.subplots(ncols=2)
ax0.plot(errors)
ax1.plot(acc)
plt.savefig("graph"+ticker+".png")
im2, (ax2, ax3) = plt.subplots(nrows=2)
ax2.plot(array_for_predacc)
ax3.plot(array_for_money)
ax3.axhline(y=(benchmark+1)*10000)
plt.savefig("test"+ticker+".png")