N° 1
Dans le livre
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é.
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.
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:
Le cadre stratégique peut être facilement construit en fonction du processus de réflexion et de transaction stratégiques.
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.
É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
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.
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.
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.
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.
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.
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.
É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
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.
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.
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 ().
É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.
N° 8 Ci-dessus, nous avons créé une simple stratégie d'arbitrage intertemporel de monnaie numérique à travers plus de 200 lignes.
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
}
}
L'inventeur de la quantification - un petit rêveÇa, c'est bien!