비트코인 · 자동매매 봇 · 익절 · 실측 재현 페이지
같은 비트코인 봇(트레이딩뷰 슈퍼트렌드 기본값 + 일봉 30일 평균 조건)에 익절만 다르게 걸고 돌렸습니다. 바이낸스 비트코인 현물 실제 가격 · 2017년 12월 2일 ~ 2026년 10월 28일(UTC) · 1,000만원 · 사고팔 때마다 편도 0.1%. 업비트 가격으로도 같이 돌렸고, 영상의 숫자는 덜 나온 바이낸스 쪽입니다.
| 항목 | 값 |
|---|---|
| 차트 | 비트코인 4시간봉 |
| 슈퍼트렌드 | 트레이딩뷰 기본값 — ATR 길이 10 · 배수 3. 초록(상승)일 때만 산다 |
| 조건 | 4시간봉 종가가 어제까지 끝난 일봉(UTC) 30일 평균보다 높을 때만 |
| 판다 | 슈퍼트렌드가 빨강으로 바뀌거나, 종가가 그 30일 평균 밑으로 내려가면 |
| 얼마나 사나 | 살 때 계좌 전부(100%) · 현물 · 공매도 없음 |
| 체결 | 4시간봉이 끝날 때 판정 → 다음 봉 시가에 체결 · 편도 수수료 0.1% |
| 10% 익절 계좌 | 위 규칙에 하나 더: 산 값(신호 봉 종가)보다 4시간봉 종가가 10% 이상이면 다음 봉 시가에 전부 판다 → 신호가 꺼졌다 다시 켜질 때까지 쉰다 |
| 익절 | 바이낸스 1,000만원 → | 가장 깊은 하락 | 업비트 1,000만원 → | 가장 깊은 하락 |
|---|---|---|---|---|
| 익절 없음 | 1억 5,550만원 | -36.7% | 8억 1,151만원 | -32.0% |
| 10% 전부 익절 | 2,396만원 | -32.4% | 9,490만원 | -25.9% |
| 25% 전부 익절 | 1억 1,971만원 | -35.5% | 3억 7,840만원 | -31.1% |
| 50% 전부 익절 | 1억 6,103만원 | -36.6% | 8억 549만원 | -32.0% |
| 25%에서 절반 | 1억 4,105만원 | -35.5% | 5억 8,376만원 | -31.1% |
| 50%에서 절반 | 1억 5,952만원 | -36.6% | 8억 2,156만원 | -32.0% |
바이낸스 금액은 달러 가격의 배수를 1,000만원에 곱한 값입니다(환율 변화 미반영 — 두 계좌 비교에는 영향 없음). 10% 익절 계좌가 가장 크게 빠졌을 때의 하락 폭은 조금 작았습니다 — 그 대신 남은 돈이 6분의 1도 안 됩니다.
거래 249번 중 번 거래 117번 · 잃은 거래 132번 — 봇은 절반 넘게 조금씩 잃고, 크게 오르는 몇 번이 메웁니다. 10%를 넘긴 거래 42번을 익절 계좌가 실제로 판 값(10%를 넘긴 다음 봉 시가)과 견주면 28번은 익절 없는 봇이 더 받았고 14번은 익절 계좌가 더 받았습니다. 거래마다 더 받은 몫을 모으면 봇 쪽 463.5%포인트 대 익절 쪽 41.8%포인트입니다. 이 42번 중 봇이 손실로 판 거래는 0번입니다(10% 선과 견주면 31번이 10%보다 높게, 11번이 10% 아래에서 팔렸습니다). 가장 크게 번 거래는 2020-12-13 진입 거래(98.2%)였고, 10% 익절 계좌는 그때도 10% 남짓에서 팔았습니다. 10%를 넘긴 거래 중 가운데: 2018-04-12T20:00 진입 → 8일 뒤 2018-04-20 10% 넘음 → 봇은 15.3% 에 팜.
10% 익절 계좌는 팔고 쉬는 날이 많아 평균 보유 비중이 25.8%였습니다. 익절 없는 봇의 살 때 비중을 0.674로 줄여 평균 보유 비중을 똑같이 맞추면 바이낸스 비트코인 7,675만원(10% 익절 2,396만원) — 12개 중 12/12에서 익절 없는 쪽이 더 남았습니다(공개 코드 출력의 「똑같이 맞추면」 줄).
| 익절 | 익절 없음보다 덜 남은 경우 |
|---|---|
| 10% 전부 익절 | 12 / 12 |
| 25% 전부 익절 | 11 / 12 |
| 50% 전부 익절 | 5 / 12 |
| 25%에서 절반 | 10 / 12 |
| 50%에서 절반 | 4 / 12 |
50%에서 절반 익절은 봇에 따라 갈렸습니다 — 특히 이동평균 교차 봇에서 덜 남았습니다. 「꼭 걸고 싶다면 50%에서 절반」은 이 비트코인 슈퍼트렌드 봇에서 결과가 거의 같았다는 뜻이지, 어느 봇에서나 같다는 뜻은 아닙니다. 지정가 익절(봉 안에서 +10%에 닿으면 정확히 +10%에 체결)로 다시 재도 10% 익절은 12개 모두 덜 남았습니다(바이낸스 비트코인 1억 5,517만원 대 2,406만원 — 연구 기록).
| 코인 · 봇 규칙 | 익절 | 바이낸스 | 하락 | 업비트 | 하락 |
|---|---|---|---|---|---|
| BTC · 슈퍼트렌드(10·3) | 익절 없음 | 1억 5,550만원 | -36.7% | 8억 1,151만원 | -32.0% |
| BTC · 슈퍼트렌드(10·3) | 10% 전부 익절 | 2,396만원 | -32.4% | 9,490만원 | -25.9% |
| BTC · 슈퍼트렌드(10·3) | 25% 전부 익절 | 1억 1,971만원 | -35.5% | 3억 7,840만원 | -31.1% |
| BTC · 슈퍼트렌드(10·3) | 50% 전부 익절 | 1억 6,103만원 | -36.6% | 8억 549만원 | -32.0% |
| BTC · 슈퍼트렌드(10·3) | 25%에서 절반 | 1억 4,105만원 | -35.5% | 5억 8,376만원 | -31.1% |
| BTC · 슈퍼트렌드(10·3) | 50%에서 절반 | 1억 5,952만원 | -36.6% | 8억 2,156만원 | -32.0% |
| BTC · 이동평균 50/200 교차 | 익절 없음 | 1억 4,931만원 | -72.0% | 7억 4,210만원 | -48.5% |
| BTC · 이동평균 50/200 교차 | 10% 전부 익절 | 2,051만원 | -38.3% | 1,830만원 | -34.5% |
| BTC · 이동평균 50/200 교차 | 25% 전부 익절 | 3,925만원 | -56.5% | 9,901만원 | -27.6% |
| BTC · 이동평균 50/200 교차 | 50% 전부 익절 | 1억 2,416만원 | -56.5% | 2억 6,496만원 | -48.5% |
| BTC · 이동평균 50/200 교차 | 25%에서 절반 | 8,339만원 | -67.5% | 3억 1,687만원 | -36.6% |
| BTC · 이동평균 50/200 교차 | 50%에서 절반 | 1억 4,160만원 | -66.9% | 4억 7,513만원 | -48.5% |
| BTC · 켈트너 돌파(20·1.5) | 익절 없음 | 7,992만원 | -40.3% | 7억 1,930만원 | -31.3% |
| BTC · 켈트너 돌파(20·1.5) | 10% 전부 익절 | 5,024만원 | -33.3% | 1억 8,798만원 | -20.9% |
| BTC · 켈트너 돌파(20·1.5) | 25% 전부 익절 | 8,476만원 | -36.7% | 7억 1,656만원 | -20.9% |
| BTC · 켈트너 돌파(20·1.5) | 50% 전부 익절 | 9,882만원 | -36.7% | 10억 3,967만원 | -23.3% |
| BTC · 켈트너 돌파(20·1.5) | 25%에서 절반 | 8,258만원 | -36.7% | 7억 2,181만원 | -21.2% |
| BTC · 켈트너 돌파(20·1.5) | 50%에서 절반 | 8,914만원 | -36.7% | 8억 7,057만원 | -23.3% |
| ETH · 슈퍼트렌드(10·3) | 익절 없음 | 10억 9,364만원 | -36.4% | 35억 8,005만원 | -30.9% |
| ETH · 슈퍼트렌드(10·3) | 10% 전부 익절 | 3,919만원 | -42.9% | 9,832만원 | -24.4% |
| ETH · 슈퍼트렌드(10·3) | 25% 전부 익절 | 4억 7,065만원 | -36.1% | 12억 2,710만원 | -28.7% |
| ETH · 슈퍼트렌드(10·3) | 50% 전부 익절 | 15억 3,282만원 | -36.4% | 41억 228만원 | -28.7% |
| ETH · 슈퍼트렌드(10·3) | 25%에서 절반 | 7억 5,092만원 | -36.1% | 22억 1,272만원 | -28.7% |
| ETH · 슈퍼트렌드(10·3) | 50%에서 절반 | 13억 471만원 | -36.4% | 38억 6,952만원 | -28.7% |
| ETH · 이동평균 50/200 교차 | 익절 없음 | 10억 8,221만원 | -54.3% | 11억 9,166만원 | -57.3% |
| ETH · 이동평균 50/200 교차 | 10% 전부 익절 | 5,550만원 | -39.1% | 1,375만원 | -48.0% |
| ETH · 이동평균 50/200 교차 | 25% 전부 익절 | 9,123만원 | -37.3% | 1억 698만원 | -35.3% |
| ETH · 이동평균 50/200 교차 | 50% 전부 익절 | 4억 2,877만원 | -37.3% | 7억 2,658만원 | -39.8% |
| ETH · 이동평균 50/200 교차 | 25%에서 절반 | 3억 8,488만원 | -47.8% | 4억 3,929만원 | -52.7% |
| ETH · 이동평균 50/200 교차 | 50%에서 절반 | 7억 4,787만원 | -42.6% | 10억 3,254만원 | -46.5% |
| ETH · 켈트너 돌파(20·1.5) | 익절 없음 | 6억 962만원 | -33.7% | 96억 9,678만원 | -29.8% |
| ETH · 켈트너 돌파(20·1.5) | 10% 전부 익절 | 1억 3,161만원 | -33.7% | 5억 9,239만원 | -24.4% |
| ETH · 켈트너 돌파(20·1.5) | 25% 전부 익절 | 5억 7,634만원 | -33.7% | 46억 3,993만원 | -29.8% |
| ETH · 켈트너 돌파(20·1.5) | 50% 전부 익절 | 6억 8,990만원 | -33.7% | 106억 2,312만원 | -29.8% |
| ETH · 켈트너 돌파(20·1.5) | 25%에서 절반 | 6억 702만원 | -33.7% | 69억 3,780만원 | -29.8% |
| ETH · 켈트너 돌파(20·1.5) | 50%에서 절반 | 6억 4,923만원 | -33.7% | 101억 8,478만원 | -29.8% |
돌리는 법: zip 을 풀고 python run_takeprofit.py
비트코인 봇에 10% 익절을 걸까, 봇이 팔 때까지 둘까 — 재현 코드 (알고랩 · 2026-10-29 영상)
기준일: 2026-10-28T16:00:00 UTC 봉까지
■ BTC · 슈퍼트렌드(10·3) · 2017-12-02 ~ 2026-10-28 · 1,000만원
익절 없음 바이낸스 1억 5,550만원 (가장 깊은 하락 -36.7%) | 업비트 8억 1,151만원 (가장 깊은 하락 -32.0%)
10% 전부 익절 바이낸스 2,396만원 (가장 깊은 하락 -32.4%) | 업비트 9,490만원 (가장 깊은 하락 -25.9%)
25% 전부 익절 바이낸스 1억 1,971만원 (가장 깊은 하락 -35.5%) | 업비트 3억 7,840만원 (가장 깊은 하락 -31.1%)
50% 전부 익절 바이낸스 1억 6,103만원 (가장 깊은 하락 -36.6%) | 업비트 8억 549만원 (가장 깊은 하락 -32.0%)
25%에서 절반 바이낸스 1억 4,105만원 (가장 깊은 하락 -35.5%) | 업비트 5억 8,376만원 (가장 깊은 하락 -31.1%)
50%에서 절반 바이낸스 1억 5,952만원 (가장 깊은 하락 -36.6%) | 업비트 8억 2,156만원 (가장 깊은 하락 -32.0%)
익절 없이 보유 비중만 10% 익절 계좌와 똑같이 맞추면: 바이낸스 살 때 비중 0.674 → 7,675만원 (10% 익절 2,396만원 · 평균 보유 비중 25.8%) | 업비트 살 때 비중 0.674 → 2억 3,855만원 (10% 익절 9,490만원 · 평균 보유 비중 25.2%)
■ BTC · 이동평균 50/200 교차 · 2017-12-02 ~ 2026-10-28 · 1,000만원
익절 없음 바이낸스 1억 4,931만원 (가장 깊은 하락 -72.0%) | 업비트 7억 4,210만원 (가장 깊은 하락 -48.5%)
10% 전부 익절 바이낸스 2,051만원 (가장 깊은 하락 -38.3%) | 업비트 1,830만원 (가장 깊은 하락 -34.5%)
25% 전부 익절 바이낸스 3,925만원 (가장 깊은 하락 -56.5%) | 업비트 9,901만원 (가장 깊은 하락 -27.6%)
50% 전부 익절 바이낸스 1억 2,416만원 (가장 깊은 하락 -56.5%) | 업비트 2억 6,496만원 (가장 깊은 하락 -48.5%)
25%에서 절반 바이낸스 8,339만원 (가장 깊은 하락 -67.5%) | 업비트 3억 1,687만원 (가장 깊은 하락 -36.6%)
50%에서 절반 바이낸스 1억 4,160만원 (가장 깊은 하락 -66.9%) | 업비트 4억 7,513만원 (가장 깊은 하락 -48.5%)
익절 없이 보유 비중만 10% 익절 계좌와 똑같이 맞추면: 바이낸스 살 때 비중 0.371 → 3,619만원 (10% 익절 2,051만원 · 평균 보유 비중 18.1%) | 업비트 살 때 비중 0.356 → 6,840만원 (10% 익절 1,830만원 · 평균 보유 비중 18.1%)
■ BTC · 켈트너 돌파(20·1.5) · 2017-12-02 ~ 2026-10-28 · 1,000만원
익절 없음 바이낸스 7,992만원 (가장 깊은 하락 -40.3%) | 업비트 7억 1,930만원 (가장 깊은 하락 -31.3%)
10% 전부 익절 바이낸스 5,024만원 (가장 깊은 하락 -33.3%) | 업비트 1억 8,798만원 (가장 깊은 하락 -20.9%)
25% 전부 익절 바이낸스 8,476만원 (가장 깊은 하락 -36.7%) | 업비트 7억 1,656만원 (가장 깊은 하락 -20.9%)
50% 전부 익절 바이낸스 9,882만원 (가장 깊은 하락 -36.7%) | 업비트 10억 3,967만원 (가장 깊은 하락 -23.3%)
25%에서 절반 바이낸스 8,258만원 (가장 깊은 하락 -36.7%) | 업비트 7억 2,181만원 (가장 깊은 하락 -21.2%)
50%에서 절반 바이낸스 8,914만원 (가장 깊은 하락 -36.7%) | 업비트 8억 7,057만원 (가장 깊은 하락 -23.3%)
익절 없이 보유 비중만 10% 익절 계좌와 똑같이 맞추면: 바이낸스 살 때 비중 0.796 → 5,657만원 (10% 익절 5,024만원 · 평균 보유 비중 19.4%) | 업비트 살 때 비중 0.756 → 2억 8,188만원 (10% 익절 1억 8,798만원 · 평균 보유 비중 18.4%)
■ ETH · 슈퍼트렌드(10·3) · 2017-12-05 ~ 2026-10-28 · 1,000만원
익절 없음 바이낸스 10억 9,364만원 (가장 깊은 하락 -36.4%) | 업비트 35억 8,005만원 (가장 깊은 하락 -30.9%)
10% 전부 익절 바이낸스 3,919만원 (가장 깊은 하락 -42.9%) | 업비트 9,832만원 (가장 깊은 하락 -24.4%)
25% 전부 익절 바이낸스 4억 7,065만원 (가장 깊은 하락 -36.1%) | 업비트 12억 2,710만원 (가장 깊은 하락 -28.7%)
50% 전부 익절 바이낸스 15억 3,282만원 (가장 깊은 하락 -36.4%) | 업비트 41억 228만원 (가장 깊은 하락 -28.7%)
25%에서 절반 바이낸스 7억 5,092만원 (가장 깊은 하락 -36.1%) | 업비트 22억 1,272만원 (가장 깊은 하락 -28.7%)
50%에서 절반 바이낸스 13억 471만원 (가장 깊은 하락 -36.4%) | 업비트 38억 6,952만원 (가장 깊은 하락 -28.7%)
익절 없이 보유 비중만 10% 익절 계좌와 똑같이 맞추면: 바이낸스 살 때 비중 0.561 → 1억 9,238만원 (10% 익절 3,919만원 · 평균 보유 비중 21.1%) | 업비트 살 때 비중 0.545 → 3억 4,427만원 (10% 익절 9,832만원 · 평균 보유 비중 19.9%)
■ ETH · 이동평균 50/200 교차 · 2017-12-05 ~ 2026-10-28 · 1,000만원
익절 없음 바이낸스 10억 8,221만원 (가장 깊은 하락 -54.3%) | 업비트 11억 9,166만원 (가장 깊은 하락 -57.3%)
10% 전부 익절 바이낸스 5,550만원 (가장 깊은 하락 -39.1%) | 업비트 1,375만원 (가장 깊은 하락 -48.0%)
25% 전부 익절 바이낸스 9,123만원 (가장 깊은 하락 -37.3%) | 업비트 1억 698만원 (가장 깊은 하락 -35.3%)
50% 전부 익절 바이낸스 4억 2,877만원 (가장 깊은 하락 -37.3%) | 업비트 7억 2,658만원 (가장 깊은 하락 -39.8%)
25%에서 절반 바이낸스 3억 8,488만원 (가장 깊은 하락 -47.8%) | 업비트 4억 3,929만원 (가장 깊은 하락 -52.7%)
50%에서 절반 바이낸스 7억 4,787만원 (가장 깊은 하락 -42.6%) | 업비트 10억 3,254만원 (가장 깊은 하락 -46.5%)
익절 없이 보유 비중만 10% 익절 계좌와 똑같이 맞추면: 바이낸스 살 때 비중 0.330 → 7,609만원 (10% 익절 5,550만원 · 평균 보유 비중 16.3%) | 업비트 살 때 비중 0.362 → 9,418만원 (10% 익절 1,375만원 · 평균 보유 비중 18.0%)
■ ETH · 켈트너 돌파(20·1.5) · 2017-12-05 ~ 2026-10-28 · 1,000만원
익절 없음 바이낸스 6억 962만원 (가장 깊은 하락 -33.7%) | 업비트 96억 9,678만원 (가장 깊은 하락 -29.8%)
10% 전부 익절 바이낸스 1억 3,161만원 (가장 깊은 하락 -33.7%) | 업비트 5억 9,239만원 (가장 깊은 하락 -24.4%)
25% 전부 익절 바이낸스 5억 7,634만원 (가장 깊은 하락 -33.7%) | 업비트 46억 3,993만원 (가장 깊은 하락 -29.8%)
50% 전부 익절 바이낸스 6억 8,990만원 (가장 깊은 하락 -33.7%) | 업비트 106억 2,312만원 (가장 깊은 하락 -29.8%)
25%에서 절반 바이낸스 6억 702만원 (가장 깊은 하락 -33.7%) | 업비트 69억 3,780만원 (가장 깊은 하락 -29.8%)
50%에서 절반 바이낸스 6억 4,923만원 (가장 깊은 하락 -33.7%) | 업비트 101억 8,478만원 (가장 깊은 하락 -29.8%)
익절 없이 보유 비중만 10% 익절 계좌와 똑같이 맞추면: 바이낸스 살 때 비중 0.711 → 2억 1,813만원 (10% 익절 1억 3,161만원 · 평균 보유 비중 16.5%) | 업비트 살 때 비중 0.668 → 12억 3,335만원 (10% 익절 5억 9,239만원 · 평균 보유 비중 16.0%)
■ 익절 없음보다 돈이 적게 남은 경우 (12개 = 코인 2 × 봇 규칙 3 × 거래소 2)
10% 전부 익절: 12/12
25% 전부 익절: 11/12
50% 전부 익절: 5/12
25%에서 절반: 10/12
50%에서 절반: 4/12
■ 10% 익절 계좌와 평균 보유 비중을 똑같이 맞춘 익절 없는 봇이 더 남긴 경우: 12/12
■ 비트코인 슈퍼트렌드 봇(익절 없음) 거래 하나하나 — 2017-12-02 이후 진입
바이낸스: 거래 249번 · 번 거래 117번 · 잃은 거래 132번
10% 를 넘긴 거래 42번 — 봇이 10% 보다 높은 값에 판 거래 31번 · 10% 아래로 판 거래 11번 · 손실로 끝난 거래 0번
익절 계좌가 실제로 판 값과 견주면 — 익절 없는 봇이 더 받은 거래 28번 · 익절 계좌가 더 받은 거래 14번 · 더 받은 몫을 모으면 봇 쪽 463.5%포인트 대 익절 쪽 41.8%포인트
가장 크게 번 거래: 2020-12-13 진입 · 98.2%
10% 를 넘긴 거래 중 가운데: 2018-04-12T20:00 진입 → 8일 뒤 2018-04-20 10% 넘음 → 봇은 15.3% 에 팜
업비트: 거래 224번 · 번 거래 118번 · 잃은 거래 106번
10% 를 넘긴 거래 43번 — 봇이 10% 보다 높은 값에 판 거래 28번 · 10% 아래로 판 거래 15번 · 손실로 끝난 거래 0번
익절 계좌가 실제로 판 값과 견주면 — 익절 없는 봇이 더 받은 거래 27번 · 익절 계좌가 더 받은 거래 16번 · 더 받은 몫을 모으면 봇 쪽 527.7%포인트 대 익절 쪽 51.8%포인트
가장 크게 번 거래: 2020-12-13 진입 · 113.3%
끝.
# -*- coding: utf-8 -*-
"""비트코인 봇에 10% 익절을 걸까, 봇이 팔 때까지 둘까 — 재현 코드 (알고랩 · 2026-10-29 영상)
파이썬 표준 라이브러리만 씁니다. 같은 폴더의 data/ 에 가격 자료(4시간봉 CSV)가 있어야 합니다.
python run_takeprofit.py
봇 규칙
· 4시간봉 슈퍼트렌드(트레이딩뷰 기본값 ATR 10 · 배수 3)가 상승(초록)이고
· 4시간봉 종가가 '어제까지 끝난' 일봉(UTC) 30일 평균보다 높을 때 산다(계좌 전부 · 현물).
· 둘 중 하나라도 꺼지면 판다. 봉 마감에 판정하고 다음 봉 시가에 체결. 편도 수수료 0.1%.
익절 계좌는 여기에 하나를 더한다
· 산 값(신호 봉 종가)보다 4시간봉 종가가 p% 이상이면 다음 봉 시가에 판다(전부 또는 절반).
· 전부 판 뒤에는 신호가 꺼졌다 다시 켜질 때까지 쉰다.
기준일 고정(ASOF): 2026-10-28 16:00 UTC 봉까지. 바이낸스 금액은 달러 가격의 배수를 1,000만원에 곱한 값."""
import csv, datetime, math, os
HERE = os.path.dirname(os.path.abspath(__file__))
ASOF = "2026-10-28T16:00:00"
COST = 0.001
WARM = 400
SEED = 1000 # 만원
NaN = float("nan")
def load(fn):
d, o, h, l, c = [], [], [], [], []
with open(os.path.join(HERE, "data", fn), encoding="utf-8") as f:
r = csv.reader(f); next(r)
for row in r:
if row[0] > ASOF:
break
d.append(row[0]); o.append(float(row[1])); h.append(float(row[2])); l.append(float(row[3])); c.append(float(row[4]))
return dict(d=d, o=o, h=h, l=l, c=c, n=len(c))
def sma(x, n):
"""누적합 차이로 계산한다(연구 코드 numpy 판과 같은 반올림)."""
cs = [0.0]
for v in x:
cs.append(cs[-1] + v)
return [NaN if i < n - 1 else (cs[i + 1] - cs[i + 1 - n]) / n for i in range(len(x))]
def ema(x, n):
a = 2.0 / (n + 1); out = [x[0]]
for v in x[1:]:
out.append(a * v + (1 - a) * out[-1])
return out
def atr(h, l, c, n):
tr = [max(h[i] - l[i], abs(h[i] - (c[i - 1] if i else c[0])), abs(l[i] - (c[i - 1] if i else c[0]))) for i in range(len(c))]
a = [NaN] * len(c)
if len(c) >= n:
a[n - 1] = sum(tr[:n]) / n
for i in range(n, len(c)):
a[i] = a[i - 1] + (tr[i] - a[i - 1]) / n
return a
def supertrend(S, n=10, mult=3.0):
h, l, c = S["h"], S["l"], S["c"]
a = atr(h, l, c, n)
up = [(h[i] + l[i]) / 2 - mult * a[i] for i in range(S["n"])]
dn = [(h[i] + l[i]) / 2 + mult * a[i] for i in range(S["n"])]
d = [1.0] * S["n"]
for i in range(1, S["n"]):
if math.isnan(a[i]):
continue
if c[i - 1] > up[i - 1]:
up[i] = max(up[i], up[i - 1])
if c[i - 1] < dn[i - 1]:
dn[i] = min(dn[i], dn[i - 1])
if c[i] > dn[i - 1]:
d[i] = 1.0
elif c[i] < up[i - 1]:
d[i] = -1.0
else:
d[i] = d[i - 1]
return [1.0 if x > 0 else 0.0 for x in d]
def ma_cross(S, fast=50, slow=200):
f, s = sma(S["c"], fast), sma(S["c"], slow)
return [1.0 if (not math.isnan(f[i]) and not math.isnan(s[i]) and f[i] > s[i]) else 0.0 for i in range(S["n"])]
def keltner(S, n=20, k=1.5):
c = S["c"]; e = ema(c, n); a = atr(S["h"], S["l"], c, n)
out, st = [], 0.0
for i in range(S["n"]):
buy = (not math.isnan(a[i])) and c[i] > e[i] + k * a[i]
if i < n + 1:
st = 0.0
elif buy:
st = 1.0
elif c[i] < e[i]:
st = 0.0
out.append(st)
return out
def daily_filter(S, n=30):
days = [x[:10] for x in S["d"]]
uniq, last = [], []
for i, dd in enumerate(days):
if not uniq or uniq[-1] != dd:
uniq.append(dd); last.append(i)
else:
last[-1] = i
dsma = sma([S["c"][i] for i in last], n)
f, j = [], -1
for i, dd in enumerate(days):
if j < 0 or uniq[j] != dd:
j += 1
y = j - 1
f.append(1.0 if (y >= 0 and not math.isnan(dsma[y]) and S["c"][i] > dsma[y]) else 0.0)
return f
def take_profit(S, base, levels):
"""levels = ((수익률, 그때부터의 비중), …). 비중 0 = 전부 판다(신호가 꺼질 때까지 쉼)."""
c = S["c"]; out = [0.0] * S["n"]; holding, armed, e, w = False, True, 0.0, 1.0
for t in range(S["n"]):
on = base[t] > 0
if not holding:
if not on:
armed = True
elif armed:
holding, e, w = True, c[t], 1.0
if holding:
if not on:
holding = False; out[t] = 0.0; continue
for p, lw in levels:
if c[t] / e - 1 >= p:
w = min(w, lw)
out[t] = w
return out
def run(S, w, want_pos=False):
"""수량 고정 엔진: 0→x 면 계좌 x 만큼 수량을 산다 · x→y 면 수량 × y/x · →0 이면 전부 판다. 다음 봉 시가 체결."""
o, c, n = S["o"], S["c"], S["n"]
cash, qty, eq, pos = 1.0, 0.0, [1.0] * n, [0.0] * n
for t in range(1, n):
wn, wp = w[t - 1], (w[t - 2] if t >= 2 else 0.0)
if wn != wp:
px = o[t]
if wp == 0 and wn > 0:
q = wn * (cash + qty * c[t - 1]) / c[t - 1]
elif wn == 0:
q = 0.0
else:
q = qty * wn / wp
dq = q - qty
cash -= dq * px + COST * abs(dq) * px
qty = q
eq[t] = cash + qty * c[t]
pos[t] = qty * c[t] / eq[t] if eq[t] > 0 else 0.0
return (eq, pos) if want_pos else eq
def window(series):
day = lambda s: datetime.date.fromisoformat(s[:10])
a = max(day(S["d"][WARM]) for S in series)
b = min(day(S["d"][-1]) for S in series) + datetime.timedelta(days=1)
return a, b
def stat(S, eq, a, b):
ds = [x[:10] for x in S["d"]]
i = next(k for k, x in enumerate(ds) if x >= a.isoformat())
j = next((k for k, x in enumerate(ds) if x >= b.isoformat()), S["n"])
e = [v / eq[i] for v in eq[i:j]]
peak, mdd = e[0], 0.0
for v in e:
peak = max(peak, v); mdd = min(mdd, v / peak - 1)
yrs = (datetime.date.fromisoformat(S["d"][j - 1][:10]) - datetime.date.fromisoformat(S["d"][i][:10])).days / 365.25
return SEED * e[-1], e[-1] ** (1 / yrs) - 1, mdd, i, j
def exposure(S, w, i, j):
"""평균 보유 비중 — 봉 끝마다 (코인 평가액 ÷ 계좌) 의 평균."""
_, pos = run(S, w, True)
return sum(pos[i:j]) / (j - i)
def match_k(S, base, target, i, j):
"""익절 없는 봇의 살 때 비중 k 를 줄여 평균 보유 비중을 target 에 맞춘다(이분법 14번)."""
lo, hi = 0.05, 1.0
for _ in range(14):
k = (lo + hi) / 2
if exposure(S, [x * k for x in base], i, j) < target:
lo = k
else:
hi = k
return (lo + hi) / 2
def won(x):
x = round(x)
return f"{x // 10000}억 {x % 10000:,}만원" if x >= 10000 else f"{x:,}만원"
VARS = [("익절 없음", None), ("10% 전부 익절", ((0.10, 0.0),)), ("25% 전부 익절", ((0.25, 0.0),)),
("50% 전부 익절", ((0.50, 0.0),)), ("25%에서 절반", ((0.25, 0.5),)), ("50%에서 절반", ((0.50, 0.5),))]
RULES = [("슈퍼트렌드(10·3)", supertrend), ("이동평균 50/200 교차", ma_cross), ("켈트너 돌파(20·1.5)", keltner)]
print(__doc__.split("\n")[0]); print("기준일:", ASOF, "UTC 봉까지\n")
less = {v[0]: 0 for v in VARS[1:]}; total = 0; match_win = 0
for coin in ("BTC", "ETH"):
mk = {"바이낸스": load(f"{coin}USDT_4h.csv"), "업비트": load(f"KRW-{coin}_4h.csv")}
a, b = window(mk.values())
filt = {m: daily_filter(S) for m, S in mk.items()}
for rn, fn in RULES:
print(f"■ {coin} · {rn} · {a} ~ {b - datetime.timedelta(days=1)} · 1,000만원")
res = {}
for m, S in mk.items():
base = [x * y for x, y in zip(fn(S), filt[m])]
for vn, lv in VARS:
w = base if lv is None else take_profit(S, base, lv)
res[(m, vn)] = stat(S, run(S, w), a, b)
for vn, _ in VARS:
print(f" {vn:10s} " + " | ".join(f"{m} {won(res[(m, vn)][0])} (가장 깊은 하락 {res[(m, vn)][2] * 100:.1f}%)" for m in mk))
mt = []
for m, S in mk.items():
base = [x * y for x, y in zip(fn(S), filt[m])]
i, j = res[(m, "익절 없음")][3:5]
tgt = exposure(S, take_profit(S, base, ((0.10, 0.0),)), i, j)
k = match_k(S, base, tgt, i, j)
mm = stat(S, run(S, [x * k for x in base]), a, b)[0]
match_win += mm > res[(m, "10% 전부 익절")][0]
mt.append(f"{m} 살 때 비중 {k:.3f} → {won(mm)} (10% 익절 {won(res[(m, '10% 전부 익절')][0])} · 평균 보유 비중 {tgt * 100:.1f}%)")
print(" 익절 없이 보유 비중만 10% 익절 계좌와 똑같이 맞추면: " + " | ".join(mt))
for m in mk:
total += 1
for vn, _ in VARS[1:]:
less[vn] += res[(m, vn)][0] < res[(m, "익절 없음")][0]
if coin == "BTC" and rn.startswith("슈퍼트렌드"):
keep = (mk, filt, fn)
print()
print(f"■ 익절 없음보다 돈이 적게 남은 경우 ({total}개 = 코인 2 × 봇 규칙 3 × 거래소 2)")
for vn, k in less.items():
print(f" {vn}: {k}/{total}")
print(f"■ 10% 익절 계좌와 평균 보유 비중을 똑같이 맞춘 익절 없는 봇이 더 남긴 경우: {match_win}/{total}")
# 거래 하나하나 — 비트코인 슈퍼트렌드 봇(익절 없음)
mk, filt, fn = keep
print("\n■ 비트코인 슈퍼트렌드 봇(익절 없음) 거래 하나하나 — 2017-12-02 이후 진입")
for m, S in mk.items():
base = [x * y for x, y in zip(fn(S), filt[m])]
c, o, d, n = S["c"], S["o"], S["d"], S["n"]
tr, t = [], 1
while t < n:
if base[t] > 0 and base[t - 1] == 0:
e, u = c[t], t
while u + 1 < n and base[u + 1] > 0:
u += 1
ein = o[t + 1] if t + 1 < n else c[t]
xout = o[u + 1] if u + 1 < n else c[-1]
best = max(c[t:u + 1]) / e - 1
hit = next((k for k in range(t, u + 1) if c[k] / e - 1 >= 0.10), None)
# 익절 계좌가 실제로 판 값: 종가가 +10% 를 처음 넘은 봉의 다음 봉 시가
tp = o[hit + 1] / ein - 1 if (hit is not None and hit + 1 < n) else None
tr.append(dict(d=d[t], end=xout / ein - 1, hit=hit is not None, hitd=d[hit] if hit is not None else "", tp=tp))
t = u + 1
else:
t += 1
tr = [x for x in tr if x["d"] >= "2017-12-02"]
hit = [x for x in tr if x["hit"]]
up = sum(x["end"] >= 0.10 for x in hit)
print(f" {m}: 거래 {len(tr)}번 · 번 거래 {sum(x['end'] > 0 for x in tr)}번 · 잃은 거래 {sum(x['end'] <= 0 for x in tr)}번")
print(f" 10% 를 넘긴 거래 {len(hit)}번 — 봇이 10% 보다 높은 값에 판 거래 {up}번 · 10% 아래로 판 거래 {len(hit) - up}번 · 손실로 끝난 거래 {sum(x['end'] < 0 for x in hit)}번")
more = [x for x in hit if x["end"] > x["tp"]]
less_ = [x for x in hit if x["end"] < x["tp"]]
gain = sum(x["end"] - x["tp"] for x in more) * 100
loss = sum(x["tp"] - x["end"] for x in less_) * 100
print(f" 익절 계좌가 실제로 판 값과 견주면 — 익절 없는 봇이 더 받은 거래 {len(more)}번 · 익절 계좌가 더 받은 거래 {len(less_)}번"
f" · 더 받은 몫을 모으면 봇 쪽 {gain:.1f}%포인트 대 익절 쪽 {loss:.1f}%포인트")
big = max(tr, key=lambda x: x["end"])
print(f" 가장 크게 번 거래: {big['d'][:10]} 진입 · {big['end'] * 100:.1f}%")
if m == "바이낸스":
hs = sorted(hit, key=lambda x: x["end"]); mid = hs[len(hs) // 2]
dd = (datetime.date.fromisoformat(mid["hitd"][:10]) - datetime.date.fromisoformat(mid["d"][:10])).days
print(f" 10% 를 넘긴 거래 중 가운데: {mid['d'][:16]} 진입 → {dd}일 뒤 {mid['hitd'][:10]} 10% 넘음 → 봇은 {mid['end'] * 100:.1f}% 에 팜")
print("\n끝.")
알고랩 Strategy Lab — 전략을 검증하고, 검증한 것만 자동매매로 옮깁니다. 파는 때를 봇이 정하게 두는 일은 사람보다 봇이 잘 지킵니다. 알고랩 자동매매 살펴보기 · 전략 검증 전체 보기
과거 데이터를 돌려 본 결과이며 미래 수익을 보장하지 않습니다. 투자 판단과 책임은 본인에게 있습니다.