Tengo este código python de la implementación de supertrend. Estoy usando el marco de datos de pandas. el código funciona bien, pero la función de supertendencia se ejecuta cada vez más lentamente a medida que aumenta la longitud del marco de datos. Me preguntaba si hay algo que pueda cambiar en el código para optimizarlo y hacerlo más rápido incluso con una gran longitud de marco de datos.
def trueRange(df): df['prevClose'] = df['close'].shift(1) df['high-low'] = df['high'] - df['low'] df['high-pClose'] = abs(df['high'] - df['prevClose']) df['low-pClose'] = abs(df['low'] - df['prevClose']) tr = df[['high-low','high-pClose','low-pClose']].max(axis=1) return tr def averageTrueRange(df, peroid=12): df['trueRange'] = trueRange(df) the_atr = df['trueRange'].rolling(peroid).mean() return the_atr def superTrend(df, peroid=5, multipler=1.5): df['averageTrueRange'] = averageTrueRange(df, peroid=peroid) h2 = ((df['high'] + df['low']) / 2) df['Upperband'] = h2 + (multipler * df['averageTrueRange']) df['Lowerband'] = h2 - (multipler * df['averageTrueRange']) df['inUptrend'] = None for current in range(1,len(df.index)): prev = current- 1 if df['close'][current] > df['Upperband'][prev]: df['inUptrend'][current] = True elif df['close'][current] < df['Lowerband'][prev]: df['inUptrend'][current] = False else: df['inUptrend'][current] = df['inUptrend'][prev] if df['inUptrend'][current] and df['Lowerband'][current] < df['Lowerband'][prev]: df['Lowerband'][current] = df['Lowerband'][prev] if not df['inUptrend'][current] and df['Upperband'][current] > df['Upperband'][prev]: df['Upperband'][current] = df['Upperband'][prev]versión vectorial
def superTrend(df, peroid=5, multipler=1.5): df['averageTrueRange'] = averageTrueRange(df, peroid=peroid) h2 = ((df['high'] + df['low']) / 2) df['Upperband'] = h2 + (multipler * df['averageTrueRange']) df['Lowerband'] = h2 - (multipler * df['averageTrueRange']) df['inUptrend'] = None cond1 = df['close'].values[1:] > df['Upperband'].values[:-1] cond2 = df['close'].values[1:] < df['Lowerband'].values[:-1] df.loc[cond1, 'inUptrend'] = True df.loc[cond2, 'inUptrend'] = False df.loc[(~cond1) & (cond2), 'inUptrend'] = df['inUptrend'][:-1] df.loc[(~cond1) & (cond2) & (df['inUptrend'].values[1:] == True) & (df['Lowerband'].values[1:] < df['Lowerband'].values[:-1]), 'Lowerband'] = df['Lowerband'][:-1] df.loc[(~cond1) & (cond2) & (df['inUptrend'].values[1:] == False) & (df['Upperband'].values[1:] > df['Upperband'].values[:-1]), 'Upperband'] = df['Upperband'][:-1]Aquí está la versión Numba / Numpy de su código. Tienes que convertir tu df[ 'close' ], df[ 'high' ] y df[ 'low' ] como matrices numpy para beneficio de la velocidad. No verifiqué si los valores de salida son correctos, pero entendiste la idea.
import numpy as np from numba import jit # UNCOMMENT THIS LINE IF YOU DON'T HAVE THE OPEN PRICES # c_open = np.concatenate((np.array([np.nan]), c_close[1:])) @jit(nopython=True) def true_range(c_open, c_high, c_low): return np.maximum(np.maximum(c_high - c_low, np.abs(c_high - c_open)), np.abs(c_low - c_open)) @jit(nopython=True) def average_true_range(c_open, c_high, c_low, period=12): true_r = true_range(c_open, c_high, c_low) size = len(true_r) out = np.array([np.nan] * size) for i in range(period - 1, size): window = true_r[i - period + 1:i + 1] out[i] = np.mean(window) return out @jit(nopython=True) def super_trend(c_close, c_open, c_high, c_low, period=5, multipler=1.5): size = len(c_close) avg_true_r = average_true_range(c_open, c_high, c_low, period=period) h2 = (c_high + c_low) / 2 upper_band = h2 + (multipler * avg_true_r) lower_band = h2 - (multipler * avg_true_r) in_up_trend = np.array([np.nan] * size) for current in range(1, size): prev = current - 1 if c_close[current] > upper_band[prev]: in_up_trend[current] = True elif c_close[current] < lower_band[prev]: in_up_trend[current] = False else: in_up_trend[current] = in_up_trend[prev] if in_up_trend[current] and lower_band[current] < lower_band[prev]: lower_band[current] = lower_band[prev] if not in_up_trend[current] and upper_band[current] > upper_band[prev]: upper_band[current] = upper_band[prev] return upper_band, lower_band, in_up_trendEditar: si no usa Heiken Ashi, no necesita cambiar los precios de cierre para obtener los últimos precios de cierre, ya que son equivalentes a los precios de apertura;)
Siéntase libre de revisar mi biblioteca de indicadores rápidos @ github
En lugar de import pandas as pd , intente usar Modin . Modin automáticamente hace que los pandas sean mucho más rápidos. Solo import modin.pandas as pd . No necesita cambiar ningún código que no sea la importación.
Si necesita usar el método df.apply() , hay un paquete llamado Swifter . Después de pip install swifter , todo lo que necesita hacer es import swifter , y luego en lugar de hacer df.apply() , haga df.swifter.apply() . Lo conveniente es que Swifter también funciona con Modin.