양적 거래에서 자산 관리 - 절대 수익을 위한 CTA 전략 개발

저자:FMZ~리디아, 창작: 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 Sell timeout Futures_OP); exchange.IO ((currency, name + _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의 한 가격을 판매) if (data.sabb > boll.middle && data.sabb < boll.up) { // 만약 sabb가 중간 트랙보다 높다면 if (data.mp(tradeTypeA, 0)) { // 주문을 하기 전에 계약 A가 긴 주문을 가지고 있는지 확인 data.trade ((tradeTypeA, closebuy); // 계약 A는 긴 포지션을 닫습니다 } if (data.mp(tradeTypeB, 1)) { // 주문을 하기 전에 계약 B가 짧은 주문을 가지고 있는지 확인 data.trade ((tradeTypeB, closesell); // 계약 B는 짧은 포지션을 닫습니다 } } else if (data.basb < boll.middle && data.basb > boll.down) { // basb가 중간 트랙보다 낮다면 if (data.mp(tradeTypeA, 1)) { // 주문을 하기 전에 계약 A가 짧은 주문을 가지고 있는지 확인 data.trade ((tradeTypeA, closesell); // 계약 A는 짧은 포지션을 닫습니다 } if (data.mp(tradeTypeB, 0)) { // 주문을 하기 전에 계약 B가 긴 주문을 가지고 있는지 확인 data.trade ((tradeTypeB, closebuy); // 계약 B는 긴 포지션을 닫습니다 } } 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는 긴 포지션을 개설합니다 } if (!data.mp(tradeTypeB, 1)) { // 주문을 하기 전에 계약 B가 짧은 주문을 가지고 있는지 확인 data.trade ((tradeTypeB, sell); // 계약 B가 단위 포지션을 개시합니다. } } else if (data.sabb > boll.up) { // 만약 sabb 가격 차이가 상단 트랙보다 높다면 if (!data.mp(tradeTypeA, 1)) { // 주문을 하기 전에 계약 A가 짧은 주문을 가지고 있는지 확인 data.trade ((tradeTypeA, sell); // 계약 A는 짧은 포지션을 개설합니다 } if (!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.drawingChart ((bol); // 도면 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: true, 도구 팁: { xDateFormat: %Y-%m-%d %H:%M:%S, %A }, 제목: { 텍스트: 거래 수익과 손실 곡선 (정밀) }, rangeSelector: { 버튼: { 타입: 시간 수: 1, 텍스트: 1h }, { 타입: 시간 2개 문장: 3h }, { 타입: 시간 8개 텍스트: 8h }, { 타입: all 문장: 모든 문장 ]] 선택: 0, 입력 활성화: false }, x축: { 타입: 데이터타임 }, y축: { 제목: { 텍스트: 가격차 }, 반대: 거짓 }, 시리즈: [{ 이름: 올라기 트랙 id: line1,up, 데이터: [] }, { 이름: 중간 경로 id: 줄2,중, 데이터: [] }, { 이름: 하철, id: 선3, 아래로, 데이터: [] }, { 이름: basb, id: line4,basb, 데이터: [] }, { 이름: 사브 id: line5,sabb, 데이터: [] ♪ ♪ }; var ObjChart = Chart(chart); // 그림 객체 varbar = []; // 저장 가격 차이 시리즈 var oldTime = 0; // 기록 역사 데이터 시간표

// 매개 변수 var tradeTypeA = this_week; // 중재 A 계약 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; // Arbitrage의 한 가격을 판매 A 계약 this.bidA = depthDataA.Bids[0].Price; // Arbitrage의 한 가지 가격을 구매 A 계약 this.askB = depthDataB.Aks[0].Price; // 중재 B 계약의 한 가격을 판매 this.bidB = depthDataB.Bids[0].Price; // 중재 B 계약의 한 가격을 구입 // 긍정적인 중재 가격 차이 (계약 A의 한 가격을 판매 - 계약 B의 한 가격을 구입) this.basb = depthDataA.Asks[0].Price - depthDataB.Bids[0].Price; // 부정적인 중재 가격 차이 (계약 A의 한 가격을 구입 - 계약 B의 한 가격을 판매) this.sabb = depthDataA.Bids[0].Price - depthDataB.Asks[0].Price; }

위치 확인 데이터.프로토타이프.mp = 함수 (tradeType, type) varpositionData = this.positionData; // 위치 정보를 얻는다 for (var i = 0; i 0) { 반환 위치데이터[i].금액 } } } } false를 반환합니다. }

// 새로운 K선 데이터와 볼 표시 데이터의 합성 데이터.프로토타이프.볼 = 함수 (수, 시간주기) { var self = {}; // 임시 객체 // 긍정적 인 중재 가격 차이와 부정적인 중재 가격 차이 사이의 중상 값 self.Close = (this.basb + this.sabb) / 2; if (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(바, num, 2); // 탈리브 라이브러리의 boll 표시기를 호출 반환 { 위: boll[0][boll[0].length - 1], // boll 표시 상단 트랙 중간: boll [1][boll[1].length - 1], // boll 표시자 중간 트랙 아래로: boll[2][boll[2].length - 1] // boll 표시기 아래로 트랙 } // 처리 된 boll 표시 데이터를 반환 }

// 주문을 할 때 데이터.프로토타이프.트레이드 = 함수 (트레이드 타입, 타입) { 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를 설정합니다 } 스위치 (형) { // 매치 주문 배치 모드 케이스 구입: exchange.SetDirection ((type); // 주문 배치 모드를 설정 반환 교환.구매 (구매) 가격, 단위; 케이스 판매: exchange.SetDirection ((type); // 주문 배치 모드를 설정 반환 교환.판매 (bid) 가격, 단위) 경우 closebuy: exchange.SetDirection ((type); // 주문 배치 모드를 설정 반환 교환.판매 (bid) 가격, 단위) 부문 결결: exchange.SetDirection ((type); // 주문 배치 모드를 설정 반환 교환.구매 (구매) 가격, 단위; 기본값: false를 반환합니다. } }

// 주문을 취소 데이터. 프로토타입. 취소 명령어 = 함수 () { 잠자리 ((500); // 취소 전에 지연, 일부 교환 때문에, 당신은 내가 무슨 말을 하는지 알고 var 명령 = _C(exchange.GetOrders); // 채우지 않은 명령의 배열을 얻으십시오 if (orders.length > 0) { // 채우지 않은 주문이 있다면 for (var i = 0; i < orders.length; i++) { // 채우지 않은 명령어 배열을 통해 반복 exchange.CancelOrder ((order[i].Id); // 채우지 않은 주문을 하나씩 취소 잠자리 (500); // 0.5초 동안 잠자리 } false를 반환; // 채우지 않은 주문이 취소되는 경우 false를 반환 } true 를 반환; // 채우지 않은 주문이 없으면 true 를 반환 }

// 개별 계약을 처리 Data.prototype.isEven = 함수 () { varpositionData = this.positionData; // 위치 정보를 얻는다 var type = null; // 위치 방향 전환 // 위치 배열 길이의 나머지 2는 0과 같지 않거나 위치 배열 길이가 2과 같지 않은 경우 if (positionData.length % 2!= 0 for (var i = 0; i < positionData.length; i++) { // 위치 배열을 통해 반복 if (positionData[i].Type == 0) { type = 10; // 순서 매개 변수를 설정 } else if (positionData[i].Type == 1) { // If short order if (positionData[i].Type == 1) { // 만약 짧은 순서라면 타입 = -10; // 순서 매개 변수를 설정 } // 모든 위치를 닫아 this.trade(positionData[i].ContractType, type, positionData[i].Amount) 이므로, 이 계약은 } } }

// 그림 데이터, 프로토타입, 도면 차트 = 함수 (볼) { 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의 한 가격을 판매) if (data.sabb > boll.middle && data.sabb < boll.up) { // 만약 sabb가 중간 트랙보다 높다면 if (data.mp(tradeTypeA, 0)) { // 주문을 하기 전에 계약 A가 긴 주문을 가지고 있는지 확인 data.trade ((tradeTypeA, closebuy); // 계약 A는 긴 포지션을 닫습니다 } if (data.mp(tradeTypeB, 1)) { // 주문을 하기 전에 계약 B가 짧은 주문을 가지고 있는지 확인 data.trade ((tradeTypeB, closesell); // 계약 B는 짧은 포지션을 닫습니다 } } else if (data.basb < boll.middle && data.basb > boll.down) { // basb가 중간 트랙보다 낮다면 if (data.mp(tradeTypeA, 1)) { // 주문을 하기 전에 계약 A가 짧은 주문을 가지고 있는지 확인 data.trade ((tradeTypeA, closesell); // 계약 A는 짧은 포지션을 닫습니다 } if (data.mp(tradeTypeB, 0)) { // 주문을 하기 전에 계약 B가 긴 주문을 가지고 있는지 확인 data.trade ((tradeTypeB, closebuy); // 계약 B는 긴 포지션을 닫습니다 } } 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는 긴 포지션을 개설합니다 } if (!data.mp(tradeTypeB, 1)) { // 주문을 하기 전에 계약 B가 짧은 주문을 가지고 있는지 확인 data.trade ((tradeTypeB, sell); // 계약 B가 단위 포지션을 개시합니다. } } else if (data.sabb > boll.up) { // 만약 sabb 가격 차이가 상단 트랙보다 높다면 if (!data.mp(tradeTypeA, 1)) { // 주문을 하기 전에 계약 A가 짧은 주문을 가지고 있는지 확인 data.trade ((tradeTypeA, sell); // 계약 A는 짧은 포지션을 개설합니다 } if (!data.mp(tradeTypeB, 0)) { // 주문을 하기 전에 계약 B가 긴 주문을 가지고 있는지 확인 data.trade ((tradeTypeB, buy); // 계약 B는 긴 포지션을 개설합니다. } } } data.cancelOrders(); // 주문을 취소 data.drawingChart (글라드 (글라드)) data.isEven(); // 개별 계약을 보유 처리 }

// 입력 함수 함수 main() { // 콘솔에서 중요하지 않은 정보를 필터 SetErrorFilter ((429 확인GetRecords: 확인GetOrders: 확인GetDepth: 확인GetAccount 확인: 확인SellTimeout 확인Futures_OP); exchange.IO ((currency, name + _USDT); //거래할 디지털 화폐를 설정 ObjChart.reset(); // 프로그램을 시작하기 전에 그려진 이전 차트를 삭제 LogProfitReset ((); // 프로그램을 시작하기 전에 상태 표시줄 정보를 삭제 while (true) { // 투표 모드를 입력 onTick(); // onTick 함수를 실행 잠자리 (500); // 0.5초 동안 잠자리 } } ` 중재 거래는 모건 스탠리의 주식 거래 전략에서 유래되었다. 이 아이디어는 두 가지 고도로 상관관계에 있는 품종의 가격 차이가 팝콘 프로세스에 부합한다는 것입니다. 즉, 가격 차이는 역사적 평균에서 벗어나는 위치에서 평균으로 계속 돌아갑니다. 그리고 다시 평균에서 벗어납니다.

따라서, 우리는 수익을 얻기 위해 가격 차이에서 낮게 구입하고 높게 판매 할 수 있습니다. 그러면, 통계에서 표준 편차의 원칙에 따라 볼린거 대역은 중간 트랙과 표준 편차에 의해 계산 된 상위 및 하위 트랙으로 형성되며, 가격 차이 중재 거래에서 매우 실용적인 세 개의 메시 대역을 형성합니다.

이 전략에 따라 작동하는 테스트 후 전체 수익은 상대적으로 안정적이지만 처리 수수료와 영향 비용을 고려하지 않고 매번 수익이 많지 않습니다. 통계적 중재로 인해 가격 차이의 역 확장 위험이 있다는 점에 유의해야합니다. 설계할 때 스톱 로스 문제를 고려해야합니다. 둘째, 영향 비용에도주의를 기울여야합니다. 거래에 관련된 두 계약의 유동성이 줄어들면 수익에 큰 영향을 미치며 투자자는 적절히 피해야합니다.

4. CTA 전략 개발의 고급 반복

4.1 미래에 대한 CTA 전략의 함정을 피하십시오

지난 두 수업에서 우리는 MyLanguage에서 트렌드 전략과 자바스크립트에서 중재 전략을 작성했습니다. 우리는 전략 백테스트에서 문제를 보지 못했습니다. 그러나 양적 거래는 백테스트가 직접적으로 문제없이 수행 될 수있는 프로그램이 아닙니다.

사실, 백테스트는 전략의 시뮬레이션에 불과합니다. 그것은 단지 역사적 데이터에서 전략의 성능을 평가하는 데 사용됩니다. 그것은 거래자가 일부 거래 전략을 빠르게 평가하고 폐기 할 수 있습니다.

많은 경우, 백테스트에서 훌륭하게 보이는 전략은 여러 가지 이유로 실제 시장에서 백테스트 표준을 충족시키지 못합니다. 그 중 일부는 거래자의 통제를 벗어납니다. 그러나 실패의 일부는 일반적인 또는 잠재적 인 오류로 인해 발생합니다.

정적 데이터와 동적 데이터

먼저 정적 데이터와 동적 데이터의 개념을 정량화해야 합니다. 백테스트에서는 정적 역사 데이터를 사용합니다. 각 K 라인에서 높은 오픈 가격과 낮은 폐쇄 가격이 완료되고 각 거래 신호는 100%로 닫을 수 있습니다. 그러나 실제 시장의 데이터는 동적입니다. 예를 들어, 최대 가격이 오픈 후 1 시간 이내에 최대 가격보다 크다면 구매하십시오. 그러나 현재 K 라인이 끝나지 않은 경우 최대 가격은 동적이며 거래 신호가 앞뒤로 깜박일 수 있습니다. 이 상황은 전략이 구매 및 판매 거래의 조건을 판단하는 미래 기능을 사용하는 것을 나타냅니다.

미래 기능

미래 함수는 무엇입니까? 먼저 바이두 백과사전의 설명을 살펴보자: 양은 양 A와 양 B와 같은 다른 양에 의존합니다. B가 변하면 A가 변하면 A는 B의 함수입니다.

일반적으로, 그것은 내일의 가격과 내일의 가격을 예측하는 것과 같은 미래 데이터를 인용하는 기능입니다. 기술적 인 지표가 미래 기능을 포함하면 신호는 불확실합니다. 그것은 종종 현재 거래 신호입니다. 다음 K 라인이 나타나면 신호가 사라지거나 위치를 변경합니다.

폐쇄 가격은 미래 함수입니다. 마지막 K 라인이 만료될 때까지 폐쇄 가격은 항상 변합니다. 종료 가격을 결정하기 위해 K 라인이 만료 될 때까지 기다려야합니다. 종료 가격이 자체는 미래 함수이기 때문에 종료 가격에 기반한 모든 기술적 지표는 또한 미래 함수입니다.

따라서, 기술 지표가 확인 된 폐쇄 가격을 기본 데이터로 사용한다면, 거래 신호는 얼마나 오래 지나도 변하지 않을 것입니다. 기술 지표는 미래 기능을 참조하지 않는다고 말할 수 있습니다. 그러나 그것이 사용하는 기본 데이터는 확인되지 않은 폐쇄 가격입니다. 따라서이 기술 지표는 미래 기능을 참조하며, 거래 신호는 실제 적용에서 변경 될 수 있습니다.

과거 가격

미래 함수는 미래 가격을 사용하며, 이는 역으로 과거 가격을 사용할 수도 있습니다. 이것은 또한 많은 초보자들이 무시하는 경향이 있는 문제입니다. 미래에 이 문제를 더 잘 설명하기 위해 예를 들어 보겠습니다. 현재 최대 가격이 오픈 후 1 시간 이내에 최대 가격보다 크다면 오픈 가격으로 구매하십시오. 분명히 구매 및 판매 신호의 조건에 문제가 없지만 주문의 가격이 과거 가격을 사용했습니다.

백테스트에서는 전략이 정상적이기 때문에 정적 데이터에 기반한 백테스트 엔진은 구매 신호가 있을 때만 100% 닫을 수 있습니다. 그러나 오픈 후 1시간 이내에 가장 높은 가격보다 높은 가격이 있을 경우, 이전 가격 오픈 가격으로 주문을 발행할 수 없다는 것이 확실합니다.

가격 진공

소위 가격 진공은 K-라인 차트에 표시된 가격을 의미하지만 실제 시장에서 거래할 수 없는 가격은 주로 다음과 같은 경우로 나니다.

  • 1. 거래 를 해 본 사람 들 은 가격 이 상승 할 때 구매 하는 것 이 어렵고, 가격 이 하락 할 때 판매 하는 것 이 어렵다는 것 을 알고 있다. 그러나 그 점 을 뒷 테스트 에서 결론 지을 수 있다.
  • 2. 교환의 매칭 메커니즘은 가격 우선 순위와 시간 우선 순위입니다. 일부 품종은 종종 시장에서 많은 수의 주문을 가지고 있습니다. 실제 시장에서 주문을 거래하는 경우 다른 주문 뒤에 순위를 매겨야합니다. 다른 주문이 거래 된 후에만 거래를 할 수 있습니다. 가격이 거래되기 전에 가격이 변경되었습니다. 그러나 백테스트에서 전략이 주문을 처리하는 경우 실제 시장 환경과는 다른 시간에 거래를 할 것입니다.
  • 3. 중재 전략을 사용하는 경우, 백테스트의 이윤은 매우 높습니다. 왜냐하면 매번 이러한 가격 차이를 포착했다고 가정하기 때문입니다. 실제로 많은 가격 차이는 잡을 수 없거나 한 다리가만 잡을 수 있습니다. 일반적으로 말하면, 그것은 당신의 방향에 도움이되지 않는 것이어야합니다. 그 다음 당신은 즉시 다른 다리를 채워야합니다. 이 시점에서 슬라이딩 포인트는 1 또는 2 지점이 더 이상 없으며, 중재 전략 자체는 이러한 포인트의 가격 차이를 얻는 것을 목표로합니다. 이 상황을 백테스트에서 시뮬레이션 할 수 없습니다. 실제 이익은 백테스트만큼 좋지 않습니다.
  • 4. 블랙 스완 이벤트는 일반적으로 사용되지 않지만 여전히 양적 거래에 큰 영향을 미칩니다. 아래 차트에서 보이는 바와 같이, 외환 스위스 프랑의 블랙 스완 이벤트의 경우 차트에서 높은 가격과 낮은 가격을 모두 볼 수 있습니다. 사실, 극심한 시장에서 중간 가격은 진공이며 많은 수의 스톱 로스 오더가 스탬프 이벤트를 유발합니다. 유동성은 0이고 처리하기가 매우 어렵습니다. 그러나 백테스트에서 손실을 막을 수 있습니다.

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. 낙하산을 온라인에서 판매하는 사람들은 낙하산에 문제가 있는 사람들이 더 이상 살지 않기 때문에 칭찬을 받는다. 3. 기자는 승객들이 버스에서 티켓을 구입했는지 여부를 인터뷰했습니다. 왜냐하면 티켓이 없는 사람들은 버스에 올라갈 수 없기 때문입니다. 4. 언론 은 복권 을 이길 수 있다고 광고 하기 때문 에, 언론 은 복권 을 이기지 않는 사람 들 을 적극적으로 홍보 하지 않을 것 이다.

위의 예제에서, 우리는 사람들이 일반적으로 받는 정보가 실제로 필터링되어 많은 수의 데이터 또는 샘플이 선택적으로 무시되고 그 결과는 생존 편향에 기반한 결론이 실시간에서 벗어나게 된다는 것을 발견할 수 있습니다. 따라서 양적 거래에서, 우리는 또한 백테스트의 결과가 행운의 일부인지에 초점을 맞추어야합니다. 많은 경우 백테스트의 결과는 전체 백테스트에서 가장 좋은 성능이 될 수 있습니다. 다음 그림에 유의하십시오.

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

  • 왼쪽 차트 (모습): 매우 좋은 거래 전략. 큰 인출 없이 투자자는 안정적인 투자 수익을 얻을 수 있습니다.
  • 오른쪽 차트 (실제): 이것은 200개의 무작위 거래 백테스트 중 가장 좋은 것입니다.

왼쪽에 있는 그림은 매우 좋은 거래 전략입니다. 자본 곡선은 좋고, 상당한 인출이 없으며, 안정적인 수익이 얻을 수 있습니다. 그러나 오른쪽의 그림을 보세요. 백테스트 거래의 수백에서 가장 좋은 것입니다. 다른 한편으로, 우리가 금융 시장을 볼 때, 항상 더 많은 별이 있고, 오래 사는 별이 적습니다. 거래자의 전략이 시장 상황과 일치한다면, 시장은 매년 별들을 만들 수 있지만, 3년 이상 연속적으로 안정적인 이익을 얻을 수 있는 오래 사는 별을 보는 것은 어렵습니다.

비용 충격

주문이 미뤄지지 않는 한, 거래할 때 슬라이딩 가격이 있을 수 있습니다. 활성 거래의 종류에 있어서, 입찰 가격과 요청 가격은 일반적으로 한 지점에서 다릅니다. 비활성 거래의 종류에 있어서, 차이는 더 커질 수 있습니다. 거래를 종료하기 위한 주도권을 취하고 싶을 때마다, 적어도 한 지점의 차이는 필요하거나 더 필요합니다. 그러나, 백테스트에서, 우리는 신호가 있는 한 거래의 문제를 고려할 필요가 없습니다. 따라서 실제 거래 환경을 시뮬레이션하기 위해서는 적어도 하나의 슬라이딩 가격을 추가해야 합니다.

특히 더 자주 거래되는 전략의 경우, 전략이 백테스트 될 때 슬라이딩 가격이 추가되지 않으면 자본 곡선이 항상 상향으로 기울어지고 합리적인 슬라이딩 가격이 추가되면 즉시 손실로 변합니다. 또한,이 현상은 포인트 차이로 인해 발생할뿐만 아니라 실제 거래 환경에서 고려해야합니다. 네트워크 지연, 소프트웨어 및 하드웨어 시스템, 서버 응답 및 기타 문제.

전략적 역량

같은 전략은 효율적인 시장과 비효율적인 시장에서, 심지어는 그 반대에도 상당히 다를 것입니다. 예를 들어, 국내 주식 시장, 재화 선물 및 외국 디지털 통화와 같은 비효율적인 시장에서, 거래 부피의 작은 기반으로 인해, 고주파 전략 자체의 용량은 매우 크지 않으며, 더 많은 사람들에게 이익 공간이 없으며, 원래 수익성이 있었던 전략조차도 손실이되었습니다. 그러나 효율적인 외환 시장에서, 그것은 많은 다른 유형의 고주파 전략을 수용 할 수 있습니다.

위는 전략의 개발 및 사용에 발생할 수있는 문제와 함정입니다. 경험이 많은 거래 시스템 개발자에게는 역 테스트가 필수적입니다. 왜냐하면 전략적 아이디어가 역사적 거래에서 검증 될 수 있는지 여부를 알려 줄 수 있기 때문입니다. 그러나 많은 경우, 역 테스트는 미래에 수익성이있을 것이라는 것을 의미하지는 않습니다. 역 테스트에 너무 많은 함정이 있기 때문에 몇 가지 수업을 지불하지 않고는 이해하지 못할 것입니다. 이 과정은 적어도 많은 양적 우회로와 함정을 피하는 데 도움이 될 수 있습니다.

4.2 가장 좋은 위치 관리

주식운영자의 추억에는 매우 흥미로운 단락이 있다: 영웅 리버모어와 같은 증권회사에서 일하는 올드 터키 (전에는 파트리지로 알려져 있었다) 는 항상 큰 거래를 한다. 그는 이익을 취한 후 판매하고 주가가 다시 상승한 후에 다시 구매할 것을 조언했을 때. 올드 터키는 항상 이렇게 말했다:

심지어 리버모어도 마침내 sighed: 트렌드에 주목할만한 것은 아무것도 없습니다. 항상 황소 시장에서 상승하고 곰 시장에서 하락하는 많은 사람들이 있습니다. 그러나 그들은 항상 시장과 협상하는 데 잘하고, 가장 낮은 지점에서 구입하고 가장 높은 지점에서 판매하려고합니다. 구 터키와 마찬가지로, 시장을보고 위치를 유지하는 사람들이 실제로 큰 부를 창출합니다. 이것은 목표와 타이밍의 선택뿐만 아니라 더 중요한 질문과도 직면합니다. 우리는 얼마나 많은 위치 (위험) 를 보유해야합니까 (곰)?

모든 실패한 트레이더들은 일방적인 사고를 가지고 있다. 트레이딩을 할 때 탐욕스러운 사람들은 위험보다는 이윤을 볼 뿐이고, 수줍은 사람들은 이익보다는 위험을 볼 뿐이다. 탐욕스럽고 수줍은 사람들은 상승할 때 위험을 잊고, 하락할 때 이윤을 잊는다. 그러나 성공적인 트레이더들은 위험과 수익을 모두 고려할 것이다. 즉, 그들이 벌어들이는 모든 달러에 대해 몇 달러의 위험을 감수할 것이다. 그러면 수익과 위험을 측정하는 지수는 수익 위험 비율이다.

많은 사람들이 위험은 이익만큼이나 크다는 것을 알고 있습니다. 즉 수익은 위험에 비례합니다. 일부 사람들의 견해에 따르면 수익과 위험 사이의 관계는 다음과 같습니다. 수평 축은 위험의 비율이고 수직 축은 수익의 비율입니다.

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

그러나 실제 거래에서 수익과 위험은 선의 두 지점만큼 간단하지 않습니다. 적어도 항상 선형적으로 움직이지 않습니다. 실제 위험은 예상 수익과 함께 취할 수있는 최대 손실 금액 또는 최대 변동성이라고합니다. 때로는 최대 부동 손실이 항상 거래의 결과 측면에서 종료 손실과 같지는 않지만 최대 부동 손실은 사실입니다.

이로부터 우리는 위의 그림의 위험 대비 수익률이 실제 성과가 아니라는 것을 알 수 있습니다. 실제 거래 환경에서 위험 대비 수익률은 아래 그래프와 동일해야합니다.

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% 를 투자 하는 것 이 불합리 한 것 임 은 분명 하다. 왜냐하면, 일단 자본금을 잃게 될 때 까지는, 그 금액 은 잃어질 것 이다. 아주 가능성이 거의 없더라도 마찬가지 이다. 왜냐하면, 당신이 충분히 많이 도박 하는 동안, 돈 을 잃는 것 이 확실 히 일어날 것이기 때문 이다.

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%에 비해 수익이 없습니다. 이것은 지식의 힘입니다.

당신이 인생에서 켈리 기준에서 이익을 얻고 싶다면, 당신은 켈리 기준의 적용 조건을 충족해야합니다. 이 내기가 금융 시장에서 나올 수 있다는 데는 의심의 여지가 없습니다. 특히 양적 거래에서, 우리는 역사적 데이터 백테스팅을 통해 해당 승률 비율과 확률을 대략 계산 할 수 있습니다.

물론, 금융 거래에서 켈리 기준의 실질적인 적용은 그렇게 간단할 수 없으며, 레버레이드 거래에서 자본 비용, 실제 거래에서 자본과 지위가 무선으로 나눌 수 없으며, 거래에서 승률과 손실 비율이 동적으로 변화하고 있습니다.


관련 내용

더 많은 내용