[BollingerBand]
워치봇에서 제공하는 BollingerBand는 percentB 개념으로 BollingerBand를 %로 변환한 값입니다.
따라서 이를 Multichart에 적용하기 위해 기존 지표를 변형해서 적용했습니다.
var: percentB(0);
if (BollingerBand(c,a1,a2)-BollingerBand(c,a1,-a2))>0 then begin
percentB=((c-BollingerBand(c,a1,-a2))/(BollingerBand(c,a1,a2)-BollingerBand(c,a1,-a2)))*100;
end else percentB=0;
if percentB>a3 then buy 1 contracts next bar at market; if percentB<-a4 then sell 1 contracts next bar at market;
변수가 네 개라 모든 경우의 수를 세밀하게 최적화 하기에는 시간이 많이 걸리기 때문에 러프하게 검토해 보았습니다.
밴드를 벗어날 때 해당 방향으로 진입하는 추세형 프레임입니다.
세밀한 조정은 워치봇에서 직접 해 보시기 바랍니다.
다른 지표들과는 다르게 의미 있는 결과가 많이 보여서 샘플링할 값도 여러 개 선택해 보았습니다.
워치봇 지표 값으로 보면
[BTC]
매수(20, 1, 180) >, 매도(20, 1, -120) < "lastBalance": 10972608, "earningsRate": 9.9726, "totalFee": 3667890, "tradeCount": 142, "from": "2017-01-01 19:15", "to": "2018-04-10 10:00", "lastBalance": 1125528, "earningsRate": 0.1255, "totalFee": 264580, "tradeCount": 90, "from": "2018-01-01 16:15", "to": "2018-04-10 10:00",
매수(40, 1, 200) >, 매도(40, 1, -100) < "lastBalance": 4518548, "earningsRate": 3.5185, "totalFee": 2366188, "tradeCount": 196, "from": "2017-01-01 19:30", "to": "2018-04-10 10:00", "lastBalance": 1080369, "earningsRate": 0.0804, "totalFee": 217577, "tradeCount": 38, "from": "2018-01-03 03:15", "to": "2018-04-10 10:00",
매수(60, 1, 140) >, 매도(60, 1, -60) < "lastBalance": 7021680, "earningsRate": 6.0217, "totalFee": 5792489, "tradeCount": 306, "from": "2017-01-01 16:00", "to": "2018-04-10 10:00", "lastBalance": 971672, "earningsRate": -0.0283, "totalFee": 377877, "tradeCount": 68, "from": "2018-01-01 16:15", "to": "2018-04-10 10:00",
매수(60, 1, 140) >, 매도(60, 1, -20) < "lastBalance": 4087595, "earningsRate": 3.0876, "totalFee": 4878607, "tradeCount": 412, "from": "2017-01-01 16:00", "to": "2018-04-10 10:00", "lastBalance": 897991, "earningsRate": -0.102, "totalFee": 473034, "tradeCount": 90, "from": "2018-01-01 16:15", "to": "2018-04-10 10:00",
매수(80, 1, 140) >, 매도(80, 1, -60) < "lastBalance": 8512746, "earningsRate": 7.5127, "totalFee": 4578146, "tradeCount": 242, "from": "2017-01-01 10:30", "to": "2018-04-10 10:00", "lastBalance": 1313026, "earningsRate": 0.313, "totalFee": 319055, "tradeCount": 46, "from": "2018-01-03 03:15", "to": "2018-04-10 10:00",
매수(80, 1, 80) >, 매도(80, 1, -60) < "lastBalance": 7330771, "earningsRate": 6.3308, "totalFee": 5294672, "tradeCount": 300, "from": "2017-01-01 10:00", "to": "2018-04-10 10:00", "lastBalance": 939505, "earningsRate": -0.0605, "totalFee": 361915, "tradeCount": 68, "from": "2018-01-01 10:00", "to": "2018-04-10 10:00",
매수(80, 1, 100) >, 매도(80, 1, -40) < "lastBalance": 5306313, "earningsRate": 4.3063, "totalFee": 5140271, "tradeCount": 374, "from": "2017-01-01 10:00", "to": "2018-04-10 10:00", "lastBalance": 826672, "earningsRate": -0.1733, "totalFee": 401744, "tradeCount": 84, "from": "2018-01-01 10:00", "to": "2018-04-10 10:00",
매수(100, 1, 120) >, 매도(100, 1, -40) < "lastBalance": 8911304, "earningsRate": 7.9113, "totalFee": 5045493, "tradeCount": 250, "from": "2017-01-01 10:15", "to": "2018-04-10 10:00", "lastBalance": 1203724, "earningsRate": 0.2037, "totalFee": 343310, "tradeCount": 52, "from": "2018-01-02 22:15", "to": "2018-04-10 10:00",
매수(100, 1, 120) >, 매도(100, 1, -20) < "lastBalance": 8758714, "earningsRate": 7.7587, "totalFee": 5354951, "tradeCount": 292, "from": "2017-01-01 10:15", "to": "2018-04-10 10:00", "lastBalance": 1311629, "earningsRate": 0.3116, "totalFee": 380917, "tradeCount": 56, "from": "2018-01-02 22:15", "to": "2018-04-10 10:00",
매수(100, 1, 120) >, 매도(100, 1, 0) < "lastBalance": 6290177, "earningsRate": 5.2902, "totalFee": 4548252, "tradeCount": 330, "from": "2017-01-01 10:15", "to": "2018-04-10 10:00", "lastBalance": 1277026, "earningsRate": 0.277, "totalFee": 401212, "tradeCount": 62, "from": "2018-01-02 22:15", "to": "2018-04-10 10:00",
거래 횟수가 충분히 많으면서 최근까지 수익이 적당히 나는 결과는 다음과 같습니다.
매수(80, 1, 140) >, 매도(80, 1, -60) <
매수(100, 1, 120) >, 매도(100, 1, -20) <
매수(100, 1, 120) >, 매도(100, 1, 0) <
위 세 개의 결과 중
매수(100, 1, 120) >, 매도(100, 1, -20) <
만 이용해서
1. 다른 코인에서의 결과
2. 세밀한 조정
3. 손절/익절
을 해보도록 하겠습니다.
1. 다른 코인에서의 결과
[ETH]
"lastBalance": 46128272, "earningsRate": 45.1283, "totalFee": 37800446, "tradeCount": 291, "from": "2017-01-01 10:00", "to": "2018-04-10 10:00", "lastBalance": 1080950, "earningsRate": 0.0809, "totalFee": 412061, "tradeCount": 59, "from": "2018-01-01 10:00", "to": "2018-04-10 10:00",
[ETC]
"lastBalance": 3187087, "earningsRate": 2.1871, "totalFee": 3436316, "tradeCount": 340, "from": "2017-01-01 11:45", "to": "2018-04-10 10:00", "lastBalance": 1084781, "earningsRate": 0.0848, "totalFee": 428244, "tradeCount": 64, "from": "2018-01-01 12:00", "to": "2018-04-10 10:00",
[XRP]
"lastBalance": 5680155, "earningsRate": 4.6802, "totalFee": 3285364, "tradeCount": 226, "from": "2017-05-12 22:30", "to": "2018-04-10 10:00", "lastBalance": 1082262, "earningsRate": 0.0823, "totalFee": 403314, "tradeCount": 60, "from": "2018-01-02 08:45", "to": "2018-04-10 10:00",
[LTC]
"lastBalance": 725767, "earningsRate": -0.2742, "totalFee": 366911, "tradeCount": 76, "from": "2017-12-18 19:45", "to": "2018-04-10 10:00", "lastBalance": 1000767, "earningsRate": 0.0008, "totalFee": 442448, "tradeCount": 66, "from": "2018-01-01 14:00", "to": "2018-04-10 10:00",
[BCH]
"lastBalance": 4744167, "earningsRate": 3.7442, "totalFee": 2394884, "tradeCount": 154, "from": "2017-08-11 19:30", "to": "2018-04-10 10:00", "lastBalance": 897674, "earningsRate": -0.1023, "totalFee": 249780, "tradeCount": 54, "from": "2018-01-01 13:45", "to": "2018-04-10 10:00",
2. 세밀한 조정
if (BollingerBand(c,a1,a2)-BollingerBand(c,a1,-a2))>0 then begin
percentB=((c-BollingerBand(c,a1,-a2))/(BollingerBand(c,a1,a2)-BollingerBand(c,a1,-a2)))*100;
end else percentB=0;
if percentB>a3 then buy 1 contracts next bar at market;
if percentB<-a4 then sell 1 contracts next bar at market;
위 결과는 2015년부터 시뮬레이션한 결과입니다.
슬리피지를 20000원 적용했기 때문에 100만 원도 하지 않던 시절에는 승률이 당연히 떨어지게 보일 것이고 따라서 승률이 낮게 표시될 것입니다.
위 결과에서 네 가지를 선택했습니다.
매수 (102, 1, 120) >, 매도 (102, 1, -38)
"lastBalance": 1339591, "earningsRate": 0.3396, "totalFee": 338180, "tradeCount": 48, "from": "2018-01-02 22:15", "to": "2018-04-10 10:00",
매수 (100, 1, 122) >, 매도 (100, 1, -36)
"lastBalance": 1239322, "earningsRate": 0.2393, "totalFee": 345773, "tradeCount": 52, "from": "2018-01-02 22:15", "to": "2018-04-10 10:00",
매수 (104, 1, 140) >, 매도 (104, 1, -36)
"lastBalance": 1227280, "earningsRate": 0.2273, "totalFee": 284376, "tradeCount": 44, "from": "2018-01-03 03:15", "to": "2018-04-10 10:00",
매수 (106, 1, 138) >, 매도 (106, 1, -36)
"lastBalance": 1196951, "earningsRate": 0.197, "totalFee": 277629, "tradeCount": 44, "from": "2018-01-03 03:15", "to": "2018-04-10 10:00",
위 결과에서 매수와 매도를 비대칭 적으로 최적화해 봅니다.
var: percentB_B(0), percentB_S(0);
if (BollingerBand(c,a1,1)-BollingerBand(c,a1,-1))>0 then begin
percentB_B=((c-BollingerBand(c,a1,-1))/(BollingerBand(c,a1,1)-BollingerBand(c,a1,-1)))*100;
end else percentB_B=0;
if (BollingerBand(c,a2,1)-BollingerBand(c,a2,-1))>0 then begin
percentB_S=((c-BollingerBand(c,a2,-1))/(BollingerBand(c,a2,1)-BollingerBand(c,a2,-1)))*100;
end else percentB_S=0;
if percentB_B>a3 then buy 1 contracts next bar at market;
if percentB_S<-a4 then sell 1 contracts next bar at market;
워치봇 테스트 선별은 다음과 같습니다.
[BTC]
매수 (110, 1, 100) >, 매도 (100, 1, -40) <
"lastBalance": 1328466, "earningsRate": 0.3285, "totalFee": 359830, "tradeCount": 52, "from": "2018-01-01 12:15", "to": "2018-04-10 10:00",
매수 (50, 1, 150) >, 매도 (100, 1, -40) <
"lastBalance": 1277254, "earningsRate": 0.2773, "totalFee": 413796, "tradeCount": 59, "from": "2018-01-02 09:45", "to": "2018-04-10 10:00",
매수 (100, 1, 110) >, 매도 (80, 1, -30) <
"lastBalance": 552609, "earningsRate": -0.4474, "totalFee": 456775, "tradeCount": 113, "from": "2018-01-01 14:15", "to": "2018-04-10 10:00",
매수 (40, 1, 170) >, 매도 (70, 1, -60) <
"lastBalance": 1344313, "earningsRate": 0.3443, "totalFee": 351819, "tradeCount": 53, "from": "2018-01-02 22:15", "to": "2018-04-10 10:00",
매수 (50, 1, 150) >, 매도 (90, 1, -30) <
"lastBalance": 1445550, "earningsRate": 0.4456, "totalFee": 466287, "tradeCount": 61, "from": "2018-01-02 09:45", "to": "2018-04-10 10:00",
매수 (60, 1, 140) >, 매도 (90, 1, -30) <
"lastBalance": 1353406, "earningsRate": 0.3534, "totalFee": 414545, "tradeCount": 62, "from": "2018-01-01 16:15", "to": "2018-04-10 10:00",
매수 (100, 1, 110) >, 매도 (100, 1, -40) <
"lastBalance": 1219234, "earningsRate": 0.2192, "totalFee": 349912, "tradeCount": 54, "from": "2018-01-01 14:15", "to": "2018-04-10 10:00",
매수 (100, 1, 110) >, 매도 (90, 1, -30) <
"lastBalance": 1440543, "earningsRate": 0.4405, "totalFee": 384347, "tradeCount": 54, "from": "2018-01-01 14:15", "to": "2018-04-10 10:00",
매수 (50, 1, 150) >, 매도 (80, 1, -50) <
"lastBalance": 1199847, "earningsRate": 0.1998, "totalFee": 410525, "tradeCount": 61, "from": "2018-01-02 09:45", "to": "2018-04-10 10:00",
매수 (110, 1, 100) >, 매도 (70, 1, -60) <
"lastBalance": 1342046, "earningsRate": 0.342, "totalFee": 361944, "tradeCount": 52, "from": "2018-01-01 12:15", "to": "2018-04-10 10:00",
매수 (50, 1, 150) >, 매도 (70, 1, -60) <
"lastBalance": 1254005, "earningsRate": 0.254, "totalFee": 431401, "tradeCount": 61, "from": "2018-01-02 09:45", "to": "2018-04-10 10:00",
매수 (100, 1, 110) >, 매도 (70, 1, -60) <
"lastBalance": 1231697, "earningsRate": 0.2317, "totalFee": 352279, "tradeCount": 54, "from": "2018-01-01 14:15", "to": "2018-04-10 10:00",
매수 (50, 1, 170) >, 매도 (100, 1, -40) <
"lastBalance": 1296708, "earningsRate": 0.2967, "totalFee": 354198, "tradeCount": 51, "from": "2018-01-02 11:15", "to": "2018-04-10 10:00",
매수 (50, 1, 170) >, 매도 (70, 1, -60) <
"lastBalance": 1315076, "earningsRate": 0.3151, "totalFee": 357134, "tradeCount": 51, "from": "2018-01-02 11:15", "to": "2018-04-10 10:00",
매수 (50, 1, 180) >, 매도 (70, 1, -60) <
"lastBalance": 1430024, "earningsRate": 0.43, "totalFee": 294588, "tradeCount": 43, "from": "2018-01-03 03:15", "to": "2018-04-10 10:00",
2018년 BTC 복리 수익률과 기타 통계 값과 어떤 상관관계가 있는지 알아보기 위해 정렬해 보았습니다.
승률과 약한 양의 상관관계를 보이는 것 같습니다만 명확하지는 않습니다.
승률이 높고 수익률도 높은 구간에서 세밀하게 최적화해 보겠습니다.
매수 (46, 1, 180) >, 매도 (86, 1, -36) <
[BTC]
"lastBalance": 9043588, "earningsRate": 8.0436, "totalFee": 3925348, "tradeCount": 253, "from": "2017-01-01 19:15", "to": "2018-04-10 10:00", "lastBalance": 1536463, "earningsRate": 0.5365, "totalFee": 309775, "tradeCount": 43, "from": "2018-01-03 03:15", "to": "2018-04-10 10:00",
[ETH]
"lastBalance": 46932052, "earningsRate": 45.9321, "totalFee": 27554019, "tradeCount": 253, "from": "2017-01-01 11:30", "to": "2018-04-10 10:00", "lastBalance": 1196108, "earningsRate": 0.1961, "totalFee": 340961, "tradeCount": 49, "from": "2018-01-01 10:45", "to": "2018-04-10 10:00",
[LTC]
"lastBalance": 746685, "earningsRate": -0.2533, "totalFee": 342716, "tradeCount": 73, "from": "2017-12-18 20:45", "to": "2018-04-10 10:00", "lastBalance": 873615, "earningsRate": -0.1264, "totalFee": 356800, "tradeCount": 65, "from": "2018-01-02 10:45", "to": "2018-04-10 10:00",
위 결과에 STDEV 도 함께 최적화해보겠습니다.
var: percentB_B(0), percentB_S(0);
if (BollingerBand(c,46,a1)-BollingerBand(c,46,-a1))>0 then begin
percentB_B=((c-BollingerBand(c,46,-a1))/(BollingerBand(c,46,a1)-BollingerBand(c,46,-a1)))*100;
end else percentB_B=0;
if (BollingerBand(c,86,a2)-BollingerBand(c,86,-a2))>0 then begin
percentB_S=((c-BollingerBand(c,86,-a2))/(BollingerBand(c,86,a2)-BollingerBand(c,86,-a2)))*100;
end else percentB_S=0;
if percentB_B>a3 then buy 1 contracts next bar at market;
if percentB_S<-a4 then sell 1 contracts next bar at market;
매수 (46, 1, 180) >, 매도 (86, 1.5, -37) <
"lastBalance": 10393194, "earningsRate": 9.3932, "totalFee": 3490018, "tradeCount": 187, "from": "2017-01-01 19:15", "to": "2018-04-10 10:00",
"lastBalance": 1592170, "earningsRate": 0.5922, "totalFee": 259707, "tradeCount": 35, "from": "2018-01-03 03:15", "to": "2018-04-10 10:00",
3. 손절/익절
위 결과에 손절과 익절을 적용해 보겠습니다.
var: percentB_B(0), percentB_S(0);
if (BollingerBand(c,46,1)-BollingerBand(c,46,-1))>0 then begin
percentB_B=((c-BollingerBand(c,46,-1))/(BollingerBand(c,46,1)-BollingerBand(c,46,-1)))*100;
end else percentB_B=0;
if (BollingerBand(c,86,1.5)-BollingerBand(c,86,-1.5))>0 then begin
percentB_S=((c-BollingerBand(c,86,-1.5))/(BollingerBand(c,86,1.5)-BollingerBand(c,86,-1.5)))*100;
end else percentB_S=0;
if percentB_B>180 then buy 1 contracts next bar at market;
if percentB_S<-37 then sell 1 contracts next bar at market;
setprofittarget(c*0.01*a1);
위 결과에서 고르면 됩니다.
개인적으로는 16, 16.5, 14.5, 15, 13.5 와 같이 상대적으로 낮으면서도 수익을 해치지 않는 값이 좋습니다.
13.5%, 16% 를 선택해 보았습니다.
매수 (46, 1, 180) >, 매도 (86, 1.5, -37) < 익절 13.5%
"lastBalance": 6900478, "earningsRate": 5.9005, "totalFee": 3692950, "tradeCount": 267, "from": "2017-01-01 19:15", "to": "2018-04-10 10:00", "lastBalance": 1596539, "earningsRate": 0.5965, "totalFee": 347672, "tradeCount": 47, "from": "2018-01-03 03:15", "to": "2018-04-10 10:00",
매수 (46, 1, 180) >, 매도 (86, 1.5, -37) < 익절 16%
"lastBalance": 8732563, "earningsRate": 7.7326, "totalFee": 4446629, "tradeCount": 259, "from": "2017-01-01 19:15", "to": "2018-04-10 10:00",
"lastBalance": 1534270, "earningsRate": 0.5343, "totalFee": 349664, "tradeCount": 47, "from": "2018-01-03 03:15", "to": "2018-04-10 10:00",
전체 수익은 줄이고, 최근 수익은 유지됩니다.
손절을 추가해 보겠습니다.
손절은 익절에도 영향을 줄 수 있기 때문에 같이 확인해 보겠습니다.
Trailing-Stop을 걸어보겠습니다.
Trailing-Stop 착각을 일으키게 할 수 있는 매우 위험한 기능입니다.
Multichart에도 setpercenttrailing 이란 기능이 있지만 종가 기준으로 바꿔서 테스트해보겠습니다.
var: percentB_B(0), percentB_S(0);
if (BollingerBand(c,46,1)-BollingerBand(c,46,-1))>0 then begin
percentB_B=((c-BollingerBand(c,46,-1))/(BollingerBand(c,46,1)-BollingerBand(c,46,-1)))*100;
end else percentB_B=0;
if (BollingerBand(c,86,1.5)-BollingerBand(c,86,-1.5))>0 then begin
percentB_S=((c-BollingerBand(c,86,-1.5))/(BollingerBand(c,86,1.5)-BollingerBand(c,86,-1.5)))*100;
end else percentB_S=0;
if percentB_B>180 then buy 1 contracts next bar at market;if percentB_S<-37 then sell 1 contracts next bar at market;
setprofittarget(c*0.01*16.4);
setstoploss(c*0.01*14.4);
if maxpositionprofit>c*0.01*a1 and positionprofit<c*0.01*(a1-a2) then sell 1 contracts next bar at market;
setprofittarget(c*0.01*16.4);
setstoploss(c*0.01*14.4);
if maxpositionprofit>c*0.01*15.3 and positionprofit<c*0.01*(15.3-4.1) then sell 1 contracts next bar at market;
위 결과가 최종입니다.
보통 위와 같은 과정으로 점점 최적화하게 되는데 정답은 아닙니다.
너무 최적화하다 보면 과거 수익률에 취하게 됩니다.
수익률은 적절히 본인이 원하는 수준인 것이 좋습니다.
4. 역추세형
var: percentB(0);
if (BollingerBand(c,a1,a2)-BollingerBand(c,a1,-a2))>0 then begin
percentB=((c-BollingerBand(c,a1,-a2))/(BollingerBand(c,a1,a2)-BollingerBand(c,a1,-a2)))*100;
end else percentB=0;
if percentB<a3 then buy 1 contracts next bar at market;
if percentB>a3+a4 then sell 1 contracts next bar at market;
과거에 수익이 나는 결과는 확인했습니다만 최근에는 20% 이상 손실이 발생하기 때문에 생략하도록 하겠습니다.