Hinweise zur Beschleunigung des Python-Codes mit Numba Ich fand also heraus, dass Numba die technische Indexfunktion mithilfe der for-Anweisung effektiv beschleunigt, aber es gibt andere Indikatoren, die die if-Anweisung stark nutzen.
Eine davon ist Parabolic SAR. Dies ist kein besonders ungewöhnlicher Indikator, sondern sehr beliebt. Da jedoch der aufsteigende und der absteigende Modus umgeschaltet werden und sich die Schrittweite ändert, kann dies nicht allein durch die for-Anweisung beschrieben werden. Dies war das letzte Mal, dass wir die technischen Indikatoren von MetaTrader nach Python portiert haben.
Diese Zeit ist ein Memo, wenn Sie dies beschleunigen.
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)
Die for-Anweisung ist einfach, dauert aber einige Zeit.
1 loop, best of 3: 1min 19s per loop
Lassen Sie uns zuerst mit Numba beschleunigen. Ändern Sie einfach das Pandas-Array in ein Numpy-Array und fügen Sie "@ jit" hinzu.
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
Es ist ungefähr 55 mal schneller. Es gibt nur wenige Codekorrekturen, daher ist das Ergebnis ziemlich gut.
Versuchen Sie als nächstes, mit Cython zu beschleunigen. Ich dachte, Cython sei mühsam einzurichten, aber mit dem Jupyter-Notebook war die Installation ziemlich einfach. Da jedoch ein externer Compiler verwendet wird, müssen Sie Visual C ++ installieren. Ich musste mit der von mir erstellten Version von Anaconda übereinstimmen, also habe ich diesmal den folgenden Compiler installiert.
Das erste ist, wenn Sie Cython nur einstellen, ohne den Code zu ändern.
%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)
Ergebnis
1 loop, best of 3: 1.07 s per loop
Cython ist mit dem gleichen Code etwas schneller.
Als nächstes beim Hinzufügen der Variablentypdeklaration mit 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)
Ergebnis ist
1 loop, best of 3: 533 ms per loop
war. Es ist ungefähr doppelt so schnell. Es kann schneller sein, wenn Sie es optimieren, aber es kann Ihren Code weniger lesbar machen, also ist es das.
Nur bei der for-Anweisung beschleunigt Numba ebenfalls erheblich, aber wenn die if-Anweisung ebenfalls enthalten ist, nimmt der Effekt ab. Wenn Sie es etwas schneller machen möchten, können Sie Cython mit einigen Codeänderungen verwenden.
Recommended Posts