Before We discuss further, Please read make sure You have read the previous articles in this following order –
Let’s follow the path shown in Markov Chains in Stock Market Using Python – Getting Transition Matrix, Here is the sum of the whole python code so far to get Transition Matrix –
symbol = "NIFTY 50"
days = 1000
end_date = datetime.datetime.now().strftime("%d-%b-%Y")
end_date = str(end_date)
start_date = (datetime.datetime.now()- datetime.timedelta(days=days)).strftime("%d-%b-%Y")
start_date = str(start_date)
df=index_history("NIFTY 50",start_date,end_date)
df["state"]=df["CLOSE"].astype(float).pct_change()
df['state']=df['state'].apply(lambda x: 'Upside' if (x > 0.001) else ('Downside' if (x<=0.001) else 'Consolidation'))
df['priorstate']=df['state'].shift(1)
states = df [['priorstate','state']].dropna()
states_matrix = states.groupby(['priorstate','state']).size().unstack().fillna(0)
transition_matrix= states_matrix.apply(lambda x: x/float(x.sum()),axis=1)
print(transition_matrix)
Output –
state Downside Upside
priorstate
Consolidation 0.000000 1.000000
Downside 0.638821 0.361179
Upside 0.554307 0.445693
Now, We will walk the sections discussed in Markov Chain and Linear Algebra – Calculation of Stationary Distribution using Python again but this time using Python. Remember this diagram?
Let’s consider time as t
. Now, We will see observe other probability matrices.
In case You are confused with the terms of “Transition Matrix” and “Probability Matrix” again. “Transition Matrix” is the probability matrix at t=0
. It shows the probability at t=0
, right?
So, Let’s build the Markov Chain by multiplying this transition matrix by itself to obtain the probability matrix in t=1
which would allow us to make one-day forecasts.
t_0 = transition_matrix.copy()
t_1 = round(t_0.dot(t_0),4)
t_1
Output –
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
in
1 t_0 = transition_matrix.copy()
----> 2 t_1 = round(t_0.dot(t_0),4)
3 t_1
\python39\lib\site-packages\pandas\core\frame.py in dot(self, other)
1242 common = self.columns.union(other.index)
1243 if len(common) > len(self.columns) or len(common) > len(other.index):
-> 1244 raise ValueError("matrices are not aligned")
1245
1246 left = self.reindex(columns=common, copy=False)
ValueError: matrices are not aligned
The dot function only works if the Matrix is 2x2
or 3x3
. As The “consolidation” state’s column in the last is filled with 0,0,0. Our 3x3
matrix becomes 3x2
. So, Let’s just remove the consolidation state as it has so low outcome.
symbol = "NIFTY 50"
days = 1000
end_date = datetime.datetime.now().strftime("%d-%b-%Y")
end_date = str(end_date)
start_date = (datetime.datetime.now()- datetime.timedelta(days=days)).strftime("%d-%b-%Y")
start_date = str(start_date)
df=index_history("NIFTY 50",start_date,end_date)
df["state"]=df["CLOSE"].astype(float).pct_change()
df['state']=df['state'].apply(lambda x: 'Upside' if (x > 0) else 'Downside' )
df['priorstate']=df['state'].shift(1)
states = df [['priorstate','state']].dropna()
states_matrix = states.groupby(['priorstate','state']).size().unstack().fillna(0)
transition_matrix= states_matrix.apply(lambda x: x/float(x.sum()),axis=1)
print(transition_matrix)
Output –
state Downside Upside
priorstate
Downside 0.595238 0.404762
Upside 0.515152 0.484848
t_0 = transition_matrix.copy()
t_1 =t_0.dot(t_0)
t_1
Output –
state Downside Upside
priorstate
Downside 0.562822 0.437178
Upside 0.556408 0.443592
The Initial Transition Matrix
Just putting the image of Transition Matrix to help to visualize!
Just syncing with the last chapter where we discussed this in Linear Algebra section,
Here the π_0 = t_0 = A
.
Now, We need to extend the Markov Chain similarly. You can refer the below diagram if it helps to recall.
So, π_1.A =
Similarly, π_2.A =
If we continue multiplying the transition matrix that we have obtained in t=1
by the original transition matrix in t0, we obtain the probabilities in time t=2
. Let’s find the transition matrix at t=2
and t=3
and so on in a similar manner.
t_2 = t_0.dot(t_1)
t_2
Output –
state Downside Upside
priorstate
Downside 0.560226 0.439774
Upside 0.559712 0.440288
t_3 = t_0.dot(t_2)
t_3
Output –
state Downside Upside
priorstate
Downside 0.560018 0.439982
Upside 0.559977 0.440023
Let’s Normalize –
import numpy as np
pd.DataFrame(np.linalg.matrix_power(t_0,4))
Output –
#
0 1
0 0.560018 0.439982
1 0.559977 0.440023
This numpy
trick gives us identical results. If You know the rules of Linear Algebra it will make sense as our π_0 = t_0 = A
. So, We are raising the initial transition matrix to n
days to obtain the same result. So –
t_n = pd.DataFrame(np.linalg.matrix_power(t_0,n+1))
To find out the equilibrium matrix we can iterate the process up to the probabilities don’t change more.
Input –
t_0 = transition_matrix.copy()
t_m = t_0.copy()
t_n = t_0.dot(t_0)
i = 1
while(not(t_m.equals(t_n))):
i += 1
t_m = t_n.copy()
t_n = t_n.dot(t_0)
print("Equilibrium Matrix Number: " + str(i))
print(t_n)
Output –
Equilibrium Matrix Number: 16
state Downside Upside
priorstate
Downside 0.56 0.44
Upside 0.56 0.44
So, t = 16, We get our equilibrium matrix.
The equilibrium Matrix is a stationary state. So, As per the theory of the Markov Chain, This figure will stay the same for foreseeable data points (hence, future) right? Let’s test it on ∞ days like We did while doing our random walk.
Input –
symbol = "NIFTY 50"
days = 9209
end_date = datetime.datetime.now().strftime("%d-%b-%Y")
end_date = str(end_date)
start_date = (datetime.datetime.now()- datetime.timedelta(days=days)).strftime("%d-%b-%Y")
start_date = str(start_date)
df=index_history("NIFTY 50",start_date,end_date)
df["state"]=df["CLOSE"].astype(float).pct_change()
df['state']=df['state'].apply(lambda x: 'Upside' if (x > 0) else 'Downside' )
df['priorstate']=df['state'].shift(1)
states = df [['priorstate','state']].dropna()
states_matrix = states.groupby(['priorstate','state']).size().unstack().fillna(0)
transition_matrix= states_matrix.apply(lambda x: x/float(x.sum()),axis=1)
t_0 = transition_matrix.copy()
t_m = t_0.copy()
t_n = t_0.dot(t_0)
i = 1
while(not(t_m.equals(t_n))):
i += 1
t_m = t_n.copy()
t_n = t_n.dot(t_0)
print("Equilibrium Matrix Number: " + str(i))
print(t_n)
Output –
Equilibrium Matrix Number: 15
state Downside Upside
priorstate
Downside 0.536083 0.463917
Upside 0.536083 0.463917
So, t = 15, We get our equilibrium matrix.
Anyways, the number of the matrix where we get the equilibrium does not matter much. What matters is the values. You can see the values are really close!
Interpreting,
P(priorstate="Downside"/state="Downside)
i.e. If We had a Downside day today, Tomorrow there is 53.6083% probability of having a Downside day.
Similarly,
If We had a Downside day today, Tomorrow there is 46.3917% probability of having an Upside day.