مقداری تجارت سے اثاثہ جات کے انتظام تک - مطلق واپسی کے لئے سی ٹی اے کی حکمت عملی کی ترقی

مصنف:لیدیہ, تخلیق: 2023-02-07 09:58:41, تازہ کاری: 2023-09-18 20:25:11

، [nowTime، اس.basb]]) ؛ ObjChart.add (([4، [nowTime، اس.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 کے لئے: خریدنے کے لئےSelltimeout کے لئےFutures_OP);exchange.IO("کرنسی"، نام + _USDT) ؛ // ڈیجیٹل کرنسی کی تجارت کرنے کے لئے مقرر کریں ObjChart.reset(); // پروگرام شروع کرنے سے پہلے تیار کردہ پچھلے چارٹ کو صاف کریں LogProfitReset(); // پروگرام شروع کرنے سے پہلے حالت بار کی معلومات کو صاف کریں while (true) { // پولنگ موڈ درج کریں onTick(); // onTick فنکشن کو چلائیں نیند ((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); // معاہدہ A طویل پوزیشن بند کرتا ہے } اگر (data.mp(tradeTypeB, 1)) { // ایک آرڈر رکھنے سے پہلے چیک کریں کہ معاہدہ B میں مختصر احکامات ہیں یا نہیںdata.trade(tradeTypeB, closesell); // معاہدہ B مختصر پوزیشن بند کرتا ہے } } 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); // معاہدہ B طویل پوزیشن بند کرتا ہے } } if (accountStocks * Math.max(data.askA, data.askB) > 1) { // اگر اکاؤنٹ میں بیلنس موجود ہے if (data.basb < boll.down) { // اگر basb قیمت کا فرق نیچے ٹریک سے کم ہے اگرdata.mp(tradeTypeA, 0)) { // چیک کریں کہ معاہدہ A میں آرڈر دینے سے پہلے طویل آرڈر ہیں یا نہیںdata.trade(tradeTypeA, buy); // معاہدہ A طویل پوزیشن کھولتا ہے } (!data.mp(tradeTypeB, 1)) { // ایک آرڈر رکھنے سے پہلے چیک کریں کہ معاہدہ B میں مختصر احکامات ہیں یا نہیںdata.trade(tradeTypeB, sell); // معاہدہ B مختصر پوزیشن کھولتا ہے } } else if (data.sabb > boll.up) { // If sabb قیمت کا فرق اوپری ٹریک سے زیادہ ہے (!data.mp(tradeTypeA, 1)) { // ایک آرڈر رکھنے سے پہلے چیک کریں کہ معاہدہ A میں مختصر احکامات ہیں یا نہیںdata.trade(tradeTypeA, sell); // معاہدہ A مختصر پوزیشن کھولتا ہے } (!data.mp(tradeTypeB, 0)) { // ایک آرڈر رکھنے سے پہلے چیک کریں کہ معاہدہ B میں طویل احکامات ہیں یا نہیںdata.trade(tradeTypeB, buy); // معاہدہ B طویل پوزیشن کھولتا ہے } } }

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: { بٹن: قسم: گھنٹے، گنتی: 1، متن: 1h }، { قسم: گھنٹے، گنتی: 2، متن: 3h }، { قسم: گھنٹے، گنتی: 8 متن: 8h }، { قسم: تمام متن: تمام }] منتخب: 0، ان پٹ فعال: غلط }، x محور: { قسم: تاریخ وقت }، y محور: { عنوان: { متن: قیمتوں میں فرق }، مخالف: غلط، }، سیریز: نام: اوپر ٹریک، id: line1,up، اعداد و شمار: [] }، { نام: مڈل ٹریک، id: line2,middle، اعداد و شمار: [] }، { نام: ڈاؤن ٹریک، id: لائن3، نیچے ، اعداد و شمار: [] }، { نام: basb، id: line4،basb، اعداد و شمار: [] }، { نام: sabb، id: line5,sabb، اعداد و شمار: [] }] }؛ var ObjChart = Chart(chart) ؛ // ڈرائنگ آبجیکٹ var bars = []; // اسٹوریج قیمت فرق سیریز var oldTime = 0؛ // ریکارڈ تاریخی ڈیٹا ٹائم اسٹیمپ

// پیرامیٹرز var tradeTypeA = this_week؛ // ثالثی ایک معاہدہ var tradeTypeB = quarter؛ // ثالثی B معاہدہ var dataLength = 10؛ // اشارے کی مدت کی لمبائی var timeCycle = 1; // K لائن مدت var name = ETC; // کرنسیاں var یونٹ = 1؛ // آرڈر کی مقدار

