You are on page 1of 3

What is the optimal holding period for shares?

The plan for today is: 1. Define a volatility band for the log of stock prices and mean reverting strategy based on dips below the band. 2. Optimization for the holding period of shares. 3. Profit and champagne(optional).

The band
The first step in defining the band is transforming to the logarithm of the stock price. Next, I find the local minimas. For now, I define the local minimum as the point with the lowest value of the set containing this point and 5 earlier and 5 later points.
1 def locMins(arr, period=1): 2 mins = [] 3 4 for i in range(period,len(arr) - period): 5 themin = min(arr[i - period : i + period]) 6 7 if arr[i] <= themin: 8 mins.append(i) 9 10 return mins

Then, I fit a line through these minima. If the fit fails, Numpy returns an empty residuals array so I check for that.
1 2 3 4 5 6 7 8 9 10 11 12 logc = log(c[: int(argv[1]) ]) mins = locMins(logc, 5) y = [] for m in mins: y.append( logc[m] ) (a,b,residuals) = fitline(mins, y) if len(residuals) == 0: continue

The band is formed by adding and subtracting the standard deviation of log of the close price with respect to the regression line. I also check whether a certain percentage of the historical prices falls within this band.
1 def within_band_ratio(arr, a, b, err): 2 count = 0 3 4 for i in range( len(arr) ): 5 if arr[i] <= (a * i + b + err): 6 if arr[i] >= (a * i + b - err): 7 count += 1

8 9

return count / float( len(arr) )

This is what the histogram of the within band ratio looks like. Seems to be skewed the right way, dont you agree?

Now its time for the mean reverting strategy that selects dips below the band.
1 2 3 4 5 6 7 8 9 10 STD = std(logc) last = log( c[ int(argv[1] ) + 1 ] ) if last >= ( a * len(logc) + b - STD): continue wbr = within_band_ratio(logc, a, b, STD) if wbr < float( argv[2] ): continue

Optimal holding period


Common sense tells us that the optimal holding period would be less than a day. However, sometimes we dont have enough data for that or whatever. The best choice is of course associated with the largest return, so I try to estimate this. O yeah, I did something with time averaging, ignore it for now.
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 ... def expected_return( p, period ): indices = arange( 0, len(p), period ) q = take( p, indices ) r = get_returns( q ) return geomean( r )

o,c = loadtxt(path( argv[ 1 ] + '.csv' ), delimiter=',', usecols=(3,6), unpack=True, co ers = [] twers = [] maxEr = expected_return( c, 1 ) ers.append( maxEr ) maxTwer = expected_return( c, 1 ) twers.append( maxTwer ) optPeriod = 1 optTWPeriod = 1 for i in range(2, 30): er = expected_return( c, i) twer = er / i ers.append( er ) twers.append( twer ) if er > maxEr:

29 30 31 32 if 33 34 35 ...

maxEr = er optPeriod = i twer > maxTwer: maxTwer = twer optTWPeriod = i

Here are the plots of holding periods and expected returns.

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

You might also like