<jupyter_start><jupyter_text>Time Series and Forecasting  Goal : To analyze the data leading upto Volkswagen buyout of Porsche<jupyter_code>import numpy as np
import pandas as pd
import scipy
import statsmodels.api as sm
import matplotlib.pyplot as plt
import seaborn as sns
import sklearn
import statsmodels.graphics.tsaplots as sgt
import statsmodels.tsa.stattools as sts
from statsmodels.tsa.arima_model import ARIMA
from statsmodels.tsa.statespace.sarimax import SARIMAX
from pmdarima.arima import auto_arima
from pmdarima.arima import OCSBTest 
from statsmodels.tsa.arima_model import ARIMA
from arch import arch_model
import seaborn as sns
import yfinance 
import warnings
warnings.filterwarnings("ignore")
sns.set()<jupyter_output><empty_output><jupyter_text>Importing the Data<jupyter_code>#  Directky scrapping the data from Yahoo finance instead of importing fixed data  
#  The abbreveations for certain equities on the stock market are : VOW3-Volkswagen, PAH3 -Porsche, BMW-Bayerische Motoren Werke AG
# .DE shows the data are from German stock market since, both the companies are German based.
#  To make sure all the changes or values are stock specific we nedd to market benchmark. 
     # Ideally this wolud be some other German automobile comapny selling stocks in the German market.
     # So BMW is the obvious choice 
        

raw_data = yfinance.download (tickers = "VOW3.DE, PAH3.DE, BMW.DE", interval = "1d", group_by = 'ticker',
                              auto_adjust = True, treads = True)
df = raw_data.copy()<jupyter_output><empty_output><jupyter_text>Defining Key Dates<jupyter_code># Starting Date - This is the earliest date that we have recorded values for both stocks 
start_date = "2009-04-05" 

# First Official Announcement - 49.9% (VOW announced they owned 49.9% of Porsche)
ann_1 = "2009-12-09" 

# Second Official Announcement - 51.1% (VOW announced they owned the remaing 50.1% of Porsche- means full ownership)
ann_2 = "2012-07-05" 

#Ending Date 
end_date = "2014-01-01"<jupyter_output><empty_output><jupyter_text>Pre-processing the Data<jupyter_code># Extracting Closing Prices
df['vol'] = df['VOW3.DE'].Close
df['por'] = df['PAH3.DE'].Close
df['bmw'] = df['BMW.DE'].Close

# Creating Returns- returns are represent in Percentage that are Scale free and can have statistical Stationarity
df['ret_vol'] = df['vol'].pct_change(1).mul(100)
df['ret_por'] = df['por'].pct_change(1).mul(100)
df['ret_bmw'] = df['bmw'].pct_change(1).mul(100)

# Creating Squared Returns ( To calculate Volatility of the equity stocks)
df['sq_vol'] = df.ret_vol.mul(df.ret_vol)
df['sq_por'] = df.ret_por.mul(df.ret_por)
df['sq_bmw'] = df.ret_bmw.mul(df.ret_bmw)

# Extracting Volume - The number of purchases and sales each day 
df['q_vol'] = df['VOW3.DE'].Volume
df['q_por'] = df['PAH3.DE'].Volume
df['q_bmw'] = df['BMW.DE'].Volume
# Assigning the Frequency and Filling NA Values
df = df.asfreq('b')
df = df.fillna(method='bfill')
# Removing Surplus Data
del df['VOW3.DE']
del df['PAH3.DE']
del df['BMW.DE']
# Ploting to see how the 3 time series move over time 
# There is  similarities on how the series move which shows trends of the entire automobile industry market
# VW prices shift alot more in magnitude after the 3rd quater of 2009

df['vol'][start_date:end_date].plot(figsize= (20,8), color = "blue")
df['por'][start_date:end_date].plot(color = "green")
df['bmw'][start_date:end_date].plot(color = "gold")
plt.show()
# For better visual using diffrent shades of colors
# The gap between VW and other 2 increases drastically over time
# BMW resemble Porsche much more

df['vol'][start_date:ann_1].plot(figsize= (20,8), color = "#33B8FF")
df['por'][start_date:ann_1].plot(color = "#49FF3A")
df['bmw'][start_date:ann_1].plot(color = "#FEB628")

df['vol'][ann_1:ann_2].plot(color = "#1E7EB2")
df['por'][ann_1:ann_2].plot(color = "#2FAB25")
df['bmw'][ann_1:ann_2].plot(color = "#BA861F")

