Thursday 6 August 2015

Markov Chains Used in Stock Index Forecast

I shortly introduced via a simple weather prediction model the use of Markov chains and respectively Python implementation. Here we will have a look at a stock index – I take the S&P 500 index for the period Aug 5, 2014 to Aug 5, 2015 (252 daily returns) as an example.

First we calculate daily returns and decide on three states of the daily changes – decrease (coded as ‘1’), neutral (coded as ‘2’) and increase (coded as ‘3’). Then we calculate 9 states (resp. probabilities based on historical figures):

(i)                  yesterday index decreased and today  is down as well (coded as ‘11’)
(ii)                yesterday index decreased but today is neutral (coded as ‘12’)
(iii)               yesterday index decreased but today is up (coded as ‘13’)
(iv)              yesterday index was neutral but today is down (coded as ‘21’)
(v)                yesterday index was neutral and today is neutral too (coded as ‘22’)
(vi)              yesterday index was neutral but today is up (coded as ‘23’)
(vii)             yesterday index increased but today is down (coded as ‘31’)
(viii)           yesterday index increased but today is neutral (coded as ‘32’)
(ix)              yesterday index increased and today is up as well (coded as ‘33’)


The algorithm I follow is as follows: (1) count all daily decreases, neutral and increases in index values (i.e. index returns over 1-day period), then (2) count all cases within the nine states (as stated above) – from prior day decrease to current day decrease, from prior day decrease to current day increase and so on and finally (3) calculating the probabilities is straightforward: divide state coded as ‘11’ by total number of daily decreases, divide state coded as ‘12’ by total number of daily decreases, divide state coded as ‘21’ by total number of daily increases and divide state coded as ‘22’ by total number of daily increases and so on.

For instance:

Counts

Daily decreases (state '1')
121

Daily neutral (state '2')
6

Daily increases (state ‘3’)
125


Counts
Probabilities
State ‘11’
57
0.47
State ‘12’
1
0.01
State ‘13’
63
0.52
State '21'
3
0.5
State '22'
0
0
State '23'
3
0.5
State '31'
61
0.49
State '31'
4
0.04
State '33'
59
0.47


         To
From
Decrease
(‘1’)
Neutral
(‘2’)
Increase
(‘3’)
Decrease
(‘1’)
0.47
(‘11’)
0.01
(‘12’)
0.52
(‘13’)
Neutral
(‘2’)
0.5
(‘21’)
0
(‘22’)
0.5
(‘23’)
Increase
(‘3’)
0.49
(‘31’)
0.04
 (‘32’)
0.47
(‘33’)

For S&P 500 example there is 47% probability of decrease today given yesterday index decreased and 47% probability of increase today given increased yesterday. Quite fair!

