Momentum portfolio (отслеживание тренда) количественное моделирование на pandas

#python #pandas #quantitative-finance #momentum

#python #pandas #количественный-финансы #momentum

Вопрос:

Я пытаюсь построить стратегию портфеля, следующую за трендом, на основе индекса S amp; P500 (данные за месяц)

Я использовал коэффициент фрактальной эффективности Кауфмана для фильтрации сигнала whipsaw (http://etfhq.com/blog/2011/02/07/kaufmans-efficiency-ratio /)

Я преуспел в кодировании, но это очень неуклюже, поэтому мне нужен совет по улучшению кода.

СТРАТЕГИИ

  1. Получить данные индекса S amp; P 500 от yahoo finance
  2. Вычислите коэффициент эффективности Кауфмана для периода ретроспективного анализа X (1, если close> close (n), 0)
  3. Среднее расчетное значение 2, период времени от 1 до 12 —> Ежемесячный коэффициент распределения активов, 1-коэффициент распределения активов = денежные средства (3% в год)

У меня возникают трудности с усреднением коэффициента эффективности от 1 до 12. Конечно, я знаю, что это может быть просто реализовано с помощью цикла for, и это очень простая задача, но я потерпел неудачу.

Мне нужен более краткий и уточненный код, кто-нибудь может мне помочь?

a['meanfractal'] меня беспокоит приведенный ниже код..

 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)>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()
  

Ответ №1:

Вы могли бы еще больше упростить, сохранив значения, соответствующие p в DF , а не вычисляя для каждой серии отдельно, как показано:

 def fractal(a, p):
    df = pd.DataFrame()
    for count in range(1,p 1):
        a['direction'] = np.where(a['price'].diff(count)>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
  

Затем вы можете назначить повторяющиеся операции переменной, что сокращает время повторного вычисления.

 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() 
  

Полученный график:

 meanfractal(a)
  

Изображение

Примечание: если скорость не является серьезной проблемой, вы можете выполнять операции с помощью встроенных методов, присутствующих в pandas , вместо преобразования их в соответствующие numpy значения массива.

Комментарии:

1. Большое вам спасибо… Это было очень полезно

2. Когда я вычисляю поэлементную операцию между фреймами данных, иногда возникает ошибка, если я не кодирую с помощью ‘df.values’, но, похоже, в вашем коде нет проблем, напрямую работающих между фреймами данных (например, a [‘fractal’] = a [‘abs’] / a[‘volatility’] * a[‘направление’] ). В чем разница?

3. Хороший вопрос. Пока они являются частью одного и того же фрейма данных, вы можете выполнять арифметические операции, транслируя их. Проблема возникает, когда вы хотите поэлементно умножить два фрейма данных или две их серии, имеющие несоответствие в размерах, что приводит к вашему DF возврату Nans . В этих случаях вы должны преобразовать его в его numpy аналог, обратившись к .values атрибуту DF's объекта, с которым нужно работать.

4. @ Nickil Maveli

5. Спасибо за любезное объяснение, теперь я ясно понял, чего я и ожидал.