es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Manteniendo una conexión ib_insync siempre activa con Sanic.

Estoy desarrollando una API (usando Sanic) que es una puerta de enlace a IB, utilizando ib insync. Esta API expone puntos finales para realizar un nuevo pedido y obtener las posiciones en tiempo real, pero también se encarga de actualizar los estados de los pedidos en una base de datos utilizando los eventos de ib insync.

Mi pregunta es: ¿es posible que la API se conecte solo una vez a IB cuando se inicia, y reutilice la misma conexión para todas las solicitudes?

Actualmente me estoy conectando a IB utilizando connectAsync en cada solicitud. Y aunque esto funciona, la API no recibirá eventos si no está manejando actualmente una solicitud.

Este es el código de un punto final, como referencia

@app.post(“/order/“)
async def post_order(request, symbol):
order = jsonpickle.decode(request.body)
with await IB().connectAsync(“127.0.0.1”, 7496, clientId=100) as ib:
ib.orderStatusEvent += onOrderStatus
ib.errorEvent += onTWSError
ib.newOrderEvent += onNewOrderEvent

    contract = await ib.qualifyContractsAsync(contract)
    trade = ib.placeOrder(contract[0], order)

return text(trade.order.orderId)

Entonces, deseo no usar la instrucción “with” y simplemente usar una conexión global de IB.

Cuando me conecto en la inicialización del módulo (usando connectAsync), cualquier llamada posterior que sea asíncrona, como qualifyContractsAsync, simplemente se bloquea. La depuración me mostró que se bloquea en asyncio.gather, lo que significa que algo está mal con los bucles de eventos.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Sí, es posible tener la API conectada solo una vez a IB cuando se inicia, y reutilizar la misma conexión para todas las solicitudes.

    En lugar de conectarse a IB utilizando connectAsync en cada solicitud, puede mover el código de conexión a la inicialización del módulo, de modo que la conexión se establezca solo una vez cuando se cargue el módulo. Puede crear una variable global ib para este propósito e inicializarla en el método __init__ del módulo.

    import ib_insync
    
    ib = ib_insync.IB()
    
    async def run():
        await ib.connectAsync('127.0.0.1', 7496, clientId=100)
        ib.qualifyContractsEvent += onQualifyContracts
    
    def onQualifyContracts(qualifiedContracts):
        # manejar los contratos calificados
    
    # inicializar la conexión IB al cargar el módulo
    asyncio.get_event_loop().run_until_complete(run())
    

    Luego, puedes usar este objeto ib global en tus controladores de solicitud, sin el uso de la declaración with.

    @app.post("/order/<symbol>")
    async def post_order(request, symbol):
        order = jsonpickle.decode(request.body)
        contract = ib_insync.Stock(symbol, 'SMART', 'USD')
        contract = await ib.qualifyContractsAsync(contract)
        trade = ib.placeOrder(contract[0], order)
        return text(trade.order.orderId)
    

    Ten en cuenta que aún necesitas asegurarte de que cualquier código asíncrono en tus controladores de solicitud no bloquee el bucle de eventos, de lo contrario, las solicitudes posteriores pueden quedarse bloqueadas. Si encuentras bloqueos en asyncio.gather, asegúrate de usar declaraciones async with con cualquier administrador de contexto asíncrono y evitar operaciones de bloqueo.

    “`python
    async def some_async_operation():
    async with ib_insync.IB().connectAsync(‘127.0.0.1’, 7496, clientId=100) as ib:
    # usar instancia ib

    @app.post(“/async_operation”)
    async def async_operation(request):
    await some_async_operation() # usar async with para asegurar que el contexto se cierre rápidamente
    return text(“Operación asíncrona completada.”)
    “`

Comments are closed.