Presentación de las monedas

USDT: Es el USD Tether; Su propósito es funcionar como una criptomoneda y al mismo tiempo no, porque su precio nunca cambia. Es una manera segura de guardar dinero al cambio, cuando no tiene sentido tenerlo en una moneda más arriesgada (Por ejemplo, si el BTC está bajando y no hay otros intercambios de altcoins disponibles que puedan ser beneficiosos , por lo que tendría sentido guardar el dinero en USDT hasta que la situación cambie).

BTC: Esta es la criptomoneda dominante, usualmente más estable que las altcoins. Sin embargo, es una moneda que tiene que ser intercambiada activamente, significando que todo dinero guardado en BTC, en lugar de USDT, tiene que ser constantemente evaluado como una propuesta riesgosa. En el momento en el que el BTC presente señales de una buena estabilidad, tendría sentido mantener aquí las reservas de monedas en lugar de en USDT; Ahora bien, si el BTC está cayendo, sería más viable mantener las reservas en USDT.

ALT-TIPO-1: Estas son monedas que pueden ser intercambiadas desde BTC y USDT. Actualmente son las altcoins más populares, y entre ellas están el ETH, el LTC, etc.

Es probable que haya menos de 10 altcoins de este tipo a la vez (Como todo en las criptomonedas, las cosas cambian rápido).

ALT-TIPO-2: Estas son las monedas que sólo pueden ser intercambiadas desde BTC. Así que, para estas, la única manera posible de intercambiarlas es poseyendo el monto requerido en BTC (Por ejemplo, si el saldo en BTC es 0, pero hay saldo disponible en USDT, primero tiene que ser convertido en BTC para realizar el intercambio). La desventaja para esto es que, si éstas necesitan ser cambiadas a USDT (Pongamos como ejemplo que, si el BTC no está funcionando bien por el momento, sería riesgoso guardar dinero en BTC), primero tienen que venderse para obtener BTC, y luego, se tiene que vender el BTC para convertirlo en USDT, dando como consecuencia que se duplique la tarifa en transacciones.

Existen alrededor de 40 o 50 altcoins de este tipo consideradas como comerciables.

La lista completa de pares de monedas puede ser consultada aquí:

https://cryptocoincharts.info/markets/show/poloniex

Ten en cuenta que ellos tienen al BTC o al USDT en la segunda posición del par, por ejemplo XRP/BTC. Internamente,. siempre mencionaremos a estos pares con el BTC o el USDT en primera posición para dejar las cosas más claras, por ejemplo: BTC_XRP.

Cada unión en la imagen mostrada debajo representa los intercambios que son posibles

Cada unión representa la conversión de una moneda a otra. Estas pueden considerarse como ventas, por su similitud a comprar y vender acciones.

Sin embargo, cada conversión es en realidad una transacción, significando que incurrirá en una tarifa en la plataforma de intercambio que estamos usando (Que por ahora es Poloniex, pero eso puede cambiar en un futuro).

Debido a las tarifas involucradas, en cada intercambio / conversión potencial se debe tener en cuenta esta tarifa, para determinar si vale la pena hacerlo.

Estructuras de Datos

Ejemplo de la estructura de datos de series temporales. Por ejemplo, cada 5 minutos se cargarían nuevos datos de series temporales desde Poloniex. Esto es similar a como se reportan los precios en el mercado de acciones, pero en lugar de precios, son pares de monedas. El par de monedas representa al precio de una moneda en relación a la otra, es decir, USDT_ETH es el precio del ETH (Ethereum) en USDT (Que es una criptomoneda que está específicamente diseñada para ser directamente USD). Un ejemplo de esto es:

https://poloniex.com/exchange/#usdt_eth

Debido al propósito de esta aplicación, todos los cálculos de intercambios deben realizarse en términos de USDT, porque el USD es la moneda base donde es realmente importante ganar dinero. Esto puede resultar lioso, porque usualmente el valor de las criptomonedas están calculados en términos de BTC; Por ejemplo, BTC_ETH.

Para algunas monedas, Poloniex (La herramienta que estamos usando para obtener nuestros datos de series temporales) sólo ofrece cotizaciones en términos de BTC, por lo tanto, nacen complicaciones adicionales al calcular e intercambiar éstas.

La estructura de datos que se usa en esta aplicación debe estar separada por completo de cualquier formato de intercambio, por lo que debe asumirse que existiría una aplicación cliente que llame a la API para obtener los datos, y transformarlos en el formato que se usa en esta aplicación. Una aplicación como esta es relativamente trivial, y no necesita ser parte de la aplicación principal discutida en este documento.

