2 votos

Backtesting de la estrategia de venta en corto usando pandas dataframe

Me gustaría hacer un simple backtest para una de mis estrategias de venta en corto. Estoy usando pandas dataframes. Así que tengo un dataframe como el siguiente, que indica cuántas posiciones para abrir / cerrar cada día.

                position_change position_total
2018-01-03      1               1
2018-01-04      0               1
2018-01-05      0               1
2018-01-08      0               1
2018-01-09      0               1
2018-01-10      1               2
2018-01-11      0               2
2018-01-12      0               2
2018-01-16      0               2

También tengo un dataframe con los precios del activo:

            price       short_sell_change       accum_change
2018-01-03  10          1                       1
2018-01-04  9           1,1111111111            1,1111111111
2018-01-05  8           1,125                   1,25
2018-01-08  7           1,1428571429            1,4285714286
2018-01-09  6           1,1666666667            1,6666666667
2018-01-10  5           1,2                     2
2018-01-11  4           1,25                    2,5
2018-01-12  3           1,3333333333            3,3333333333
2018-01-16  2,5         1,2                     4 

El marco de datos final (importe neto) debería ser:

            net_amount
2018-01-03  10
2018-01-04  11,1111111111
2018-01-05  12,5
2018-01-08  14,2857142857
2018-01-09  16,6666666667
2018-01-10  25
2018-01-11  31,25
2018-01-12  41,6666666667
2018-01-16  50

Esto es fácil de hacer con Excel acumulando el importe neto anterior con una referencia a la celda anterior y añadiendo la información de position_chage: enter image description here

¿Cómo se puede hacer esto a la manera de los pandas? (Lamentablemente supongo que la única forma posible es iterando sobre las filas)

3voto

dmuir Puntos 146

Suponiendo que su marco de datos se parece a esto y el nombre del marco de datos es your_dataframe (He omitido una de sus columnas que no era necesaria para esto):

   position  pos_total  price  ss_change
0         1          1   10.0   1.000000
1         0          1    9.0   1.111111
2         0          1    8.0   1.125000
3         0          1    7.0   1.142857
4         0          1    6.0   1.166667
5         1          2    5.0   1.200000
6         0          2    4.0   1.250000
7         0          2    3.0   1.333333
8         0          2    2.5   1.200000
9         0          2    1.0   2.500000

A continuación, para replicar su fórmula de Excel definí una función que toma un marco de datos y su valor inicial como entradas y devuelve el marco de datos con una nueva columna y los valores que está buscando:

def net_amount(df, initial_value):
    df['net_amount'] = float(initial_value)
    for row in range(1, len(df)):
        df['net_amount'][row] = (df['net_amount'][row-1] *
                                 df['ss_change'][row] +
                                 df['position'][row] *
                                 df['price'][row])
    return df

Esta es una forma iterativa de hacerlo y con grandes cantidades de datos llevará mucho tiempo. Si tienes una tonelada de datos hay formas mejores.

A continuación, sólo hay que llamar a la función:

net_amount(your_dataframe, 10)

Esto es lo que se devuelve:

   position  pos_total  price  ss_change  net_amount
0         1          1   10.0   1.000000   10.000000
1         0          1    9.0   1.111111   11.111111
2         0          1    8.0   1.125000   12.500000
3         0          1    7.0   1.142857   14.285714
4         0          1    6.0   1.166667   16.666667
5         1          2    5.0   1.200000   25.000000
6         0          2    4.0   1.250000   31.250000
7         0          2    3.0   1.333333   41.666667
8         0          2    2.5   1.200000   50.000000
9         0          2    1.0   2.500000  125.000000

Hay muchas maneras de mejorar esto y de hacerlo más dinámico si es necesario. La forma en que se encuentra depende de que las columnas tengan un nombre específico, pero se puede utilizar como plantilla y hacer cambios.

Editar:

Para mayor rapidez puedes incorporar el uso de numba así:

import pandas as pd
from numba import jit

@jit
def numba_calc(net, ss, pos, price):
    for i in range(1, len(net)):
        net[i] = (net[i-1] * ss[i] + pos[i] * price[i])
    return net

def net_amount_numba(df, initial_value):
    df['net_amount'] = float(initial_value)
    net = df['net_amount'].to_numpy()
    ss = df['ss_change'].to_numpy()
    pos = df['position'].to_numpy()
    price = df['price'].to_numpy()

    df['net_amount'] = numba_calc(net, ss, pos, price)

    return df

En mi máquina, esto mejora el rendimiento en ~8x de ~2,4 milisegundos a ~300 microsegundos. Documentación sobre Pandas/Numba

Finanhelp.com

FinanHelp es una comunidad para personas con conocimientos de economía y finanzas, o quiere aprender. Puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X