df['vol'][ann_2:end_date].plot(color = "#0E3A52")
df['por'][ann_2:end_date].plot(color = "#225414")
df['bmw'][ann_2:end_date].plot(color = "#7C5913")

plt.legend(['Volkswagen','Porsche','BMW'])

plt.show()<jupyter_output><empty_output><jupyter_text>Correlation<jupyter_code># To see any similarities between the series
# Volkswagen and BMW correlation is the highest
# This shows VW moves in a similar way to the market benchmark, in higher values.

print('Correlation among manufacturers from ' + str(start_date) + ' to ' + str(end_date)+ '\n')
print('Volkswagen and Porsche correlation: \t'+ str(df['vol'][start_date:end_date].corr(df['por'][start_date:end_date])))
print('Volkswagen and BMW correlation: \t'+ str(df['vol'][start_date:end_date].corr(df['bmw'][start_date:end_date])))
print('Porsche and BMW correlation: \t\t'+ str(df['por'][start_date:end_date].corr(df['bmw'][start_date:end_date])))
# Correlation based on start date alone
# Porsche and BMW correlation is the lowest-this suggest the stock prices for the brands were not too similar before the start of the buyout


 
print('Correlation among manufacturers from ' + str(start_date) + ' to ' + str(ann_1)+ '\n')
print('Volkswagen and Porsche correlation: \t'+ str(df['vol'][start_date:ann_1].corr(df['por'][start_date:ann_1])))
print('Volkswagen and BMW correlation: \t'+ str(df['vol'][start_date:ann_1].corr(df['bmw'][start_date:ann_1])))
print('Porsche and BMW correlation: \t\t'+ str(df['por'][start_date:ann_1].corr(df['bmw'][start_date:ann_1])))
# changing the start and end data 
# Volkswagen and BMW correlation is the highest

print('Correlation among manufacturers from ' + str(ann_1) + ' to ' + str(ann_2)+ '\n')
print('Volkswagen and Porsche correlation: \t'+ str(df['vol'][ann_1:ann_2].corr(df['por'][ann_1:ann_2])))
print('Volkswagen and BMW correlation: \t'+ str(df['vol'][ann_1:ann_2].corr(df['bmw'][ann_1:ann_2])))
print('Porsche and BMW correlation: \t\t'+ str(df['por'][ann_1:ann_2].corr(df['bmw'][ann_1:ann_2])))
# After buying Porsche
# the VW remains to be the market trend setter

print('Correlation among manufacturers from ' + str(ann_2) + ' to ' + str(end_date)+ '\n')
print('Volkswagen and Porsche correlation: \t'+ str(df['vol'][ann_2:end_date].corr(df['por'][ann_2:end_date])))
print('Volkswagen and BMW correlation: \t'+ str(df['vol'][ann_2:end_date].corr(df['bmw'][ann_2:end_date])))
print('Porsche and BMW correlation: \t\t'+ str(df['por'][ann_2:end_date].corr(df['bmw'][ann_2:end_date])))
# the correlation between VW and BMW decrease because of the Dieselgate Scandal
print('Correlation among manufacturers from ' + str(end_date) + ' to ' + str(df.index[-1])+ '\n')
print('Volkswagen and Porsche correlation: \t'+ str(df['vol'][end_date:].corr(df['por'][end_date:])))
print('Volkswagen and BMW correlation: \t'+ str(df['vol'][end_date:].corr(df['bmw'][end_date:])))
print('Porsche and BMW correlation: \t\t'+ str(df['por'][end_date:].corr(df['bmw'][end_date:])))<jupyter_output>Correlation among manufacturers from 2014-01-01 to 2021-04-30 00:00:00

Volkswagen and Porsche correlation: 	0.9645773398506455
Volkswagen and BMW correlation: 	0.5867842623215198
Porsche and BMW correlation: 		0.5707941278918959<jupyter_text>Best Fitting Models  For Volkswagen<jupyter_code>mod_pr_pre_vol = auto_arima(df.vol[start_date:ann_1], exogenous = df[['por','bmw']][start_date:ann_1],
                            m = 5, max_p = 5, max_q = 5)
mod_pr_btn_vol = auto_arima(df.vol[ann_1:ann_2], exogenous = df[['por','bmw']][ann_1:ann_2],
                            m = 5, max_p = 5, max_q = 5)