Debe haber un currencyTickSet por cada par de monedas, como es mostrado en el ejemplo de abajo. En el backtesting, probablemente estaremos trabajando con al menos 5 meses en ticks (Es decir, datos cada 5 minutos durante 5 meses).

"currencyTickSet": [ [ { "time": "5:00-2017-5-11", "priceUSD": "300.00", "currencyPair": "USDT_ETH" }, { "time": "5:05-2017-5-11"", "priceUSD": "301.00", "currencyPair": "USDT_ETH" }, { "time": "5:10-2017-5-11"", "priceUSD": "302.50", "currencyPair": "USDT_ETH" }, ] ]

Habría un currencyTickSet por cada par de monedas, dando como resultado una cantidad aproximada entre 30 y 50 de currencyTickSet, cada uno conteniendo el conjunto completo de ticks para ese par de monedas en particular durante el periodo de tiempo especificado.

Algoritmo

Este algoritmo describe al backtesting debido a que es el caso de uso inicial, ya que, una vez que el backtesting muestra buenos resultados, el algoritmo se usaría en un intercambio real; Sin embargo, el intercambio real sería algo similar a este algoritmo, con algunas pequeñas diferencias.

En un principio, se comienza con una cuenta de USDT con saldo disponible, y todas las otras cuentas en cero.

El iterador base para el algoritmo podría ser un número entero que indique el tick actual. Por ejemplo, si el periodo de tiempo siendo testeado es:

Primero de marzo del 2017 - Primero de agosto del 2017

Podría significar que habría una iteración en un periodo de cada 5 minutos, desde el primero de marzo hasta el primero de agosto. Esto es debido a que, el backtesting simula lo que ocurriría en un intercambio real. En los intercambios reales, esta aplicación estaría funcionando en intervalos de 5 minutos, para determinar qué intercambios pueden ser necesarios para luego llevarlos a cabo.

Para un tick, cada currencyTickSet se ejecutaría a través de una función para calcular si el precio actual indica la acción de comprar o de vender. Un ejemplo de indicador, que en un principio podría usarse, es la media móvil exponencial. Este es un indicador común que ha demostrado potencial en la versión de prueba de concepto de java. Esto actualmente requiere datos previos de ticks (Usualmente son algo alrededor de los 26 ticks anteriores). En el backtesting eso iteraría a través del primer número n de ticks, hasta que llegue al punto en el que tuvo suficientes ticks previos para usarse en el cálculo, sólo así comenzaría a hacer este cálculo.

El cálculo de comprar / vender es completamente realizado de manera independiente de cualquier dato aparte del currencyTickSet para esa moneda en específico, significando que sólo busca ticks actuales y pasados, y no otros factores, como podrían ser datos de ticks de otras monedas, o el saldo actual de esa moneda. Mejor dicho, sólo está realizando un simple análisis sobre si se indica una compra / venta, no si realmente es posible o necesario.

El resultado del paso número 3 daría dos colecciones, una sería buyCollection (Colección de compra) y la otra sellCollection (Colección de venta). Cada una de estas contendrá pares de monedas correspondientes a la recomendación de compra / venta del paso número 3. Es posible que haya datos por cada moneda que podrían usarse para valorarlas con otras, por ejemplo, para determinar si una es más “potente” que otra; No obstante, esto queda por determinar. A pesar de todo, se puede asumir que esta es una colección, y no una serie, así que no existe orden para indicar esto; Más bien, cada elemento dentro de la colección tendría que ser procesado para determinar si terminó obteniendo algún tipo de dato “valioso”.

Este paso puede considerarse como un paso “distribuidor”, donde tendrá que examinar al buyCollection y al sellCollection, para luego también verificar los saldos actuales de la cuenta y determinar qué intercambio tiene que ser realizado. Al comienzo de este paso, solo sabemos qué monedas son recomendables de comprar / vender, pero esto todavía no tiene ninguna base en relación a nuestro intercambio actual porque, por ejemplo, pueden haber recomendaciones de ventas para monedas que actualmente se poseen o que no están disponibles para gastar, por lo tanto, las órdenes de compras no pueden ser posibles sin antes vender otras monedas. Entonces, las posibles acciones que el distribuidor debe realizar, en orden serían:

