Überzeitliche Arbitragestrategie für digitale Währungen auf Basis des Bollinger Bands

Schriftsteller:Lydia., Erstellt: 2022-12-02 16:58:27, Aktualisiert: 2023-09-20 09:33:29

img

Überzeitliche Arbitragestrategie für digitale Währungen auf Basis des Bollinger Bands

I. Zusammenfassung

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.

II. Strategische Grundsätze

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.

III. Strategische Logik

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.

Schaffung einer Zeitrahmenübergreifenden Arbitrage-Strategie für digitale Währungen

Schwierigkeiten: Normal

Strategieumfeld

  • Gegenstand der Transaktion: Ether Classic (ETC)
  • Spread-Daten: ETC laufende Woche - ETC Quartal (Kointegrationstest weglassen)
  • Transaktionsdauer: 5 Minuten
  • Positionsabgleich: 1:1
  • Art der Transaktion: Querschnittsperiode desselben Typs

Strategie Logik

  • Voraussetzungen für die Eröffnung von Positionen mit Longing der Kursdifferenz: Wenn das Girokonto keine Positionen aufweist und die Kursdifferenz kleiner als die untere Grenze der Boll ist, wird die Kursdifferenz langgehalten.
  • Voraussetzungen für die Eröffnung von Positionen mit Shorting der Kursdifferenz: Wenn es keine Position auf dem Leistungsbilanzkonto gibt und die Kursdifferenz größer ist als die obere Grenze der Boll, dann wird die Kursdifferenz shorting. Das heißt, Verkauf von Eröffnungspositionen ETC für die Woche, Kauf von Eröffnungspositionen ETC für das Quartal.
  • Bedingungen für den Schluß von Positionen mit Long-Price-Differenz: Wenn das Girokonto in der laufenden Woche Long-Orders von ETC hält und im Quartal Short-Orders von ETC hält und die Preisdifferenz größer ist als die mittlere Grenze der Boll, dann schließt man die Preisdifferenz lang. Das heißt, man verkauft Schließpositionen ETC für die Woche, kauft Schließpositionen ETC für das Quartal.
  • Bedingungen für den Schluß von Positionen mit dem Shorten der Preisdifferenz: Wenn das Girokonto in der laufenden Woche laufende Short-Orders von ETC hält und laufende Long-Orders von ETC-Quartalen hält und die Preisdifferenz kleiner als die mittlere Grenze des Boll ist, dann schließt man die Preisdifferenz. Das heißt, man kauft Schließpositionen ETC für die Woche, verkauft Schließpositionen ETC für das Quartal.

IV. Schreiben eines Strategierahmens

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

V. Schreibstrategie

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:

  • SetErrorFilter (()) Filtern Sie die unwichtigen Informationen in der Konsole
  • exchange.IO ( https://www.squadhelp.com/name/exchange.io?lp=d) ()) zur Festlegung der zu handelnden digitalen Währung
  • ObjChart-Reset ( ) zum Löschen des vor dem Programmstart gezeichneten vorherigen Diagramms
  • LogProfitReset() um die Statusleiste vor dem Start des Programms zu löschen
//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
}

VI. Vollständige Strategie

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

VII. Zusammenfassung

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...


Verwandt

Mehr