mod_pr_post_vol = auto_arima(df.vol[ann_2:end_date], exogenous = df[['por','bmw']][ann_2:end_date],
                            m = 5, max_p = 5, max_q = 5)

# For period prior to First Official Announcement we see AR(1) model with 2 exog variables are best fit
# All P-values are significant so it is a best fit model

mod_pr_pre_vol.summary()
# For period after the  First Official Announcement we see ARIMAX(0,1,0) model is the best fit
# The optimal model is an integrated one
# SInce auto Arima forces stationary so the data is non-stationary
# The model finds past residuals to have significant explanatory power 
    # "this indicate that the real life announcement actually changes the trend for VW prices"

mod_pr_btn_vol.summary()
mod_pr_post_vol.summary()

# The optimal model is ARIMAX(0,1,0)
#  The coefficient change in Porche Prices  occurs bcoz the 2 automobile manufactures are now a single entity
# This shows the price of Porche today will be more accurate estimator than the price of VW yesterday<jupyter_output><empty_output><jupyter_text>Inference: New information seems to have a higher impact on trends compared to past patterns  For Porsche<jupyter_code>mod_pr_pre_por = auto_arima(df.por[start_date:ann_1], exogenous = df[['vol','bmw']][start_date:ann_1],
                            m = 5, max_p = 5, max_q = 5)
mod_pr_btn_por = auto_arima(df.por[ann_1:ann_2], exogenous = df[['vol','bmw']][ann_1:ann_2],
                            m = 5, max_p = 5, max_q = 5)
mod_pr_post_por = auto_arima(df.por[ann_2:end_date], exogenous = df[['vol','bmw']][ann_2:end_date],
                             m = 5, max_p = 5, max_q = 5)
# For period prior to First Official Announcement we see AR(2) model with 2 exog variables are best fit


mod_pr_pre_por.summary()
# For period after the  First Official Announcement we see ARIMA(1,1,1) model is the best fit
# The optimal model is an integrated one
# the coefficent of VW has icrease 

mod_pr_btn_por.summary()
mod_pr_post_por.summary()<jupyter_output><empty_output><jupyter_text>Predictions for the Future1. Taking the best fitting models and forcast them into the future2. Comparing the predicition(based on data before the announcement) to the actual values following it   means prediction for Volkswagen, time period  between the first and second  announcement based on    the trend prior to the first announcement  For Volkswagen<jupyter_code># Exogenous variable not inculded

model_auto_pred_pr = auto_arima(df.vol[start_date:ann_1], m = 5, max_p = 5, max_q = 5, max_P = 5, max_Q = 5, trend = "ct")

df_auto_pred_pr = pd.DataFrame(model_auto_pred_pr.predict(n_periods = len(df[ann_1:ann_2])), index = df[ann_1:ann_2].index)
df_auto_pred_pr[ann_1:ann_2].plot(figsize = (20,5), color = "red")

df.vol[ann_1:ann_2].plot(color = "blue")
plt.title("VW Predictions (no Exog) vs Real Data", size = 24)
plt.show()
# showing only first quater of 2010
#  The prediciton not really close day-by-day but capture the general trend over the entire period
# So the prediciton would only be useful if we are trying to "ballpark"(or rough estimate) the quaterly performance

df_auto_pred_pr[ann_1:'2010-03-01'].plot(figsize = (20,5), color = "red")
df.vol[ann_1:'2010-03-01'].plot(color = "blue")
plt.title("VW Predictions (no Exog) vs Real Data (short term)", size = 24)
plt.show()
# Exog varaibles (Porsche prices) are included 
# We see a trend that doesnt simply die off exponentially
# Therefore adding Porsche prices improve predictions but not substantially 
#    (Since some portion og Porsche was owned by VW by 2010)
 
model_auto_pred_pr = auto_arima(df.vol[start_date:ann_1], exogenous = df[['por']][start_date:ann_1],
                          m = 5, max_p = 5, max_q = 5, max_P = 5, max_Q = 5, trend = "ct")

df_auto_pred_pr = pd.DataFrame(model_auto_pred_pr.predict(n_periods = len(df[ann_1:ann_2]),exogenous = df[['por']][ann_1:ann_2]),
                               index = df[ann_1:ann_2].index)
df_auto_pred_pr[ann_1:ann_2].plot(figsize = (20,5), color = "red")

