





18



19 Shares

Últimamente, muchos posts han estado hablando sobre como los traders se hacen ricos debido a las oportunidades de arbitraje en el criptomercado. He tratado de realizar arbitraje durante meses, pero nunca pude obtener una estrategia rentable. No obstante, les contaré los problemas con los que me encontré mientras lo intentaba. Esto puede ser beneficioso para aquellos que están comenzando para que no tengan que transitar el mismo doloroso camino. Resumiendo, esto es lo que pude sacar en concreto:

La mayoría de las oportunidades de arbitraje se esfuman luego de considerar las tasas del exchange y las comisiones por transacción.

La mayoría de las oportunidades de arbitraje aparecen entre exchanges donde las wallets están en mantenimiento, lo cual hace que los depósitos y retiros sean imposibles.

Los tiempos de transacción entre los exchanges hacen que el arbitraje se convierta en una lotería débito a la volatilidad del mercado.

Sigan leyendo para descubrir como construir un monitoreador de arbitrajes con python y obtener información valiosa en consecuencia.

¿Qué es el arbitraje?

Arbitraje (por definición), es la practica que aprovecha una diferencia de precios entre dos o más mercados. Por ejemplo, si descubres que las acciones de una empresa se están tradeado a menos precio en un mercado que en otros, podrías comprarlas en ese mercado y venderlas en otro por un precio mayor, logrando de esta manera una rentabilidad por la diferencia de precios. Simple. Desafortunadamente, muy simple.

Esta simplicidad le da a los traders la oportunidad de sacarle provecho a la situación; esto incrementa la demanda de acciones en un mercado donde los precios están bajos y, al mismo tiempo, aumenta la oferta en los mercados donde los precios están mas elevados. Por lo tanto, involuntariamente estabilizan la desigualdad de precios. Además, cuantos más traders tenga el mercado, más eficientemente trabajan para estabilizar los precios. De hecho, el modelo financiero asume la condición libre de arbitraje. Lo que implica que, en mercados eficientes, no debería haber oportunidades de arbitrar.

Pero seamos honestos, los mercados de cripto activos están relativamente inmaduros. Constantemente aparecen nuevos exchanges con bajos volúmenes de operaciones. Este mercado esta lejos de ser eficiente.

Cómo encontrar oportunidades de arbitraje en los cripto mercados?

Hay muchas herramientas que pueden ayudarlos a encontrar oportunidades de arbitraje. Comencemos con la más simple: sitos que monitorean estas oportunidades (por ejemplo, este). El problema con estos sitios es que no se puede controlar que exchange y que activos se monitorean. Y, en la practica, esto es algo que definitivamente necesitamos hacer, porque para aventajarnos de una oportunidad necesitamos contar con los activos indicados, en el momento indicado, en el exchange indicado.

Entonces, vamos a construir nuestro propio monitor desde cero. Buscará oportunidades que realmente nos interesen. Para hacerlo, vamos a usar la librería ccxt de Python que nos permite conectar a diversos exchanges (115 para ser precisos) y tradear cripto de un modo estandarizado (a los desarrolladores de ccxt: hicieron un excelente trabajo!). Vamos a usar estas librerías para consultar los precios de compra/venta de diferentes activos en diferentes exchages, compararlos y luego pensar la estrategia de arbitraje.

Vamos a comenzar. Ante nada, importar las librerías:

import numpy as np import ccxt 1 2 import numpy as np import ccxt

Vamos a utilizar numpy luego para realizar los cálculos. Ahora, definamos algunos exchanges:

exchanges = ["Allcoin", "Binance", "Bitfinex", "Bittrex", "Cex", "Cryptopia", "Exmo", "Gatecoin", "Hitbtc", "Huobipro", "Kraken", "Kucoin", "Livecoin", "Okex", "Poloniex", "Qryptos", "Quadrigacx", "Southxchange", "Yobit"] 1 2 exchanges = [ "Allcoin" , "Binance" , "Bitfinex" , "Bittrex" , "Cex" , "Cryptopia" , "Exmo" , "Gatecoin" , "Hitbtc" , "Huobipro" , "Kraken" , "Kucoin" , "Livecoin" , "Okex" , "Poloniex" , "Qryptos" , "Quadrigacx" , "Southxchange" , "Yobit" ]

Con exchanges definido, ahora podemos inicializar los correspondiente clientes para pedirles los datos. Lo pueden definir así:

allcoin = ccxt.allcoin() 1 allcoin = ccxt . allcoin ( )

O mejor aún, lo pueden hacer así para evitar escribir tanto:

clients = [getattr(ccxt, e.lower())() for e in exchanges] 1 clients = [ getattr ( ccxt , e . lower ( ) ) ( ) for e in exchanges ]

