Как быстрее вычислить экспоненциальное скользящее среднее с питоном? - PullRequest
0 голосов
/ 23 мая 2018

Я занят созданием программного обеспечения для тестирования на истории и столкнулся с проблемой создания экспоненциальной скользящей средней.Мне удалось создать его с помощью цикла for, но для каждого символа, который я хочу протестировать, потребовалось около 20 секунд (слишком долго).

Я пытаюсь найти более быстрое решение,если у кого-то есть какие-либо предложения.

Мой текущий код выглядит следующим образом, но он не дает правильных результатов.

def exponential_moving_average(df, period):
    # Create a copy of original dataframe to work with.
    dataframe = df.copy()

    dataframe['EMA'] = dataframe['Close'].ewm( span        = period,
                                               adjust      = False,
                                               min_periods = period,
                                               ignore_na   = True
                                               ).mean()

    return dataframe['EMA']

Этот метод находится в классе Indicatorsи входные данные принимают следующие значения:

  • df - это цена Open, High, Low и Close в день, а также любые другие индикаторы, которые будут использоваться для тестирования на истории и
  • period - это «окно» или количество дней, для которых необходимо рассчитать экспоненциальную скользящую среднюю.

Вот фрагмент кода со значениями df:

            symbol     Open     High      Low    Close  ATR     slow_ma
Date        
2010-01-03  EURUSD  1.43075  1.43369  1.43065  1.43247  NaN       NaN   
2010-01-04  EURUSD  1.43020  1.44560  1.42570  1.44120  NaN       NaN   
2010-01-05  EURUSD  1.44130  1.44840  1.43460  1.43650  NaN       NaN   
2010-01-06  EURUSD  1.43660  1.44350  1.42820  1.44060  NaN       NaN   
2010-01-07  EURUSD  1.44070  1.44470  1.42990  1.43070  NaN       NaN   
2010-01-08  EURUSD  1.43080  1.44380  1.42630  1.44160  NaN       NaN   
2010-01-10  EURUSD  1.44245  1.44252  1.44074  1.44110  NaN       NaN   
2010-01-11  EURUSD  1.44280  1.45560  1.44080  1.45120  NaN       NaN   
2010-01-12  EURUSD  1.45120  1.45450  1.44530  1.44840  NaN       NaN   
2010-01-13  EURUSD  1.44850  1.45790  1.44570  1.45100  NaN  1.442916   
2010-01-14  EURUSD  1.45090  1.45550  1.44460  1.44990  NaN  1.444186   
2010-01-15  EURUSD  1.45000  1.45110  1.43360  1.43790  NaN  1.443043   
2010-01-17  EURUSD  1.43597  1.43655  1.43445  1.43480  NaN  1.441544   
2010-01-18  EURUSD  1.43550  1.44000  1.43340  1.43830  NaN  1.440954   
2010-01-19  EURUSD  1.43820  1.44130  1.42520  1.42870  NaN  1.438726

Вот ожидаемый результат для slow_ma (10-дневный период)

            symbol     Open     High      Low    Close  ATR     slow_ma
Date        
2010-01-03  EURUSD  1.43075  1.43369  1.43065  1.43247  NaN       NaN   
2010-01-04  EURUSD  1.43020  1.44560  1.42570  1.44120  NaN       NaN   
2010-01-05  EURUSD  1.44130  1.44840  1.43460  1.43650  NaN       NaN   
2010-01-06  EURUSD  1.43660  1.44350  1.42820  1.44060  NaN       NaN   
2010-01-07  EURUSD  1.44070  1.44470  1.42990  1.43070  NaN       NaN   
2010-01-08  EURUSD  1.43080  1.44380  1.42630  1.44160  NaN       NaN   
2010-01-10  EURUSD  1.44245  1.44252  1.44074  1.44110  NaN       NaN   
2010-01-11  EURUSD  1.44280  1.45560  1.44080  1.45120  NaN       NaN   
2010-01-12  EURUSD  1.45120  1.45450  1.44530  1.44840  NaN       NaN   
2010-01-13  EURUSD  1.44850  1.45790  1.44570  1.45100  NaN   1.44351   
2010-01-14  EURUSD  1.45090  1.45550  1.44460  1.44990  NaN   1.44467   
2010-01-15  EURUSD  1.45000  1.45110  1.43360  1.43790  NaN   1.44344   
2010-01-17  EURUSD  1.43597  1.43655  1.43445  1.43480  NaN   1.44187   
2010-01-18  EURUSD  1.43550  1.44000  1.43340  1.43830  NaN   1.44122   
2010-01-19  EURUSD  1.43820  1.44130  1.42520  1.42870  NaN   1.43894

Я изменил значения первого кадра данных, чтобы он отображал числа, которые использовались для вычисления значений slow_ma.

Это мой первый пост на Stackoverflow, поэтому просто спросите,что-то неясно.

1 Ответ

0 голосов
/ 25 мая 2018