df.vol[ann_1:ann_2].plot(color = "blue")
plt.title("VW Predictions (Porsche as Exog) vs Real Data", size = 24)

plt.show()
# Exog varaibles (BMW  prices) are included -using the market benchmark BMW
# The forecasts line up with general trend over the entire period
# But it doesnt justify the rise and fall periods 

model_auto_pred_pr = auto_arima(df.vol[start_date:ann_1], exogenous = df[['bmw']][start_date:ann_1],
                          m = 5, max_p = 5, max_q = 5, max_P = 5, max_Q = 5, trend = "ct")

df_auto_pred_pr = pd.DataFrame(model_auto_pred_pr.predict(n_periods = len(df[ann_1:ann_2]), exogenous = df[['bmw']][ann_1:ann_2]),
                               index = df[ann_1:ann_2].index)
df_auto_pred_pr[ann_1:ann_2].plot(figsize = (20,5), color = "red")

df.vol[ann_1:ann_2].plot(color = "blue")
plt.title("VW Predictions (Market Benchmark as Exog) vs Real Data", size = 24)
plt.show()
# Exog varaibles (BMW & Porsche prices) are included 
# Forecast look similar to when only including BMW prices
# This one matches the smaller shifts better 

model_auto_pred_pr = auto_arima(df.vol[start_date:ann_1], exogenous = df[['por', 'bmw']][start_date:ann_1],
                          m = 5, max_p = 5, max_q = 5, max_P = 5, max_Q = 5, trend = "ct")

df_auto_pred_pr = pd.DataFrame(model_auto_pred_pr.predict(n_periods = len(df[ann_1:ann_2]), exogenous = df[['por','bmw']][ann_1:ann_2]),
                               index = df[ann_1:ann_2].index)
df_auto_pred_pr[ann_1:ann_2].plot(figsize = (20,5), color = "red")

df.vol[ann_1:ann_2].plot(color = "blue")
plt.title("VW Predictions (Porsche and Market as Exog) vs Real Data", size = 24)
plt.show()<jupyter_output><empty_output><jupyter_text>Inference : Introduction to new variables can alter our predictions drastically  Volatility  Volatility of VW for Each Period<jupyter_code># Squared return represents the volatility of the stock
# VW has the highest volatility before any of the announcements
# Stock becomes extremely stable following each of the 2 announcements
# It shows instability to the time leading upto each purchase (may be bcoz of the rumors spreading accorss the market about a deal in the horizon)

df['sq_vol'][start_date:ann_1].plot(figsize = (20,5), color = "#33B8FF")
df['sq_vol'][ann_1:ann_2].plot(color = "#1E7EB2")
df['sq_vol'][ann_2:end_date].plot(color = "#0E3A52")
plt.show()<jupyter_output><empty_output><jupyter_text>Volatility Trends for Each Period<jupyter_code># applying GARCH(1,1) models for returns for 3 different periods


model_garch_pre = arch_model(df.ret_vol[start_date:ann_1], mean = "Constant",  vol = "GARCH", p = 1, q = 1)
results_garch_pre = model_garch_pre.fit(update_freq = 5)

model_garch_btn = arch_model(df.ret_vol[ann_1:ann_2], mean = "Constant",  vol = "GARCH", p = 1, q = 1)
results_garch_btn = model_garch_btn.fit(update_freq = 5)

model_garch_post = arch_model(df.ret_vol[ann_2:end_date], mean = "Constant",  vol = "GARCH", p = 1, q = 1)
results_garch_post = model_garch_post.fit(update_freq = 5)
# Shows a P-value of 1 tells trends and variance are not persistent

results_garch_pre.summary()
# p-value  is zero means autocorrelation in the conditiona varaince is significant
# mu shows some constant trends in the returns value


results_garch_btn.summary()
# shows change in volatility from previous time periods
# We never expect returns or their volatility to ever be perfectly stable which normal for a market lacking efficiency
results_garch_post.summary()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12617940199335548, 'fraction_numerical': 0.02857142857142857, 'mean_word_length': 5.1332518337408315, 'pattern_counts': {'":': 0, '<': 40, '<?xml version=': 0, '>': 40, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '422435', 'license': 'MIT', 'n_tokens_mistral': 5583, 'n_tokens_neox': 5224, 'n_words': 1471, 'path': 'Time series an Forecasting.ipynb', 'repo_name': 'dchanda21/Time-Series-and-Forecasting', 'size': '15050'}