From Quantitative Trading to Asset Management - CTA Strategy Development for Absolute Return (5)

in fmz •  last year 
  1. After the order is placed, it is necessary to deal with the abnormal situations such as the unsettled order and the holding of a single contract. And draw the chart.
data.cancelOrders(); // cancel orders
data.drawingChart(boll); // drawing
data.isEven(); // Handle holding individual contracts

As above, we have created a simple cross-period arbitrage strategy of digital currency completely through more than 200 lines code. The complete code is as follows:

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

To be continued...

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!