// بنیادی اعداد و شمار فنکشن ڈیٹا ((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) ؛ // ثالثی ایک معاہدے کی گہرائی کے اعداد و شمار exchange.SetContractType(tradeTypeB); // ثالثی B معاہدے کو سبسکرائب کریں var depthDataB = _C(exchange.GetDepth) ؛ // ثالثی B معاہدے کی گہرائی کے اعداد و شمار this.time = recordsData[recordsData.length - 1].Time؛ // تازہ ترین ڈیٹا حاصل کرنے کا وقت this.askA = depthDataA.Asks[0].Price؛ // بیچیں ایک قیمت کی ثالثی ایک معاہدہ this.bidA = depthDataA.Bids[0].Price؛ // خریدیں ایک قیمت کی ثالثی ایک معاہدہ this.askB = depthDataB.Asks[0].Price؛ // بیچیں ایک قیمت کی ثالثی B معاہدے this.bidB = depthDataB.Bids[0].Price؛ // خریدیں ایک قیمت کی ثالثی 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؛ // پوزیشن کی معلومات حاصل کریں کے لئے (var i = 0؛ i < positionData.length؛ i++) { اگر (positionData[i].ContractType == tradeType) { if (positionData[i].Type == type) { اگر (positionData[i].Type == type) { اگر (positionData[i].Type == type) { اگر (positionData[i].Type == type) { if (positionData[i].Amount > 0) { واپسی کی پوزیشنData[i].amount؛ } } } } false واپس کریں }

// نئے K لائن کے اعداد و شمار اور بول اشارے کے اعداد و شمار کی ترکیب ڈیٹا.پروٹوٹائپ.بول = فنکشن (نمبر، وقت سائیکل) { var خود = {}؛ // عارضی اشیاء // مثبت آربیٹریج قیمت فرق اور منفی آربیٹریج قیمت فرق کے درمیان میڈین قدر self.Close = (یہ.basb + یہ.sabb) / 2؛ اگر (this.timeA == this.timeB) { self.Time = this.time؛ } // دو گہرائی ڈیٹا ٹائم اسٹیمپ کا موازنہ کریں if (this.time - oldTime > timeCycle * 60000) { سلاخوں.دباؤ ((خود) ؛ oldTime = this.time؛ } // مخصوص وقت کی مدت کے مطابق K لائن صف میں قیمت فرق ڈیٹا آبجیکٹ میں منتقل if (bars.length > num * 2) { bars.shift(); // K لائن صف کی لمبائی کو کنٹرول کریں } دیگر { واپسی } var boll = TA.BOLL(بار، نمبر، 2) ؛ // طالب لائبریری میں boll اشارے کال کریں واپسی { up: boll[0][boll[0].length - 1، // boll اشارے اوپری ٹریک وسط: بول [1][بول [1]] لمبائی - 1، // بول اشارے وسط ٹریک نیچے: بول[2][بول[2].لمبائی - 1] // بول اشارے نیچے ٹریک } // ایک عملدرآمد boll اشارے کے اعداد و شمار واپس }

// ایک آرڈر رکھیںData.prototype.trade= فنکشن (تجارتی قسم) { exchange.SetContractType(tradeType); // آرڈر دینے سے پہلے کسی معاہدے کی دوبارہ رکنیت لیں وار 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 } سوئچ (ٹائپ) { // میچ آرڈر کی جگہ کا تعین کرنے کا موڈ کیس خریدیں: exchange.SetDirection(type); // آرڈر کی جگہ کا تعین موڈ مقرر کریں واپسی کا تبادلہ.خریداری (سوال) قیمت، یونٹ؛ کیس فروخت: exchange.SetDirection(type); // آرڈر کی جگہ کا تعین موڈ مقرر کریں واپسی کا تبادلہ۔فروخت (bid) قیمت، یونٹ؛ کیس closebuy: exchange.SetDirection(type); // آرڈر کی جگہ کا تعین موڈ مقرر کریں واپسی کا تبادلہ۔فروخت (bid) قیمت، یونٹ؛ کیس closesell: exchange.SetDirection(type); // آرڈر کی جگہ کا تعین موڈ مقرر کریں واپسی کا تبادلہ.خریداری (سوال) قیمت، یونٹ؛ ڈیفالٹ: false واپس کریں } }

// احکامات منسوخ کریں ڈیٹا.پروٹوٹائپ.بند کریںOrders = فنکشن () { نیند ((500) ؛ // منسوخ کرنے سے پہلے تاخیر، کیونکہ کچھ تبادلے، آپ کو میرا مطلب سمجھ var احکامات = _C ((exchange.GetOrders) ؛ // خالی احکامات کی ایک صف حاصل کریں if (orders.length > 0) { // اگر خالی احکامات ہیں کے لئے (var i = 0؛ i < احکامات.length؛ i++) { // خالی احکامات کی صف کے ذریعے تکرار exchange.CancelOrder ((آرڈر[i].Id) ؛ // ایک ایک کر کے خالی احکامات منسوخ کریں نیند ((500) ؛ // 0.5 سیکنڈ کے لئے نیند } false لوٹائیں؛ // false لوٹائیں اگر ایک خالی آرڈر منسوخ کیا جاتا ہے } true لوٹائیں؛ // اگر کوئی خالی احکامات نہیں ہیں تو true لوٹائیں }

