有没有办法在Python中向量化Renko计算?

问题描述 投票:0回答:2

好吧,现在我在块中使用

df.iterrows()
来循环每分钟并与之前的砖形收盘进行比较。然而,这需要很长时间。我一直在想是否有一种方法可以更快地进行矢量化和回测。因为我将对刻度数据进行回测,这意味着数百万行。

原始 csv

砖形 csv

下面是我一直在使用的for循环。我是这方面的新手,所以请原谅我编写的代码中的任何低效之处,并以任何可能的方式帮助我。

def trend(box, df, lasttrend, lastrenko):
for rows in df.itertuples():
    index = rows.Index
    print(index)
    df.loc[index, 'renko close'] = lastrenko
    if index == 0:
        df.loc[index, 'renko close'] = df.loc[index, 'close']
        df.loc[index, 'trend'] = 'S'
        lasttrend = 'S'
        lastrenko = df.loc[index, 'renko close']
        print('Trend start: S', lastrenko, '\n-------------------------------------')
        continue
    if df.loc[index, 'close'] - lastrenko >= box:
        if lasttrend == 'R':
            if df.loc[index, 'close'] - lastrenko >= 2*box:
                df.loc[index, 'renko close'] = lastrenko + (2*box)
                df.loc[index, 'deviation'] = abs(df.loc[index, 'close'] - df.loc[index, 'renko close'])
                df.loc[index, 'deviation boxes'] = df.loc[index, 'deviation']/box
                df.loc[index, 'trend'] = 'G'
                if df.loc[index,'deviation boxes'] >= 1:
                    df.loc[index, 'renko close'] = df.loc[index, 'renko close'] + (math.floor(df.loc[index,'deviation boxes']))*(box)
                lasttrend = 'G'
                lastrenko = df.loc[index, 'renko close']
                print('Trend change: R - G', lastrenko, '\n-------------------------------------')
        elif lasttrend == 'G' or lasttrend == 'S':
            df.loc[index, 'renko close'] = lastrenko + (box)
            df.loc[index, 'deviation'] = abs(df.loc[index, 'close'] - df.loc[index, 'renko close'])
            df.loc[index, 'deviation boxes'] = df.loc[index, 'deviation']/box
            df.loc[index, 'trend'] = 'G'
            if df.loc[index, 'deviation boxes'] >= 1:
                df.loc[index, 'renko close'] = df.loc[index, 'renko close'] + (math.floor(df.loc[index, 'deviation boxes']))*(box)
            lasttrend = 'G'
            lastrenko = df.loc[index, 'renko close']
            print('Trend change: G - G', lastrenko, '\n-------------------------------------')
        else:
            df.loc[index, 'deviation'] = abs(df.loc[index, 'close'] - df.loc[index, 'renko close'])
            df.loc[index, 'deviation boxes'] = df.loc[index, 'deviation']/box
            df.loc[index, 'trend'] = 'N'
            print('Trend change: R - N', lastrenko, '\n-------------------------------------')
    elif df.loc[index, 'close'] - lastrenko <= -box:
        if lasttrend == 'G':
            if df.loc[index, 'close'] - lastrenko <= -2*box:
                df.loc[index, 'renko close'] = lastrenko - (2*box)
                df.loc[index, 'deviation'] = abs(df.loc[index, 'close'] - df.loc[index, 'renko close'])
                df.loc[index, 'deviation boxes'] = df.loc[index, 'deviation']/box
                df.loc[index, 'trend'] = 'R'
                if df.loc[index,'deviation boxes'] >= 1:
                    df.loc[index, 'renko close'] = df.loc[index, 'renko close'] - (math.floor(df.loc[index,'deviation boxes']))*(box)
                lasttrend = 'R'
                lastrenko = df.loc[index, 'renko close']
                print('Trend change: G - R', lastrenko, '\n-------------------------------------')
        elif lasttrend == 'R' or lasttrend == 'S':
            df.loc[index, 'renko close'] = lastrenko - (box)
            df.loc[index, 'deviation'] = abs(df.loc[index, 'close'] - df.loc[index, 'renko close'])
            df.loc[index, 'deviation boxes'] = df.loc[index, 'deviation']/box
            df.loc[index, 'trend'] = 'R'
            if df.loc[index,'deviation boxes'] >= 1:
                df.loc[index, 'renko close'] = df.loc[index, 'renko close'] - (math.floor(df.loc[index,'deviation boxes']))*(box)
            lasttrend = 'R'
            lastrenko = df.loc[index, 'renko close']
            print('Trend change: R - R', lastrenko, '\n-------------------------------------')
        else:
            df.loc[index, 'deviation'] = abs(df.loc[index, 'close'] - df.loc[index, 'renko close'])
            df.loc[index, 'deviation boxes'] = df.loc[index, 'deviation']/box
            df.loc[index, 'trend'] = 'N'
            print('Trend change: G - N', lastrenko, '\n-------------------------------------')
    else:
        df.loc[index, 'renko close'] = lastrenko
        df.loc[index, 'deviation'] = abs(df.loc[index, 'close'] - df.loc[index, 'renko close'])
        df.loc[index, 'deviation boxes'] = df.loc[index, 'deviation']/box
        df.loc[index, 'trend'] = 'N'
        print('Trend change: N', lastrenko, '\n-------------------------------------')
return df, lasttrend, lastrenko
python pandas numpy vectorization technical-indicator
2个回答
1
投票

