Jarque Bera, the CAPM and undervalued stocks

This entry is part of 23 in the series Numpy Strategies

Numpy Strategies 0.0.4

The Capital Asset Pricing Model ( CAPM ) links the expected return of assets to their risk. A linear fit of this relationship gives us the so called Security Market Line ( SML ). One of the problems with this model is that it assumes a normal distribution of returns. The python scikits.statsmodels.stattools module provides a Jarque Bera normality test, which allows me to select only the stocks which have nearly normal return distribution.

Recap of this week’s action

The Numpy 3 portfolio started out with a loss last week. This trend continued throughout the week. Thanks to the breakout of RBNF, the portfolio arrived in positive territory. This made me think of locking in profits and getting rid of the losers. So no more Christmas exit strategies from now on, but for instance a trailing stop.

numpy4numpy3
numpy4numpy3Chart

Jarque Bera test

I check with the Jarque-Bera test for normality. Normality implies predictability. Predictability leads to safety. Safety leads to joy. The code below screens for a certain Jarque Bera test p – value of open, high, low and close prices returns.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
def get_returns( arr ):
   beforeLast = len( arr ) - 2
   return diff( arr[ : beforeLast] ) / arr[ : beforeLast - 1]
 
def get_pvals( returns ):
   pvals = []
 
   for i in range(0, len( returns ) ):
      (jb, pval, skew, kurtosis) = jarque_bera( returns[ i ] )
      pvals.append( pval )
 
   return pvals
 
def check_pvals( pvals ):
   for i in range(0, len( pvals )):
      if pvals[ i ] < float( argv[ 1 ] ):
         return False
 
   return True
 
...
   returns = []
   returns.append( get_returns( c ) )
   returns.append( get_returns( o ) )
   returns.append( get_returns( h ) )
   returns.append( get_returns( l ) )
 
   output = []
   pvals = get_pvals( returns )
 
   if check_pvals( pvals ): 
      ev = geomean( returns[ 0 ] )
...

The expected return is estimated by the geometric mean function below. Actually it calls a scipy.stats function with positive values. This requires a bit of cheating in the form of taking the absolute value etcetera.

1
2
3
4
5
6
def geomean( arr ):
   filtered = abs( arr )
   indices = flatnonzero( filtered )
   filtered = take( filtered, indices )
 
   return scipy.stats.gmean( filtered)

CAPM

So we need to have the slope and intercept of the security market line.

1
2
3
4
5
6
7
8
9
10
11
12
13
...
   returns = []
   returns.append( get_returns( c ) )
   ev = geomean( returns[ 0 ] )
   evs.append( ev )
   stdC = std( returns[ 0 ] )
   stds.append( stdC )
 
 
A = vstack([stds, ones(len(stds))]).T
(p,residuals,rank,s) = linalg.lstsq(A, evs)
a,b=p
...

After that it’s just a question of selecting the points above the SML, which should be undervalued ( see spreadsheet ).

A Klingon Portfolio

Perhaps today is a good day to die?

Many, many years into the future, in a galaxy far away, in a parallel universe lived the Klingon merchant Kurn. He was wrongly accused in the past of illegal trading practices on the Romulan Stock Exchange. This brought dishonor to him and his family. Being a mere merchant and not a warrior like his older brother, made him a bit of outcast in Klingon society already. Life was hard for Kurn. He had trouble making ends meet, constantly evading assasins sent by the Romulan compliance officers.

One day Kurn learned about a model, with which he could find undervalued stocks. His brother advised him to apply a “jerky bear” test, for this would filter away “jerky” prices and tell him whether markets were behaving normally. Kurn decided to be careful as the Klingon proverb says:

A fool and his head are soon parted.
tugh qoH nachDaj je chevlu’ta’

He set the trailing stop size of his investments to be equal to his estimate of their respective returns. The stops would be manual and would be in effect at the end of each week, for Kurn was used to trust his instincts.

A sharp knife is nothing without a sharp eye.
leghlaHchu’be’chugh mIn lo’laHbe’ taj jej

Here is a summary of the trailing stop details.

Kurn bought on friday the following stocks for the open price at the Khitomer exchange:

numpy004Chart

Already there was some virtual profit. Of course, Kurn knew that he would not earn as much latinum as the professionals, who traded at warp speed with cloaked orders and positronic quantum brains. It would be enough however to mend his bat’leth, so that he could kill the Romulan traitors who wronged him and clear his name.

Revenge is a dish best served cold.
bortaS bIr jablu’DI’ reH QaQqu’ nay’

THE END

Random links of interest

If you liked this post and are interested in NumPy check out NumPy Beginner’s Guide by yours truly.

Series NavigationSecret Transitions of a Markov Chain
By the author of NumPy Beginner's Guide, NumPy Cookbook and Instant Pygame. If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.
Share
This entry was posted in programming and tagged , . Bookmark the permalink.