# load ammo
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn import preprocessing
from sklearn.model_selection import train_test_split, cross_val_score

"""
Explanation: Predicting TCS Stock Performance
In this jupyter notebook, we will be training linear models for predicting TCS stock price based on 2016 trading data.
Lets Get Data
Get the historic data of TCS scrip from NSE
- choose Price, Volume and Delivery Position data as it provides insight into investors pulse
- Enter Symbol 'TCS' and select series equity 'EQ'
- Get data for past 365 days
- Click get data and then download full data
End of explanation
"""


# loading data sec_bhavdata_full.csv
# column name is present in data 
df = pd.read_csv('01-01-2016-TO-30-12-2016TCSEQN.csv')
print(df.shape)
df.dtypes

# let see what we got here
df.describe()

"""
Explanation: Loading data into DataFrame
Assuming the downloaded data is in your current working directory, the dataset should have name like this 01-01-2016-TO-30-12-2016TCSEQN.csv
End of explanation
"""


df.head(2)

df.tail(2)

"""
Explanation: TCS being largest company by market capitalization it maintains very high liquidity so we will have data for all the trading days of 2016.
End of explanation
"""


df['Average Price'].plot(color='black',linewidth=0.7)
df['High Price'].plot(color='green', linewidth=0.5)
df['Low Price'].plot(color='red', linewidth=0.5,)
plt.plot([df['Average Price'].mean()]*247, 'b--')
plt.show()

"""
Explanation: Exploring dataset
Lets see how the scrip has performed over the year
End of explanation
"""


df['Average Price'].plot(color='black',linewidth=0.7)
df['Open Price'].plot(color='green', linewidth=0.5)
df['Close Price'].plot(color='red', linewidth=0.5,)
plt.plot([df['Average Price'].mean()]*247, 'b--')
plt.show()

"""
Explanation: We see a lot of swing in the price, the stock started & ended the year in the same range.
End of explanation
"""


# feature and label selection
features = ['Open Price','High Price','Low Price','Close Price','Average Price']
label = ['Average Price']

# prepare dataset with only required columns
# label is the avg. price shifted to next day
dataset = df[features].assign(label=df[label].shift(-1))

# lets check head of the dataset, now the label is previous days avg. price
dataset.head(5)

# the last label is nan cause we shifted the label
dataset.tail(2)

# drop last datapoint as it lacks label
print(dataset.shape)
dataset.dropna(inplace=True)
print(dataset.shape)

"""
Explanation: Feature Selection
Lets build a simple model based on open, high, low, close and average price features to pridect next day average price
End of explanation
"""


# separate data and target label
data = dataset[features].values
target = dataset['label'].values

# scale the dataset to ease model
data_scaled = preprocessing.scale(data)

"""
Explanation: Preprocessing Data
we will scale the features for obvious performace upgrade
End of explanation
"""


test_size = 0.3 # hold out 30% for prediction
random_state = 42 # answer to the univers could be better choice :P

X_train, X_test, y_train, y_test = train_test_split(data_scaled,target,test_size=test_size,random_state=random_state)

X_train.shape, y_train.shape

X_test.shape, y_test.shape

"""
Explanation: Train and Test Data
Split data into train and test, with train data representing 70%
End of explanation
"""


# lets use multiple models and determine their merit with kfold cross validation
from sklearn.svm import SVR
from sklearn.linear_model import LinearRegression

models = []
models.append(('Linear Regression',LinearRegression()))
models.append(('SVR Linear',SVR(kernel='linear')))
models.append(('SVR Ploy',SVR(kernel='poly')))
models.append(('SVR RBF',SVR(kernel='rbf')))

"""
Explanation: Model Selection
Let us run this data through few linear models to compare their relative preformace. We will choose top two models
End of explanation
"""


# lets evaluate models 
results = []
names = []
scoring = 'neg_mean_squared_error'

# kfold with shuffling
from sklearn.model_selection import KFold
num_splits = 10
kf = KFold(n_splits=num_splits,shuffle=True,random_state=random_state)

# kfold without shuffling
cv_fold = 10

# if you wish to try cv will shuffling pass kf to cv instead of sv_fold

for name, model in models:
    result = cross_val_score(model, X_train, y_train, cv=cv_fold,scoring=scoring)
    names.append(name)
    results.append(result)
    msg = "{:20} : mean = {:.5f}  std = {:.5f}".format(name,result.mean(),result.std())
    print(msg)

"""
Explanation: Cross Validation
I tried cv with shuffling(by explicitly using KFold class) and without shuffling(by just passing cv=10), the models performed significantly worse when shuffled, mainly because this is a time series problem and we are not using the key feature Date which I'm saving it for later.
Model evaluation metric for out problem would be Mean Squard Error
End of explanation
"""


# Compare Algorithms
fig = plt.figure()
fig.suptitle('Algorithm Comparison')
ax = fig.add_subplot(111)
plt.boxplot(results)
ax.set_xticklabels(names)
plt.show()

"""
Explanation: Comparing CV Score
End of explanation
"""


# lets predict
accuracy_threshold = -1000
cv_models = []
cv_results = []
cv_names = []

for model,result in zip(models,results):
    if result.mean() > accuracy_threshold:
        cv_models.append(model)
        cv_results.append(result)
        cv_names.append(model[0])
        print('adding model... {}'.format(model[0]))

# lets have a closer look at the 'relatively' good models
fig = plt.figure()
fig.suptitle('Final Algorithm Comparison')
ax = fig.add_subplot(111)
plt.boxplot(cv_results)
ax.set_xticklabels(cv_names)
plt.show()

"""
Explanation: As we can see in the comparison Linear Regressionand and SVR with Linear Kernel have higest accuracy and very low deviation.
SVR Poly and SVR RBF are bad idea if you gonna put your money on this :P
Choosing Final Models
I have set MSE threshold to -1000 which shoudl get us LR and SVR-Linear
End of explanation
"""


# make prediction on test set
from sklearn.metrics import mean_squared_error
predictions = []
mseResult = []
for name,model in cv_models:
    model.fit(X_train,y_train)
    prediction = model.predict(X_test)
    predictions.append(prediction)
    mse = mean_squared_error(y_test,prediction)
    mseResult.append(mse)
    msg = "{:20} : mae = {:.5f}".format(name,mse)
    print(msg)

"""
Explanation: there are some outlies but the inter quartail range is short (compared to the one trained on shuffled features)
Predicting Test Set
End of explanation
"""


df_predictions = pd.DataFrame(np.transpose(predictions),columns=['Linear Reg','SVR Linear'])
df_predictions = df_predictions.assign(y_test=y_test)
df_predictions.head()

df_predictions['Linear Reg'].plot(color='green',linewidth=0.5)
df_predictions['SVR Linear'].plot(color='red', linewidth=0.5)
df_predictions['y_test'].plot(color='black', linewidth=0.5,)
plt.show()

"""
Explanation: The predicton MSE is in line with what we seen in cross validation
End of explanation
"""