Как рассчитать экспоненциальную скользящую среднюю с Python быстрее?

скоростей при < 50 [us] дляВаши данные / период на старом устройстве i5 с тактовой частотой 2,6 [ГГц] достижимы ...


Шаг 0: Получите результаты (процесс), пройдя проверку качества

Быстро, нок ошибочным данным добавлено отрицательное значение, верно?

Учитывая, что вы используете "аппаратный" метод .ewm(), вы можете только перечитать его параметры параметризации, если они отличаются dataframe['Close'] возможны режимы обработки столбцов.

В качестве быстрой проверки:

aPV = [ 1.43247, # borrowed from dataframe['Close']
        1.44120,
        1.43650,
        1.44060, 1.43070, 1.44160, 1.44110, 1.45120, 1.44840,
        1.45100, 1.44990, 1.43790, 1.43480, 1.43830, 1.42870,
        ]
|>>> QuantFX.numba_EMA_fromPrice2( N_period     = 10,
                                   aPriceVECTOR = QuantFX.np.array( aPV )
                                   )
array([ 
        1.43247   ,
        1.43405727,
        1.4345014 ,
        1.43561024,
        1.43471747,
        1.43596884,
        1.43690178,
        1.43950145,
        1.44111937,
        1.44291585,
        1.44418569,
        1.44304284,
        1.44154414,
        1.4409543 ,
        1.43872624
        ]
      )

, для которых есть некоторые ~ +/- 3E-7 различия числового представленияиз значений в первой таблице выше (то есть на 2 порядка ниже LSD).

|>>> ( QuantFX.numba_EMA_fromPrice2( 10,
                                     QuantFX.np.array( aPV )
                                     )
     - QuantFX.np.array( slow_EMA_1 )# values borrowed from Table 1 above
       )

array([             nan,
                    nan,
                    nan,
                    nan,
                    nan,
                    nan,
                    nan,
                    nan,
                    nan,
        -1.50656152e-07,
        -3.05082306e-07,
        -1.58703705e-07,
         1.42878787e-07,
         2.98719007e-07,
         2.44406460e-07
         ]
        )

Шаг 1: отрегулируйте (подтвержденную QA) обработку для лучшей скорости

Во время этой фазылот зависит от внешнего контекста использования.

Наилучших результатов можно ожидать от cythonize(), но пока profiling может показывать некоторые сюрпризы на лету.

Не переводя обработку в код Cython, можно получить интересные ускорения при глобальном использовании float64 -s вместо float32 -s (сбрилинекоторые 110 ~ 200 [us] на аналогичных глубинах EMA), векторизованные назначения на месте (~ 2-кратное ускорение, от ~ 100 [us] до ~ 50 [us] в лучшем комбинированном распределении векторной памяти результирующего вектора и его векторизованной обработки значений) и наилучшее, если математическая переформулировкаможет помочь вообще пропустить некоторые «механические» операции.

Тем не менее, все приемы ускорения зависят от используемых инструментов - если чисто numpy или numpy + numba (что может привести к отрицательным последствиям для такой простой обработки, как EMA: вопрос не так много математическое " мясо для доктора Джексона" на самом делеnumber-crunch) или cython -оптимизированное решение, поэтому профилирование в целевом CPU-контексте является обязательным условием для достижения наилучших результатов.


пытаетсянайти более быстрое решение ...

Было бы интересно обновить ваш пост с указанием ожидаемого целевого ускорения или лучше для целевого вызовастоимость обработки в [TIME] -домене для указанной проблемы, в данной [SPACE] -доменной области данных (window == 10, aPriceVECTOR.shape[0] ~ 15), и если целевая платформа исполнения кода имеет некоторое оборудование / ЦП / кэшограничения иерархии или нет, потому что построение платформы backtester на самом деле массово подчеркивает любой и весь дизайн кода + выполнение кода неэффективность .


Принимая во внимание, что EMA достаточно эффективен, инструменты могут получить ~ 4-кратное ускорение

История QuantFX перешла с ~ 42000 [us] до ~ 21000[us] без numba / JIT инструментов просто за счетвекторная обработка с оптимизированной памятью (использование полезных нагрузок искусственного размера, обработка блока aPV[:10000]).

Затем время выполнения еще сократилось до ~ 10600 [us], используя действующий Cpкодовая база ython, только с разрешением на авто-Cythonise, где это возможно, код import с использованием pyximport:

pass;        import pyximport
pass;               pyximport.install( pyimport = True )
from QuantFX import numba_EMA_fromPrice2
...

Таким образом, можно получить скорость
~ 45 ~ 47 [us] для данных вашего размера aPV[:15], период = 10 на обычном 2,6 [ГГц] i5 устройстве.


Если вы настаиваете на использовании pandas dataframe-инструменты и методы, ваша работа в основном находится в руках команды панд, и здесь мало что нужно делать с их компромиссами в дизайне, что нужно было сделать из постоянно существующей дилеммы между скоростью и универсальностью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...