資源の読み込みに... 荷物...

量的な取引から資産管理へ - 絶対的収益のためのCTA戦略開発

作者: リン・ハーンFMZ~リディア, 作成日:2023-02-07 09:58:41, 更新日:2023-09-18 20:25:11

[nowTime, this.basb]]) について 対象チャート.add (([4, [nowTime, this.sabb]]); ObjChart.update (チャート) について { \ pos (192,220) }

### 4. In the entry function main(), execute the pre-transaction pre-processing code, which will only run once after the program is started, including:

- ```SetErrorFilter ( )``` to filter the unimportant information in the console
- ```exchange.IO ( )``` to set the digital currency to be traded
- ```ObjChart.reset ( )``` to clear the previous chart drawn before starting the program
- ```LogProfitReset ( )``` to clear the status bar information before starting the program

After the above pre-transaction pre-processing is defined, the next step is to enter the polling mode and execute the onTick() function repeatedly. It also sets the sleep time for Sleep () polling, because the API of some digital currency exchanges has built-in access limit for a certain period of time.

基本関数 (main)) { // コンソール内の非重要な情報をフィルター SetErrorFilter (セットエラーフィルター) 429 稼ぐ記録:稼ぐGetOrders:稼ぐGetDepth:稼ぐGetAccount: 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐFutures_OP) exchange.IO ((currency, name + _USDT); // 取引されるデジタル通貨を設定する ObjChart.reset(); // プログラムを起動する前に描いた前のチャートをクリアする LogProfitReset ((); // プログラムを起動する前に状態バー情報を削除 while (true) { // 投票モードを入力する onTick ((); // onTick関数を実行する 睡眠 (500); // 0.5秒間の睡眠 { \ pos (192,220) } { \ pos (192,220) }

## II. Get and calculate data

1. Obtain basic data object, account balance, and boll indicator data for use in the trading logic.

機能はオンです var data = new Data ((tradeTypeA, tradeTypeB); // 基本的なデータオブジェクトを作成する var accountStocks = data.accountData.Stocks; // 口座残高について バル・ボール = data.boll ((dataLength, timeCycle); // ボール指標データを取得する if (!boll) return; // boll データがない場合は戻す { \ pos (192,220) }

## III. Place an order and handle the follow-up

1. Execute the buying and selling operation according to the above strategic logic. First, judge whether the price and indicator conditions are valid, then judge whether the position conditions are valid, and finally execute the trade () order function.

// 価格差の説明 // basb = (契約Aの1つの価格を売る - 契約Bの1つの価格を買う) // sabb = (契約Aの1つの価格を購入 - 契約Bの1つの価格を売る) if (data.sabb > boll.middle && data.sabb < boll.up) { // If sabb は中間線より高い場合 if (data.mp(tradeTypeA, 0)) { // 注文をする前に,契約Aが長注文を持っているかどうかを確認します data.trade ((tradeTypeA, closebuy); // 契約Aはロングポジションを閉じる { \ pos (192,220) } if (data.mp(tradeTypeB, 1)) { // 注文をする前に,契約Bにショートオーダーがあるかどうかを確認する data.trade ((tradeTypeB, closesell); // B契約はショートポジションを閉じる { \ pos (192,220) } } else if (data.basb < boll.middle && data.basb > boll.down) { // basbが中間トラックより低い場合 if (data.mp(tradeTypeA, 1)) { // 注文をする前に,契約Aがショートオーダーを持っているかどうかを確認する data.trade ((tradeTypeA, closesell); // 契約Aはショートポジションを閉じる { \ pos (192,220) } if (data.mp(tradeTypeB, 0)) { // 注文をする前に,契約Bが長注文を持っているかどうかを確認する data.trade ((tradeTypeB, closebuy); // 契約Bはロングポジションを閉じる { \ pos (192,220) } { \ pos (192,220) } if (accountStocks * Math.max(data.askA, data.askB) > 1) { // 口座に残高がある場合 if (data.basb < boll.down) { // If basb の価格差がダウントラックより低い場合 if (!data.mp(tradeTypeA, 0)) { // 注文をする前に,契約Aが長注文を持っているかどうかを確認します data.trade ((tradeTypeA, buy); // 契約Aはロングポジションを開く { \ pos (192,220) } if (!data.mp(tradeTypeB, 1)) { // 注文をする前に,契約Bにショートオーダーがあるかどうかを確認する data.trade ((tradeTypeB, sell); // 契約Bはショートポジションを開設する { \ pos (192,220) } } else if (data.sabb > boll.up) { // もし sabb の価格差が上位線よりも大きい場合 if (!data.mp(tradeTypeA, 1)) { // 注文をする前に,契約Aにショートオーダーがあるかどうかを確認する data.trade ((tradeTypeA, sell); // 契約Aはショートポジションを開く { \ pos (192,220) } if (!data.mp(tradeTypeB, 0)) { // 注文をする前に,契約Bが長注文を持っているかどうかを確認する data.trade ((tradeTypeB, buy); // 契約Bはロングポジションを開く { \ pos (192,220) } { \ pos (192,220) } { \ pos (192,220) }

2. 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(); // 注文をキャンセルする data.drawingチャート (ボール) //図 data.isEven(); // 個別契約を保持する処理

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:

// グローバル変数 // 設定チャート用のチャートオブジェクトを宣言する バールチャート = { __isStock: true, ツール・ティップ: { xDateFormat: %Y-%m-%d %H:%M:%S, %A }, タイトル: テキスト: 取引利益損失曲線 (詳細) }, rangeSelector: { 選択する ボタン: [ タイプ: 時間 数: 1 テキスト: 1h { \ pos (192,220) }, { \ pos (192,220) } タイプ: 時間 計数: 2 テキスト: 3h { \ pos (192,220) }, { \ pos (192,220) } タイプ: 時間 計数: 8 テキスト: 8h { \ pos (192,220) }, { \ pos (192,220) } タイプ: すべて テキスト: すべて ) ] 選択された: 0, input有効: false }, x軸: { タイプ: 日時 }, y軸: { タイトル: テキスト: 価格差 }, 逆: 偽 }, シリーズ: [ 名称: 上線 id: line1,up, データ: [] { \ pos (192,220) }, { \ pos (192,220) } 名称: 中道 id: 行2,中, データ: [] { \ pos (192,220) }, { \ pos (192,220) } 名称: 下線 id: 線3,下へ, データ: [] { \ pos (192,220) }, { \ pos (192,220) } 名前: basb id: 行4,basb データ: [] { \ pos (192,220) }, { \ pos (192,220) } 名前: sabb id: ライン5,sabb, データ: [] {a1pos (110,268) } ) var ObjChart = Chart(chart); // 図を描くオブジェクト var bars = []; // 貯蔵価格差のシリーズ var oldTime = 0; // 過去データタイムスタンプを記録する

// パラメーター var tradeTypeA = this_week; // 仲裁 A契約 var tradeTypeB = 四半期; // 仲裁B契約 var dataLength = 10; // インディケーター 期間の長さ var timeCycle = 1; // K線周期 var name = ETC; // 通貨 var 単位 = 1; // 注文量

// 基本データ 関数 Data ((tradeTypeA, tradeTypeB) { // アビタージA契約とアビタージB契約の通過 this.accountData = _C(exchange.GetAccount); //アカウント情報を取得する this.positionData = _C(exchange.GetPosition); //位置情報を取得する var recordsData = _C(exchange.GetRecords); // K線データを取得する exchange.SetContractType(tradeTypeA); // 契約の仲裁にサインする var depthDataA = _C ((exchange.GetDepth); // Arbitrage 契約の深さのデータ exchange.SetContractType ((tradeTypeB); // 契約を書き込みする var depthDataB = _C(exchange.GetDepth); // Arbitrage B 契約の深さのデータ this.time = recordsData[recordsData.length - 1].Time; // 最新のデータを入手する時間 this.askA = depthDataA.Asks[0].Price; // 1つの価格の仲介を販売する this.bidA = depthDataA.Bids[0].Price; // 1つの価格の仲介契約を購入する this.askB = depthDataB.Asks[0].Price; // アブタージB契約の1つの価格を販売する this.bidB = depthDataB.Bids[0].Price; // アブタージB契約の1つの価格を購入する // ポジティブ・アービタージ価格差 (契約Aの1つの価格を売却 - 契約Bの1つの価格を購入) this.basb = depthDataA.Asks[0].Price - depthDataB.Bids[0].Price: 価格: 価格: 価格: 価格 // 負の仲介価格差 (契約Aの1つの価格を購入 - 契約Bの1つの価格を売る) this.sabb = depthDataA.Bids[0].Price - depthDataB.Asks[0].Price. 詳細は次のとおり { \ pos (192,220) }

位置を把握する Data.prototype.mp = 関数 (tradeType, type) { 取引型,タイプ var positionData = this.positionData; //位置情報を取得する for (var i = 0; i <位置Data.length; i++) { if (positionData[i].ContractType == tradeType) { (位置データ[i].ContractType == tradeType) { 取引の種類を表示する) if (位置データ[i].タイプ ==タイプ) { if (位置データ[i].数値 > 0) { 返信位置データ[i].金額 { \ pos (192,220) } { \ pos (192,220) } { \ pos (192,220) } { \ pos (192,220) } false を返します. { \ pos (192,220) }

// 新しいK線データとBoll指標データの合成 データ.プロトタイプ.ボール = 関数 (数,時間サイクル) { var self = {}; // 一時的なオブジェクト // ポジティブなアビトラージ価格差とネガティブなアビトラージ価格差のメディアン値 self.Close = (this.basb + this.sabb) / 2 について この時間A == この時間B) { self.time = this.time; self.time = この時間 } // 2つの深度データタイムスタンプを比較する if (this.time - oldTime > timeCycle * 60000) { 任意の時間帯を表示する バール.プッシュ ((自己); oldTime = this.time; oldTime = この時間 } // 指定された時間帯に従ってK線配列に価格差データオブジェクトをパスする if (bars.length > num * 2) { bars.shift(); // K線配列の長さを制御する { \ ⌒ \ ⌒ \ ⌒ \ } 返却 { \ pos (192,220) } バール = TA.BOLL(バー,num,2); // タリブ図書館のボールインジケーターを呼んで 返信 { 上へ: ボール[0][ボール[0].長さ - 1], // ボール表示 上部トラック 中間:ボール[1][ボール[1].長さ - 1], // ボール指標 中間トラック ダウン: ボール[2][ボール[2].長さ - 1] // ボール指示線 } // 処理されたboll指標データを返します { \ pos (192,220) }

オーダーする Data.prototype.trade = 機能 (trade) タイプ exchange.SetContractType(tradeType); // 注文をする前に契約を再登録する 価格を尋ねる,価格を提示する if (tradeType == tradeTypeA) { // オーダーが契約Aに記載されている場合 askPrice = this.askA; // askPrice をセットする bidPrice = this.bidA; // bidPrice を設定する } else if (tradeType == tradeTypeB) { // オーダーが契約Bに付与されている場合 askPrice = this.askB; // askPrice をセットする bidPrice = this.bidB; // bidPrice を設定する { \ pos (192,220) } switch (type) { // マッチオーダー配置モード ケース 買い: exchange.SetDirection(type); // 注文の配置モードを設定する 返信交換.購入 (求) 価格,単位; ケース 販売: exchange.SetDirection(type); // 注文の配置モードを設定する 返品交換. 販売 (オファー) 価格,単位; ケース closebuy: exchange.SetDirection(type); // 注文の配置モードを設定する 返品交換. 販売 (オファー) 価格,単位; ケース closesell: exchange.SetDirection(type); // 注文の配置モードを設定する 返信交換.購入 (求) 価格,単位; デフォルト: false を返します. { \ pos (192,220) } { \ pos (192,220) }

// 注文をキャンセル データ.プロトタイプ.キャンセルOrders = 関数 () { キャンセル前に遅刻,いくつかの交換のために,あなたは私が何を意味するか知っている var orders = _C(exchange.GetOrders); //未完成の注文の配列を取得する if (orders.length > 0) { // 満たされていない注文がある場合 for (var i = 0; i < orders.length; i++) { //未完成の注文の配列を繰り返す exchange.CancelOrder ((orders[i].Id); // 満たされていない注文を1つずつキャンセル 睡眠 (500); // 0.5秒間の睡眠 { \ pos (192,220) } false を返します. // 未完了の注文がキャンセルされた場合 false を返します. { \ pos (192,220) } true を返します. // 満たされていない注文がない場合は true を返します. { \ pos (192,220) }

// 個別契約の保持を処理する データ.プロトタイプ.isEven = 関数 () { var positionData = this.positionData; //位置情報を取得する var type = null; // 位置方向を切り替える // 位置配列の長さの残りの2が0に等しくなければ,または位置配列の長さが2に等しくなければ if (positionData.length % 2!= 0 の場合,位置Data.length!= 2) { for (var i = 0; i < positionData.length; i++) { //位置配列を繰り返す if (positionData[i].Type == 0) { // long の順序である場合 type = 10; // 順序パラメータを設定する { else if (positionData[i].Type == 1) { // もし短い順序である場合 type = -10; // 順序パラメータを設定する { \ pos (192,220) } // すべての位置を閉じる this.trade(positionData[i].Contract 種類,種類,位置 データ[i].金額 { \ pos (192,220) } { \ pos (192,220) } { \ pos (192,220) }

// 描く データ.プロトタイプ.図表 = 機能 (ボール) { var nowTime = new Date (().getTime (()); 変更する ObjChart.add (([0, [nowTime,boll.up]])); この項目は ObjChart.add (([1, [nowTime,boll.middle]])); この項目は ObjChart.add (([2, [nowTime,boll.down]])); この項目は 対象チャート.add (([3, [nowTime, this.basb]]); 対象チャート.add (([4, [nowTime, this.sabb]]); ObjChart.update (チャート) について { \ pos (192,220) }

// 取引条件 機能はオンです var data = new Data ((tradeTypeA, tradeTypeB); // 基本的なデータオブジェクトを作成する var accountStocks = data.accountData.Stocks; // 口座残高について バル・ボール = data.boll ((dataLength, timeCycle); // ボール指標データを取得する if (!boll) return; // boll データがない場合は戻す // 価格差の説明 // basb = (契約Aの1つの価格を売る - 契約Bの1つの価格を買う) // sabb = (契約Aの1つの価格を購入 - 契約Bの1つの価格を売る) if (data.sabb > boll.middle && data.sabb < boll.up) { // If sabb は中間線より高い場合 if (data.mp(tradeTypeA, 0)) { // 注文をする前に,契約Aが長注文を持っているかどうかを確認します data.trade ((tradeTypeA, closebuy); // 契約Aはロングポジションを閉じる { \ pos (192,220) } if (data.mp(tradeTypeB, 1)) { // 注文をする前に,契約Bにショートオーダーがあるかどうかを確認する data.trade ((tradeTypeB, closesell); // B契約はショートポジションを閉じる { \ pos (192,220) } } else if (data.basb < boll.middle && data.basb > boll.down) { // basbが中間トラックより低い場合 if (data.mp(tradeTypeA, 1)) { // 注文をする前に,契約Aがショートオーダーを持っているかどうかを確認する data.trade ((tradeTypeA, closesell); // 契約Aはショートポジションを閉じる { \ pos (192,220) } if (data.mp(tradeTypeB, 0)) { // 注文をする前に,契約Bが長注文を持っているかどうかを確認する data.trade ((tradeTypeB, closebuy); // 契約Bはロングポジションを閉じる { \ pos (192,220) } { \ pos (192,220) } if (accountStocks * Math.max(data.askA, data.askB) > 1) { // 口座に残高がある場合 if (data.basb < boll.down) { // If basb の価格差がダウントラックより低い場合 if (!data.mp(tradeTypeA, 0)) { // 注文をする前に,契約Aが長注文を持っているかどうかを確認します data.trade ((tradeTypeA, buy); // 契約Aはロングポジションを開く { \ pos (192,220) } if (!data.mp(tradeTypeB, 1)) { // 注文をする前に,契約Bにショートオーダーがあるかどうかを確認する data.trade ((tradeTypeB, sell); // 契約Bはショートポジションを開設する { \ pos (192,220) } } else if (data.sabb > boll.up) { // もし sabb の価格差が上位線よりも大きい場合 if (!data.mp(tradeTypeA, 1)) { // 注文をする前に,契約Aにショートオーダーがあるかどうかを確認する data.trade ((tradeTypeA, sell); // 契約Aはショートポジションを開く { \ pos (192,220) } if (!data.mp(tradeTypeB, 0)) { // 注文をする前に,契約Bが長注文を持っているかどうかを確認する data.trade ((tradeTypeB, buy); // 契約Bはロングポジションを開く { \ pos (192,220) } { \ pos (192,220) } { \ pos (192,220) } data.cancelOrders(); // 注文をキャンセルする data.drawingチャート (ボール) // 図 data.isEven(); // 個別契約の保持を処理する { \ pos (192,220) }

// 入力関数 基本関数 (main)) { // コンソールで重要でない情報をフィルター SetErrorFilter (セットエラーフィルター) 429 稼ぐ記録:稼ぐGetOrders:稼ぐGetDepth:稼ぐGetAccount: 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ 稼ぐ) exchange.IO ((currency, name + _USDT); //取引されるデジタル通貨を設定する ObjChart.reset(); // プログラムを起動する前に描いた前のチャートをクリアする LogProfitReset ((); // プログラムを起動する前に状態バー情報を削除 while (true) { // 投票モードを入力する onTick ((); // onTick関数を実行する 睡眠 (500); // 0.5秒間の睡眠 { \ pos (192,220) } { \ pos (192,220) } ` アルバイト取引は,モルガン・スタンレーの株式取引戦略から生まれた.その考えは,高度に相関する2つの品種の価格差が"ポップコーンプロセス"に準拠していること,すなわち,価格差は歴史的な平均値から逸脱した位置から平均値に戻り,その後再び平均値から逸脱するというものです.

値差で低値で購入し高値で売却して利益を得ることができます.次に,統計における標準偏差の原理に従って,ボリンガー帯は,標準偏差で計算された中間線と上下線で形成され,価格差仲介取引では非常に実用的な3メッシュ帯を形成します.

この戦略に従って動作するテスト後,総収入は比較的安定しているが,処理手数料と影響コストを考慮せずに収入は毎回あまり多くない.統計的仲裁により,価格差の逆拡大のリスクがあることに注意すべきである.設計するときにストップロスの問題を考慮する必要があります.第二に,影響コストにも注意する必要があります.取引に関与する2つの契約の流動性が縮小すると,収入に大きな影響があり,投資家は適切にそれを避けるべきです.

4. CTA 戦略 開発 の 先進 的 な 繰り返し

4.1 将来のCTA戦略の罠を避ける

過去2つのクラスでは,MyLanguageでトレンド戦略とJavaScriptでアビレージ戦略を書きました. 戦略バックテストでは問題はありませんでした. しかし,定量取引は,バックテストが問題なく直接行えるプログラムではありません.

実際,バックテストは戦略のシミュレーションに過ぎない.それは,歴史的なデータにおける戦略のパフォーマンスを評価するためにのみ使用される.それはトレーダーがいくつかの取引戦略を迅速に評価し,廃棄することを可能にする.

多くの場合,バックテストで素晴らしいように見える戦略は,さまざまな理由から現実市場でのバックテスト基準を満たすことができません.そのうちのいくつかはトレーダーの制御を超えていますが,失敗のいくつかは一般的なまたは潜在的なエラーによって引き起こされます.

静的データと動的データ

まず定量化するための静的データと動的データの概念を持つべきです.バックテストでは,静的歴史的データを使用します.各Kラインでオープン高値と閉じる低値の価格は完了し,各取引信号は100%閉じることができます.しかし,実際の市場のデータは動的です.例えば,オープンから1時間以内に最大価格が最大価格よりも大きい場合は,購入します.しかし,現在のKラインが終了していない場合は,最大価格が動的であり,取引信号が前後を点滅する可能性があります.この状況は,戦略が購入と売却取引の条件を判断する将来機能を使用することを示します.

将来の役割

未来関数は? まず,百科事典の説明を見てみましょう. 量 A と量 B のような他の量に依存します. B が変化すると,A が変化すると,A は B の関数です. B が後者の量であれば,A は以前の量で,A は B と変化し,A は B の将来の関数です.あなたは混乱するかもしれません.

一般的には,明日の価格を明日の価格で予測するなど,将来のデータを引用する機能である.技術指標が将来の関数を含んでいる場合,その信号は不確実である.それはしばしば現在の取引信号である.次のK線が表示されると,信号は消えるか位置を変更する.

閉じる価格は将来の関数である.閉じる価格は,最新のK線が終了するまで常に変化している.閉じる価格を決定するには,K線が終了するまで待つ必要があります.閉じる価格自体は将来の関数であるため,閉じる価格に基づくすべての技術指標も将来の関数です.

したがって,テクニカルインジケーターが確認済みの閉盤価格をベースデータとして使用した場合,取引信号は,どれだけの時間が経過しても変化しないので,テクニカルインジケーターは将来の関数を指していないと言える.しかし,使用する基本データは未確認済みの閉盤価格であるため,このテクニカルインジケーターは将来の関数を指し,取引信号は実用的な応用で変化する可能性があります.

過去の価格

フューチャー関数では,過去価格を逆にしても使用できる未来価格を使用します.これはまた,多くの初心者が無視する傾向のある問題です.将来この問題をよりよく説明するために,例を挙げましょう.開封後1時間以内に現在の最大価格が最大価格よりも大きい場合は,開封価格で購入します.明らかに,買取・売却信号の条件には問題はありませんが,オーダーの価格が過去価格を使用しています.

バックテストでは,ストティックデータに基づいたバックテストエンジンが100%閉鎖できるため,戦略は正常である.しかし,開封後1時間以内に最高価格が最高価格よりも大きい場合,上記の価格開封価格でオーダーを発行できないことは確実である.

価格の真空

"価格真空"とは,K線グラフに表示される価格をいうが,実際の市場で取引できない価格をいう.主に以下のケースに分けられる.

  • 1. 取引をした人は誰でも,価格が上がると買うのが難しく,価格が下がると売るのは難しいと知っています.しかし,バックテストで結論付けることができます.
  • 2. 取引のマッチングメカニズムは価格優先度と時間優先度です. いくつかの品種は,しばしば市場で多くの注文を持っています. あなたが実際の市場で注文で取引している場合,あなたは他の注文の後ろにランクする必要があります. あなたは他の注文が取引された後にのみ取引することができます. 価格が取引される前に,価格が変化しています. しかし,バックテストでは,あなたの戦略が注文に対処することであれば,あなたは時間内に取引します.これは実際の市場環境とは異なります.
  • 3. 引換戦略を使用する場合は,バックテストの利益は非常に高く,この価格差を毎回捕獲したと仮定される.実際には,多くの価格差は捉えることができない,または片足しか捉えられない.一般的に言えば,あなたの方向に有利でないのがなければならない.その後,すぐに他の片足を満たす必要があります.この時点で,スライディングポイントは1または2ポイントではなく,引換戦略自体はこれらのポイントの価格差を稼ぐことを目的としています.この状況はバックテストでシミュレートすることはできません.実際の利益はバックテストほど良くない.
  • 4.ブラック・スワン・イベントは一般的には使用されていないが,定量取引には依然として大きな影響を与える.下記の図のように,スイス・フランのブラック・スワン・イベントの場合,高値と低値の両方がチャートから見ることができる.実際,日の極端な市場では,中間価格が真空であり,多数のストップ・ロスの注文が急激なイベントを引き起こします.流動性はゼロであり,対処が非常に困難ですが,バックテストで損失を止めることができます.

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

オーバーフィッティング

オーバーフィッティングは,定量取引初心者による一般的な間違いです.オーバーフィッティングとは何か?簡単な例を挙げると,ある人は学校試験の各質問を暗記するために多くの練習を使用します.試験中に科目が少し変われば,彼はそれをできません.彼は非常に複雑な方法で各質問の練習を暗記したため,一般規則を抽象化しませんでした.

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

上記のチャートのように,モデルが十分に複雑である限り,データに完全に適応することができます.これは定量取引におけるオーバーフィッティングにも当てはまります.あなたの戦略が複雑で,多くの外部パラメータを持っている場合,限られた歴史的データバックテストで歴史的な市場に完全に適合できる1つまたは複数のパラメータが常に存在します.

しかし,将来のリアルマーケットでは,価格変動が戦略の限界を超えることがあります. 実際,定量的な取引戦略開発の本質は,多くの見かけのランダムなデータから,ローカルな非ランダムなデータをマッチするプロセスです. したがって,罠を避けるために統計知識を使用する必要があります. どのようにそれを行うか.

妥協の解決策は,サンプル内のデータとサンプル外データを使用することです. 全体のデータを2つに分け,データバックテストの責任を持つトレーニングセットとしてサンプル内を使用します. テストセットとして使用され,検証の責任があります. 歴史的なデータが少ない場合は,クロステスト方法も使用できます.

モデルを失うのは悪いことだと感じたり モデルが良くないことを認めようとせず モデルを最適化し続けると 余分なサンプルデータもうまく機能しない限り 最終的にはお金を失うことになるでしょう

生き残りの偏見

生き残りの偏見は以下の例で説明できます. 1. トゥイエレに立つと,豚は飛ぶ. 2. パラシュートをオンラインで売る人は称賛される. パラシュートに問題を抱えている人は,もはや生きていないからです. 3. 記者は乗客がバスでチケットを買ったかどうか尋ねました. 4 メディア は 宝くじ を 勝てる こと が でき ます と 宣伝 し て い ます.なぜなら,メディア は 宝くじ を 勝て ない 人々 を 積極的に 宣伝 し て い ない の で ある から です.

上記の例では,人々が通常受け取る情報が実際にフィルタリングされ,多くのデータやサンプルが選択的に無視され,結果として生存バイアスに基づく結論がリアルタイムから逸脱していることがわかります.したがって,定量取引では,バックテストの結果が運の一部であるかどうかにも焦点を当てる必要があります.多くの場合,バックテストの結果は,バックテスト全体の最高のパフォーマンスかもしれません.以下の図に注意してください:

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

  • 左図 (類似): 投資家は大きな引き上げなしに安定した投資収益を得ることができます.
  • 右図 (現実): これは 200のランダムな取引のバックテストの中で 最高の1つです

左の画像は非常に良い取引戦略です.資本曲線は良好で,有意な引き上げはありませんし,安定した利益利益が得られます.しかし右の画像を見てください.それは数百のバックテスト取引の中で最高のものです.一方,金融市場を見ると,恒星は常に多く,長寿の恒星は少なくなります.トレーダーの戦略が市場の状況と一致している場合,市場は毎年恒星のバッチを作成することができますが,連続して3年以上安定した利益を得ることができる長寿の恒星を見るのは困難です.

コストショック

注文を待機している場合を除き,取引時にスライディング価格がある可能性があります.アクティブ取引の種類では,オファー価格とオーク価格が通常,1点で異なります.アクティブでない取引の種類では,差はより大きい可能性があります.取引を終了するイニシアティブを取りたいとき,少なくとも1ポイント差,またはそれ以上が必要です.しかし,バックテストでは,取引の問題を考慮する必要はありません.信号がある限り,取引することができます.したがって,実際の取引環境をシミュレートするために,少なくとも1つのスライディング価格を追加する必要があります.

特に頻繁に取引されている戦略では,戦略をバックテストしたときにスライディング価格が追加されない場合,資本曲線は常に向上し,合理的なスライディング価格が追加されるとすぐに損失になります. さらに,この現象はポイント差によって引き起こされるだけでなく,実際の取引環境でも考慮する必要があります.ネットワーク遅延,ソフトウェアおよびハードウェアシステム,サーバーレスポンスの問題など.

戦略的能力

同じ戦略は,効率的な市場と非効率的な市場ではかなり異なるでしょう.例えば,国内株式市場,商品先物,外国デジタル通貨などの非効率な市場で,取引量の少なからず,高周波戦略そのものの容量はそれほど大きくなく,より多くの人々のために利益空間がなく,当初は収益性の高い戦略でさえ損失になり得ます.しかし,効率的な外為市場では,多くの異なる種類の高周波戦略に対応できます.

上記は,戦略の開発および使用で発生する問題や落とし穴です.経験豊富な取引システム開発者にとって,バックテストは必須です.それは,戦略的なアイデアが歴史的な取引で検証できるか教えてくれるからです.しかし,多くの場合,バックテストは,将来的に利益を得ることを意味しません.バックテストに落とし穴がたくさんあるため,いくつかのレッスンに支払わない限り理解できません.このコースは,少なくとも多くの定量的な道外や落とし穴を避けるのに役立ちます.

4.2 最良のポジション管理を確立する

株主経営者の思い出には,非常に興味深い段落があります: オールドターキー (旧称パートリッジ) は,ヒーローのリバーモアと同じ証券会社で,常に大きな取引をしています. 利益を得て売却し,株価が引き下げられた後に再び購入することを助言されたとき. オールドターキーは常に口調を入れていました:いや,あなたは知っている,これは牛市場です!

リヴァーモアでさえも,最後に叹息した.この傾向には驚くべきことなど何もない.牛市場ではいつも高落し,熊市場では熊市する人が多い.しかし,彼らは常に市場と交渉し,最低点で購入し,最高点で販売しようとするのが得意である.オールドターキーのように,本当に大きな富を手に入れるのは,市場を見てポジションを保持する人々であり,それは最も学ぶのが難しい.これはターゲットとタイミングの選択だけでなく,より重要な質問に直面しています.私たちはどれくらいのポジション (リスク) を保持すべきか (熊)?

すべての失敗したトレーダーは片方的な考えを持っている. 取引をするとき,貪欲な人はリスクではなく利益しか見ない. 臆病な人は利益ではなくリスクしか見ない. 貪欲で臆病な人は上昇するときにリスクを忘れ,低下するときに利益を忘れます. しかし,成功したトレーダーはリスクと利益の両方を考慮します. つまり,彼らは稼ぐ1ドルごとに数ドルのリスクを負います. その後,収益とリスクを測定する指標はリターンリスク比率です.

リスクは利益と同じくらい大きく,つまり利益はリスクに比例する,と多くの人が知っています.一部の人の見解では,利益とリスクの関係は次のとおりであるべきです.水平軸はリスクの割合で,垂直軸は利益の割合です.

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

しかし,実際の取引では,リターンとリスクは2つの点のように単純なものとは程遠い.少なくともそれは常に線形に動かない.実際のリスクは,期待されるリターン,または私たちが最大不安定性と呼ぶものと取ることができる最大損失量です.時には最大浮動損失は,取引の結果の観点から常に閉じる損失に等しくありませんが,最大浮動損失は現実です.

上記の図のリターン対リスク比は,実際のパフォーマンスではないことがわかります.実際の取引環境では,リターン対リスク比は,以下のグラフと同じでなければなりません.

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

上記のグラフを見てみましょう. 黄色い曲線は,さまざまなリスクで純資産の変動を示しています. 期待されるリターンが拡大するにつれて,リスクも徐々に拡大しています. 破産を0.5で設定した場合,つまり最大損失が50%に達すると,これは失敗した取引戦略です. 戦略の最終的なリターンは結果から正であるものの,それはすでに真ん中に破産しました.

ポジションの管理は,ポジティブな戦略であっても,間違ったポジションの管理による清算になります.この観点から,どれだけの購入と販売が,いつ購入と販売するよりも重要になります.ポジションを科学的に管理する方法が,金融取引における基本的な問題になりました.この問題を解決しようとする前に,賭博で科学的に賭ける方法を見てみましょう.

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

コインの両面が等しく重量化されていると仮定します. 2元頭利益と 1元尾損失がある場合,これは肯定的な期待ゲームであることが明らかです. 勝率は50%と損失は2. ここで質問があります. 100元を持っている今,どうやって100元が最速で100万元に達できるように賭けを繰り返すのですか.

慎重に考えなければ,賭け物のリターンは 50% * 2-50% * 1 ですので,つまり,50% ですので,最大リターンを迅速に達成するためには,できるだけ多くの資本を賭け物に投資する必要があります.この賭けは100%でなければなりません.

しかし,賭博のどのゲームにも 100% の本金 を投資するのは不合理だ.なぜなら,あなたが1回本金を失う限り,それは失うだろう.それは非常に不可能性だとしても.あなたが十分に何度も賭博する限り,お金を失うことは必ず起こるからです.

100%の賭けは不合理であるため,90%またはより低い賭けはどうでしょう? 実際,この問題を解決するために,賭けのゲームをシミュレートして,各賭けの結果を見ることができる実験を行います. 次の図のように:

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

グラフから,同じ賭けで,ポジションを90%,80%,70%,60%および50%から徐々に減らすと,結果はまったく異なります.注意深い友人は,ポジションの徐々に減少とともに,最終資本が徐々に拡大していることを気づいているかもしれません.

賭けの割合は,毎回賭けが小さいほど良いか,例えば10%など,疑問に思う人もいるかもしれません.すべての賭け比率を計算することは不可能です.これは有名なケリー基準によって解決される問題です.統計学では,ケリー基準は,繰り返し賭けをポジティブに期待して戦略の長期成長率を最大化することができ,各賭けで最高の賭け比率を計算することができます.

ケリー基準は,賭け金と賭け金を無限に分割できるという前提で,ケリー基準を使用することで賭け金に破産することは不可能である.特に金融取引の実践的な応用では,攻撃と防衛の両方を含むポジション管理戦略である.ケリー基準の計算方法を見て,次の図を見てみましょう:

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

  • fは,利用可能な資本に対する最適な賭け比です.
  • bは,取引における利益/損失比とも呼ばれる確率比です.
  • p は成功率です
  • qは失敗率です

このレッスンの賭博例をケリー基準に従って計算できます. 100元の初期資本は,賭け比率が50%で,確率が2である場合,賭け比率を使用して,最速で100万元に達することができます. ケリー基準に設定すると,計算プロセスは以下のとおりです.

(0.5*(2+1) -1)/2=0.25

50%の勝率は0.5です. 確率を2+1で掛け,それから1を引いて2で割ります. 計算結果は0.25です. つまり,本金の25%を使用した各賭けでは,最速で100万元に達できます. 計算結果に従って手動でシミュレーションして,それが正しいかどうかを確認できます.

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

上記の図は手動シミュレーションの結果です.最後の行を参照してください.同じ賭けでは,100回以上経った後,ポジションの25%が最初に100万元に達しました. 90%,80%,70%および60%のポジションの結果は負です.これは,ポジティブな期待取引戦略でさえ,間違ったポジション管理で破産することを示しています.

また,50%のポジションが最終的に負けたり勝ち取ったりしないことも見られます.これは大数の法則の結果にも一致します.問題をさらに説明するために,手動シミュレーションに10%のポジションも追加されました.最終結果はポジティブなリターンでしたが,効果は25%のポジションよりも数階位悪いものでした.

ケリー基準の力を見ることができます. 実際のアプリケーションでは,本位ポジションの10%を選択すると,本位は100以上の賭けで3万以上になります. 収益は大きいが,本位ポジションの25%と比較すると,利益はありません. これが知識の力です.

ケリー基準から人生で利益を得たいなら,ケリー基準の適用条件を満たす必要があります.この賭けは金融市場から来る必要があることは間違いありません.特に定量取引では,歴史的なデータバックテストを通じて,対応する勝利比率と確率を粗略に計算することができます.

もちろん,金融取引におけるケリー基準の実用的な適用は,それほど単純ではありません.そして,レバレッジ取引における資本コスト,実際の取引における資本とポジションがワイヤレスに分割できないこと,取引における勝利比と損失比が動的に変化していることなど,多くの細部が取り扱わなければなりません.とにかく,ケリー基準は,最良のポジション管理方法を確立する方法を示しています.


関連コンテンツ

もっと見る