Arbitraje de pases de futuros de dólar en Rofex con ArQuants.

Un arbitraje obtiene una rentabilidad sin asumir ningún riesgo. Vamos a tratar este tema desde un concepto teórico, dado que la estrategia que mostraremos no esta pensada para correr productivamente.

Nos vamos a enfocar en el arbitraje de pases de futuros en Rofex. En esta ocasión usaremos los contratos de futuro de dolar (DOMar19, DOAbr19) y el pase de futuro de dolar (DOP 03/04).

Pasemos a la estrategia

Primero definimos los imports que vamos a utilizar en nuestro código. En este caso seran Strategy y Order, ambas provistas por ArQuants.

from arquants import Strategy
from arquants import Order

En segundo lugar definimos la clase de la estrategia. La misma tiene que extender la clase Strategy. Podemos definir los parámetros que la estrategia soporta dentro de la firma del método __init__, en este caso min_diff. También podemos definir atributos.

class ArbitrajePases(Strategy):
    
    def __init__(self, min_diff=0.01):
        self.orders = []
        self.min_diff = min_diff

Nos queda presentar lo mas importante de la estrategia, el metodo next. Este método es invocado cada vez que se recibe market data.

def next(self):
    self.log("Market data recibidia. Chequeando arbitraje")
    if self.data1.bid_px[0] - self.data0.offer_px[0] > self.data2.offer_px[0]:
        self.logs("Arbitraje detectado, comprando pase, vendiendo combinada")
        size = min(self.data1.bid_qty[0], self.data0.offer_qty[0], self.data2.offer_qty[0])
        self.sell(data=self.data1, price=self.data1.bid_px[0], size=size, exectype=Order.Limit)
        self.buy(data=self.data0, price=self.data0.offer_px[0], size=size, exectype=Order.Limit)
        self.buy(data=self.data2, price=self.data2.offer_px[0], size=size, exectype=Order.Limit)

    elif self.data1.offer_px[0] - self.data0.bid_px[0] < self.data2.bid_px[0]:
        self.logs("Arbitraje detectado, vendiendo pase, comprando combinada")
        size = min(self.data1.offer_qty[0], self.data0.bid_qty[0], self.data2.bid_qty[0])
        self.buy(data=self.data1, price=self.data1.offer_px[0], size=size, exectype=Order.Limit)
        self.sell(data=self.data0, price=self.data0.bid_px[0], size=size, exectype=Order.Limit)
        self.sell(data=self.data2, price=self.data2.bid_px[0], size=size, exectype=Order.Limit)

Podemos ver que se hace referencia a atributos llamados data0, data1, y data2. Los mismos representan cada uno de los contratos que se están operando. En este caso data0 está asociado al contrato corto (por ejemplo DOMar19), data1 al contrato largo (por ejemplo DOAbr19) y data2 al pase (DOP 03/04).

Cada data contiene market data correspondiente al contrato. En particular la market data actual es accedida invocando el tipo de market data que se desea en el indice 0. Por ejemplo self.data0.offer_px[0] retorna el valor del mejor offer de DOMar19 en el momento actual.

También vemos que se utilizan los métodos sell y buy. Estos métodos pertenecen a la libreria de ArQuants y permiten comprar y vender. Sus parámetros permiten especificar que se va a operar, a que precio, que cantidad, y con que tipo de orden. Existen más parámetros que permiten
hacer una definición más precisa de la orden.

Finalmente, la estrategia comprará DOP 03/04 y hará una venta de pase vendiendo DOAbr19 y comprando DOMar19 si el precio de venta de DOAbr19 menos el precio de compra de DOMar19 es mayor al precio de compra de DOP 03/04.
En caso de que no sea posible, intentará vender DOP 03/04 y hacer una compra de pase comprando DOAbr19 y vendiendo DOMar19 si el precio de compra de DOAbr19 menos el precio de venta de DOMar19 es menor al precio de venta de DOP 03/04

Si consigue realizar alguna de las dos operaciones habrá arbitrado un pase de contratos de futuros de dólar.

El código completo de la estrategia queda de la siguiente manera

from arquants import Strategy
from arquants import Order


class ArbitrajePases(Strategy):

    def __init__(self, min_diff=0.01):
        self.orders = []
        self.min_diff = min_diff

    def next(self):
        self.log("Market data recibidia. Chequeando arbitraje")
        if self.data1.bid_px[0] - self.data0.offer_px[0] > self.data2.offer_px[0]:
            self.logs("Arbitraje detectado, comprando pase, vendiendo combinada")
            size = min(self.data1.bid_qty[0], self.data0.offer_qty[0], self.data2.offer_qty[0])
            self.sell(data=self.data1, price=self.data1.bid_px[0], size=size, exectype=Order.Limit)
            self.buy(data=self.data0, price=self.data0.offer_px[0], size=size, exectype=Order.Limit)
            self.buy(data=self.data2, price=self.data2.offer_px[0], size=size, exectype=Order.Limit)

        elif self.data1.offer_px[0] - self.data0.bid_px[0] < self.data2.bid_px[0]:
            self.logs("Arbitraje detectado, vendiendo pase, comprando combinada")
            size = min(self.data1.offer_qty[0], self.data0.bid_qty[0], self.data2.bid_qty[0])
            self.buy(data=self.data1, price=self.data1.offer_px[0], size=size, exectype=Order.Limit)
            self.sell(data=self.data0, price=self.data0.bid_px[0], size=size, exectype=Order.Limit)
            self.sell(data=self.data2, price=self.data2.bid_px[0], size=size, exectype=Order.Limit)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s