Entonces clients es un listado que contiene todos los clientes que necesitamos. Ahora, definamos algunos pares de interés:

symbols = ["ADA/BTC", "BCH/BTC", "BTG/BTC", "BTS/BTC", "CLAIM/BTC", "DASH/BTC", "DOGE/BTC", "EDO/BTC", "EOS/BTC", "ETC/BTC","ETH/BTC", "FCT/BTC", "ICX/BTC", "IOTA/BTC", "LSK/BTC", "LTC/BTC", "MAID/BTC", "NEO/BTC", "OMG/BTC", "QTUM/BTC", "STR/BTC", "TRX/BTC","VEN/BTC", "XEM/BTC", "XLM/BTC", "XMR/BTC", "XRP/BTC", "ZEC/BTC"] 1 2 3 symbols = [ "ADA/BTC" , "BCH/BTC" , "BTG/BTC" , "BTS/BTC" , "CLAIM/BTC" , "DASH/BTC" , "DOGE/BTC" , "EDO/BTC" , "EOS/BTC" , "ETC/BTC" , "ETH/BTC" , "FCT/BTC" , "ICX/BTC" , "IOTA/BTC" , "LSK/BTC" , "LTC/BTC" , "MAID/BTC" , "NEO/BTC" , "OMG/BTC" , "QTUM/BTC" , "STR/BTC" , "TRX/BTC" , "VEN/BTC" , "XEM/BTC" , "XLM/BTC" , "XMR/BTC" , "XRP/BTC" , "ZEC/BTC" ]

Pueden modificar las variables anteriores acorde a sus preferencias. Luego definimos otras variables útiles:

ask = np.zeros((len(symbols), len(clients))) bid = np.zeros((len(symbols), len(clients))) 1 2 ask = np . zeros ( ( len ( symbols ) , len ( clients ) ) ) bid = np . zeros ( ( len ( symbols ) , len ( clients ) ) )

Finalmente, pedimos los datos de los clientes. Vamos a usar la función fetch_order_book en cada cliente, que nos devolverá el libro de ordenes completo, pero vamos a focalizar solamente en los últimos precios de compra / venta (este es un primer planteo, podemos explorar mejores opciones calculando el valor promedio de nuestro trade).

Ejecutando el monitor de arbitraje

Asumiendo que no hayan modificado el listado exchanges, las próximas lineas pueden tardar un poco. Para acelerarlo, volvamos a definir la lista de clientes.

for row, symbol in enumerate(symbols): for col, client in enumerate(clients): try: book = client.fetch_order_book(symbol) ask[row, col] = book['asks'][0][0] bid[row, col] = book['bids'][0][0] except: pass 1 2 3 4 5 6 7 8 9 for row , symbol in enumerate ( symbols ) : for col , client in enumerate ( clients ) : try : book = client . fetch_order_book ( symbol ) ask [ row , col ] = book [ 'asks' ] [ 0 ] [ 0 ] bid [ row , col ] = book [ 'bids' ] [ 0 ] [ 0 ] except : pass

He definido el pedido dentro de un bloque try porque algunos símbolos no se tradean en todos los exchanges, y los pedidos incorrectos acarrean errores fastidiosos. Otra fuente de errores podría ser el rate request limits que, de momento, lo estamos dejando de lado. También podemos implementar un delay para reducir la frecuencia de los pedidos para cada exchange. Esee delay debería ser ajustado dependiendo a cuales exchanges nos estamos conectando, porque cada uno tiene sus propias limitaciones. Para profundizar sobre esto pueden chequear la documentación de cada exchange. También he definido los ask y bid ndarrays en el bloque try ya que algunos pedidos pueden devolver arrays vacíos, y por ahora estamos tratando de evitar eso.

En un planteo mas eficiente, no queremos esperar hasta que todo el loop finalice de buscar una oportunidad de arbitraje. Pero por ahora, vamos a dejarlo así y continuaremos explorando los datos para evaluar cuales pueden ser nuestras mejores opciones.

Habiendo definido los precios de compra venta con los valores ask y bid para cada moneda en cada exchange, ahora podemos definir nuestra estrategia y calcular nuestras ganancias y pérdidas. Nuestra estrategia para tradear la moneda C entre los exchanges E1 y E2 implican comprar C en E1, transferir la moneda C a E2 y venderla allí. Queremos realizar todos estos pasos lo más rapido posible porque no queremos que alguien se nos adelante. Así que vamos a ejecutar cada trade inmediatamente, donde inmediatamente significa comprar al precio mas bajo que alguien esta dispuesto a vender. Así que definamos los pasos:

En E1, pongo la orden de compra para C.

Transfiero la moneda C a E2

En E2, pongo una orden de venta para C.

Calculo la ganancia del Retorno de inversion (ROI) en BTC:

