ブロックチェーンの定量投資シリーズコース (3) カレンダー・スプレッド・アービトラージ

作者: リン・ハーンルービー作成日: 2018-08-27 16:49:50, 更新日:

NO. 1 1987年にソロスが書いた 『金融錬金術』では 重要な命題が提唱されています 市場の価格が 未来に対する偏った見方を 示すという意味では 常に間違っていると思います 市場有効性仮説は理論的仮定に過ぎない.実際には,市場参加者は常に合理的ではなく,各時点において,参加者はすべての情報を完全に獲得し,客観的に解釈することはできません.同じ情報であっても,すべてのフィードバックは異なります.

言い換えれば,価格そのものは既に市場参加者の誤った期待を含んでいるので,本質的には市場価格は常に誤っている.これは仲介業者にとって利益の源かもしれません.

img

NO.2 上記の原則に基づき,非効率的な先物市場では,異なる期間の配達契約の市場影響が常に同期されず,価格設定が完全に有効な理由ではないことも知っています.

次に,同じ取引目標の異なる時点での配達契約の価格に基づいて,両価格の間には大きな差がある場合,異なる期間の先物契約を同時に取引し,時間間仲介を行うことが可能です. コモディティ・フューチャーと同様に,デジタル通貨も時間間仲介契約ポートフォリオが関連している.例えば,OKEX取引所で:ETC週間,ETC来週,ETC四半期.

例えば,ETC週とETC四半期間のスプレッドが長期間5周で維持されていると仮定します.スプレッドが7に達すると,将来のある時点でスプレッドが5に戻ることを期待します.その後,ETC週を売り,ETC四半期を購入してスプレッドをショートすることができます.逆の方です.

NO.3 このスプレッドは存在するが,手動アービタージでは,手動操作の時間がかかり,精度が低いため,価格変動の影響のために多くの不確実性があります.

量的なモデルを通じて 利 arbitrageの機会を把握し 利 arbitrageの取引戦略を開発し プログラムアルゴリズムによって 取引先に自動で取引オーダーを発行し 機会を迅速かつ正確に把握し 効率的に収入を得ることができます これは量的な利 arbitrageの魅力です

img

この記事では,デジタル通貨取引におけるFMZ定量取引プラットフォームとOKEX取引所のETC先物契約の使い方について説明します.

NO.4 デジタル通貨の時間間仲介戦略を作成する 難易度:普通レベル 戦略的環境 トランザクション目標:Ethereum classic (ETC) スプレッドデータ: ETC週刊 - ETC四半期 取引期間: 5分 位置一致 1:1 トランザクションタイプ:同じ品種 期間間 戦略の論理 ローング・スプレッド・ポジションの購入条件: 経常口座にポジションがない場合,スプレッドがボール・インジケーターのダウントレイルより小さい場合,スプレッド・オーダーをします.これは週にロング・ETCを購入し,四半期にショート・ETCを売ります.

ショートセールス・スプレッドポジション条件: 経常口座にポジションがない場合,スプレッドがボール指標のアップレールより高くなった場合,スプレッドオーダーをします.これは,毎週ショート・ETCを売却し,四半期ごとにロング・ETCを購入します.

長期株価差の購入条件を閉じる: 決済口座が長期ETCの週期ポジションと短期ETCの四半期ポジションを保持し,株価差がBoll指標の中央線よりも高くなった場合,閉じる株価差の注文をします.これは,週にETCを売却し,四半期にETCをカバーするために購入します.

ショートセール・スプレッドポジション条件を閉じる: 経常口座が ETCのショート・週期ポジションと ETCのショート・四半期ポジションを保持し,スプレッドがボール指標のミドルレールより低い場合,スプレッドを閉じるオーダーを設定します.これは: ETCをカバーするために週に買い,四半期に ETCを売却します.

NO.5 上記はデジタル通貨のシンプルな説明です. デジタル通貨の時間間仲介戦略のロジックです. では,自分のアイデアをプログラムにどのように実装しますか? まずFMZの定量取引プラットフォームでフレームワークを構築してみました. 戦略の枠組み

img

戦略の枠組みは,戦略的思考と取引プロセスに従って簡単に構築できます. 戦略全体は,3つのステップに簡略化できます.

  1. 取引前の事前処理
  2. データを集めて計算します
  3. 注文して 追跡する

