Curso de la serie de inversiones cuantitativas de Blockchain (3) Arbitraje de diferencias de calendario

El autor:el rubí, Creado: 2018-08-27 16:49:50, Actualizado:

No. 1 En el libro Financial Alchemy escrito por Soros en 1987, se presentó una propuesta importante: creo que los precios de mercado siempre están equivocados en el sentido de que presentan una visión sesgada del futuro. La hipótesis de la validez del mercado es solo una suposición teórica. De hecho, los participantes del mercado no siempre son racionales, y en cada momento, los participantes no pueden adquirir completamente e interpretar objetivamente toda la información. Incluso si es la misma información, la retroalimentación de todos es diferente.

En otras palabras, el precio en sí mismo ya contiene las expectativas erróneas de los participantes en el mercado, por lo que en esencia el precio de mercado siempre está equivocado.

img

No. 2 Sobre la base de los principios anteriores, también sabemos que en un mercado de futuros no efectivo, el impacto del mercado de los contratos de entrega en diferentes períodos no siempre es sincronizado, y la fijación de precios no es la razón de la efectividad completa.

Luego, basándose en el precio del contrato de entrega en diferentes momentos del mismo objetivo de transacción, si existe un gran diferencial entre los dos precios, es posible negociar simultáneamente contratos de futuros de diferentes períodos y llevar a cabo arbitraje intertemporal. Al igual que los futuros de materias primas, las monedas digitales también tienen una cartera de contratos de arbitraje intertemporal asociada a ellas.

Por ejemplo, supongamos que el diferencial entre la semana ETC y el trimestre ETC se mantiene en torno a 5 durante mucho tiempo. Si el diferencial alcanza 7, esperamos que el diferencial vuelva a 5 en algún momento en el futuro. Entonces puede vender la semana ETC y comprar el trimestre ETC para acortar el diferencial. viceversa.

No. 3 A pesar de que existe este diferencial, a menudo hay muchas incertidumbres en el arbitraje manual debido al tiempo que consume, a la poca precisión de las operaciones manuales y a los efectos de cambio de precios.

A través del modelo cuantitativo para capturar oportunidades de arbitraje y desarrollar estrategias de negociación de arbitraje, así como algoritmos programáticos que liberan automáticamente órdenes de negociación a la bolsa, para capturar oportunidades de forma rápida y precisa y ganar ingresos de manera eficiente, que es el encanto del arbitraje cuantitativo.

img

Este artículo le enseñará cómo usar la plataforma de negociación cuantitativa FMZ y el contrato de futuros ETC en el intercambio OkEX en el comercio de divisas digitales, con una estrategia de arbitraje simple para demostrar cómo capturar las oportunidades de arbitraje instantáneas y aprovechar todos los beneficios visibles mientras que simultáneamente cubre los riesgos que pueden encontrarse.

No 4 Crear una estrategia de arbitraje intertemporal de moneda digital Dificultad: nivel ordinario Entorno estratégico: Objetivo de la transacción: Ethereum classic (ETC) Datos de diferenciación: ETC semanal - ETC trimestral Período de negociación: 5 minutos Compatibilidad de posición: 1:1. Tipo de transacción: misma variedad intertemporal La lógica de la estrategia: Condiciones de compra de posiciones de diferencias largas: si la cuenta corriente no tiene posiciones y el diferencial es menor que el rastro descendente del indicador Boll, se realiza una orden de diferencias, que es: comprar ETC largo semanalmente, vender ETC corto trimestralmente.

Condiciones de posición de venta a corto de diferencias: si la cuenta corriente no tiene posiciones y el diferencial es mayor que la línea ascendente del indicador de Boll, se realiza una orden de venta a corto de ETC semanalmente, comprando ETC largo trimestralmente.

Cierre de la condición de posición de compra de diferencias largas: si la cuenta corriente tiene una posición larga semanal de ETC y una posición corta trimestral de ETC, y el diferencial es mayor que la línea media del indicador de Boll, se realiza una orden de cierre de diferencias, que consiste en vender ETC semanalmente, comprar para cubrir ETC trimestralmente.

Cierre de la condición de posición de margen de venta a corto plazo: si la cuenta corriente mantiene una posición semanal corta de ETC y una posición trimestral larga de ETC, y el margen es inferior al carril medio del indicador de Boll, se realiza una orden de margen cerrado, que consiste en: comprar para cubrir la ETC semanalmente, vender ETC trimestralmente.

No. 5 Lo anterior es una simple descripción de la moneda digital intertemporal lógica estrategia de arbitraje, entonces, ¿cómo implementar sus propias ideas en el programa? Marco estratégico:

img

El marco estratégico puede ser fácilmente construido de acuerdo con el proceso de pensamiento estratégico y transacción.

  1. Preprocesamiento antes de la transacción.
  2. Obtener y calcular datos.
  3. Ponga un pedido y siga adelante.

No. 6 A continuación, debemos completar los detalles necesarios en el marco estratégico basados en el proceso real de transacción y los detalles de la transacción.

En primer lugar, el preprocesamiento antes de la transacción Paso 1: En el entorno global, declarar las variables globales necesarias. Declarar un objeto de gráfico que configura el gráfico El gráfico var = { } Llama a la función de gráfico para iniciar el gráfico Var ObjChart = Gráfico (gráfico) Declarar una matriz vacía para almacenar la secuencia de difusión Var barras = [ ] Declarar una variable de marca de tiempo que registra datos históricos Var oldTime = 0 Paso 2: Configurar los parámetros externos de la estrategia.

img

Paso 3: Definir la función de procesamiento de datos Función de datos básicos: Datos ()) Crear un constructor Datos y definir sus propiedades internas, incluyendo: datos de cuenta, datos de posición, datos de marca de tiempo de la línea K, el último precio de compra/venta del contrato de arbitraje A/B, diferencial de arbitraje positivo/reverso

img

Obtener la función de posición: mp ()) Compruebe toda la matriz de posiciones, devuelva el contrato especificado y el número de posiciones en la dirección especificada.

img

Línea K y función del indicador: boll ()) Sintetice una nueva secuencia de K-línea basada en los datos del diferencial de arbitraje positivo / inverso y devuelva los datos de tren ascendente / medio / descendente calculados por el indicador de bolla.

img

Función de las órdenes: comercio ()) Introduzca el nombre del contrato de la orden y el tipo de operación, luego coloque la orden en el último precio de compra/venta y devuelva el resultado después de realizar la orden.

img

Función de cancelación de órdenes: cancelar órdenes ()) Obtenga una matriz de todos los pedidos pendientes y cancele uno por uno. Y si hay un pedido pendiente, devuelva falso, y si no hay ninguno, devuelva verdadero.

img

Contrato único de mantenimiento de procesos: isEven ()) En el caso de la situación de una sola pierna en el comercio de arbitraje, se maneja directamente simplemente cerrando todas las posiciones.

img

Función de dibujo de gráficos: dibujo de gráficos ()) Se utilizará el método ObjChart.add ( ) para extraer los datos de mercado y los datos de indicadores necesarios en el gráfico: al alza, al medio, al descenso, diferencial de arbitraje positivo/inverso.

img

Paso 4: En la función de entrada principal (), ejecute el código de preprocesamiento antes de la transacción, que solo se ejecuta una vez después de que se inicie el programa, incluido:

Filtrar la información que no es muy importante en la consola SetErrorFilter ()) Configurar el tipo de moneda digital a negociarexchange.IO()) Vacie los gráficos dibujados antes de iniciar el programa ObjChart.reset ()) Despeje la información de la barra de estado antes de iniciar el programa LogProfitReset ())

img

No 7 Después de definir el preprocesamiento anterior antes de la transacción, es necesario proceder al siguiente paso, entrar en el modo de votación y repetir la función onTick (). Y establecer el tiempo de sueño cuando la encuesta, porque algunos de los intercambios de divisas digitales API tiene un límite de acceso incorporado para un cierto período de tiempo.

img

En segundo lugar, obtener y calcular datos Paso 1: Obtener el objeto de datos subyacente, el saldo de la cuenta y los datos del indicador de boll para la lógica comercial.

img

Tercero, hacer un pedido y seguir adelante Paso 1: Realice la operación de compra y venta de acuerdo con la lógica de la estrategia anterior. Primero, compruebe si las condiciones del precio y del indicador son ciertas, y luego compruebe si las condiciones de la posición son ciertas, y finalmente ejecute la función de orden de comercio ().

img

Paso 2: Después de realizar el pedido, es necesario hacer frente a situaciones anormales como pedidos pendientes y contrato único, y elaborar gráficos.

img

No. 8 En la parte superior, hemos creado una estrategia de arbitraje intertemporal de moneda digital simple a través de más de 200 líneas.

img

No 9 Esta estrategia sólo sirve como un gatillo. El mercado real no es tan simple, pero se puede utilizar este ejemplo para jugar con su imaginación.

Lo que hay que recordar es que, basado en mi limitada experiencia, la estrategia de arbitraje de período puro básicamente no vale la pena ejecutarse en la situación actual del mercado de divisas digitales, ya sea un arbitraje triangular sin riesgo o un arbitraje entre mercados.

La razón es que no importa en qué mercado de futuros de cambio de moneda digital, el margen no es fiduciario. Casi todas las monedas digitales han caído alrededor del 70% desde el comienzo del año. En otras palabras, la estrategia siempre es hacer moneda, pero el precio de la moneda está cayendo.

En general, el mercado de divisas digitales ya ha abandonado la cadena de bloques, al igual que los tulipanes, el precio siempre proviene de las expectativas y la confianza de las personas, y la confianza proviene del precio...

Aquí para obtener el código completo:

// global variable
// Declare a chart object that configures the chart
var chart = {
    __isStock: true,
    tooltip: {
        xDateFormat: '%Y-%m-%d %H:%M:%S, %A'
    },
    title: {
        text: 'Profit and loss chart(detail)'
    },
    rangeSelector: {
        buttons: [{
            type: 'hour',
            count: 1,
            text: '1h'
        }, {
            type: 'hour',
            count: 2,
            text: '3h'
        }, {
            type: 'hour',
            count: 8,
            text: '8h'
        }, {
            type: 'all',
            text: 'All'
        }],
        selected: 0,
        inputEnabled: false
    },
    xAxis: {
        type: 'datetime'
    },
    yAxis: {
        title: {
            text: 'spread'
        },
        opposite: false,
    },
    series: [{
        name: "up",
        id: "line1,up",
        data: []
    }, {
        name: "middle",
        id: "line2,middle",
        data: []
    }, {
        name: "down",
        id: "line3,down",
        data: []
    }, {
        name: "basb",
        id: "line4,basb",
        data: []
    }, {
        name: "sabb",
        id: "line5,sabb",
        data: []
    }]
};
var ObjChart = Chart(chart); // Drawing object
var bars = []; // Store spread sequence
var oldTime = 0; // Record historical data timestamp

// Parameter
var tradeTypeA = "this_week"; // Arbitrage contract A
var tradeTypeB = "quarter"; // Arbitrage contract B
var dataLength = 10; //Length of indicator cycle
var timeCycle = 1; // The cycle of K-line
var name = "ETC"; // Currency type
var unit = 1; // Quantity of orders

// Basic data
function Data(tradeTypeA, tradeTypeB) { // input arbitrage contract A&B
    this.accountData = _C(exchange.GetAccount); // get account data
    this.positionData = _C(exchange.GetPosition); // get position data
    var recordsData = _C(exchange.GetRecords); //get k-line data
    exchange.SetContractType(tradeTypeA); // subscribe arbitrage contract A
    var depthDataA = _C(exchange.GetDepth); // deep data of arbitrage contract A
    exchange.SetContractType(tradeTypeB); // subscribe arbitrage contract B
    var depthDataB = _C(exchange.GetDepth); // deep data of arbitrage contract B
    this.time = recordsData[recordsData.length - 1].Time; // get the latest time data
    this.askA = depthDataA.Asks[0].Price; // the latest selling price of arbitrage contract A
    this.bidA = depthDataA.Bids[0].Price; // the latest buying price of arbitrage contract A
    this.askB = depthDataB.Asks[0].Price; // the latest selling price of arbitrage contract B
    this.bidB = depthDataB.Bids[0].Price; // the latest buying price of arbitrage contract B
    // Positive arbitrage spread(the latest selling price of contract A -the latest buying price of contract B )
    this.basb = depthDataA.Asks[0].Price - depthDataB.Bids[0].Price;
    // Reverse arbitrage spread(the latest buying price of contract A -the latest selling price of contract B )
    this.sabb = depthDataA.Bids[0].Price - depthDataB.Asks[0].Price;
}

// get position information
Data.prototype.mp = function (tradeType, type) {
    var positionData = this.positionData; // get position data
    for (var i = 0; i < positionData.length; i++) {
        if (positionData[i].ContractType == tradeType) {
            if (positionData[i].Type == type) {
                if (positionData[i].Amount > 0) {
                    return positionData[i].Amount;
                }
            }
        }
    }
    return false;
}

// Synthetize new K-line data and boll indicator data
Data.prototype.boll = function (num, timeCycle) {
    var self = {}; // Temporary object
    // the median of Positive arbitrage spread and reverse arbitrage spread
    self.Close = (this.basb + this.sabb) / 2;
    if (this.timeA == this.timeB) {
        self.Time = this.time;
    } // Comparing two depth data timestamps
    if (this.time - oldTime > timeCycle * 60000) {
        bars.push(self);
        oldTime = this.time;
    } // According to the specified time period, insert the spread data object in the K-line array.
    if (bars.length > num * 2) {
        bars.shift(); // Control K-line array length
    } else {
        return;
    }
    var boll = TA.BOLL(bars, num, 2); // Call the boll indicator in the Talib Library
    return {
        up: boll[0][boll[0].length - 1], // up rail of boll indicator
        middle: boll[1][boll[1].length - 1], // middle rail of boll indicator
        down: boll[2][boll[2].length - 1] // down rail of boll indicator
    } // Return a processed boll indicator data.
}

// place order
Data.prototype.trade = function (tradeType, type) {
    exchange.SetContractType(tradeType); // Resubscribe contract before placing order
    var askPrice, bidPrice;
    if (tradeType == tradeTypeA) { // if it's contract A
        askPrice = this.askA; // set askPrice
        bidPrice = this.bidA; // set bidPrice
    } else if (tradeType == tradeTypeB) { // if it's contract B
        askPrice = this.askB; // set askPrice
        bidPrice = this.bidB; // set bidPrice
    }
    switch (type) { // Match order mode
        case "buy":
            exchange.SetDirection(type); // Set order mode
            return exchange.Buy(askPrice, unit);
        case "sell":
            exchange.SetDirection(type); // Set order mode
            return exchange.Sell(bidPrice, unit);
        case "closebuy":
            exchange.SetDirection(type); // Set order mode
            return exchange.Sell(bidPrice, unit);
        case "closesell":
            exchange.SetDirection(type); // Set order mode
            return exchange.Buy(askPrice, unit);
        default:
            return false;
    }
}

// cancel order
Data.prototype.cancelOrders = function () {
    Sleep(500); // delay before canceling, because some exchanges you know...
    var orders = _C(exchange.GetOrders); // Get the array of pending orders
    if (orders.length > 0) { // if there is pending order
        for (var i = 0; i < orders.length; i++) { //check through the array of pending orders
            exchange.CancelOrder(orders[i].Id); //cancel pending orders one by one
            Sleep(500); //Delay 0.5 seconds
        }
        return false; // return false if pending orders have been cancelled
    }
    return true; //return true if there is no pending order
}

// handle holding single contract
Data.prototype.isEven = function () {
    var positionData = this.positionData; // get position data
    var type = null; // converse position direction 
    // If the length of the position array divided by some number and the remainder is 2, the result is not equal to 0 or the length of the position array is not equal to 2
    if (positionData.length % 2 != 0 || positionData.length != 2) {
        for (var i = 0; i < positionData.length; i++) { // check through the array of positions
            if (positionData[i].Type == 0) { // if it's long position
                type = 10; // Set order parameters
            } else if (positionData[i].Type == 1) { // if it's short position
                type = -10; // Set order parameters
            }
            // close all positions
            this.trade(positionData[i].ContractType, type, positionData[i].Amount);
        }
    }
}

// drawing chart
Data.prototype.drawingChart = function (boll) {
    var nowTime = new Date().getTime();
    ObjChart.add([0, [nowTime, boll.up]]);
    ObjChart.add([1, [nowTime, boll.middle]]);
    ObjChart.add([2, [nowTime, boll.down]]);
    ObjChart.add([3, [nowTime, this.basb]]);
    ObjChart.add([4, [nowTime, this.sabb]]);
    ObjChart.update(chart);
}

// trading condition
function onTick() {
    var data = new Data(tradeTypeA, tradeTypeB); // Create a base data object
    var accountStocks = data.accountData.Stocks; // account balance
    var boll = data.boll(dataLength, timeCycle); // get boll indicator data
    if (!boll) return; // return if there is no boll data
    // Spread description
    // basb = (the latest selling price of contract A - the latest buying price of contract B)
    // sabb = (the latest buying price of contract A - the latest selling price of contract B)
    if (data.sabb > boll.middle && data.sabb < boll.up) { // if sabb is higher than the middle rail
        if (data.mp(tradeTypeA, 0)) { // check if contract A has long positon before placing order
            data.trade(tradeTypeA, "closebuy"); // close long position of contract A
        }
        if (data.mp(tradeTypeB, 1)) { // check if contract B has short positon before placing order
            data.trade(tradeTypeB, "closesell"); // close short position of contract B
        }
    } else if (data.basb < boll.middle && data.basb > boll.down) { // if basb is lower than the middle rail
        if (data.mp(tradeTypeA, 1)) { // check if contract A has short positon before placing order
            data.trade(tradeTypeA, "closesell"); // close short position of contract A
        }
        if (data.mp(tradeTypeB, 0)) { // check if contract B has long positon before placing order
            data.trade(tradeTypeB, "closebuy"); // close long position of contract B
        }
    }
    if (accountStocks * Math.max(data.askA, data.askB) > 1) { // If there is balance in the account
        if (data.basb < boll.down) { // if basb spread is lower than the down rail
            if (!data.mp(tradeTypeA, 0)) { // check if contract A has long positon before placing order
                data.trade(tradeTypeA, "buy"); // open long position of contract A
            }
            if (!data.mp(tradeTypeB, 1)) { // check if contract B has short positon before placing order
                data.trade(tradeTypeB, "sell"); // open short position of contract B
            }
        } else if (data.sabb > boll.up) { // if sabb spread is higher than the up rail
            if (!data.mp(tradeTypeA, 1)) { // check if contract A has short positon before placing order
                data.trade(tradeTypeA, "sell"); // open short position of contract A
            }
            if (!data.mp(tradeTypeB, 0)) { // check if contract B has long positon before placing order
                data.trade(tradeTypeB, "buy"); // open long position of contract B
            }
        }
    }
    data.cancelOrders(); // cancel orders
    data.drawingChart(boll); // drawing chart
    data.isEven(); // process holding single contract
}

//enter function
function main() {
    // filter the information that is not very important in the console
    SetErrorFilter("429|GetRecords:|GetOrders:|GetDepth:|GetAccount|:Buy|Sell|timeout|Futures_OP");
    exchange.IO("currency", name + '_USDT'); //Set the cryptocurrency type to be traded
    ObjChart.reset(); //Empty the drawn charts before the program starts
    LogProfitReset(); //Empty the status bar information before the program starts
    while (true) { // Enter polling mode
        onTick(); // Execute onTick function
        Sleep(500); // sleep for o.5 seconds
    }
}


Más.

Un sueño pequeño.¡Qué bien!