$ROI =\left\{ \frac {bid_{E2} }{ask_{E1}} – 1 \right\} \cdot 100 \%$

En la practica, deberían también pagar tasas (fees) en los exchanges. Así que el ROI quedaría mejor definido así:

$ROI =\left\{ \frac {bid_{E2} \cdot (1-fee)}{ask_{E1} \cdot (1+fee)} – 1 \right\} \cdot 100 \%$

Luego, vamos a definir la variable fee para calcular el ROI. Podemos definir un array o un diccionario de fees por cada exchange, pero por ahora, a fines de simplificar, solo vamos a definir un porcentaje general (conservador) de fee.

fee = 0.25 1 fee = 0.25

Finalmente, deberíamos también descontar la comisión por transacción. Pero por ahora vamos a proceder sin tener esto en cuenta, porque las comisiones dependen de cada moneda y de la carga de la red en ese momento, y ahora nos vamos a preocupar por eso.

Vamos a calcularlo, y a contar cuantas oportunidades de ganancia hemos encontrado:

opportunities = [] for i, symbol in enumerate(symbols): for j1, exchange1 in enumerate(exchanges): for j2, exchange2 in enumerate(exchanges): roi = 0 if j1 != j2 and ask[i, j1]>0: roi = ((bid[i, j2]*(1-fee/100)) / (ask[i, j1]*(1+fee/100)) - 1) * 100 if roi>0: opportunities.append([symbol, exchange1, ask[i, j1], exchange2, bid[i, j2], round(roi,2)]) print("Number of profitable opportunities:", len(opportunities)) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 opportunities = [ ] for i , symbol in enumerate ( symbols ) : for j1 , exchange1 in enumerate ( exchanges ) : for j2 , exchange2 in enumerate ( exchanges ) : roi = 0 if j1 != j2 and ask [ i , j1 ] > 0 : roi = ( ( bid [ i , j2 ] * ( 1 - fee / 100 ) ) / ( ask [ i , j1 ] * ( 1 + fee / 100 ) ) - 1 ) * 100 if roi > 0 : opportunities . append ( [ symbol , exchange1 , ask [ i , j1 ] , exchange2 , bid [ i , j2 ] , round ( roi , 2 ) ] ) print ( "Number of profitable opportunities:" , len ( opportunities ) )

Hemos encontrado 108 oportunidades!. Prometedor, cierto? Vamos a ordenarlas por su origen y observemos cuales son las mejores:

opportunities = sorted(opportunities, reverse=True, key=lambda x: x[5]) print(opportunities[:10]) 1 2 opportunities = sorted ( opportunities , reverse = True , key = lambda x : x [ 5 ] ) print ( opportunities [ : 10 ] )

Al momento de escribir este articulo, la mejor opción es comprar QTUM/BTC en Bitfinex and venderlos en Qryptos. Por cadaQTUM/BTCtradeado, podemos obtener un ROI del 75.45%

El enfoque ingenuo…

Ahora que hemos encontrado algunas oportunidades, podemos comenzar el arbitraje. Las primeras oportunidades que hemos encontrado involucran todas al QTUM en determinados exchanges y vendiéndolos todos en Qryptos. El retorno de ese arbitraje es alrededor de un 75%. 75%!!!. Vamos a tradear todo el día. Nos vamos a hacer ricos. Tan fácil…

Solo por curiosidad, busquemos “qryptos+qtum+deposit” en Google para ver si todo va a ser tan simple cuando tratemos de depositar nuestros QTUM ahí. Encontré:

Al parecer no todo va a salir tan bien. Observemos el tercer enlace: FAQ de Qryptos explicando que nuestra wallet no va a ser compatible con los tokens de QTUM que compramos allí.

No perdamos tiempo, tenemos 101 posibilidades más. Tomemos la siguiente. Podemos comprar un poco de BTG en yobit y venderlas en CEX. Pero…un momento…las dos oportunidades luego de esta implican vender BTC compradas en yobit. Sospechoso.

Abro mi cuenta de Yobit e intento hacer un retiro de BTG para ver si todo funciona bien. Cuando le hago click al botón withdrawl, me da la siguiente notificación:

Wallet Status: Maintenance (billetera/cartera en mantimiento). OK, no estamos avanzando. Sigamos buscando en las otras opciones

Otra oportunidad interesante de la lista: comprar algo de BCH en Binance y venderlas luego en Yobit. Esta vez con menos ganancia, algo rondando el 4% de ROI. Esto podría ser real. Ante nada, necesitamos tener disponibles los BTC en Binance para poder comprar aquí. Si afortunadamente los tenemos disponibles, comenzamos con el pie derecho. De lo contrario, comenzamos a rezar para que nuestros BTC lleguen antes de que la oportunidad desaparezca.

