4 votos

Forma eficiente de almacenar la cartera de pedidos en Python

Estoy utilizando la API de Coinbase WebSocket para extraer datos en tiempo real sobre el libro de órdenes para BTC-USD.

Estoy utilizando el siguiente código para almacenar las instantáneas de las ofertas y demandas y los cambios en el libro de órdenes cada vez que hay una actualización de la bolsa.

import websocket,json
import pandas as pd
import numpy as np
from datetime import datetime, timedelta,timezone
from dateutil.parser import parse

pd.DataFrame(columns=['time','side','price','changes']).to_csv("changes.csv")
def on_open(ws):
    print('opened connection')

    subscribe_message ={
    "type": "subscribe",
    "channels": [
        {
            "name": "level2",
            "product_ids": [
                "BTC-USD"
            ]
        }
    ]
}
    print(subscribe_message)
    ws.send(json.dumps(subscribe_message))

timeZero = datetime.now(timezone.utc)
timeClose = timeZero+timedelta(seconds=61)
def on_message(ws,message):
    js=json.loads(message)
    #print([js['time'],js['trade_id'],js['last_size'],js['best_ask'],js['best_bid']])
    if js['type']=='snapshot':
        print('Start: ',timeZero)
        pd.DataFrame(js['asks'],columns=['price','size']).to_csv("snapshot_asks.csv")
        pd.DataFrame(js['bids'],columns=['price','size']).to_csv("snapshot_bids.csv")
    elif js['type']=='l2update':
        mydate=parse(js['time'])
        if mydate >= timeClose:
            print('Closing at ', mydate)
            ws.close()
        side = js['changes'][0][0]
        price = js['changes'][0][1]
        change = js['changes'][0][2]
        pd.DataFrame([[js['time'],side, price, change]],columns=['time','side','price','changes']).to_csv("changes.csv",mode='a', header=False)

socket = "wss://ws-feed.exchange.coinbase.com"
ws = websocket.WebSocketApp(socket,on_open=on_open, on_message=on_message)
ws.run_forever()

De esta manera, todos los cambios se guardan en un archivo csv. Este código se ejecuta durante aproximadamente 1 minuto, pero me gustaría hacerlo funcionar durante un día y luego reconstruir el libro de órdenes.

Una vez hecho esto, quiero analizar el libro de órdenes cada segundo para estudiar cuál es el impacto del precio de comprar (o vender) una cantidad específica de bitcoins.

Por supuesto, este código crea un archivo muy grande 'changes.csv', y si trato de hacerlo funcionar en AWS, el uso de la CPU alcanza el 90% después de algún tiempo y el proceso se mata. ¿Cuál es la forma más eficiente de almacenar el libro de órdenes en cada segundo?

10voto

Diondon Puntos 1

La mejor solución es cambiar completamente la forma de hacerlo:

  1. Almacena los datos antes de que lleguen a tu programa y procésalos después. Por ejemplo, utilizar su programa simplemente como un demonio para suscribirse a los datos. tcpdump todo lo que entra en la interfaz en la que estás recibiendo datos. Post-procésalo después. Lo más probable es que tcpdump será más rápido y tendrá menos sobrecarga de CPU o memoria que cualquier cosa que puedas escribir dentro de esta aplicación de Python.

Pero si usted tienen que utilizar este programa de Python por cualquier razón, por ejemplo, por conveniencia, entonces las 3 optimizaciones más obvias que puede hacer son:

  1. Reducir el casting y las llamadas a funciones. No lances cada evento a un DataFrame y no analizar la fecha en cada mensaje. pandas vienen con un montón de sobrecarga que no necesitas aquí si el propósito es simplemente escribir en el disco. Las llamadas a funciones son caras en Python porque cada llamada crea un nuevo marco de pila. Si tienes que hacerlo, lanza un gran número de registros a la vez. O mejor, escriba directamente en el disco sin la sobrecarga de marshalling de un objeto pandas. Procese la fecha en lote después si es necesario.

  2. Escritura en búfer . Mantener en el ámbito un objeto manejador de archivos, por ejemplo f = open(fname, 'w') y f.write() los datos dentro de su manejador de mensajes. Por defecto, Python almacenará las escrituras con el tamaño de búfer por defecto de tu sistema operativo, LOBWriter y encapsular on_message() como un método de clase del mismo; cree el manejador de archivos como un atributo de instancia dentro de __init__ al instanciar LOBWriter . Recuerda gestionar este objeto y cerrarlo antes de que tu programa termine.

  3. Utilizar un decodificador JSON más rápido. Por ejemplo UltraJSON .

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