Вычислить сложный возвращаемый ряд в Python - PullRequest
9 голосов
/ 01 апреля 2011

Приветствую всех, у меня есть две серии данных: ежедневные исходные данные о возврате акций (положительные или отрицательные значения) и торговые сигналы (покупка = 1, продажа = -1, нет торговли = 0).

Сырые возвраты цены - это просто журнал сегодняшней цены, поделенный на вчерашнюю цену:

log(p_today / p_yesterday)

Пример:

raw_return_series = [ 0.0063 -0.0031 0.0024 ..., -0.0221 0.0097 -0.0015]

Серия торговых сигналов выглядит следующим образом:

signal_series = [-1. 0. -1. -1. 0. 0. -1. 0. 0. 0.]

Чтобы получить дневной доход на основе торговых сигналов:

daily_returns = [raw_return_series[i] * signal_series[i+1] for i in range(0, len(signal_series)-1)]

Эти дневные доходности могут выглядеть следующим образом:

[0.0, 0.00316, -0.0024, 0.0, 0.0, 0.0023, 0.0, 0.0, 0.0] # results in daily_returns; notice the 0s

Мне нужно использовать ряд daily_returns для вычислениясоставные возвращается серии.Однако, учитывая, что в серии daily_returns есть 0 значений, мне нужно перенести последний ненулевой сложный возврат «через время» на следующий ненулевой сложный возврат.

Например, я вычисляюсоставное возвращается так (обратите внимание, что я иду "назад" во времени):

compound_returns = [(((1 + compounded[i + 1]) * (1 + daily_returns[i])) - 1) for i in range(len(compounded) - 2, -1, -1)]

и полученный список:

[0.0, 0.0, 0.0023, 0.0, 0.0, -0.0024, 0.0031, 0.0] # (notice the 0s)

Моя цель - перенести последний ненулевойвернуться к накоплению этих сложных возвратов.То есть, поскольку возврат по индексу i зависит от возврата по индексу i + 1, возврат по индексу i + 1 должен быть ненулевым.Каждый раз, когда понимание списка встречается с нулем в ряду daily_return, оно по существу перезапускается.

Ответы [ 3 ]

8 голосов
/ 01 апреля 2011

Существует фантастический модуль под названием pandas , который был написан парнем из AQR (хедж-фонд), который отлично справляется с такими расчетами ... что вам нужно, так это способ обработки "пропущенных данных" ... как кто-то упоминал выше, в основах используется нан (а не число) возможностей scipy или numpy; однако, даже эти библиотеки не делают финансовые расчеты намного проще ... если вы используете панд, вы можете пометить данные, которые вы не хотите рассматривать, как nan, и тогда любые будущие вычисления отклонят их при выполнении обычные операции над другими данными.

Я использую панд на своей торговой платформе около 8 месяцев ... Хотелось бы, чтобы я начал использовать ее раньше.

Уэс (автор) выступил на pyCon 2010 с докладом о возможностях модуля ... см. Слайды и видео на веб-странице pyCon 2010 . В этом видео он демонстрирует, как получать ежедневные доходы, запускать 1000 с линейных регрессий на матрице возвратов (за доли секунды), данные временных меток / графиков ... все это делается с помощью этого модуля. В сочетании с psyco, это зверь инструмента финансового анализа.

Другая замечательная вещь, которую он обрабатывает, это данные поперечного сечения ... так что вы можете получать ежедневные цены закрытия, их скользящие средние и т. Д. ... затем отметку времени каждый расчет и сохранять все это в что-то похожее на словарь Python (см. класс pandas.DataFrame) ... тогда вы получаете доступ к фрагментам данных так же просто, как:

close_prices['stdev_5d']

См. Документы о моментах качания панд для получения дополнительной информации о расчете stdev (это однострочник).

Уэс изо всех сил пытался ускорить работу модуля с помощью Cython, хотя я признаю, что рассматриваю возможность обновления своего сервера (более старого Xeon) из-за моих требований к анализу.

РЕДАКТИРОВАТЬ ДЛЯ ВОПРОСА STRIMP: После того, как вы преобразовали свой код для использования структур данных pandas, мне все еще неясно, как вы индексируете свои данные в фрейме данных pandas и требования к составной функции для обработки пропущенных данных (или в этом отношении условия для возврата 0.0 ... или если вы используете NaN в пандах ..). Я продемонстрирую, используя мою индексацию данных ... день был выбран случайным образом ... df - это кадр данных с котировками ES Futures ... проиндексирован в секунду ... пропущенные цитаты заполняются numpy.nan. Индексы DataFrame - это объекты datetime, смещенные на объекты часового пояса модуля pytz.