Afortunadamente tengo algunos BTC en Binance, así que voy a comprar 1 BCH y luego busco mi dirección de BCH en Yobit para poder enviarme allí las monedas. Cuando hago click en el botón de depósito, me encuentro con esta notificación:

Adivinen qué? La wallet esta en mantenimiento. Podemos ver esto cuando intentamos hacer el retiro de algunas monedas, lo que nos arroja la siguiente notificación.

Así que espero por unos 5 minutos e intento de nuevo…

Y nada ocurre. Nada en 5 minutos, en 10 o en 30. Incluso si hubiéramos tenido previamente la dirección de BCH, los depósitos hubieran tenido una significante demora (créanme, esta no es la primera vez que lo hago). Entonces, no tengo más remedio que conservar mi BCH. De todos modos, comprar y retener si ha sido una buena estrategia de trading en el cripto mercado, al menos hasta finales del 2017

Intentemos con otra de las opciones de nuestra lista, con un ROI similar al anterior. La última, BTG desde Huobi hacia Cex. ¿Qué ocurre cuando intento retirar el BTG desde Huobi? Otra wallet en mantenimiento. Esta vez sin advertencias, pero los depósitos y retiros están deshabilitados.

.

… y el reality show

Estuve intentando encontrar un arbitraje con rendimientos durante meses. No les voy a mentir, nunca lo encontré. Hubo algunas oportunidades, pero no logré encontrar una manera consistente de detectarlas únicamente con el monitor, y sin chequear cada wallet de cada exchange por mi cuenta. Independientemente del hecho que muchas de las oportunidades son descartadas desde el comienzo por no dar rendimientos (teniendo en cuenta los fees y las comisiones de los exchanges), y teniendo que lidiar con wallets en mantenimiento.

Y considérense afortunados si sus exchanges los notifican sobre el mantenimiento. Algunos ni siquiera eso. Por ejemplo, en una oportunidad intenté arbitrar entre Exmo y otro exchange. Espere el depósito de mis BTC en Exmo por 2 horas hasta que les escribí. Luego de 3 horas, me respondieron:

Finalmente, mis BTC tardaron otros 2 días en ser depositados. Nunca se sabe si todo va a salir de acuerdo a lo planeado cuando se trata de transferir cripto activos.

Incluso cuando encuentras una oportunidad de arbitraje entre exchanges donde todo funciona bien, se debe lidiar con los tiempos de transferencia. La mayoría de los exchanges no permiten tradear cripto hasta que se hayan recibido un buen numero de confirmaciones. Esto generalmente tarda docenas de minutos. Y si esperan que los precios se mantengan estables durante ese lapso de tiempo, probablemente nunca hayan tradeado cripto. Cuando la rentabilidad del arbitraje es cercana al 2% (si!, no esperen encontrar una mejor oportunidad sin wallets en mantenimiento), y, si luego del fee y de las comisiones, disminuye cerca de un 1.5%, o incluso menos, esperando que los precios no cambien más de ese monto en un lapso tan corto como 20 minutos es absurdo. Es incluso más descabellado si también tienen en cuenta que habrá traders que estén al tanto de esa misma diferencia e implementaran algoritmos para sacar provecho rápidamente, dejándolos de este modo con las manos vacías.

Algunas recomendaciones finales

Cuando estén analizando oportunidades de arbitraje, siempre estén atentos a:

Un correcto calculo de renta, considerando: fees de compra en el exchange comisión de la transacción fees de venta en el exchange

Mantenimiento de las wallets

Demora de la transacción y los cambios estimados del precio en ese tiempo.

Algunos exchanges no permiten que se retiren fondos a menos que se haya completado la verificación total.

Investiguen en google sobre el arbitraje que se disponen a hacer, para saber si hay algo que no están teniendo en cuenta.

Siempre sospechen si encuentran una oportunidad de arbitraje que implica dinero fiat a pares de cripto, como ser BTC/USD o ETH/USD. Por ejemplo, BTC/USD hoy esta siendo tradeado a \$7549 en Bitfinex y a \$7721 en Bithumb. Eso suena a otra buena oportunidad, no es así?. Bueno, les tengo malas noticias: una vez que transfieren sus BTC a bithumb, la única divisa por la que la pueden cambiar ahí es KWC (por un equivalente a \$7721 USD). Y luego, también tienen que pensar una estrategia para transferir su dinero desde Korea del sur a su país.

Siempre, siempre sospechen antes de entregar su dinero.

Y , antes de despedirme, voy a intentar una vez mas depositar mis BCH en Yobit:

Mmm no, no es mi día.

En nuestro próximo articulo, vamos a analizar un mejor método de abordar las oportunidades de arbitraje. Quiero decir, esta vez en serio.

Puedes consultar la versión original en inglés del artículo aquí.

Si te ha gustado este artículo, puede que también te interese: