Le cours de la série d'investissements quantitatifs sur la chaîne de blocs (3) Arbitrage de diffusion de calendrier

Auteur:le rubis, Créé: 2018-08-27 16:49:50, Mis à jour:

N° 1 Dans le livre Alchimie financière écrit par Soros en 1987, une proposition importante a été avancée: je crois que les prix du marché sont toujours faux dans le sens où ils présentent une vision biaisée de l'avenir. L'hypothèse de validité du marché n'est qu'une hypothèse théorique. En fait, les participants au marché ne sont pas toujours rationnels et, à chaque moment, les participants ne peuvent pas acquérir pleinement et interpréter objectivement toutes les informations. Même s'il s'agit de la même information, les commentaires de chacun sont différents.

En d'autres termes, le prix lui-même contient déjà les attentes erronées des participants au marché, de sorte qu'en substance le prix du marché est toujours erroné.

img

N° 2 Sur la base des principes ci-dessus, nous savons également que dans un marché des contrats à terme non efficace, l'impact sur le marché des contrats de livraison dans des périodes différentes n'est pas toujours synchronisé et que la tarification n'est pas la raison de l'efficacité complète.

Ensuite, sur la base du prix du contrat de livraison à différents moments de la même cible de transaction, s'il existe un écart important entre les deux prix, il est possible de négocier simultanément des contrats à terme de différentes périodes et d'effectuer un arbitrage intertemporel. Comme les contrats à terme sur matières premières, les monnaies numériques ont également un portefeuille de contrats d'arbitrage intertemporel associé à elles.

Par exemple, supposons que l'écart entre la semaine ETC et le trimestre ETC soit maintenu à environ 5 pendant une longue période. Si l'écart atteint 7, nous nous attendons à ce que l'écart revienne à 5 à un moment donné dans le futur. Ensuite, vous pouvez vendre la semaine ETC et acheter le trimestre ETC pour raccourcir l'écart. vice versa.

N° 3 Bien que cet écart existe, il y a souvent beaucoup d'incertitudes dans l'arbitrage manuel en raison du temps et de la mauvaise précision des opérations manuelles et des effets de variation des prix.

Grâce au modèle quantitatif pour saisir les opportunités d'arbitrage et développer des stratégies de négociation d'arbitrage, ainsi que des algorithmes programmatiques libèrent automatiquement des ordres de négociation à la bourse, pour saisir rapidement et avec précision les opportunités et gagner efficacement des revenus, ce qui est le charme de l'arbitrage quantitatif.

img

Cet article vous apprendra à utiliser la plateforme de négociation quantitative FMZ et le contrat à terme ETC dans l'échange OkEX dans le commerce de devises numériques, avec une stratégie d'arbitrage simple pour démontrer comment saisir les opportunités d'arbitrage instantanées, et saisir tous les bénéfices visibles tout en couvrant simultanément les risques qui peuvent être rencontrés.

N° 4 Créer une stratégie d'arbitrage intertemporel en monnaie numérique Difficulté: niveau normal Environnement stratégique: Objectif de la transaction: Ethereum classique (ETC) Données sur les écarts: ETC hebdomadaire - ETC trimestriel Période de négociation: 5 minutes Correspondance de position: 1:1. Type de transaction: même variété intertemporelle La logique de la stratégie: Conditions d'achat de positions sur les écarts longs: si le compte courant ne comporte aucune position et que l'écart est inférieur à la traînée descendante de l'indicateur Boll, placer un ordre sur écarts, à savoir: acheter des ETC longs hebdomadairement, vendre des ETC courts trimestriellement.

Conditions de position de vente à découvert: si le compte courant ne possède pas de positions et que l'écart est supérieur à la barre supérieure de l'indicateur Boll, passer un ordre de vente à découvert, à savoir: vendre des ETC à découvert hebdomadairement, acheter des ETC à découvert trimestriellement.

Fermeture de la condition de position d'achat à long écart: si le compte courant détient une position hebdomadaire longue ETC et une position trimestrielle courte ETC, et que l'écart est supérieur à la ligne médiane de l'indicateur Boll, passer un ordre de fermeture de l'écart, à savoir: vendre ETC hebdomadairement, acheter pour couvrir l'ETC trimestriellement.

Si le compte courant détient une position hebdomadaire courte ETC et une position trimestrielle longue ETC, et que l'écart est inférieur à la ligne médiane de l'indicateur Boll, placer un ordre d'écart proche, à savoir: acheter pour couvrir l'ETC hebdomadairement, vendre l'ETC trimestriellement.

N° 5 Ce qui précède est une description simple de la logique de stratégie d'arbitrage intertemporel de monnaie numérique, alors comment mettre en œuvre vos propres idées dans le programme? Cadre stratégique:

img

Le cadre stratégique peut être facilement construit en fonction du processus de réflexion et de transaction stratégiques.

  1. Pré-traitement avant la transaction.
  2. Obtenez et calculez les données.
  3. Faites une commande et suivez-la.

N° 6 Ensuite, nous devons remplir les détails nécessaires dans le cadre stratégique basé sur le processus de transaction réel et les détails de la transaction.

Premièrement, le pré-traitement avant la transaction Étape 1: dans l'environnement global, déclarer les variables globales nécessaires. Déclarer un objet graphique qui configure le graphique Le graphique Var = { } Appeler la fonction Graphique pour initialiser le graphique Var ObjChart = Graphique (graphique) Déclarer un tableau vide pour stocker la séquence de propagation Var bar = [ ] Déclarer une variable timestamp qui enregistre les données historiques Var oldTime est égal à 0 Étape 2: configurer les paramètres externes de la stratégie.

img

Étape 3: définition de la fonction de traitement des données Fonction de base des données: Données ()) Créer un constructeur Données et définir ses propriétés internes, y compris: données de compte, données de position, timestamp de données de ligne K, dernier prix d'achat/de vente du contrat d'arbitrage A/B, écart d'arbitrage positif/inverse

img

Obtenez la fonction de position: mp ()) Vérifiez l'ensemble du tableau des positions, retournez le contrat spécifié et le nombre de positions dans la direction spécifiée.

img

Ligne K et fonction d'indicateur: boll ()) Synthétisez une nouvelle séquence de lignes K basée sur les données de l'arbitrage positif/inverse et retournez les données de rails haut/moyen/bas calculées par l'indicateur Boll.

img

Fonction de commande: commerce ()) Insérer le nom du contrat d'ordre et le type de transaction, puis placer l'ordre au dernier prix d'achat/de vente et retourner le résultat après avoir passé l'ordre.

img

Fonction annuler les commandes: cancelOrders ()) Obtenez un tableau de toutes les commandes en attente et annulez-les une par une. et s'il y a une commande en attente, retournez faux, et s'il n'y en a pas, retournez vrai.

img

Contrats uniques de détention de processus: isEven ()) Dans le cas d'une situation à pied unique dans le trading d'arbitrage, il est directement géré en fermant simplement toutes les positions.

img

Fonction de dessin graphique: dessin graphique ()) Appeler la méthode ObjChart.add () pour obtenir les données de marché et les données d'indicateur nécessaires dans le graphique: en hausse, en milieu, en baisse, différence d'arbitrage positive/inverse.

img

Étape 4: Dans la fonction d'entrée main (), exécutez le code de pré-traitement avant la transaction, qui n'est exécuté qu'une seule fois après le démarrage du programme, y compris:

Filtrer les informations qui ne sont pas très importantes dans la console SetErrorFilter ()) Définir le type de monnaie numérique à échangerexchange.IO() Vider les graphiques dessinés avant le démarrage du programme ObjChart.reset () Vider les informations de la barre d'état avant le démarrage du programme

img

N° 7 Après avoir défini le prétraitement ci-dessus avant la transaction, il est nécessaire de passer à l'étape suivante, d'entrer dans le mode de sondage et de répéter la fonction onTick (). Et définissez l'heure de sommeil lors du sondage, parce que certaines des API des échanges de devises numériques ont une limite d'accès intégrée pour une certaine période de temps.

img

Deuxièmement, obtenir et calculer les données Étape 1: Obtenir l'objet de données sous-jacent, le solde du compte et les données de l'indicateur Boll pour la logique de trading.

img

Troisièmement, passer une commande et faire un suivi Étape 1: Effectuer l'opération d'achat et de vente selon la logique de stratégie ci-dessus. Tout d'abord, vérifier si les conditions de prix et d'indicateur sont vraies, puis vérifier si les conditions de position sont vraies, et enfin exécuter la fonction d'ordre de transaction ().

img

Étape 2: Après la passation de commande, il est nécessaire de traiter les situations anormales telles que les commandes en attente et le maintien d'un contrat unique, et de dresser des graphiques.

img

N° 8 Ci-dessus, nous avons créé une simple stratégie d'arbitrage intertemporel de monnaie numérique à travers plus de 200 lignes.

img

N° 9 Cette stratégie sert juste de déclencheur. Le marché réel n'est pas si simple, mais vous pouvez utiliser cet exemple pour jouer avec votre imagination.

Ce qu'il faut rappeler, c'est que, sur la base de mon expérience limitée, la stratégie d'arbitrage purement périodique ne vaut pas la peine d'être utilisée dans la situation actuelle du marché des devises numériques, qu'il s'agisse d'arbitrage triangulaire sans risque ou d'arbitrage intermarché.

La raison en est que peu importe le marché des contrats à terme de l'échange de devises numériques, la marge n'est pas fiduciaire.

Prenez une vue d'ensemble, le marché de la monnaie numérique a déjà quitté la blockchain.

Voici le code complet:

// 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
    }
}


Plus de

Le petit rêveÇa, c'est bien!