Solving for the steady state probabilities (as explained here: http://elenamarinova.blogspot.com/2015/06/markov-chains-in-python-simple-weather.html) 49% of the days the index will increase and 48% of the days the index will experience a decrease over the prior day. The steady state is already independent on the current state, this is the memoryless property of the process.

(1) transition=np.array([[0.47, 0.01, 0.52],[0.5, 0.00, 0.5], [0.49, 0.04,0.47]])
initial=np.array([0,0,1]) #today is increase
Result: [decrease, neutral, increase]
[ 0.49 0.04 0.47]
[ 0.4806  0.0237  0.4957]
[ 0.480625  0.024634  0.494741]
[ 0.48063384  0.02459589  0.49477027]
[ 0.48063328  0.02459715  0.49476957]
[ 0.48063331  0.02459712  0.49476958]



(2) transition=np.array([[0.47, 0.01, 0.52],[0.5, 0.00, 0.5], [0.49, 0.04,0.47]])
initial=np.array([1,0,0]) #today is decrease
Result: [decrease, neutral, increase]
[ 0.47  0.01  0.52]
[ 0.4807  0.0255  0.4938]
[ 0.480641  0.024559  0.4948  ]
[ 0.48063277  0.02459841  0.49476882]
[ 0.48063333  0.02459708  0.49476959]
[ 0.4806333   0.02459712  0.49476958]

(3) transition=np.array([[0.47, 0.01, 0.52],[0.5, 0.00, 0.5], [0.49, 0.04,0.47]])
initial=np.array([0,1,0]) #today is neutral
Result: [decrease, neutral, increase]
[ 0.5  0.   0.5]
[ 0.48   0.025  0.495]
[ 0.48065  0.0246   0.49475]
[ 0.480633   0.0245965  0.4947705]
[ 0.48063331  0.02459715  0.49476954]
[ 0.48063331  0.02459711  0.49476958]


A somehow more decisive stock market example we found in Wikipedia (https://en.wikipedia.org/wiki/Markov_chain):
 Labelling the state space {1 = bull, 2 = bear, 3 = stagnant} the transition matrix for this example is
P = \begin{bmatrix}
0.9 & 0.075 & 0.025 \\
0.15 & 0.8 & 0.05 \\
0.25 & 0.25 & 0.5
\end{bmatrix}.
Assuming we are at initial state 'bear' for the probabilities the result is:
Result: [bull, bear, stagant]
[ 0.15  0.8   0.05]
[ 0.2675   0.66375  0.06875]
[ 0.3575   0.56825  0.07425]
[ 0.42555   0.499975  0.074475]
[ 0.47661   0.450515  0.072875]
[ 0.514745   0.4143765  0.0708785]
[ 0.5431466  0.3878267  0.0690267]
[ 0.56426262  0.36825403  0.06748335]
[ 0.5799453   0.35379376  0.06626094]
[ 0.59158507  0.34309614  0.06531879]
[ 0.60022068  0.33517549  0.06460383]
[ 0.60662589  0.3293079   0.06406621]
[ 0.61137604  0.32495981  0.06366415]
[ 0.61489845  0.32173709  0.06336446]
[ 0.61751028  0.31934817  0.06314155]
[ 0.61944687  0.3175772   0.06297594]
[ 0.62088274  0.31626426  0.062853  ]
[ 0.62194736  0.31529086  0.06276178]
[ 0.6227367   0.31456919  0.06269412]
[ 0.62332193  0.31403413  0.06264394]
[ 0.62375584  0.31363743  0.06260672]
[ 0.62407756  0.31334332  0.06257913]
[ 0.62431608  0.31312525  0.06255867]
[ 0.62449293  0.31296357  0.0625435 ]
[ 0.62462404  0.3128437   0.06253225]
[ 0.62472126  0.31275483  0.06252391]
[ 0.62479334  0.31268894  0.06251773]
[ 0.62484677  0.31264008  0.06251314]
[ 0.6248864   0.31260386  0.06250975]
[ 0.62491577  0.312577    0.06250723]
[ 0.62493755  0.31255709  0.06250536]
[ 0.6249537   0.31254233  0.06250397]
[ 0.62496567  0.31253138  0.06250294]
[ 0.62497455  0.31252327  0.06250218]
[ 0.62498113  0.31251725  0.06250162]
[ 0.62498601  0.31251279  0.0625012 ]
[ 0.62498963  0.31250948  0.06250089]
[ 0.62499231  0.31250703  0.06250066]
[ 0.6249943   0.31250521  0.06250049]
[ 0.62499577  0.31250387  0.06250036]
[ 0.62499687  0.31250287  0.06250027]
[ 0.62499768  0.31250212  0.0625002 ]
[ 0.62499828  0.31250158  0.06250015]
[ 0.62499872  0.31250117  0.06250011]
[ 0.62499905  0.31250087  0.06250008]
[ 0.6249993   0.31250064  0.06250006]
[ 0.62499948  0.31250048  0.06250004]
[ 0.62499961  0.31250035  0.06250003]
[ 0.62499971  0.31250026  0.06250002]
[ 0.62499979  0.31250019  0.06250002]
[ 0.62499984  0.31250014  0.06250001]
[ 0.62499988  0.31250011  0.06250001]
[ 0.62499991  0.31250008  0.06250001]
[ 0.62499994  0.31250006  0.06250001]
[ 0.62499995  0.31250004  0.0625    ]
[ 0.62499996  0.31250003  0.0625    ]
[ 0.62499997  0.31250002  0.0625    ]
[ 0.62499998  0.31250002  0.0625    ]
[ 0.62499999  0.31250001  0.0625    ]
[ 0.62499999  0.31250001  0.0625    ]
[ 0.62499999  0.31250001  0.0625    ]
[ 0.62499999  0.31250001  0.0625    ]
[ 0.625   0.3125  0.0625]