Notes sur l'accélération du code Python avec Numba Donc, j'ai trouvé que Numba est efficace pour accélérer la fonction d'index technique à l'aide de l'instruction for, mais il existe d'autres indicateurs qui utilisent beaucoup l'instruction if.
L'un d'eux est Parabolic SAR. Ce n'est pas un indicateur particulièrement inhabituel, mais plutôt populaire. Cependant, puisque le mode ascendant et le mode descendant sont commutés et que la largeur du pas change, il ne peut pas être décrit par l'instruction for seule. C'était la dernière fois que nous portions les indicateurs techniques de MetaTrader sur Python.
Cette fois, c'est un mémo pour accélérer cela.
import numpy as np
import pandas as pd
dataM1 = pd.read_csv('DAT_ASCII_EURUSD_M1_2015.csv', sep=';',
names=('Time','Open','High','Low','Close', ''),
index_col='Time', parse_dates=True)
def iSAR(df, step, maximum):
last_period = 0
dir_long = True
ACC = step
SAR = df['Close'].copy()
for i in range(1,len(df)):
last_period += 1
if dir_long == True:
Ep1 = df['High'][i-last_period:i].max()
SAR[i] = SAR[i-1]+ACC*(Ep1-SAR[i-1])
Ep0 = max([Ep1, df['High'][i]])
if Ep0 > Ep1 and ACC+step <= maximum: ACC+=step
if SAR[i] > df['Low'][i]:
dir_long = False
SAR[i] = Ep0
last_period = 0
ACC = step
else:
Ep1 = df['Low'][i-last_period:i].min()
SAR[i] = SAR[i-1]+ACC*(Ep1-SAR[i-1])
Ep0 = min([Ep1, df['Low'][i]])
if Ep0 < Ep1 and ACC+step <= maximum: ACC+=step
if SAR[i] < df['High'][i]:
dir_long = True
SAR[i] = Ep0
last_period = 0
ACC = step
return SAR
%timeit y = iSAR(dataM1, 0.02, 0.2)
L'instruction for est unique, mais cela prend un certain temps.
1 loop, best of 3: 1min 19s per loop
Tout d'abord, accélérons avec Numba. Changez simplement le tableau pandas en un tableau numpy et ajoutez @ jit
.
from numba import jit
@jit
def iSARjit(df, step, maximum):
last_period = 0
dir_long = True
ACC = step
SAR = df['Close'].values.copy()
High = df['High'].values
Low = df['Low'].values
for i in range(1,len(SAR)):
last_period += 1
if dir_long == True:
Ep1 = High[i-last_period:i].max()
SAR[i] = SAR[i-1]+ACC*(Ep1-SAR[i-1])
Ep0 = max([Ep1, High[i]])
if Ep0 > Ep1 and ACC+step <= maximum: ACC+=step
if SAR[i] > Low[i]:
dir_long = False
SAR[i] = Ep0
last_period = 0
ACC = step
else:
Ep1 = Low[i-last_period:i].min()
SAR[i] = SAR[i-1]+ACC*(Ep1-SAR[i-1])
Ep0 = min([Ep1, Low[i]])
if Ep0 < Ep1 and ACC+step <= maximum: ACC+=step
if SAR[i] < High[i]:
dir_long = True
SAR[i] = Ep0
last_period = 0
ACC = step
return SAR
%timeit y = iSARjit(dataM1, 0.02, 0.2)
1 loop, best of 3: 1.43 s per loop
C'est environ 55 fois plus rapide. Il y a peu de modifications de code, donc c'est un très bon résultat.
Ensuite, essayez d'accélérer avec Cython. Je pensais que Cython était un problème à configurer, mais avec le notebook Jupyter, il était assez facile à installer. Toutefois, comme il utilise un compilateur externe, vous devez installer Visual C ++. Je devais correspondre à la version d'Anaconda que j'avais construite, j'ai donc installé le compilateur suivant cette fois.
Le premier est lorsque vous définissez uniquement Cython sans modifier le code.
%load_ext Cython
%%cython
cimport numpy
cimport cython
def iSAR_c0(df, step, maximum):
last_period = 0
dir_long = True
ACC = step
SAR = df['Close'].values.copy()
High = df['High'].values
Low = df['Low'].values
for i in range(1,len(SAR)):
last_period += 1
if dir_long == True:
Ep1 = High[i-last_period:i].max()
SAR[i] = SAR[i-1]+ACC*(Ep1-SAR[i-1])
Ep0 = max([Ep1, High[i]])
if Ep0 > Ep1 and ACC+step <= maximum: ACC+=step
if SAR[i] > Low[i]:
dir_long = False
SAR[i] = Ep0
last_period = 0
ACC = step
else:
Ep1 = Low[i-last_period:i].min()
SAR[i] = SAR[i-1]+ACC*(Ep1-SAR[i-1])
Ep0 = min([Ep1, Low[i]])
if Ep0 < Ep1 and ACC+step <= maximum: ACC+=step
if SAR[i] < High[i]:
dir_long = True
SAR[i] = Ep0
last_period = 0
ACC = step
return SAR
%timeit y = iSAR_c0(dataM1, 0.02, 0.2)
résultat
1 loop, best of 3: 1.07 s per loop
Cython est un peu plus rapide avec le même code.
Ensuite, lors de l'ajout de la déclaration de type de variable avec cdef
.
%%cython
cimport numpy
cimport cython
def iSARnew(df, double step, double maximum):
cdef int last_period = 0
dir_long = True
cdef double ACC = step
cdef numpy.ndarray[numpy.float64_t, ndim=1] SAR = df['Close'].values.copy()
cdef numpy.ndarray[numpy.float64_t, ndim=1] High = df['High'].values
cdef numpy.ndarray[numpy.float64_t, ndim=1] Low = df['Low'].values
cdef double Ep0, Ep1
cdef int i, N=len(SAR)
for i in range(1,N):
last_period += 1
if dir_long == True:
Ep1 = max(High[i-last_period:i])
SAR[i] = SAR[i-1]+ACC*(Ep1-SAR[i-1])
Ep0 = max([Ep1, High[i]])
if Ep0 > Ep1 and ACC+step <= maximum: ACC+=step
if SAR[i] > Low[i]:
dir_long = False
SAR[i] = Ep0
last_period = 0
ACC = step
else:
Ep1 = min(Low[i-last_period:i])
SAR[i] = SAR[i-1]+ACC*(Ep1-SAR[i-1])
Ep0 = min([Ep1, Low[i]])
if Ep0 < Ep1 and ACC+step <= maximum: ACC+=step
if SAR[i] < High[i]:
dir_long = True
SAR[i] = Ep0
last_period = 0
ACC = step
return SAR
%timeit y = iSARnew(dataM1, 0.02, 0.2)
Le résultat est
1 loop, best of 3: 533 ms per loop
était. C'est environ deux fois plus rapide. Cela peut être plus rapide si vous le réglez, mais cela peut rendre votre code moins lisible, alors c'est tout.
Dans le cas de l'instruction for uniquement, Numba a également pour effet d'accélérer considérablement, mais lorsque l'instruction if est également incluse, l'effet est réduit. Si vous voulez le rendre un peu plus rapide, vous pouvez utiliser Cython, avec quelques modifications de code.
Recommended Posts