রিসোর্স লোড হচ্ছে... লোডিং...

পরিমাণগত ট্রেডিং থেকে সম্পদ ব্যবস্থাপনা - পরম রিটার্নের জন্য সিটিএ কৌশল বিকাশ

লেখক:এফএমজেড-লিডিয়া, তৈরিঃ 2023-02-07 09:58:41, আপডেটঃ 2023-09-18 20:25:11

, [nowTime, this.basb]]); ObjChart.add (([4, [nowTime, this.sabb]]); ObjChart.update ((চার্ট); }

### 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 GetRecords: GetOrders: GetDepth: GetAccount: Buy Selltimeout Futures_OP);exchange.IO("মুদ্রা", নাম + _USDT); // ট্রেড করা ডিজিটাল মুদ্রা সেট করুন ObjChart.reset(); // প্রোগ্রাম শুরু করার আগে আঁকা পূর্ববর্তী চার্ট সাফ করুন LogProfitReset(); // প্রোগ্রাম শুরু করার আগে অবস্থা বার তথ্য মুছে দিন while (true) { // পোলিং মোডে প্রবেশ করুন onTick(); // onTick ফাংশন চালান Sleep ((500); // 0.5 সেকেন্ডের জন্য ঘুম } }

## 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; // অ্যাকাউন্ট ব্যালেন্স var boll = data.boll ((dataLength, timeCycle); // boll সূচক তথ্য পান if (!boll) return; // boll ডেটা না থাকলে রিটার্ন }

## 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 এর একটি মূল্য বিক্রি করুন - কন্ট্রাক্ট B এর একটি মূল্য কিনুন) // sabb = (কন্ট্রাক্ট A এর একটি মূল্য কিনুন - কন্ট্রাক্ট B এর একটি মূল্য বিক্রি করুন) যদি (data.sabb > boll.middle && data.sabb < boll.up) { // যদি sabb মধ্য ট্র্যাকের চেয়ে বেশি হয় যদি (data.mp(tradeTypeA, 0)) { // অর্ডার দেওয়ার আগে A চুক্তিতে দীর্ঘ অর্ডার আছে কিনা তা পরীক্ষা করুনdata.trade(tradeTypeA, closebuy); // কন্ট্রাক্ট এ লং পজিশন বন্ধ করে } যদি (data.mp(tradeTypeB, 1)) { // অর্ডার দেওয়ার আগে বি চুক্তিতে শর্ট অর্ডার আছে কিনা তা পরীক্ষা করুনdata.trade(tradeTypeB, closesell); // চুক্তি বি শর্ট পজিশন বন্ধ করে } } else if (data.basb < boll.middle && data.basb > boll.down) { // যদি basb মধ্য ট্র্যাকের চেয়ে কম হয় যদি (data.mp(tradeTypeA, 1)) { // অর্ডার দেওয়ার আগে A চুক্তিতে শর্ট অর্ডার আছে কিনা তা পরীক্ষা করুনdata.trade(tradeTypeA, closesell); // চুক্তি A শর্ট পজিশন বন্ধ করে } যদি (data.mp(tradeTypeB, 0)) { // অর্ডার দেওয়ার আগে B চুক্তিতে দীর্ঘ অর্ডার আছে কিনা তা পরীক্ষা করুনdata.trade(tradeTypeB, closebuy); // বি চুক্তি দীর্ঘ অবস্থান বন্ধ করে } } if (accountStocks * Math.max(data.askA, data.askB) > 1) { // যদি একাউন্টে ব্যালেন্স থাকে if (data.basb < boll.down) { // If basb price difference is lower than the down track যদি বাসবের দামের পার্থক্য ডাউন ট্র্যাকের চেয়ে কম হয় যদি (!data.mp(tradeTypeA, 0)) { // অর্ডার দেওয়ার আগে A চুক্তিতে দীর্ঘ অর্ডার আছে কিনা তা পরীক্ষা করুনdata.trade(tradeTypeA, buy); // কন্ট্রাক্ট এ লং পজিশন খোলে } যদি (!data.mp(tradeTypeB, 1)) { // অর্ডার দেওয়ার আগে বি চুক্তিতে শর্ট অর্ডার আছে কিনা তা পরীক্ষা করুনdata.trade(tradeTypeB, sell); // চুক্তি বি শর্ট পজিশন খোলে } } else if (data.sabb > boll.up) { // যদি sabb দামের পার্থক্য উপরের ট্র্যাকের চেয়ে বেশি হয় যদি (!data.mp(tradeTypeA, 1)) { // অর্ডার দেওয়ার আগে A চুক্তিতে শর্ট অর্ডার আছে কিনা তা পরীক্ষা করুনdata.trade(tradeTypeA, sell); // চুক্তি A শর্ট পজিশন খোলে } যদি (!data.mp(tradeTypeB, 0)) { // অর্ডার দেওয়ার আগে B চুক্তিতে দীর্ঘ অর্ডার আছে কিনা তা পরীক্ষা করুনdata.trade(tradeTypeB, buy); // বি চুক্তি দীর্ঘ পজিশন খোলে } } }

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

// গ্লোবাল ভেরিয়েবল // কনফিগারেশন চার্টের জন্য একটি চার্ট বস্তু ঘোষণা করুন var চার্ট = { __isStock: সত্য, টুল টিপ: { xDateFormat: %Y-%m-%d %H:%M:%S, %A }, শিরোনাম: { টেক্সটঃ ট্রানজেকশন লাভ ও ক্ষতি কার্ভ (বিস্তারিত) }, rangeSelector: { বোতামঃ [{ টাইপঃ ঘন্টা, গণনাঃ ১ পাঠ্যঃ 1h }, { টাইপঃ ঘন্টা, সংখ্যাঃ ২, পাঠ্যঃ 3h }, { টাইপঃ ঘন্টা, গণনাঃ ৮ পাঠ্যঃ 8h }, { প্রকারঃ সমস্ত, পাঠ্যঃ সব }], নির্বাচিতঃ 0, ইনপুট সক্রিয়ঃ মিথ্যা }, xAxis: { টাইপঃ date-time }, yAxis: { শিরোনাম: { পাঠ্যঃ মূল্যের পার্থক্য }, বিপরীতঃ মিথ্যা, }, সিরিজঃ [{ নামঃ উপরের ট্র্যাক, id: line1,up, তথ্যঃ [] }, { নামঃ মিডল ট্র্যাক id: line2,middle, তথ্যঃ [] }, { নামঃ ডাউন ট্র্যাক, id: line3,down, তথ্যঃ [] }, { নামঃ বাসব, id: line4,basb, তথ্যঃ [] }, { নামঃ সাব, id: line5,sabb, তথ্যঃ [] }] }; var ObjChart = Chart(chart); // অঙ্কন বস্তু var bars = []; // স্টোরেজ মূল্য পার্থক্য সিরিজ var oldTime = 0; // ইতিহাসের ডেটা টাইমস্ট্যাম্প রেকর্ড করুন

// পরামিতি var tradeTypeA = this_week; // Arbitrage একটি চুক্তি var tradeTypeB = quarter; // Arbitrage B চুক্তি var dataLength = 10; // সূচক সময়ের দৈর্ঘ্য var timeCycle = 1; // কে-লাইন সময়কাল var নাম = ETC; // মুদ্রা var ইউনিট = 1; // অর্ডার পরিমাণ

// বেসিক ডেটা ফাংশন ডেটা ((tradeTypeA, tradeTypeB) { // মধ্যস্থতা A চুক্তি এবং মধ্যস্থতা বি চুক্তিতে পাস 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; // Arbitrage এর একটি মূল্য বিক্রি করুন একটি চুক্তি this.bidA = depthDataA.Bids[0].Price; // Arbitrage এর একটি মূল্য কিনুন একটি চুক্তি this.askB = depthDataB.Aks[0].Price; // Arbitrage B চুক্তির একটি মূল্য বিক্রি করুন this.bidB = depthDataB.Bids[0].Price; // Arbitrage B চুক্তির একটি মূল্য কিনুন // পজিটিভ আর্বিট্রেজ মূল্য পার্থক্য (একটি চুক্তি A মূল্য বিক্রি - চুক্তি B এক মূল্য কিনতে) this.basb = depthDataA.Aks[0].Price - depthDataB.Bids[0].Price; // নেতিবাচক সালিশ মূল্য পার্থক্য (কন্ট্রাক্ট A এর একটি মূল্য কিনুন - কন্ট্রাক্ট B এর একটি মূল্য বিক্রি) this.sabb = depthDataA.Bids[0].Price - depthDataB.Aks[0].Price; }

// অবস্থান পানData.prototype.mp= ফাংশন (ট্রেডটাইপ, টাইপ) { var positionData = this.positionData; // অবস্থান তথ্য পান for (var i = 0; i < positionData.length; i++) { যদি (positionData[i].ContractType == tradeType) { if (positionData[i].Type == type) { if (positionData[i].Amount > 0) { রিটার্ন পজিশনData[i].amount; } } } } false রিটার্ন করুন; }

// নতুন কে-লাইন ডেটা এবং বোল সূচক ডেটা সংমিশ্রণ ডেটা.প্রোটোটাইপ.বোল = ফাংশন (সংখ্যা, সময়চক্র) { var self = {}; // অস্থায়ী বস্তু // ইতিবাচক আরবিট্রেজ মূল্য পার্থক্য এবং নেতিবাচক আরবিট্রেজ মূল্য পার্থক্যের মধ্যম মান self.Close = (this.basb + this.sabb) / 2; যদি (this.timeA == this.timeB) { self.time = this.time; } // দুই গভীরতা তথ্য সময় স্ট্যাম্প তুলনা if (this.time - oldTime > timeCycle * 60000) { বার.পশ ((স্ব); oldTime = this.time; } // নির্দিষ্ট সময়কাল অনুযায়ী কে-লাইন অ্যারেতে মূল্য পার্থক্য ডেটা বস্তু পাস করুন if (bars.length > num * 2) { bars.shift(); // কে-লাইন অ্যারের দৈর্ঘ্য নিয়ন্ত্রণ করুন { অন্য { ফেরত; } var boll = TA.BOLL(বার, নং, 2); // তালিব লাইব্রেরিতে বোল সূচক কল করুন রিটার্ন { উপরেঃ বোল[0][বোল[0].দৈর্ঘ্য - 1], // বোল সূচক উপরের ট্র্যাক মাঝখানেঃ বোল [1][বোল [1]]দৈর্ঘ্য - 1], // বোল সূচক মধ্য ট্র্যাক নিচেঃ বোল[2][বোল[2].দৈর্ঘ্য - 1] // বোল সূচক নিচে ট্র্যাক } // একটি প্রক্রিয়াকৃত বোল সূচক তথ্য ফেরত }

// অর্ডার দিনData.prototype.trade= ফাংশন (ট্রেডটাইপ, টাইপ) { exchange.SetContractType(tradeType); // অর্ডার দেওয়ার আগে একটি চুক্তিতে পুনরায় সাবস্ক্রাইব করুন var askPrice, bidPrice; if (tradeType == tradeTypeA) { // যদি অর্ডারটি চুক্তি A তে স্থাপন করা হয় askPrice = this.askA; // askPrice সেট করুন bidPrice = this.bidA; // bidPrice সেট করুন } অন্যথায় যদি (tradeType == tradeTypeB) { // যদি অর্ডারটি চুক্তি B তে স্থাপন করা হয় askPrice = this.askB; // askPrice সেট করুন bidPrice = this.bidB; // bidPrice সেট করুন } স্যুইচ (টাইপ) { // ম্যাচ অর্ডার প্লেসমেন্ট মোড কেস buy: exchange.SetDirection(type); // অর্ডার স্থাপন মোড সেট করুন রিটার্ন এক্সচেঞ্জ.কুপন ((অ্যাপস প্রাইস, ইউনিট); কেস বিক্রয় : exchange.SetDirection(type); // অর্ডার স্থাপন মোড সেট করুন রিটার্ন এক্সচেঞ্জ।বিক্রয় ((বিক্রয় মূল্য, ইউনিট); কেস closebuy: exchange.SetDirection(type); // অর্ডার স্থাপন মোড সেট করুন রিটার্ন এক্সচেঞ্জ।বিক্রয় ((বিক্রয় মূল্য, ইউনিট); কেস ক্লোজসেল: exchange.SetDirection(type); // অর্ডার স্থাপন মোড সেট করুন রিটার্ন এক্সচেঞ্জ.কুপন ((অ্যাপস প্রাইস, ইউনিট); ডিফল্টঃ false রিটার্ন করুন; } }

// অর্ডার বাতিল করুন ডেটা.প্রোটোটাইপ.বাতিল করুনOrders = ফাংশন () { ঘুম ((500); // বিলম্ব আগে বাতিল, কারণ কিছু বিনিময়, আপনি কি বোঝাতে চাইছেন var অর্ডার = _C(exchange.GetOrders); // অপরিপূর্ণ অর্ডার একটি অ্যারে পান if (orders.length > 0) { // যদি অপ্রাপ্ত অর্ডার থাকে for (var i = 0; i < orders.length; i++) { // unfilled orders এর অ্যারে জুড়ে পুনরাবৃত্তি করুন exchange.CancelOrder ((অর্ডার[i].Id); // একের পর এক অর্ডার বাতিল করুন Sleep ((500); // 0.5 সেকেন্ডের জন্য ঘুম } return false; // যদি একটি পূরণ না করা অর্ডার বাতিল করা হয় তাহলে false ফেরত দিন } return true; // যদি কোন অর্ডার পূরণ না হয় তাহলে true ফেরত দিন }

// পৃথক চুক্তি রাখা পরিচালনা ডেটা.প্রোটোটাইপ.আইস ইভেন = ফাংশন () { var positionData = this.positionData; // অবস্থান তথ্য পান var type = null; // অবস্থান দিক পরিবর্তন করুন // যদি অবস্থান অ্যারে দৈর্ঘ্য অবশিষ্ট 2 0 সমান নয় বা অবস্থান অ্যারে দৈর্ঘ্য 2 সমান নয় যদি (positionData.length % 2!= 0 তাহলে positionData.length!= 2) { for (var i = 0; i < positionData.length; i++) { // অবস্থান অ্যারে মাধ্যমে পুনরাবৃত্তি if (positionData[i].Type == 0) { // যদি এটি একটি দীর্ঘ অর্ডার হয় type = 10; // অর্ডার প্যারামিটার সেট করুন } else if (positionData[i].Type == 1) { // যদি এটি একটি সংক্ষিপ্ত অর্ডার হয় type = -10; // অর্ডার প্যারামিটার সেট করুন } // সব অবস্থান বন্ধ করুনthis.trade(positionData[i].ContractType, type, positionData[i].amount) (পজিশন ডেটা[i].কন্ট্রাক্ট টাইপ, টাইপ, পজিশন ডেটা[i].আয়) } } }

// অঙ্কন ডেটা.প্রোটোটাইপ.অঙ্কনগ্রাফ = ফাংশন (বোল) { 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 ((চার্ট); }

// ট্রেডিং শর্তাবলী ফাংশন চালু চিহ্নিত করুন (() { var data = new Data ((tradeTypeA, tradeTypeB); // একটি মৌলিক তথ্য বস্তু তৈরি করুন var accountStocks = data.accountData.Stocks; // অ্যাকাউন্ট ব্যালেন্স var boll = data.boll ((dataLength, timeCycle); // boll সূচক তথ্য পান if (!boll) return; // boll ডেটা না থাকলে রিটার্ন // দামের পার্থক্যের ব্যাখ্যা // basb = (কন্ট্রাক্ট A এর একটি মূল্য বিক্রি করুন - কন্ট্রাক্ট B এর একটি মূল্য কিনুন) // sabb = (কন্ট্রাক্ট A এর একটি মূল্য কিনুন - কন্ট্রাক্ট B এর একটি মূল্য বিক্রি করুন) যদি (data.sabb > boll.middle && data.sabb < boll.up) { // যদি sabb মধ্য ট্র্যাকের চেয়ে বেশি হয় যদি (data.mp(tradeTypeA, 0)) { // অর্ডার দেওয়ার আগে A চুক্তিতে দীর্ঘ অর্ডার আছে কিনা তা পরীক্ষা করুনdata.trade(tradeTypeA, closebuy); // কন্ট্রাক্ট এ লং পজিশন বন্ধ করে } যদি (data.mp(tradeTypeB, 1)) { // অর্ডার দেওয়ার আগে বি চুক্তিতে শর্ট অর্ডার আছে কিনা তা পরীক্ষা করুনdata.trade(tradeTypeB, closesell); // চুক্তি বি শর্ট পজিশন বন্ধ করে } } else if (data.basb < boll.middle && data.basb > boll.down) { // যদি basb মধ্য ট্র্যাকের চেয়ে কম হয় যদি (data.mp(tradeTypeA, 1)) { // অর্ডার দেওয়ার আগে A চুক্তিতে শর্ট অর্ডার আছে কিনা তা পরীক্ষা করুনdata.trade(tradeTypeA, closesell); // চুক্তি A শর্ট পজিশন বন্ধ করে } যদি (data.mp(tradeTypeB, 0)) { // অর্ডার দেওয়ার আগে B চুক্তিতে দীর্ঘ অর্ডার আছে কিনা তা পরীক্ষা করুনdata.trade(tradeTypeB, closebuy); // বি চুক্তি দীর্ঘ অবস্থান বন্ধ করে } } if (accountStocks * Math.max(data.askA, data.askB) > 1) { // যদি একাউন্টে ব্যালেন্স থাকে if (data.basb < boll.down) { // If basb price difference is lower than the down track যদি বাসবের দামের পার্থক্য ডাউন ট্র্যাকের চেয়ে কম হয় যদি (!data.mp(tradeTypeA, 0)) { // অর্ডার দেওয়ার আগে A চুক্তিতে দীর্ঘ অর্ডার আছে কিনা তা পরীক্ষা করুনdata.trade(tradeTypeA, buy); // কন্ট্রাক্ট এ লং পজিশন খোলে } যদি (!data.mp(tradeTypeB, 1)) { // অর্ডার দেওয়ার আগে বি চুক্তিতে শর্ট অর্ডার আছে কিনা তা পরীক্ষা করুনdata.trade(tradeTypeB, sell); // চুক্তি বি শর্ট পজিশন খোলে } } else if (data.sabb > boll.up) { // যদি sabb দামের পার্থক্য উপরের ট্র্যাকের চেয়ে বেশি হয় যদি (!data.mp(tradeTypeA, 1)) { // অর্ডার দেওয়ার আগে A চুক্তিতে শর্ট অর্ডার আছে কিনা তা পরীক্ষা করুনdata.trade(tradeTypeA, sell); // চুক্তি A শর্ট পজিশন খোলে } যদি (!data.mp(tradeTypeB, 0)) { // অর্ডার দেওয়ার আগে B চুক্তিতে দীর্ঘ অর্ডার আছে কিনা তা পরীক্ষা করুনdata.trade(tradeTypeB, buy); // বি চুক্তি দীর্ঘ পজিশন খোলে } } } data.cancelOrders(); // অর্ডার বাতিল করুন তথ্য.অঙ্কনচার্ট ((বোল); // অঙ্কন data.isEven(); // পৃথক চুক্তির হোল্ডিং হ্যান্ডেল }

// এন্ট্রি ফাংশন ফাংশন main() { // কনসোলে অপ্রয়োজনীয় তথ্য ফিল্টার করুন SetErrorFilter ((429 GetRecords: GetOrders: GetDepth: GetAccount: Buy Selltimeout Futures_OP);exchange.IO("মুদ্রা", নাম + _USDT); //ব্যবহারযোগ্য ডিজিটাল মুদ্রা সেট করুন ObjChart.reset(); // প্রোগ্রাম শুরু করার আগে আঁকা পূর্ববর্তী চার্ট সাফ করুন LogProfitReset(); // প্রোগ্রাম শুরু করার আগে অবস্থা বার তথ্য মুছে দিন while (true) { // পোলিং মোড প্রবেশ করান onTick(); // onTick ফাংশনটি চালান Sleep ((500); // 0.5 সেকেন্ডের জন্য ঘুম } }

Arbitrage trading originated from the stock trading strategy of Morgan Stanley. Its idea is that the price difference of two highly correlated varieties conforms to the "popcorn process", that is, the price difference keeps returning to the mean from a position that deviates from the historical mean, and then deviates again from the mean.

Therefore, we can buy low and sell high on the price difference to gain profits. Then, according to the principle of standard deviation in statistics, the Bollinger band is formed by a middle track and the upper and lower tracks calculated by the standard deviation, the formation of three mesh band, which are very practical in the price difference arbitrage transaction.

After testing, operating according to this strategy, the overall income is relatively stable, although the income is not very much each time without considering the handling fee and impact cost. It should be noted that due to the statistical arbitrage, there is a risk of reverse expansion of the price difference. We must consider the stop-loss problem when designing. Secondly, we also need to pay attention to the impact cost. When the liquidity of the two contracts involved in the transaction shrinks, it will have a great impact on the income, and investors should avoid it as appropriate.

## 4. Advanced iteration of CTA strategy development
### 4.1 Avoid the pitfalls of futures CTA strategy

In the last two classes, we wrote a trend strategy in MyLanguage and an arbitrage strategy in JavaScript. We didn't see any problems in the strategy backtest. However, quantitative trading is not a program, whose backtest can be done directly without any problems.

In fact, the backtest is only a simulation of the strategy. It is only used to evaluate the performance of the strategy in the historical data. It allows traders to evaluate and discard some trading strategies quickly.

In many cases, strategies that look great in the backtest often fail to meet the backtest standard in the real market for a variety of reasons. Some of them are beyond the control of traders, but some of the failures are caused by common or potential errors.

### Static data and dynamic data
We should have a concept of static data and dynamic data to quantify first. In the backtest, we use static historical data. The price of opening high and closing low with each K-line is complete, and each transaction signal can be closed 100%. But the data in the real market is dynamic. For example, if the maximum price is greater than the maximum price within 1 hour of opening, buy. But if the current K-line has not finished, the maximum price is dynamic, and the trading signal may flicker back and forth. This situation indicates that the strategy uses the future function in judging the conditions of the buy and sell trading.

### Future function
What is the future function? Let's take a look at Baidu Encyclopedia's explanation first: A quantity depends on another quantity, such as quantity A and quantity B. If B changes, A changes, then A is a function of B. If B is a later quantity, A is an earlier quantity, A changes with B, and A is a future function of B. You may be confused.

Generally speaking, it is a function of quoting future data, such as forecasting tomorrow's price with tomorrow's price. If a technical indicator contains a future function, its signal is uncertain. It is often the current transaction signal. When the next K-line appears, the signal disappears or changes position.

The closing price is a future function. The closing price is always changing until the latest K-line runs out. You must wait until the K-line runs out to determine the closing price. Since the closing price itself is a future function, all technical indicators based on the closing price are also future functions.

Therefore, if a technical indicator uses the confirmed closing price as the basic data, the trading signal will not change no matter how long it has passed, it can be said that the technical indicator does not refer to the future function. But the basic data it uses is the unconfirmed closing price, so this technical indicator refers to the future function, and the trading signal may change in practical application.

### Past prices
The future function uses the future price, which may also use the past price on the contrary. This is also a problem that many novices tend to ignore. To better illustrate this problem in the future, let's take an example: if the current maximum price is greater than the maximum price within 1 hour after the opening, buy at the opening price. Obviously, there is no problem with the conditions of the buying and selling signal, but the price of the order has used the past price.

In the backtest, the strategy is normal, because the backtest engine based on static data can be closed 100% only if there is a buy signal. However, when the highest price is greater than the highest price within 1 hour after the opening, it is certain that the order cannot be issued at the previous price opening price.

### Price vacuum
The so-called price vacuum refers to the prices displayed on the K-line chart, but the prices that cannot be traded in the real market, mainly divided into the following cases:

- 1. Anyone who has done trading knows that it is difficult to buy when the price is up and difficult to sell when the price is down. But it can be concluded in the backtest.
- 2. The matching mechanism of the exchange is price priority and time priority. Some varieties will often have a large number of orders in the market. If you are trading with orders in the real market, you must rank behind others' orders. You can only trade after others' orders are traded. Even before the price can be traded, the price has changed. However, in the backtest, if your strategy is to deal with the order, you will deal in time, which is different from the real market environment.
- 3. If you use an arbitrage strategy, the profit of the backtest is very high, because it is assumed that you have captured these price differences every time. In reality, many price differentials can't be grabbed, or only one leg can be grabbed. Generally speaking, it must be the one that is not conducive to your direction. Then you need to fill the other leg immediately. At this time, the sliding point is no longer 1 or 2 points, and the arbitrage strategy itself aims to earn the price difference of these points. This situation cannot be simulated in the backtest. The real profit is not as good as the backtest.
- 4. Although the black swan event is not used commonly, it still has a great impact on quantitative trading. As shown in the chart below, in the case of the black swan event of the foreign exchange Swiss franc, both high and low prices can be seen from the chart. In fact, in the extreme market of the day, the middle price is vacuum, and a large number of stop loss orders cause stampede events. The liquidity is zero, and it is very difficult to deal with, but it can stop loss in the backtest.

![img](/upload/asset/28de88399afe0539cb091.png)

### Overfitting
Overfitting is a common mistake made by quantitative trading beginners. What is overfitting? To take a simple example, some people use a great deal of exercises to memorize each question in the school exam. He can't do it if the subject changes a little during the exam. Because he memorized the practice of each question in a very complex way, he did not abstract the general rules.

![img](/upload/asset/28e1c4e1c23cf932a44fa.png)

Like the chart above, a model can adapt to data perfectly as long as it is complex enough. This is also true of overfitting in quantitative trading. If your strategy is complex and it has many external parameters, there will always be one or several parameters that can perfectly fit the historical market in the limited historical data backtest.

However, in the future real market, the price change may exceed your strategy limit. In fact, the essence of quantitative trading strategy development is the process of matching local non-random data from a large number of seemingly random data. Therefore, we need to use statistical knowledge to avoid the trap. How do we do it?

The compromise solution is to use intra-sample and extra-sample data. Divide the whole data into two parts, and use the intra-sample as the training set, which is responsible for the data backtest. The extra-sample is used as the test set and is responsible for verification. If there is little historical data, you can also use the cross-test method.

If you find that the data out of the sample performs not well, and you feel that it is too bad to lose the model or you are unwilling to admit that your model is not good, and you continue to optimize the model for the extra-sample data until the extra-sample data also perform well, then you must lose your money in the end.

### Survivorship bias
The survivorship bias can be explained by the following examples:
1. When standing at the tuyere, pigs will fly.
2. People who sell parachutes online are praised, because people with problems with parachutes don't live anymore.
3. The reporter interviewed whether passengers have bought tickets on the bus, because people without tickets can't get on the bus at all.
4. The media advertises that the lottery can be won, because the media will not actively promote people who do not win the lottery.

In the above example, we can find that the information that people usually receive is actually filtered, which makes a large number of data or samples ignored selectively, and the result is that the conclusions based on survivorship bias have deviated from real-time. So in quantitative trading, we also need to focus on whether the results of the backtest are part of luck. In many cases, the results of the backtest may be the best performance in the whole backtest. Pay attention to the following figure:

![img](/upload/asset/28d7909c7b391bf77c59c.png)

- Left chart (semblance): A very good trading strategy. Without major withdrawal, investors can obtain stable investment returns.
- Right chart (the reality): This is only the best one in 200 random trading backtests.

The picture on the left is a very good trading strategy. The capital curve is good, and there is no significant withdrawal, and stable profit returns can be obtained. But look at the picture on the right. It is only the best one in the hundreds of backtest transactions. On the other hand, when we look at the financial market, there are always more stars and less longevity stars. If the strategy of the traders is consistent with the market situation, then the market every year can create a batch of stars, but it is difficult to see longevity stars who can make steady profits for more than three years in a row.

### Cost shock
Unless you are pending an order, you may have a sliding price when trading. On the varieties with active trading, the bid-price and ask-price are usually different in one point. On the varieties with inactive trading, the difference may be greater. Every time you want to take the initiative to close a deal, you need one point difference at least, or even more. However, in the backtest, we do not need to consider the issue of transaction, as long as there is a signal, we can trade, so in order to simulate the real trading environment, we must add one sliding price at least.

Especially for the strategy that is traded more frequently, if the sliding price is not added when the strategy is backtested, the capital curve will always tilt upward, and once the reasonable sliding price is added, it will turn to a loss immediately. In addition, this phenomenon is not only caused by point difference, but also needs to be considered in the real trading environment: network delay, software and hardware systems, server response and other issues.

### Strategy capacity
The same strategy will be quite different in efficient and inefficient markets, even the opposite. For example, in inefficient markets such as domestic stock markets, commodity futures, and foreign digital currencies, due to the small base of trading volume, the capacity of high-frequency strategy itself is not very large, and there is no profit space for more people, and even the strategy that was originally profitable has become a loss. But in an efficient foreign exchange market, it can accommodate many different types of high-frequency strategies.

The above are the problems and pitfalls that may occur in the development and use of strategies. For an experienced trading system developer, backtesting is a must. Because it can tell you whether a strategic idea can be verified in historical transactions. But many times, backtesting does not mean that it will be profitable in the future. Because there are too many pitfalls in the backtest, you won't understand without paying for some lessons. This course can help you avoid many quantitative detours and pitfalls at least.

### 4.2 Establish the best position management
In "Reminiscences of a stock operator", there is a very interesting paragraph: the Old Turkey (formerly known as Partridge) who is in the same securities company as the hero Livermore, always makes a big deal. When he was advised to sell after taking profits and buy again after the stock price had retraced. The Old Turkey always intoned: No, you know, this is a bull market!

Even Livermore sighed finally: There is nothing remarkable about the trend. There are always many people who are bullish in the bull market and bearish in the bear market. But they are always good at bargaining with the market, trying to buy at the lowest point and sell at the highest point. Like the Old Turkey, it is those who see the market and hold their positions that really make a great fortune, which is also the most difficult to learn. This not only faces the choice of target and timing, but also faces a more important question: how much position (risk) should we hold (bear)?

All failed traders have one-sided thinking. When trading, greedy people only see profits rather than risks, while timid people only see risks rather than profits. Greedy and timid people forget risks when rising, and forget profits when falling. However, successful traders will consider both risks and returns, that is to say, they will bear several dollars of risk for every dollar they earn. Then the index to measure return and risk is the return risk ratio.

Many people know that the risk is as big as the profit, that is, the return is proportional to the risk. In the view of some people, the relationship between return and risk should be as follows: the horizontal axis is the percentage of risk, and the vertical axis is the percentage of return:

![img](/upload/asset/28e2bd10e85a67631c986.png)

But in the actual transaction, the return and risk are far from being as simple as two points of a line, at least it doesn't always move linearly. The real risk is the maximum amount of loss that can be taken with the expected return, or what we call the maximum volatility. Although sometimes the maximum floating loss does not always equal the closing loss in terms of the outcome of the trade, the maximum floating loss is real.

From this, we can know that the ratio of return to risk in the figure above is not the real performance. In a real trading environment, the ratio of return to risk should be the same as in the chart below:

![img](/upload/asset/28ea0e5e31b465376c0e7.png)

Let's look at the chart above. The yellow curve shows the fluctuation of net worth at different risks. With the expected returns expanding, the risks are also expanding gradually. If we set bankruptcy at 0.5, that is, the maximum loss reaches 50%, then this is a failed trading strategy. Although the final return of the strategy is positive from the result, it has already gone bankrupt in the middle.

Even if your strategy is a positive one, it will be liquidations under the wrong position management. So from this point of view, how much to buy and sell is more important than when to buy and sell. How to manage the position scientifically has become a fundamental issue in financial transactions. So before trying to solve this problem, let's see how to bet scientifically in gambling.

![img](/upload/asset/28de97e2d00f74ce18197.png)

Let's take the coin toss as an example. Suppose that both sides of a coin are equally weighted. If there is a head profit of 2 yuan and a tail loss of 1 yuan, it is obvious that this is a positive expectation game. The winning rate is 50% and a loss of 2. Here comes the question: Now that you have 100 yuan, how can you repeat the bet so that 100 yuan can reach 1 million yuan at the fastest speed.

If we don't think carefully, we will think that since the return of each bet is 50% * 2-50% * 1, that is, 50%, then in order to achieve the maximum return quickly, we should invest as much capital as possible in each bet. This bet must be 100%.

However, it is obvious that it is unreasonable to invest 100% of the principal in every game of gambling, because as long as you lose the principal once, it will be lost, even if it is very unlikely. Because as long as you gamble enough times, losing money will happen definitely.

Someone may ask, since 100% bet is unreasonable, what about 90% or lower bet? In fact, to solve this problem, we can make an experiment to simulate the gambling game and see how the result of each bet is. As shown in the following chart:

![img](/upload/asset/28eb1f50abbf04f70b3e8.png)

From the chart, we can see that when we gradually reduce the position from 90%, 80%, 70%, 60% and 50%, in the same gamble, the results are completely different. Careful friends may have noticed that with the gradual reduction of the position, the final capital is expanding gradually.

Then some people may ask whether the smaller the bet each time is, the better, such as 10%. It is impossible to calculate every bet proportion. This is the problem to be solved by the famous Kelly Criterion. In statistics, Kelly Criterion can maximize the long-term growth rate of a strategy with positive expectation of repeated bets, and it can calculate the best bet ratio in each bet.

Not only that, assuming that the principal and the bet can be divided endlessly, it is impossible to go bankrupt in any bet by using the Kelly Criterion. Especially in the practical application of financial transactions, it is a position management strategy with both attack and defense. Let's look at how Kelly Criterion is calculated, and see the following figure:

![img](/upload/asset/28df6aa091984c0d86478.png)

- f is the optimal betting ratio for the available capital;
- b is the odds ratio, which can also be called the profit/loss ratio in trading;
- p is the success rate;
- q is the failure rate.

Then we can calculate the gambling example in this lesson according to the Kelly Criterion. The initial capital of 100 yuan can reach 1 million yuan at the fastest speed by using the betting ratio when the winning ratio is 50% and the odds is 2. Set into the Kelly Criterion, the calculation process is as follows:

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

The winning rate of 50% is 0.5. Multiply the odds by 2 plus 1, then subtract 1, and then divide by 2. The calculation result is 0.25. That is to say, in each bet, using 25% of the principal, you can reach 1 million yuan at the fastest speed. We can simulate manually according to the calculation results to see if it is correct.

![img](/upload/asset/28d141b07518b4b946125.png)

The figure above is the result of manual simulation. Please see the last line. In the same bet, after more than 100 rounds, 25% of the positions reached 1 million yuan first. The result of 90%, 80%, 70% and 60% positions is negative, which shows that even a positive expectation trading strategy will go bankrupt under the wrong position management.

We can also see that 50% of the positions will not lose or win in the end, which is also consistent with the result of the law of large numbers. In order to further illustrate the problem, a position of 10% was also added in the manual simulation. Although the final result was a positive return, the effect was several orders of magnitude worse than that of a position of 25%.

You can see the power of Kelly Criterion. If you choose 10% of the principal position in the actual application, your principal will become more than 30,000 in more than 100 bets. Although the return is large, compared with 25% of the principal position, it is equivalent to no profit. This is the power of knowledge.

If you want to make profits from Kelly Criterion in life, you need to meet the application conditions of Kelly Criterion. There is no doubt that this bet must come from the financial market. Especially in quantitative trading, we can roughly calculate the corresponding winning ratio and odds through historical data backtesting.

Of course, the practical application of Kelly Criterion in financial transactions cannot be so simple, and there are many details to be dealt with, such as the cost of capital in leveraged transactions, the capital and position in real transactions can not be divided wirelessly, and the winning ratio and loss ratio in transactions are changing dynamically, and so on. Whatever, Kelly Criterion shows us how to establish the best position management method.

সম্পর্কিত

আরো