Momentum portfolio(trend following) quant simulation on pandas
<p>I am trying to construct trend following momentum portfolio strategy based on S&amp;P500 index (momthly data)</p>

<p>I used Kaufmann's fractal efficiency ratio to filter out whipsaw signal
(<a href="http://etfhq.com/blog/2011/02/07/kaufmans-efficiency-ratio/" rel="nofollow">http://etfhq.com/blog/2011/02/07/kaufmans-efficiency-ratio/</a>)</p>

<p>I succeeded in coding, but it's very clumsy, so I need advice for better code.</p>

<p>Strategy </p>

<ol>
<li>Get data of S&amp;P 500 index from yahoo finance</li>
<li>Calculate Kaufmann's efficiency ratio on lookback period X (1 , if close > close(n), 0)</li>
<li>Averages calculated value of 2, from 1 to 12 time period ---> Monthly asset allocation ratio, 1-asset allocation ratio = cash (3% per year)</li>
</ol>

<p>I am having a difficulty in averaging 1 to 12 efficiency ratio. Of course I know that it can be simply implemented by for loop and it's very easy task, but I failed.</p>

<p>I need more concise and refined code, anybody can help me?</p>

<p>a['meanfractal'] bothers me in the code below..</p>

<p>Thanks</p>

<pre><code>import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import pandas_datareader.data as web

def price(stock, start):
    price = web.DataReader(name=stock, data_source='yahoo', start=start)['Adj Close']
    return price.div(price.iat[0]).resample('M').last().to_frame('price')

a = price('SPY','2000-01-01')

def fractal(a,p):
    a['direction'] = np.where(a['price'].diff(p)&gt;0,1,0)
    a['abs'] = a['price'].diff(p).abs()
    a['volatility'] = a.price.diff().abs().rolling(p).sum()
    a['fractal'] = a['abs'].values/a['volatility'].values*a['direction'].values
    return a['fractal']

def meanfractal(a):
    a['meanfractal']= (fractal(a,1).values+fractal(a,2).values+fractal(a,3).values+fractal(a,4).values+fractal(a,5).values+fractal(a,6).values+fractal(a,7).values+fractal(a,8).values+fractal(a,9).values+fractal(a,10).values+fractal(a,11).values+fractal(a,12).values)/12
    a['portfolio1'] = (a.price/a.price.shift(1).values*a.meanfractal.shift(1).values+(1-a.meanfractal.shift(1).values)*1.03**(1/12)).cumprod()
    a['portfolio2'] = ((a.price/a.price.shift(1).values*a.meanfractal.shift(1).values+1.03**(1/12))/(1+a.meanfractal.shift(1))).cumprod()
    a=a.dropna()
    a=a.div(a.ix[0])
    return a[['price','portfolio1','portfolio2']].plot()        

print(a)
plt.show()
</code></pre>

<p>You could simplify further by storing the values corresponding to <code>p</code> in a <code>DF</code> rather than computing for each series separately as shown:</p>

<pre><code>def fractal(a, p):
    df = pd.DataFrame()
    for count in range(1,p+1):
        a['direction'] = np.where(a['price'].diff(count)&gt;0,1,0)
        a['abs'] = a['price'].diff(count).abs()
        a['volatility'] = a.price.diff().abs().rolling(count).sum()
        a['fractal'] = a['abs']/a['volatility']*a['direction']
        df = pd.concat([df, a['fractal']], axis=1)
    return df
</code></pre>

<p>Then, you could assign the repeating operations to a variable which reduces the re-computation time.</p>

<pre><code>def meanfractal(a, l=12):
    a['meanfractal']= pd.DataFrame(fractal(a, l)).sum(1,skipna=False)/l
    mean_shift = a['meanfractal'].shift(1)
    price_shift = a['price'].shift(1)
    factor = 1.03**(1/l)
    a['portfolio1'] = (a['price']/price_shift*mean_shift+(1-mean_shift)*factor).cumprod()
    a['portfolio2'] = ((a['price']/price_shift*mean_shift+factor)/(1+mean_shift)).cumprod()
    a.dropna(inplace=True)
    a = a.div(a.ix[0])
    return a[['price','portfolio1','portfolio2']].plot() 
</code></pre>

<p>Resulting plot obtained:</p>

<pre><code>meanfractal(a)
</code></pre>

<p><a href="https://i.stack.imgur.com/v4tp3.png" rel="nofollow"><img src="https://i.stack.imgur.com/v4tp3.png" alt="Image"></a></p>

<p>Note: If speed is not a major concern, you could perform the operations via the built-in methods present in <code>pandas</code> instead of converting them into it's corresponding <code>numpy</code> array values.</p>

python pandas quantitative-finance momentum