您可以使用下面的矢量化砖形。它是专为外汇市场设计的,为了使其与股票配合使用,您可能需要删除点转换:

brick_size = brick_size_pips / 10000.

就性能而言,大约需要。计算全年砖形图需要 250 毫秒,而迭代方法则需要 16,600 毫秒,快了大约 70 倍。

def create_renko(df_prices, brick_size_pips):
    
    t1 = time.perf_counter()

    # Renko charts generate new brick when price moves by "brick_size" from old one
    # Algorithm below splits price into "brick_size" bins, starting from firs close price (ref_price)
    # It forms new "down" brick when price left last bin in "down" direction and reaches new bin
    # The same for "up" brick but price needs to leave in "up" direction and reach new bin over existing
    # During high volatility (large candles) price may leave current bin and immediately move to new one
    # This can be detemined by "2 bins move" and is handled as edge case scenario

    # This approach has known flaw - when price gap (ie over weekend) is of 2 or more Renko brick size, it will generate 1 brick only

    df = df_prices[['high_bid', 'low_bid', 'close_bid']].dropna().copy()
    ref_price = df.iloc[0]['close_bid']
    ref_index = df.iloc[0].name
    brick_size = brick_size_pips / 10000.
    df['high_bin_float'] = ((df['high_bid'] - ref_price) / brick_size).fillna(0).round(5) # distance from ref_price
    df['high_bin'] = df['high_bin_float'].apply(np.floor) # bin number
    df['high_bin_diff'] = df['high_bin'].diff().fillna(0) # change in bin number
    df['low_bin_float'] = ((df['low_bid'] - ref_price) / brick_size).fillna(0).round(5)
    df['low_bin'] = df['low_bin_float'].apply(np.floor)
    df['low_bin_diff'] = df['low_bin'].diff().fillna(0)
    # previous bin numbers will be needed for edge case scenario
    df['high_bin_prev'] = df['high_bin'].shift(1)
    df['low_bin_prev'] = df['low_bin'].shift(1)

    # remember direction of price movement when crossing bin boundary
    df.loc[df.index == df.index[0], 'flip_direction'] = 'up'
    df.loc[(df['high_bin_diff'] > 0) | (df['low_bin_diff'] > 0), 'flip_direction'] = 'up'
    df.loc[(df['high_bin_diff'] < 0) | (df['low_bin_diff'] < 0), 'flip_direction'] = 'down'
    df['flip_direction'] = df['flip_direction'].fillna(method='pad')
    df['flip_direction_prev'] = df['flip_direction'].shift(1)
    # new "up" brick is formed when (price moves to higher bin) and ((price left last bin in "up" direction) or (high volatility, candles crossed two bins))
    df['new_brick_up'] = (df['high_bin_diff'] > 0) & ((df['flip_direction_prev'] == 'up') | (abs(df['low_bin_prev'] - df['high_bin']) > 1))
    # new "down" brick is formed when (price moves to lower bin) and ((price left last bin in "down" direction) or (high volatility, candles crossed two bins))
    df['new_brick_down'] = (df['low_bin_diff'] < 0) & ((df['flip_direction_prev'] == 'down') | (abs(df['high_bin_prev'] - df['low_bin']) > 1))

    # populate helper data, start / end datetime and start / end price for each brick
    df['end_dt'] = df.index
    df.loc[df['new_brick_up'] | df['new_brick_down'], 'start_dt'] = df['end_dt']
    df['start_dt'] = df['start_dt'].fillna(method='pad')
    df['start_dt'] = df['start_dt'].shift(1).fillna(ref_index)
    df.loc[df['new_brick_down'], 'end_price'] = ref_price + brick_size * df['low_bin_float'].round(0)
    df.loc[df['new_brick_up'], 'end_price'] = ref_price + brick_size * df['high_bin_float'].round(0)
    df['start_price'] = df['end_price'].fillna(method='pad').shift(1)
    df['start_price'] = df['start_price'].fillna(ref_price)

    # helpers to plot using OHLC charts
    df['new_brick_up_prev'] = df['new_brick_up'].shift(1)
    df['new_brick_down_prev'] = df['new_brick_down'].shift(1)
    df.loc[df['new_brick_up'], 'change'] = 10
    df.loc[df['new_brick_down'], 'change'] = -10
    df['change'] = df['change'].fillna(0)
    df['change_cumsum'] = df['change'].cumsum()
    df['change_cumsum_prev'] = df['change_cumsum'].shift(1)
    df.loc[df['new_brick_up'], 'open_bid'] = df['change_cumsum'] - 10
    df.loc[df['new_brick_down'], 'open_bid'] = df['change_cumsum']
    df.loc[df['new_brick_up'], 'close_bid'] = df['change_cumsum']
    df.loc[df['new_brick_down'], 'close_bid'] = df['change_cumsum'] - 10
    df['high_bid'] = df[['open_bid', 'close_bid']].max(axis=1)
    df['low_bid'] = df[['open_bid', 'close_bid']].min(axis=1)

    # return only relevant columns
    df = df[df['new_brick_up'] | df['new_brick_down']][['new_brick_up', 'new_brick_down', 'start_dt', 'end_dt', 'start_price', 'end_price', 'open_bid', 'high_bid', 'low_bid', 'close_bid']].copy()

    print(f'Renko built in: {((time.perf_counter()-t1)*1000.):,.2f}ms')

    return df

0
投票

在此输入图片描述

存在一些错误,如红色箭头所示。

© www.soinside.com 2019 - 2024. All rights reserved.