George Soros stellte 1987 in "The Alchemy of Finance" einen wichtigen Vorschlag vor: Ich glaube, dass die Marktpreise immer falsch sind, in dem Sinne, dass sie eine voreingenommene Sicht auf die Zukunft darstellen. Die Marktwirksamkeitshypothese ist nur eine theoretische Hypothese. In der Tat sind die Marktteilnehmer nicht immer rational und können zu jedem Zeitpunkt nicht alle Informationen vollständig erhalten und objektiv interpretieren. Darüber hinaus, auch wenn es sich um dieselben Informationen handelt, ist das Feedback von jedem anders. Das heißt, der Preis selbst enthält bereits die falschen Erwartungen der Marktteilnehmer, also ist der Marktpreis im Wesentlichen immer falsch. Dies kann die Gewinnquelle von Arbitragern sein.
Nach den oben genannten Prinzipien können wir wissen, dass in einem ineffizienten Futures-Markt der Grund, warum die Marktwirkung auf Lieferverträge in verschiedenen Perioden nicht immer synchron ist, und die Preisgestaltung nicht vollständig effektiv ist. Dann, basierend auf dem Liefervertragspreis desselben Transaktionsobjekts in verschiedenen Perioden, wenn es einen großen Preisunterschied zwischen den beiden Preisen gibt, können wir Futures-Kontrakte in verschiedenen Perioden gleichzeitig kaufen und verkaufen, um eine Quartals-Arbitrage durchzuführen. Wie Rohstoff-Futures hat auch digitale Währung ein Quartals-Arbitrage-Kontraktportfolio. Zum Beispiel gibt es in der OKEX-Börse: ETC aktuelle Woche, ETC nächste Woche, ETC Quartal. Nehmen wir zum Beispiel an, dass die Preisdifferenz zwischen der aktuellen Woche von ETC und dem Quartal von ETC für eine lange Zeit um 5 bleibt. Wenn die Preisdifferenz an einem Tag 7 erreicht, erwarten wir, dass die Preisdifferenz in Zukunft auf 5 zurückkehrt. Dann können wir ETC in dieser Woche verkaufen und ETC Quartal gleichzeitig kaufen, um die Preisdifferenz zu verkürzen und umgekehrt. Obwohl diese Preisdifferenz besteht, gibt es viele Unsicherheiten bei manueller Arbitrage aufgrund zeitaufwändiger manueller Operationen, schlechter Genauigkeit und der Auswirkungen von Preisänderungen. Der Reiz der quantitativen Arbitrage liegt darin, Arbitragechancen durch quantitative Modelle zu erfassen und Arbitrage-Handelsstrategien zu formulieren, sowie automatisch Handelsaufträge an Börsen durch programmierte Algorithmen zu platzieren, um Chancen schnell und genau zu erfassen und Profite effizient und stabil zu erzielen.
In diesem Artikel erfahren Sie, wie Sie die FMZ Quant Trading Platform und den ETC-Futures-Kontrakt in der OKEX-Börse verwenden, um zu zeigen, wie Sie die sofortigen Arbitragemöglichkeiten nutzen, die Gewinnzahlen nutzen, die jedes Mal sichtbar sind, und die Risiken absichern können, die beim Handel mit digitalen Währungen mit einer einfachen Arbitragestrategie auftreten können.
Schwierigkeiten: Normal
Die obige ist eine einfache logische Beschreibung der Querschnitts-Arbitrage-Strategie der digitalen Währung.
function Data() {} // Basic data function
Data.prototype.mp = function () {} // Position function
Data.prototype.boll = function () {} // Indicator function
Data.prototype.trade = function () {} // Order placement function
Data.prototype.cancelOrders = function () {} // Order withdrawal function
Data.prototype.isEven = function () {} // Processing single contract function
Data.prototype.drawingChart = function () {} // Drawing function
// Trading conditions
function onTick() {
var data = new Data(tradeTypeA, tradeTypeB); // Create a basic data object
var accountStocks = data.accountData.Stocks; // Account balance
var boll = data.boll(dataLength, timeCycle); // Calculate the technical indicators of boll
data.trade(); // Calculate trading conditions to place an order
data.cancelOrders(); // Cancel orders
data.drawingChart(boll); // drawing
data.isEven(); // Processing of holding individual contract
}
//Entry function
function main() {
while (true) { // Enter the polling mode
onTick(); // Execute onTick function
Sleep(500); // Sleep for 0.5 seconds
}
}
Der Strategie-Rahmen kann leicht nach der Strategieidee und dem Transaktionsprozess aufgestellt werden. Vorverarbeitung vor der Transaktion. Holen und berechnen Sie Daten. Stellen Sie eine Bestellung und kümmern Sie sich später darum. Als nächstes müssen wir den notwendigen Detailcode im Strategie-Rahmen gemäß dem tatsächlichen Transaktionsprozess und den Transaktionsdetails ausfüllen.
Vorverarbeitung vor der Transaktion Schritt 1: Die erforderlichen globalen Variablen im globalen Umfang angeben.
//Declare a chart object for the configuration chart
var chart = { }
//Call Chart function and initialize the chart
var ObjChart = Chart ( chart )
//Declare an empty array to store price difference series
var bars = [ ]
//Declare a record history data timestamp variable
var oldTime = 0
Schritt 2: Konfigurieren der externen Parameter der Strategie.
// parameters
var tradeTypeA = "this_week"; // Arbitrage A Contract
var tradeTypeB = "quarter"; // Arbitrage B Contract
var dataLength = 10; //Indicator period length
var timeCycle = 1; // K-line period
var name = "ETC"; // Currencies
var unit = 1; // Order quantity
Schritt 3: Definition der Datenverarbeitung Grunddatenfunktion: Daten Erstellen Sie einen Konstruktor, Daten, und definieren Sie seine internen Eigenschaften, einschließlich: Konto-Daten, Positionsdaten, K-Liniendaten Zeitstempel, Kauf-/Verkaufspreis eines Arbitrage-A/B-Kontrakts und positive/negative Arbitrage-Preisdifferenz.
// Basic data
function Data(tradeTypeA, tradeTypeB) { // Pass in arbitrage A contract and arbitrage B contract
this.accountData = _C(exchange.GetAccount); // Get account information
this.positionData = _C(exchange.GetPosition); // Get position information
var recordsData = _C(exchange.GetRecords); // Get K-line data
exchange.SetContractType(tradeTypeA); // Subscription arbitrage A contract
var depthDataA = _C(exchange.GetDepth); // Depth data of arbitrage A contract
exchange.SetContractType(tradeTypeB); // Subscription arbitrage B contract
var depthDataB = _C(exchange.GetDepth); // Depth data of arbitrage B contract
this.time = recordsData[recordsData.length - 1].Time; // Time of obtaining the latest data
this.askA = depthDataA.Asks[0].Price; // Sell one price of Arbitrage A contract
this.bidA = depthDataA.Bids[0].Price; // Buy one price of Arbitrage A contract
this.askB = depthDataB.Asks[0].Price; // Sell one price of Arbitrage B contract
this.bidB = depthDataB.Bids[0].Price; // Buy one price of Arbitrage B contract
// Positive arbitrage price differences (Sell one price of contract A - Buy one price of contract B)
this.basb = depthDataA.Asks[0].Price - depthDataB.Bids[0].Price;
// Negative arbitrage price differences (Buy one price of contract A - Sell one price of contract B)
this.sabb = depthDataA.Bids[0].Price - depthDataB.Asks[0].Price;
}
Erhalten Sie die Positionsfunktion: mp ()) Durchqueren Sie das gesamte Positionsarray und geben Sie die Positionsmenge des angegebenen Vertrags und der Richtung zurück.
// Get positions
Data.prototype.mp = function (tradeType, type) {
var positionData = this.positionData; // Get position information
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;
}
K-Linie und Indikatorfunktion: Boll ((() Eine neue K-Liniensequenz wird nach den Daten der positiven Arbitrage/negativen Arbitrage-Preisunterschied synthetisiert. Die Daten der oberen Spur, der mittleren Spur und der unteren Spur, die durch den Boll-Indikator berechnet werden, werden zurückgegeben.
// Synthesis of new K-line data and boll indicator data
Data.prototype.boll = function (num, timeCycle) {
var self = {}; // Temporary objects
// Median value of positive arbitrage price difference and negative arbitrage price difference
self.Close = (this.basb + this.sabb) / 2;
if (this.timeA == this.timeB) {
self.Time = this.time;
} // Compare two depth data timestamps
if (this.time - oldTime > timeCycle * 60000) {
bars.push(self);
oldTime = this.time;
} // Pass in the price difference data object into the K-line array according to the specified time period
if (bars.length > num * 2) {
bars.shift(); // Control the length of the K-line array
} 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], // boll indicator upper track
middle: boll[1][boll[1].length - 1], // boll indicator middle track
down: boll[2][boll[2].length - 1] // boll indicator down track
} // Return a processed boll indicator data
}
Auftragsfunktion: Handel Da es notwendig ist, zwei Aufträge in verschiedene Richtungen gleichzeitig zu platzieren, wird der Kauf/Verkauf eines Preises innerhalb der Funktion nach dem Vertragsnamen der Bestellung umgerechnet.
// place the order
Data.prototype.trade = function (tradeType, type) {
exchange.SetContractType(tradeType); // Resubscribe to a contract before placing an order
var askPrice, bidPrice;
if (tradeType == tradeTypeA) { // If the order is placed in contract A
askPrice = this.askA; // set askPrice
bidPrice = this.bidA; // set bidPrice
} else if (tradeType == tradeTypeB) { // If the order is placed in contract B
askPrice = this.askB; // set askPrice
bidPrice = this.bidB; // set bidPrice
}
switch (type) { // Match order placement mode
case "buy":
exchange.SetDirection(type); // Set order placement mode
return exchange.Buy(askPrice, unit);
case "sell":
exchange.SetDirection(type); // Set order placement mode
return exchange.Sell(bidPrice, unit);
case "closebuy":
exchange.SetDirection(type); // Set order placement mode
return exchange.Sell(bidPrice, unit);
case "closesell":
exchange.SetDirection(type); // Set order placement mode
return exchange.Buy(askPrice, unit);
default:
return false;
}
}
Auftrag stornieren Funktion: Auftrag stornieren Erhalten Sie eine Reihe aller ausstehenden Bestellungen und stornieren Sie sie einzeln. Zusätzlich wird false zurückgegeben, wenn es eine unerfüllte Bestellung gibt, und true wird zurückgegeben, wenn es keine unerfüllte Bestellung gibt.
// Cancel order
Data.prototype.cancelOrders = function () {
Sleep(500); // Delay before cancellation, because some exchanges, you know what I mean
var orders = _C(exchange.GetOrders); // Get an array of unfilled orders
if (orders.length > 0) { // If there are unfilled orders
for (var i = 0; i < orders.length; i++) { //Iterate through the array of unfilled orders
exchange.CancelOrder(orders[i].Id); //Cancel unfilled orders one by one
Sleep(500); //Delay 0.5 seconds
}
return false; // Return false if an unfilled order is cancelled
}
return true; // Return true if there are no unfilled orders
}
Handler, der einen einzigen Vertrag hält: isEven ((() Im Falle eines Einzelbeins in der Arbitrage-Transaktion werden wir einfach alle Positionen schließen.
// Handle holding a single contract
Data.prototype.isEven = function () {
var positionData = this.positionData; // Get position information
var type = null; // Switch position direction
// If the remaining 2 of the position array length is not equal to 0 or the position array length is not equal to 2
if (positionData.length % 2 != 0 || positionData.length != 2) {
for (var i = 0; i < positionData.length; i++) { // Iterate through the position array
if (positionData[i].Type == 0) { // If it is a long order
type = 10; // Set order parameters
} else if (positionData[i].Type == 1) { // If it is a short order
type = -10; // Set order parameters
}
// Close all positions
this.trade(positionData[i].ContractType, type, positionData[i].Amount);
}
}
}
Zeichnungsfunktion: Zeichnung Anrufen Sie die ObjChart Add () -Methode, zeichnen Sie die erforderlichen Marktdaten und Indikatordaten im Diagramm: oberer Track, mittlerer Track, unterer Track, positiver/negativer Arbitrage-Preisunterschied.
// Drawing
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);
}
Schritt 4: In der Eingabefunktion main() wird der Code zur Vorverarbeitung von Transaktionen ausgeführt, der nach dem Start des Programms nur einmal ausgeführt wird, einschließlich:
//entry function
function main() {
// Filter the unimportant information in the console
SetErrorFilter("429|GetRecords:|GetOrders:|GetDepth:|GetAccount|:Buy|Sell|timeout|Futures_OP");
exchange.IO("currency", name + '_USDT'); //Set the digital currency to be traded
ObjChart.reset(); // Clear the previous chart drawn before starting the program
LogProfitReset(); // Clear the status bar information before starting the program
}
Nachdem die oben genannte Vorverarbeitung vor der Transaktion definiert ist, ist der nächste Schritt, in den Umfrage-Modus einzutreten und die Funktion onTick ((() wiederholt auszuführen.
//entry function
function main() {
// Filter the unimportant information in the console
SetErrorFilter("429|GetRecords:|GetOrders:|GetDepth:|GetAccount|:Buy|Sell|timeout|Futures_OP");
exchange.IO("currency", name + '_USDT'); //Set the digital currency to be traded
ObjChart.reset(); //Clear the previous chart drawn before starting the program
LogProfitReset(); //Clear the status bar information before starting the program
while (true) { // Enter the polling mode
onTick(); // Execute onTick function
Sleep(500); // Sleep for 0.5 seconds
}
}
Erhalten und berechnen von Daten Schritt 1: Erhalten Sie Basisdatenobjekt, Kontostand und Boll-Indikatordaten für die Verwendung in der Handelslogik.
// Trading conditions
function onTick() {
var data = new Data(tradeTypeA, tradeTypeB); // Create a basic 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
}
Bestellen und die Nachfolge erledigen. Schritt 1: Führen Sie die Kauf- und Verkaufsaktion nach der obigen strategischen Logik aus. Beurteilen Sie zunächst, ob die Preis- und Indikatorbedingungen gültig sind, beurteilen Sie dann, ob die Positionsbedingungen gültig sind, und führen Sie schließlich die Trade () -Orderfunktion aus
// Trading conditions
function onTick() {
var data = new Data(tradeTypeA, tradeTypeB); // Create a basic 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
// Explanation of the price difference
// basb = (Sell one price of contract A - Buy one price of contract B)
// sabb = (Buy one price of contract A - Sell one price of contract B)
if (data.sabb > boll.middle && data.sabb < boll.up) { // If sabb is higher than the middle track
if (data.mp(tradeTypeA, 0)) { // Check whether contract A has long orders before placing an order
data.trade(tradeTypeA, "closebuy"); // Contract A closes long position
}
if (data.mp(tradeTypeB, 1)) { // Check whether contract B has short orders before placing an order
data.trade(tradeTypeB, "closesell"); // Contract B closes short position
}
} else if (data.basb < boll.middle && data.basb > boll.down) { // If basb is lower than the middle track
if (data.mp(tradeTypeA, 1)) { // Check whether contract A has short orders before placing an order
data.trade(tradeTypeA, "closesell"); // Contract A closes short position
}
if (data.mp(tradeTypeB, 0)) { // Check whether contract B has long orders before placing an order
data.trade(tradeTypeB, "closebuy"); // Contract B closes long position
}
}
if (accountStocks * Math.max(data.askA, data.askB) > 1) { // If there is balance in the account
if (data.basb < boll.down) { // If basb price difference is lower than the down track
if (!data.mp(tradeTypeA, 0)) { // Check whether contract A has long orders before placing an order
data.trade(tradeTypeA, "buy"); // Contract A opens long position
}
if (!data.mp(tradeTypeB, 1)) { // Check whether contract B has short orders before placing an order
data.trade(tradeTypeB, "sell"); // Contract B opens short position
}
} else if (data.sabb > boll.up) { // If sabb price difference is higher than the upper track
if (!data.mp(tradeTypeA, 1)) { // Check whether contract A has short orders before placing an order
data.trade(tradeTypeA, "sell"); // Contract A opens short position
}
if (!data.mp(tradeTypeB, 0)) { // Check whether contract B has long orders before placing an order
data.trade(tradeTypeB, "buy"); // Contract B opens long position
}
}
}
}
Schritt 2: Nach der Auftragserteilung ist es notwendig, sich mit den abnormalen Situationen wie der nicht abgewickelten Auftrag und dem Halten eines einzigen Vertrages zu befassen.
// Trading conditions
function onTick() {
var data = new Data(tradeTypeA, tradeTypeB); // Create a basic 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
// Explanation of the price difference
//basb = (Sell one price of contract A - Buy one price of contract B)
// sabb = (Buy one price of contract A - Sell one price of contract B)
if (data.sabb > boll.middle && data.sabb < boll.up) { // If sabb is higher than the middle track
if (data.mp(tradeTypeA, 0)) { // Check whether contract A has long orders before placing an order
data.trade(tradeTypeA, "closebuy"); // Contract A closes long position
}
if (data.mp(tradeTypeB, 1)) { // Check whether contract B has short orders before placing an order
data.trade(tradeTypeB, "closesell"); // Contract B closes short position
}
} else if (data.basb < boll.middle && data.basb > boll.down) { // If basb is lower than the middle track
if (data.mp(tradeTypeA, 1)) { // Check whether contract A has short orders before placing an order
data.trade(tradeTypeA, "closesell"); // Contract A closes short position
}
if (data.mp(tradeTypeB, 0)) { // Check whether contract B has long orders before placing an order
data.trade(tradeTypeB, "closebuy"); // Contract B closes long position
}
}
if (accountStocks * Math.max(data.askA, data.askB) > 1) { // If there is balance in the account
if (data.basb < boll.down) { // If basb price difference is lower than the down track
if (!data.mp(tradeTypeA, 0)) { // Check whether contract A has long orders before placing an order
data.trade(tradeTypeA, "buy"); // Contract A opens long position
}
if (!data.mp(tradeTypeB, 1)) { // Check whether contract B has short orders before placing an order
data.trade(tradeTypeB, "sell"); // Contract B opens short position
}
} else if (data.sabb > boll.up) { // If sabb price difference is higher than the upper track
if (!data.mp(tradeTypeA, 1)) { // Check whether contract A has short orders before placing an order
data.trade(tradeTypeA, "sell"); // Contract A opens short position
}
if (!data.mp(tradeTypeB, 0)) { // Check whether contract B has long orders before placing an order
data.trade(tradeTypeB, "buy"); // Contract B opens long position
}
}
}
data.cancelOrders(); // cancel orders
data.drawingChart(boll); // drawing
data.isEven(); // Handle holding individual contracts
}
Wie oben, haben wir eine einfache Querschnitts-Periode-Arbitrage-Strategie der digitalen Währung komplett durch mehr als 200 Zeilen Code erstellt.
// Global variable
// Declare a chart object for the configuration chart
var chart = {
__isStock: true,
tooltip: {
xDateFormat: '%Y-%m-%d %H:%M:%S, %A'
},
title: {
text: 'transaction profit and loss curve (detailed)'
},
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: 'price difference'
},
opposite: false,
},
series: [{
name: "upper track",
id: "line1,up",
data: []
}, {
name: "middle track",
id: "line2,middle",
data: []
}, {
name: "down track",
id: "line3,down",
data: []
}, {
name: "basb",
id: "line4,basb",
data: []
}, {
name: "sabb",
id: "line5,sabb",
data: []
}]
};
var ObjChart = Chart(chart); // Drawing object
var bars = []; // Storage price difference series
var oldTime = 0; // Record historical data timestamp
// parameters
var tradeTypeA = "this_week"; // Arbitrage A contract
var tradeTypeB = "quarter"; // Arbitrage B contract
var dataLength = 10; //Indicator period length
var timeCycle = 1; // K-line period
var name = "ETC"; // Currencies
var unit = 1; // Order quantity
// basic data
function Data(tradeTypeA, tradeTypeB) { // Pass in arbitrage A contract and arbitrage B contract
this.accountData = _C(exchange.GetAccount); // Get account information
this.positionData = _C(exchange.GetPosition); // Get position information
var recordsData = _C(exchange.GetRecords); //Get K-line data
exchange.SetContractType(tradeTypeA); // Subscribe to arbitrage A contract
var depthDataA = _C(exchange.GetDepth); // Arbitrage A contract depth data
exchange.SetContractType(tradeTypeB); // Subscribe to arbitrage B contract
var depthDataB = _C(exchange.GetDepth); // Arbitrage B contract depth data
this.time = recordsData[recordsData.length - 1].Time; // Time to get the latest data
this.askA = depthDataA.Asks[0].Price; // Sell one price of arbitrage A contract
this.bidA = depthDataA.Bids[0].Price; // Buy one price of arbitrage A contract
this.askB = depthDataB.Asks[0].Price; // Sell one price of arbitrage B contract
this.bidB = depthDataB.Bids[0].Price; // Buy one price of arbitrage B contract
// Positive arbitrage price difference (Sell one price of contract A - Buy one price of contract B)
this.basb = depthDataA.Asks[0].Price - depthDataB.Bids[0].Price;
// Negative arbitrage price difference (Buy one price of contract A - Sell one price of contract B)
this.sabb = depthDataA.Bids[0].Price - depthDataB.Asks[0].Price;
}
// Get position
Data.prototype.mp = function (tradeType, type) {
var positionData = this.positionData; // Get position information
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;
}
// Synthesis of new K-line data and boll indicator data
Data.prototype.boll = function (num, timeCycle) {
var self = {}; // Temporary objects
// Median value of between positive arbitrage price difference and negative arbitrage price difference
self.Close = (this.basb + this.sabb) / 2;
if (this.timeA == this.timeB) {
self.Time = this.time;
} // Compare two depth data timestamps
if (this.time - oldTime > timeCycle * 60000) {
bars.push(self);
oldTime = this.time;
} // Pass in the price difference data object into the K-line array according to the specified time period
if (bars.length > num * 2) {
bars.shift(); // Control the length of the K-line array
} 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], // boll indicator upper track
middle: boll[1][boll[1].length - 1], // boll indicator middle track
down: boll[2][boll[2].length - 1] // boll indicator down track
} // Return a processed boll indicator data
}
// Place an order
Data.prototype.trade = function (tradeType, type) {
exchange.SetContractType(tradeType); // Resubscribe to a contract before placing an order
var askPrice, bidPrice;
if (tradeType == tradeTypeA) { // If the order is placed in contract A
askPrice = this.askA; // Set askPrice
bidPrice = this.bidA; // Set bidPrice
} else if (tradeType == tradeTypeB) { // If the order is placed in contract B
askPrice = this.askB; // Set askPrice
bidPrice = this.bidB; // Set bidPrice
}
switch (type) { // Match order placement mode
case "buy":
exchange.SetDirection(type); // Set order placement mode
return exchange.Buy(askPrice, unit);
case "sell":
exchange.SetDirection(type); // Set order placement mode
return exchange.Sell(bidPrice, unit);
case "closebuy":
exchange.SetDirection(type); // Set order placement mode
return exchange.Sell(bidPrice, unit);
case "closesell":
exchange.SetDirection(type); // Set order placement mode
return exchange.Buy(askPrice, unit);
default:
return false;
}
}
// Cancel orders
Data.prototype.cancelOrders = function () {
Sleep(500); // Delay before cancellation, because some exchanges, you know what I mean
var orders = _C(exchange.GetOrders); //Get an array of unfilled orders
if (orders.length > 0) { // If there are unfilled orders
for (var i = 0; i < orders.length; i++) { //Iterate through the array of unfilled orders
exchange.CancelOrder(orders[i].Id); //Cancel unfilled orders one by one
Sleep(500); //Sleep for 0.5 seconds
}
return false; // Return false if an unfilled order is cancelled
}
return true; //Return true if there are no unfilled orders
}
// Handle holding individual contracts
Data.prototype.isEven = function () {
var positionData = this.positionData; // Get position information
var type = null; // Switch position direction
// If the remaining 2 of the position array length is not equal to 0 or the position array length is not equal to 2
if (positionData.length % 2 != 0 || positionData.length != 2) {
for (var i = 0; i < positionData.length; i++) { // Iterate through the position array
if (positionData[i].Type == 0) { // If it is a long order
type = 10; // Set order parameters
} else if (positionData[i].Type == 1) { // If it is a short order
type = -10; // Set order parameters
}
// Close all positions
this.trade(positionData[i].ContractType, type, positionData[i].Amount);
}
}
}
// Drawing
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 conditions
function onTick() {
var data = new Data(tradeTypeA, tradeTypeB); // Create a basic 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
// Explanation of price difference
// basb = (Sell one price of contract A - Buy one price of contract B)
// sabb = (Buy one price of contract A - Sell one price of contract B)
if (data.sabb > boll.middle && data.sabb < boll.up) { // If sabb is higher than the middle track
if (data.mp(tradeTypeA, 0)) { // Check whether contract A has long orders before placing an order
data.trade(tradeTypeA, "closebuy"); // Contract A closes long position
}
if (data.mp(tradeTypeB, 1)) { // Check whether contract B has short orders before placing an order
data.trade(tradeTypeB, "closesell"); // Contract B closes short position
}
} else if (data.basb < boll.middle && data.basb > boll.down) { // If basb is lower than the middle track
if (data.mp(tradeTypeA, 1)) { // Check whether contract A has short orders before placing an order
data.trade(tradeTypeA, "closesell"); // Contract A closes short position
}
if (data.mp(tradeTypeB, 0)) { // Check whether contract B has long orders before placing an order
data.trade(tradeTypeB, "closebuy"); // Contract B closes long position
}
}
if (accountStocks * Math.max(data.askA, data.askB) > 1) { // If there is a balance in the account
if (data.basb < boll.down) { // If basb price difference is lower than the down track
if (!data.mp(tradeTypeA, 0)) { // Check whether contract A has long orders before placing an order
data.trade(tradeTypeA, "buy"); // Contract A opens long position
}
if (!data.mp(tradeTypeB, 1)) { // Check whether contract B has short orders before placing an order
data.trade(tradeTypeB, "sell"); // Contract B opens short position
}
} else if (data.sabb > boll.up) { // If sabb price difference is higher than the upper track
if (!data.mp(tradeTypeA, 1)) { // Check whether contract A has short orders before placing an order
data.trade(tradeTypeA, "sell"); // Contract A opens short position
}
if (!data.mp(tradeTypeB, 0)) { // Check whether contract B has long orders before placing an order
data.trade(tradeTypeB, "buy"); // Contract B opens long position
}
}
}
data.cancelOrders(); // Cancel orders
data.drawingChart(boll); // Drawing
data.isEven(); // Handle holding individual contracts
}
//Entry function
function main() {
// Filter unimportant information in the console
SetErrorFilter("429|GetRecords:|GetOrders:|GetDepth:|GetAccount|:Buy|Sell|timeout|Futures_OP");
exchange.IO("currency", name + '_USDT'); //Set the digital currency to be traded
ObjChart.reset(); //Clear the previous chart drawn before starting the program
LogProfitReset(); //Clear the status bar information before starting the program
while (true) { // Enter polling mode
onTick(); // Execute the onTick function
Sleep(500); // Sleep for 0.5 seconds
}
}
Strategieadresse:https://www.fmz.com/strategy/104964
Die Strategie in diesem Artikel ist nur ein Beispiel. Der echte Bot ist nicht einfach, aber Sie können dem Beispiel folgen und Ihre eigene wilde Phantasie verwenden. Es sollte daran erinnert werden, dass auf der Grundlage meiner begrenzten Erfahrung auf dem aktuellen digitalen Währungsmarkt fast alle reinen Futures-Futures-Arbitrage-Strategien nicht wert sind, egal ob es sich um risikofreie dreieckige Arbitrage oder Marktübergreifende Arbitrage handelt. Der Grund dafür ist, dass unabhängig davon, welcher digitale Währungsaustausch-Futures-Markt, seine Marge nicht legal Währung ist. Zurzeit sind fast alle digitalen Währungen seit Jahresbeginn um etwa 70% gefallen. Das heißt, die Strategie ist immer, Währungen zu verdienen, aber der Währungspreis sinkt. Insgesamt scheint sich der digitale Währungsmarkt von der Blockchain losgelöst zu haben. Wie die Tulpen damals, kommt der Preis immer von den Erwartungen und dem Vertrauen der Menschen, und das Vertrauen kommt vom Preis...