>>> df.info
<bound method DataFrame.info of <class 'pandas.core.frame.DataFrame'>
Index: 86400 entries , 2011-03-21 00:00:00-04:00 to 2011-03-21 23:59:59-04:00
etf                                         18390  non-null values
etfvol                                      18390  non-null values
fut                                         29446  non-null values
futvol                                      23446  non-null values
...
>>> # ET is a pytz object...
>>> et
<DstTzInfo 'US/Eastern' EST-1 day, 19:00:00 STD>
>>> # To get the futures quote at 9:45, eastern time...
>>> df.xs(et.localize(dt.datetime(2011,3,21,9,45,0)))['fut']
1291.75
>>>

Чтобы дать простой пример того, как вычислить столбец непрерывных возвратов (в pandas.TimeSeries), который ссылается на цитату 10 минут назад (и заполняет отсутствующие тики), я бы сделал это:

>>> df['fut'].fill(method='pad')/df['fut'].fill(method='pad').shift(600)

В этом случае лямбда не требуется, просто разделив столбец значений 600 секунд назад. Это .shift(600) часть, потому что мои данные индексируются в секунду.

НТН, \ * 1043 микрофон *

3 голосов
/ 27 августа 2015

Кумулятивная возвращаемая часть этого вопроса рассматривается в превосходной книге Уэса МакКинни «Python для анализа данных» на стр. 339 и использует cumprod () из Pandas для создания пересчитанного / проиндексированного кумулятивного возврата из рассчитанных изменений цен.

Пример из книги:

import pandas.io.data as web

price = web.get_data_yahoo('AAPL', '2011-01-01')['Adj Close']

returns = price.pct_change()

ret_index = (1 + returns).cumprod()

ret_index[0] = 1 # Set first value to 1
1 голос
/ 05 апреля 2011

представьте, что у меня есть DataMatrix с ценами закрытия, значением индикатора и торговым сигналом, подобным этому:

 >>> data_matrix
                        close          dvi            signal
 2008-01-02 00:00:00    144.9          0.6504         -1             
 2008-01-03 00:00:00    144.9          0.6603         -1             
 2008-01-04 00:00:00    141.3          0.7528         -1             
 2008-01-07 00:00:00    141.2          0.8226         -1             
 2008-01-08 00:00:00    138.9          0.8548         -1             
 2008-01-09 00:00:00    140.4          0.8552         -1             
 2008-01-10 00:00:00    141.3          0.846          -1             
 2008-01-11 00:00:00    140.2          0.7988         -1             
 2008-01-14 00:00:00    141.3          0.6151         -1             
 2008-01-15 00:00:00    138.2          0.3714         1   

Я использую сигнал для создания DataMatrix возвратов на основе торгового сигнала:

>>> get_indicator_returns()

                   indicator_returns    
2008-01-02 00:00:00    NaN            
2008-01-03 00:00:00    0.000483       
2008-01-04 00:00:00    0.02451        
2008-01-07 00:00:00    0.0008492      
2008-01-08 00:00:00    0.01615        
2008-01-09 00:00:00    -0.01051       
2008-01-10 00:00:00    -0.006554      
2008-01-11 00:00:00    0.008069       
2008-01-14 00:00:00    -0.008063      
2008-01-15 00:00:00    0.02201 

То, что я в итоге сделал, это:

def get_compounded_indicator_cumulative(self):

    indicator_dm = self.get_indicator_returns()
    dates = indicator_dm.index

    indicator_returns = indicator_dm['indicator_returns']
    compounded = array(zeros(size(indicator_returns)))

    compounded[1] = indicator_returns[1]

    for i in range(2, len(indicator_returns)):

        compounded[i] = (1 + compounded[i-1]) * (1 + indicator_returns[i]) - 1

    data = {
        'compounded_returns': compounded
    }

    return DataMatrix(data, index=dates)

Почему-то я действительно боролся с этим ...

Я нахожусь в процессе преобразования всех моих ценовых рядов в PyTables. Пока выглядит многообещающе.

...