// انفرادی معاہدوں کی ہولڈنگ ہینڈل ڈیٹا.پروٹوٹائپ.ایس ایون = فنکشن () { var positionData = this.positionData؛ // پوزیشن کی معلومات حاصل کریں var type = null؛ // پوزیشن سمت سوئچ کریں // اگر باقی 2 پوزیشن صف کی لمبائی 0 کے برابر نہیں ہے یا پوزیشن صف کی لمبائی 2 کے برابر نہیں ہے if (positionData.length % 2!= 0 اور اگر positionData.length!= 2) { کے لئے (var i = 0؛ i < positionData.length؛ i++) { // پوزیشن صف کے ذریعے تکرار if (positionData[i].Type == 0) { // اگر یہ ایک طویل حکم ہے قسم = 10؛ // ترتیب پیرامیٹرز مقرر کریں } else if (positionData[i].Type == 1) { // اگر یہ ایک مختصر حکم ہے قسم = -10؛ // ترتیب پیرامیٹرز مقرر کریں } // تمام پوزیشن بند کریںthis.trade(positionData[i].ContractType, type, positionData[i].Amount) (مقام ڈیٹا[i].معاہدہٹائپ، قسم، مقامڈیٹا[i].مبلغ) } } }

// ڈرائنگ ڈیٹا.پروٹوٹائپ.ڈرائنگ گراف = فنکشن (بول) { var nowTime = نیا Date().getTime(؛ ObjChart.add (([0، [nowTime، boll.up]]) ؛ ObjChart.add (([1، [nowTime، boll.middle]]) ؛ ObjChart.add (([2، [nowTime، boll.down]]) ؛ ObjChart.add (([3، [nowTime، اس.basb]]) ؛ ObjChart.add (([4، [nowTime، اس.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); // معاہدہ A طویل پوزیشن بند کرتا ہے } اگر (data.mp(tradeTypeB, 1)) { // ایک آرڈر رکھنے سے پہلے چیک کریں کہ معاہدہ B میں مختصر احکامات ہیں یا نہیںdata.trade(tradeTypeB, closesell); // معاہدہ B مختصر پوزیشن بند کرتا ہے } } 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) ؛ // معاہدہ B طویل پوزیشن کو بند کرتا ہے } } if (accountStocks * Math.max(data.askA, data.askB) > 1) { // اگر اکاؤنٹ میں بیلنس موجود ہے if (data.basb < boll.down) { // اگر basb قیمت کا فرق نیچے ٹریک سے کم ہے (!data.mp(tradeTypeA, 0)) { // چیک کریں کہ معاہدہ A میں آرڈر دینے سے پہلے طویل آرڈر ہیں یا نہیںdata.trade(tradeTypeA, buy); // معاہدہ A طویل پوزیشن کھولتا ہے } (!data.mp(tradeTypeB, 1)) { // ایک آرڈر رکھنے سے پہلے چیک کریں کہ معاہدہ B میں مختصر احکامات ہیں یا نہیںdata.trade(tradeTypeB, sell); // معاہدہ B مختصر پوزیشن کھولتا ہے } } else if (data.sabb > boll.up) { // If sabb قیمت کا فرق اوپری ٹریک سے زیادہ ہے (!data.mp(tradeTypeA, 1)) { // ایک آرڈر رکھنے سے پہلے چیک کریں کہ معاہدہ A میں مختصر احکامات ہیں یا نہیںdata.trade(tradeTypeA, sell); // معاہدہ A مختصر پوزیشن کھولتا ہے } (!data.mp(tradeTypeB, 0)) { // ایک آرڈر رکھنے سے پہلے چیک کریں کہ معاہدہ B میں طویل احکامات ہیں یا نہیںdata.trade(tradeTypeB, buy); // معاہدہ B طویل پوزیشن کھولتا ہے } } } data.cancelOrders(); // احکامات منسوخ کریں اعداد و شمار.ڈرائنگچارٹ ((بُل) ؛ // ڈرائنگ data.isEven(); // انفرادی معاہدوں کو ہینڈل کرنا }

// انٹری فنکشن فنکشن main() { // کنسول میں غیر اہم معلومات فلٹر کریں SetErrorFilter ((429 کے لئےGetRecords: کے لئےGetOrders: کے لئےGetDepth: کے لئےGetAccount کے لئے: خریدنے کے لئےSelltimeout کے لئےFutures_OP);exchange.IO("کرنسی"، نام + _USDT) ؛ //ٹرانزیکٹ کرنے کے لئے ڈیجیٹل کرنسی مقرر کریں ObjChart.reset(); // پروگرام شروع کرنے سے پہلے تیار کردہ پچھلے چارٹ کو صاف کریں LogProfitReset(); // پروگرام شروع کرنے سے پہلے حالت بار کی معلومات کو صاف کریں while (true) { // پولنگ موڈ درج کریں onTick(); // onTick فنکشن کو چلائیں نیند ((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.

متعلقہ

مزید