1 votos

Prueba retrospectiva: Reconstrucción rápida de la cartera de pedidos utilizando datos de creación y finalización de pedidos en Python

Estoy buscando una forma rápida de reconstruir el libro de órdenes en el momento de la creación de cada nueva orden limitada.

Los datos que tengo son de creación y finalización de pedidos:

OrderID

hora_de_creación

tiempo_completado

precio

a

1

2

10

b

1

6

11

c

3

8

9

d

4

5

8

e

9

10

7

(Aquí se puede ignorar el volumen). Me gustaría averiguar rápidamente las órdenes existentes en el libro de órdenes al crearse cada nueva orden, y calcular los parámetros de distribución en base a ellos.

Por ejemplo, para el OrderID d, primero averiguaría que sólo las órdenes b y c están todavía en el libro de órdenes, porque en el momento de la creación de la orden d (t=4), a se ha llenado, b y c se han creado pero no se han llenado, y e todavía no se ha creado.

A partir de ahí, calcularía los parámetros de la distribución, como la media, la mediana, los percentiles, etc. En el caso de la orden d, el precio medio de las órdenes pendientes sería (11 + 9) / 2 = 10.

La forma más sencilla que se me ocurre es crear una función que filtre los datos de los pedidos no cumplidos y luego extraiga los parámetros de distribución. Esta función se aplicaría entonces de forma iterativa a cada fila del marco de datos. Por ejemplo:

def get_params(ser):
    unfilled_orders = df[(df['time_created'] < ser['time_created']) & (df['time_completed'] > ser['time_created'])]
    mean = unfilled_orders['price'].mean()
    25perc = unfilled_orders['price'].quantile(0.25)
    return pd.Series([mean, 25perc])

df.apply(get_params, axis=1)

Sin embargo, el problema de esta implementación es que es demasiado lenta. El resultado de cada fila está muy relacionado con los resultados de la fila anterior, pero esta implementación no lo aprovecha. Estoy pensando si hay una solución más rápida, quizás una solución basada en una ventana rodante (si consideramos irrelevantes los pedidos demasiado antiguos) o expansiva. Gracias.

1voto

John Rennie Puntos 6821

En mi opinión, la mejor manera de hacerlo es reconstruir la cartera de pedidos a partir del flujo de pedidos .

Pero en primer lugar me parece muy extraño que empiece con este marco de datos, normalmente no se sabe la fecha de borrado en el momento de la creación. Esto significa que los datos ya han sido procesados, así que si realmente quieres ser rápido debe volver a este paso anterior y reconstruir la cartera de pedidos en esta etapa anterior .

La estructura que adoptaré es el siguiente diccionario

{date1: 
     {'add': {order_id1: price, .... }, 
      'del': {order_id1: price, .... }}, 
 date2: ...
}

El pseudocódigo para rellenar esta estructura sería (y He compartido una aplicación en Colab )

for row in dataframe:
   1. if it is a new 'creation_time': copy the "previous" dictionary 
        except for the orders that are in the del 

   2. insert this order_id in the 'add' section of its creation_time
        (except if it is in the 'del' section 
         [would mean that you have orders that are 
          created and completed at the same timestamp]
        )
   3. insert this order_id in the 'del' section of its completion_time

Sería algo así como

for row in data_frame:
    current_timestamp = row.creation_time
    if current_timestamp > previous_timestamp:
       # it is a new timestamp: 
       # 1. store the orderbook
       full_oderbook[previous_timestamp] = current_orderbook
       # 2. delete orders if needed
       to_be_deleted = get_for_deletion(full_oderbook, previous_timestamp , current_timestamp)
       for order_id in to_be_deleted:
           current_orderbook.add.pop(order_id)
    # 3. update orderbook
    current_oderbook.add.update({row.order_id: row.price})
    full_oderbook[row.completion_time].del.update({row.order_id: row.price})
    # 4. keep track
    previous_timestamp = current_timestamp

el get_for_deletion selecciona el borrado entre la marca de tiempo anterior y la actual, su pseudocódigo está ahí:

def get_for_deletion(full_orderbook, prev_timestamp , curr_timestamp):
   return union(ob.del for ob.key between prev_timestamp and curr_timestamp)

El único inconveniente de este algoritmo es que sólo proporciona información sobre la fecha de creación de las marcas de tiempo. Deberías comprobar si hay fechas de borrado en medio y crear carteras intermedias (te dejo hacerlo por tu cuenta).

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