NO.6 次に,実際の取引プロセスと取引の詳細に基づいて,必要な詳細を戦略枠組みに記入する必要があります.

まず 取引前の事前処理 ステップ1: グローバル環境では,必要なグローバル変数を宣言します. チャートを構成するチャートオブジェクトを宣言する バールチャート = { } Chart 関数を呼び出し,チャートを初期化します Var ObjChart = チャート (チャート) 拡散配列を格納する空の配列を宣言する バール= [ ] 履歴データを記録するタイムスタンプ変数を宣言する Var oldTime = 0 について ステップ2: 戦略のための外部パラメータを設定します.

img

ステップ3:データ処理機能を定義する 基本データ機能:データ ()) コンストラクタを作成するデータとその内部プロパティを定義する.例えば:アカウントデータ,ポジションデータ,K線データタイムスタンプ,アビラージ契約の最新の購入/販売価格 A/B,ポジティブ/リバースアビラージ・スプレッド

img

位置関数:mp () を取得する 指定された契約と指定された方向のポジションの数を返します. 存在しない場合は false を返します.

img

K線と指標関数:boll ()) ポジティブ/リバース・アービタージ・スプレッドのデータに基づいて 新しいK線配列を合成し ボール指標で計算された 上/中/下レールのデータを返します

img

注文機能:取引 () オーダー契約名と取引タイプを入力し,その後,最後の購入/販売価格で注文を配置し,注文を配置した後,結果を返します.注文の2つの異なる方向を同時に注文する必要がありますので,最後の購入/販売価格は,注文契約名に従って関数内で変換されます.

img

注文をキャンセルする機能: cancelOrders ()) 待機中の注文を一列に並べて,一枚ずつキャンセルします.待機中の注文がある場合は, false を返します.存在しない場合は, true を返します.

img

プロセス保有単一の契約: isEven ()) アブタージ取引におけるシングルレグの場合は,すべてのポジションを単に閉じて直接処理されます. もちろん,価格を追いかけることもできます.

img

図を描く機能:図を描く ()) グラフに必要な市場データと指標データを引き出すためにObjChart.add () 方法を呼び出す:アップ,ミドル,ダウンレール,ポジティブ/リバース・アービタージ・スプレッド.

img

ステップ4: main () の入力関数で,プログラム開始後1回しか実行されないトランザクションの前に,次のコードを実行します.

コンソールにあまり重要でない情報をフィルタリングします SetErrorFilter ()) 取引するデジタル通貨の種類を設定するexchange.IOについて プログラム開始前に描かれたチャートを空く ObjChart.reset ()) プログラムを起動する前に状態バー情報を空にして LogProfitReset ()

img

NO.7 トランザクション前の上記の事前処理を定義した後,次のステップに移行し,投票モードに入力し,OnTick () 関数を繰り返す必要があります. 投票時に睡眠時間を設定します デジタル通貨取引所の APIには 特定の期間での アクセス制限があります

img

2つ目は,データを取得して計算する ステップ1: 取引論理のための基礎データオブジェクト,口座残高,boll指標データを取得する.

img

第3に 注文し 追跡する ステップ1:上記の戦略論理に従って買い物・販売を実行します.まず,価格と指標条件が正しいかどうかを確認し,その後にポジション条件が正しいかどうかを確認し,最後にトレード () オーダー関数を実行します.

img

ステップ2:注文後,待機中の注文や単一の契約を保持するなどの異常な状況に対処し,チャートを作成する必要があります.

img

NO.8 上記では,200行以上で簡単なデジタル通貨間の時間間仲介戦略を作成しました. 完全なコードは以下のとおりです:

img

NO.9 この戦略はトリガーとして機能します リアルマーケットはそれほど単純ではありませんが この例を使って想像力を発揮できます

私の限られた経験に基づいて デジタル通貨市場の現状では 純粋な期間の仲介戦略は リスクのない三角仲介であれ 市場間仲介であれ 実行に値しないということです

理由は,どのデジタル通貨取引所の先物市場であれ,その利回りは法定ではありません. ほぼすべてのデジタル通貨は年初から約70%下落しています. 言い換えれば,戦略は常に通貨を作っていますが,通貨の価格は下落しています.

デジタル通貨市場は既にブロックチェーンを離れています. チューリップのように,価格は常に人々の期待と信頼から来ています.

完全なコードはこちら

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


もっと

小さな夢良かった!