(Nota: Para el backtesting no se requiere la interacción en sí con la API de Poloniex para comprar y vender, más bien, sólo “finge” ejecutar órdenes de comprar / vender en el mismo precio que el tick, sin embargo, la implementación actual debería tener en cuenta esto, por lo que el código necesitaría ser desacoplado en una manera en la que pueda ser implementado en un intercambio real). Es importante tener en mente, como fue antes mencionado, que cada transacción tiene una tarifa, la cual debe tomarse en cuenta cuando se realizan los intercambios en el backtest. Lo que queremos, es usar funciones que simulen el comportamiento de interactuar con la API de Poloniex, haciendo algo como tomar una orden y aplicar la tarifa, para imitar lo que realmente ocurriría.

  1. Buscar en el sellCollection monedas que actualmente se posee, y luego, venderlas. Esto debe realizarse en primer lugar, debido a que las ganancias que generen estos, serán usadas para comprar órdenes.

  2. Enviar órdenes de compra para el buyCollection si hay monedas disponibles que puedan usarse para eso. La asignación sobre qué % de fondos disponibles hay que usar para cada moneda puede resultar compleja. Esto tiene que ser separado por completo de cualquier otra cosa; Por ahora , usaremos una estrategia básica de asignación para algo como asignarle a una moneda un % de las tenencias totales. Así que, al menos, teniendo en cuenta esto, podemos mantener el 20% de los fondos en una moneda; Luego, si al llegar a este punto ya poseemos 4 monedas (Después de vender la inicial en el paso #1), y tenemos una buyCollection a la que ya se le ha indicado comprar 5 monedas, entonces sólo una de ellas podría procesarse como si estuviera asignada al 100%.

La realidad es que el paso de asignación podría convertirse en una de las partes más complejas de toda la aplicación, debido a que puede ser el punto central de nuestras mejoras futuras. Así que, por ahora, lo mejor sería comenzar manteniéndolo relativamente básico, pero teniendo en mente que debe estar ligeramente acoplado para futuros cambios. Por ejemplo, es posible que queramos crear algunas estrategias de asignación en un futuro, y luego realizar un backtest por cada una y determinar cuál estrategia de asignación funciona mejor.

El proceso continuará con el resultado final, una salida de datos indicando las ganancias / pérdidas, etc. Todo sería calculado en términos de USDT.

Sobre el flujo de datos

Escribiré algunas ideas aquí, y luego escribiré algo más formal que incorpore estas ideas.

La cosa más importante es tener funciones pequeñas que estén centradas en hacer solamente una tarea pequeña. Esas funciones sólo recibirán un trozo de datos (Por ejemplo, un objeto JavaScript), y luego lo transformará en algo más.

Imagino esto tal y como funciona una una red neuronal. Primero tenemos una capa de entrada, y funcionará con JSON (API de Poloniex). Esta capa transforma el JSON en cualquier estructura de datos que elijamos, y desde este punto, todas las funciones sólo trabajarán con esta estructura de datos. Claro, algunas funciones van a recibir parámetros adicionales con otros tipos de datos, como booleanos, números enteros, etc. Pero la idea es centrarse en esas estructuras de datos.

Después de procesar el JSON, la salida de la capa de entrada se le da a un grupo de “capas intermedias”. Estas capas se encargan de aplicar una serie de operadores a la entrada de datos para transformarla. Después de todas las transformaciones, enviaremos esa estructura de datos a la capa de salida.

La capa de salida es una serie de funciones que toman los datos transformados, y pueden crear un reporte mostrando las ganancias/pérdidas, pueden enviar solicitudes a una cuenta de intercambio real, etc.

Esa es la idea bastante básica, claro, será más compleja que eso, y algunas partes irán contra este modelo para que funciones.

En cuanto a esa “capa intermedia”, creo que podemos resumirlo en algo como la Cartesian Genetic Programming (CGP) http://www.cartesiangp.co.uk/. En la CGP, tenemos varios nodos (Que son funciones), y esos nodos pueden ser desactivados/activados. Así que, nuestros nodos pueden ser los indicadores técnicos, redes neuronales, funciones de administración de dinero, etc. Al final, podríamos tener cientos de funciones que pueden ser parte de una estrategia de intercambio, pero sólo activamos aquellas que dieron buenos resultados. Ni la capa de entrada ni la de salida cambian, sólo tocamos la capa intermedia.

Recursos:

Útil para construir estructuras JSON:

http://www.jsoneditoronline.org/

Útil para crear diagramas:

https://www.draw.io/

Posted on Dec 04, 2017