비트코인 · 자동매매 봇 · 슈퍼트렌드 · 실측 재현 페이지
트레이딩뷰 슈퍼트렌드(ATR 14 · 배수 2)에 일봉 50일선 조건과 변동성 비중을 붙인 봇 하나를, 설정은 그대로 두고 차트 시간봉만 바꿔 돌렸습니다. 바이낸스 비트코인 현물 실제 가격 · 2017년 12월 6일 ~ 2026년 10월 18일(UTC) · 1,000만원 · 사고팔 때마다 편도 0.1%. 업비트 가격으로도 같이 돌렸고, 영상의 숫자는 덜 나온 바이낸스 쪽입니다.
| 항목 | 값 |
|---|---|
| 차트 | 비트코인 4시간봉 (6·8시간봉도 비슷 · 1·2시간봉으로 내리지 않는다) |
| 슈퍼트렌드 | ATR 길이 14 · 배수 2 — 초록(상승)일 때만 산다 |
| 조건 | 어제까지 끝난 일봉 종가가 일봉 50일선 위일 때만 |
| 판다 | 슈퍼트렌드가 빨강으로 바뀌거나, 일봉 종가가 50일선 밑으로 내려가면 |
| 얼마나 사나 | 살 때 한 번 — 계좌의 0.5 ÷ 최근 7일 연율 변동성(최대 100%). 팔 때까지 수량 그대로 |
| 어디서 | 현물. 선물·공매도는 켜지 않는다 |
트레이딩뷰에 바로 붙여 넣는 파인 스크립트: btc_supertrend_vol.pine (변동성 창 42봉 = 4시간봉 7일 — 차트를 4시간봉으로 둘 것)
| 차트 | 바이낸스 1,000만원 → | 연 | 가장 깊은 골짜기 | 사고판 횟수 | 업비트 1,000만원 → | 연 | 골짜기 |
|---|---|---|---|---|---|---|---|
| 1시간봉 | 1,956만원 | 7.9% | -47.0% | 1626번 | 2,346만원 | 10.1% | -46.3% |
| 2시간봉 | 4,868만원 | 19.5% | -39.5% | 860번 | 1억 5,120만원 | 35.8% | -25.0% |
| 4시간봉 | 1억 1,066만원 | 31.1% | -28.8% | 456번 | 2억 8,610만원 | 46.0% | -27.7% |
| 6시간봉 | 1억 2,816만원 | 33.3% | -31.2% | 350번 | 4억 3,122만원 | 52.9% | -22.9% |
| 8시간봉 | 1억 1,398만원 | 31.6% | -33.5% | 302번 | 3억 6,135만원 | 49.9% | -27.5% |
| 12시간봉 | 2억 1,626만원 | 41.5% | -40.7% | 222번 | 2억 5,130만원 | 43.9% | -32.6% |
| 일봉 | 7,366만원 | 25.3% | -47.4% | 166번 | 1억 2,586만원 | 33.1% | -52.4% |
| 그냥 보유 | 6,580만원 | 23.7% | -83.9% | — | 6,856만원 | 24.3% | -87.0% |
| 편도 수수료 | 1시간봉 연 | 4시간봉 연(끝 잔고) |
|---|---|---|
| 0.00% | 26.3% | 37.1% (1억 6,421만원) |
| 0.05% | 16.7% | 34.1% (1억 3,481만원) |
| 0.10% | 7.9% | 31.1% (1억 1,066만원) |
| 0.12% | 4.5% | 30.0% (1억 225만원) |
| 0.15% | -0.3% | 28.3% (9,083만원) |
| 0.25% | -14.9% | 22.7% (6,117만원) |
수수료를 0 으로 놓아도 1시간봉이 낮습니다 — 짧은 봉의 헛신호 몫입니다. 수수료가 오르면 1시간봉은 훨씬 빨리 무너집니다.
| 봇 | 평균 비중 | 봇 (연 · 골짜기) | 같은 비중 고정 (연 · 골짜기) |
|---|---|---|---|
| 1시간봉 바이낸스 | 24% | 연 7.9% · -47.0% | 연 9.9% · -28.6% |
| 1시간봉 업비트 | 25% | 연 10.1% · -46.3% | 연 9.6% · -35.5% |
| 4시간봉 바이낸스 | 27% | 연 31.1% · -28.8% | 연 10.6% · -33.6% |
| 4시간봉 업비트 | 28% | 연 46.0% · -27.7% | 연 10.1% · -39.1% |
| 6시간봉 바이낸스 | 29% | 연 33.3% · -31.2% | 연 11.0% · -35.7% |
| 6시간봉 업비트 | 29% | 연 52.9% · -22.9% | 연 10.4% · -40.1% |
| 8시간봉 바이낸스 | 30% | 연 31.6% · -33.5% | 연 11.2% · -35.8% |
| 8시간봉 업비트 | 30% | 연 49.9% · -27.5% | 연 10.6% · -41.8% |
고정 비중 계좌는 매 봉 비중을 맞추고 비용을 0 으로 둔, 그 계좌에 유리한 계산입니다.
| 거래소 | 1시간봉 봇 | 4시간봉 봇 | 그냥 보유 |
|---|---|---|---|
| 바이낸스 | 890만원 (-40.5%) | 1,440만원 (-20.6%) | 1,182만원 (-53.4%) |
| 업비트 | 806만원 (-37.3%) | 1,904만원 (-12.7%) | 1,175만원 (-50.3%) |
산 뒤 판 것 226번 중 계좌가 늘어난 것 97번 · 줄어든 것 129번(한 번에 가장 크게 줄어든 것 -6.1%). 계좌를 가장 많이 늘린 한 번은 2019-06-10T16:00:00 종가 7,946달러에 계좌의 69%로 사서 2019-06-27T04:00:00 종가 12,500달러에 판 거래(계좌 1.395배)입니다.
| 해 | 봇 | 그냥 보유 |
|---|---|---|
| 2018 | -17.2% | -73.0% |
| 2019 | +75.3% | +94.3% |
| 2020 | +144.5% | +302.0% |
| 2021 | +36.7% | +59.8% |
| 2022 | -22.6% | -64.2% |
| 2023 | +46.9% | +155.6% |
| 2024 | +75.4% | +121.3% |
| 2025 | +6.4% | -6.3% |
| 2026 | +2.4% | -7.5% |
크게 오른 해에는 그냥 보유보다 덜 법니다 — 봇은 대개 계좌의 일부만 사 둡니다.
| 차트 | 연 | 가장 깊은 골짜기 | 사고판 횟수 |
|---|---|---|---|
| 1시간봉 | 24.3% | -31.4% | 757번 |
| 2시간봉 | 69.7% | -20.4% | 397번 |
| 4시간봉 | 81.6% | -20.9% | 211번 |
| 6시간봉 | 58.6% | -25.8% | 177번 |
| 8시간봉 | 68.5% | -23.0% | 143번 |
| 12시간봉 | 88.1% | -25.4% | 105번 |
| 일봉 | 77.4% | -25.3% | 71번 |
| 그냥 보유 | 60.7% | -82.3% | — |
돌리는 법: zip 을 풀고 python run_supertrend4h.py (1분 안쪽)
비트코인 슈퍼트렌드 봇 · ATR 14 · 배수 2 · 일봉 50일선 · 살 때 비중 0.5÷7일 변동성 · 편도 0.1%
기간 2017-12-06T16:00:00 ~ 2026-10-18T16:00:00 (UTC) · 1,000만원
[1] 차트 시간봉만 바꾼다 — 설정은 그대로
1시간봉 바이낸스 1,956만원 (연 7.9% · 가장 깊은 골짜기 -47.0% · 사고판 횟수 1626번) | 업비트 2,346만원 (연 10.1% · -46.3% · 1600번)
2시간봉 바이낸스 4,868만원 (연 19.5% · 가장 깊은 골짜기 -39.5% · 사고판 횟수 860번) | 업비트 1억 5,120만원 (연 35.8% · -25.0% · 800번)
4시간봉 바이낸스 1억 1,066만원 (연 31.1% · 가장 깊은 골짜기 -28.8% · 사고판 횟수 456번) | 업비트 2억 8,610만원 (연 46.0% · -27.7% · 436번)
6시간봉 바이낸스 1억 2,816만원 (연 33.3% · 가장 깊은 골짜기 -31.2% · 사고판 횟수 350번) | 업비트 4억 3,122만원 (연 52.9% · -22.9% · 318번)
8시간봉 바이낸스 1억 1,398만원 (연 31.6% · 가장 깊은 골짜기 -33.5% · 사고판 횟수 302번) | 업비트 3억 6,135만원 (연 49.9% · -27.5% · 278번)
12시간봉 바이낸스 2억 1,626만원 (연 41.5% · 가장 깊은 골짜기 -40.7% · 사고판 횟수 222번) | 업비트 2억 5,130만원 (연 43.9% · -32.6% · 210번)
일봉 바이낸스 7,366만원 (연 25.3% · 가장 깊은 골짜기 -47.4% · 사고판 횟수 166번) | 업비트 1억 2,586만원 (연 33.1% · -52.4% · 138번)
그냥 보유 바이낸스 6,580만원 (연 23.7% · 가장 깊은 골짜기 -83.9%)
그냥 보유 업비트 6,856만원 (연 24.3% · 가장 깊은 골짜기 -87.0%)
1시간봉은 4시간봉보다 3.6배 자주 사고팔았다(바이낸스 1626번 대 456번)
[2] 같은 평균 비중을 늘 들고 있었다면(매 봉 맞춤 · 비용 0 — 이 계좌에 유리한 계산)
1시간봉 바이낸스 봇 평균 비중 24% → 고정 비중 계좌 연 9.9% · 가장 깊은 골짜기 -28.6% (봇 연 7.9% · -47.0%)
1시간봉 업비트 봇 평균 비중 25% → 고정 비중 계좌 연 9.6% · 가장 깊은 골짜기 -35.5% (봇 연 10.1% · -46.3%)
4시간봉 바이낸스 봇 평균 비중 27% → 고정 비중 계좌 연 10.6% · 가장 깊은 골짜기 -33.6% (봇 연 31.1% · -28.8%)
4시간봉 업비트 봇 평균 비중 28% → 고정 비중 계좌 연 10.1% · 가장 깊은 골짜기 -39.1% (봇 연 46.0% · -27.7%)
6시간봉 바이낸스 봇 평균 비중 29% → 고정 비중 계좌 연 11.0% · 가장 깊은 골짜기 -35.7% (봇 연 33.3% · -31.2%)
6시간봉 업비트 봇 평균 비중 29% → 고정 비중 계좌 연 10.4% · 가장 깊은 골짜기 -40.1% (봇 연 52.9% · -22.9%)
8시간봉 바이낸스 봇 평균 비중 30% → 고정 비중 계좌 연 11.2% · 가장 깊은 골짜기 -35.8% (봇 연 31.6% · -33.5%)
8시간봉 업비트 봇 평균 비중 30% → 고정 비중 계좌 연 10.6% · 가장 깊은 골짜기 -41.8% (봇 연 49.9% · -27.5%)
[3] 수수료를 바꾸면 (바이낸스)
편도 0.00% 1시간봉 연 26.3% · 4시간봉 연 37.1% (1억 6,421만원)
편도 0.05% 1시간봉 연 16.7% · 4시간봉 연 34.1% (1억 3,481만원)
편도 0.10% 1시간봉 연 7.9% · 4시간봉 연 31.1% (1억 1,066만원)
편도 0.12% 1시간봉 연 4.5% · 4시간봉 연 30.0% (1억 225만원)
편도 0.15% 1시간봉 연 -0.3% · 4시간봉 연 28.3% (9,083만원)
편도 0.25% 1시간봉 연 -14.9% · 4시간봉 연 22.7% (6,117만원)
[4] 최근 2년만 (2024-10-18 16:00 UTC ~) — 같은 계좌를 그날부터 다시 잰다
바이낸스 1시간봉 봇 890만원(골짜기 -40.5%) · 4시간봉 봇 1,440만원(골짜기 -20.6%) · 그냥 보유 1,182만원(골짜기 -53.4%)
업비트 1시간봉 봇 806만원(골짜기 -37.3%) · 4시간봉 봇 1,904만원(골짜기 -12.7%) · 그냥 보유 1,175만원(골짜기 -50.3%)
[5] 바이낸스 4시간봉 봇이 사고판 기록
산 뒤 판 것 226번 · 계좌가 늘어난 것 97번 · 줄어든 것 129번(한 번에 가장 크게 줄어든 것 -6.1%)
계좌를 가장 많이 늘린 한 번: 2019-06-10T16:00:00 종가 7,946달러에 계좌의 69%로 사서 → 2019-06-27T04:00:00 종가 12,500달러에 팔았다 · 계좌 1.395배
해마다(바이낸스 4시간봉 봇 대 그냥 보유):
2018 봇 -17.2% 그냥 보유 -73.0%
2019 봇 +75.3% 그냥 보유 +94.3%
2020 봇 +144.5% 그냥 보유 +302.0%
2021 봇 +36.7% 그냥 보유 +59.8%
2022 봇 -22.6% 그냥 보유 -64.2%
2023 봇 +46.9% 그냥 보유 +155.6%
2024 봇 +75.4% 그냥 보유 +121.3%
2025 봇 +6.4% 그냥 보유 -6.3%
2026 봇 +2.4% 그냥 보유 -7.5%
[6] 1시간봉에 맞게 선을 고쳐 주면? — ATR 길이 56(4시간봉 14 × 4)
1시간봉 ATR 56 · 배수 2 바이낸스 1,536만원 (연 5.0% · 골짜기 -45.0% · 1726번) | 업비트 1,940만원 (연 7.8% · 골짜기 -41.5% · 1700번)
1시간봉 ATR 56 · 배수 4 바이낸스 6,443만원 (연 23.4% · 골짜기 -32.0% · 669번) | 업비트 1억 3,655만원 (연 34.3% · 골짜기 -32.1% · 632번)
(비교: 4시간봉 ATR 14 · 배수 2 바이낸스 1억 1,066만원 · 업비트 2억 8,610만원)
[7] 다른 거래소·다른 시대 — 비트스탬프 2014-01 ~ 2017-09 (편도 0.1%)
1시간봉 연 24.3% · 가장 깊은 골짜기 -31.4% · 사고판 횟수 757번
2시간봉 연 69.7% · 가장 깊은 골짜기 -20.4% · 사고판 횟수 397번
4시간봉 연 81.6% · 가장 깊은 골짜기 -20.9% · 사고판 횟수 211번
6시간봉 연 58.6% · 가장 깊은 골짜기 -25.8% · 사고판 횟수 177번
8시간봉 연 68.5% · 가장 깊은 골짜기 -23.0% · 사고판 횟수 143번
12시간봉 연 88.1% · 가장 깊은 골짜기 -25.4% · 사고판 횟수 105번
일봉 연 77.4% · 가장 깊은 골짜기 -25.3% · 사고판 횟수 71번
그냥 보유(4시간봉 기준) 연 60.7% · 가장 깊은 골짜기 -82.3%
끝.
//@version=5
// 비트코인 4시간봉 — 원조 슈퍼트렌드(ATR 14 · 배수 2) + 어제까지의 일봉 50일선 + 살 때만 변동성 비중
// 연구 근거: 연구/pool/트레이딩뷰-신상261019/sweep8.py (이 파일과 같은 규칙을 파이썬으로 옮긴 판 '4 파인판 · 살 때만 비중')
// ⚠ 2026-10-20 기준 트레이딩뷰 전략 테스터에서 아직 돌려 보지 않았다 — 파이썬 복제판 수치만 있다.
strategy("BTC 슈퍼트렌드 + 50일선 + 변동성 비중", overlay = true,
initial_capital = 10000000, default_qty_type = strategy.cash,
commission_type = strategy.commission.percent, commission_value = 0.1,
process_orders_on_close = true, pyramiding = 0)
atrLen = input.int(14, "ATR 길이")
factor = input.float(2.0, "배수")
smaLen = input.int(50, "일봉 이동평균")
volTarget = input.float(0.5, "목표 변동성(연, 0.5 = 50%)")
volWin = input.int(42, "변동성 창(4시간봉 개수, 42 = 7일)")
[st, dir] = ta.supertrend(factor, atrLen)
// 어제까지 끝난 일봉 종가가 일봉 50일선 위인가 (lookahead_on + [1] = 다시 그려지지 않는 판)
dayUp = request.security(syminfo.tickerid, "D", close[1] > ta.sma(close, smaLen)[1], lookahead = barmerge.lookahead_on)
// 최근 42봉 수익률 표준편차(모집단) × √(6×365) = 연율 변동성
r = close / close[1] - 1
vol = ta.stdev(r, volWin) * math.sqrt(6 * 365)
w = vol > 0 ? math.min(1.0, volTarget / vol) : 1.0
want = dir < 0 and dayUp
if want and strategy.position_size == 0
strategy.entry("L", strategy.long, qty = strategy.equity * w / close)
if not want and strategy.position_size > 0
strategy.close("L")
plot(st, "슈퍼트렌드", color = dir < 0 ? color.green : color.red)
# -*- coding: utf-8 -*-
"""비트코인 슈퍼트렌드 봇 — 1시간봉에 걸까, 4시간봉에 걸까 (AlgoLab 재현 코드 · 표준 라이브러리만)
같은 폴더의 data_btc/ 에 얼려 둔 1시간봉 세 개를 읽는다.
BTCUSDT_1h.csv 바이낸스 현물(2017-08 ~ 2026-10-18)
KRW-BTC_1h.csv 업비트(2017-09 ~ 2026-10-18)
BTCUSD_1h.csv 비트스탬프(2013-06 ~ 2017-09) — 다른 거래소·다른 시대 확인용
규칙(트레이딩뷰 btc_supertrend_vol.pine 과 같은 규칙):
· 1시간봉을 UTC 경계로 묶어 2·4·6·8·12시간봉·일봉을 만든다
· 슈퍼트렌드(ATR 14 · 배수 2, 파인 ta.supertrend 와 같은 식)가 상승이고
어제까지 끝난 일봉(UTC) 종가가 일봉 50일 이동평균 위일 때 산다. 둘 중 하나라도 꺼지면 판다
· 살 때 한 번 비중 = min(1, 0.5 ÷ 최근 7일 연율 변동성) — 팔 때까지 수량 그대로
· 봉이 끝날 때 판정하고 그 봉 종가에 체결 · 사고팔 때마다 편도 수수료(기본 0.1%)
python run_supertrend4h.py
"""
import datetime
import math
import os
HERE = os.path.dirname(os.path.abspath(__file__))
DATA = os.path.join(HERE, "data_btc")
START, END = "2017-10-01", "2026-10-18T16:00:00"
SEED = 10_000_000
TFS = (1, 2, 4, 6, 8, 12, 24)
def load(name, a=START, b=END):
d, o, h, l, c = [], [], [], [], []
with open(os.path.join(DATA, name), encoding="utf-8") as f:
next(f)
for line in f:
p = line.rstrip("\n").split(",")
if len(p) < 5:
continue
t = p[0] if len(p[0]) > 10 else p[0] + "T00:00:00" # 자정 봉은 날짜만 적혀 있다
if t < a or t > b:
continue
d.append(t); o.append(float(p[1])); h.append(float(p[2])); l.append(float(p[3])); c.append(float(p[4]))
return d, o, h, l, c
def resample(d, o, h, l, c, k):
if k == 1:
return d, o, h, l, c
D, O, H, L, C = [], [], [], [], []
last = None
for i in range(len(d)):
key = d[i][:11] + "%02d" % ((int(d[i][11:13]) // k) * k)
if key != last:
D.append(key + ":00:00"); O.append(o[i]); H.append(h[i]); L.append(l[i]); C.append(c[i]); last = key
else:
H[-1] = max(H[-1], h[i]); L[-1] = min(L[-1], l[i]); C[-1] = c[i]
return D, O, H, L, C
def series(name, k, a=START, b=END):
d, o, h, l, c = resample(*load(name, a, b), k)
yrs = (datetime.datetime.fromisoformat(d[-1]) - datetime.datetime.fromisoformat(d[0])).total_seconds() / (365.25 * 86400)
return dict(d=d, h=h, l=l, c=c, ppy=len(c) / yrs)
def atr(h, l, c, n):
tr = [h[0] - l[0]] + [max(h[i] - l[i], abs(h[i] - c[i - 1]), abs(l[i] - c[i - 1])) for i in range(1, len(c))]
out = [math.nan] * len(c)
if len(c) >= n:
out[n - 1] = sum(tr[:n]) / n
for i in range(n, len(c)):
out[i] = out[i - 1] + (tr[i] - out[i - 1]) / n
return out
def supertrend_up(h, l, c, n=14, factor=2.0):
"""1 = 상승(초록) · 0 = 하락(빨강). 파인 ta.supertrend 와 같은 식."""
a = atr(h, l, c, n)
N = len(c)
up = [(h[i] + l[i]) / 2 + factor * a[i] for i in range(N)]
lo = [(h[i] + l[i]) / 2 - factor * a[i] for i in range(N)]
is_upper = [True] * N
res = [0.0] * N
for i in range(1, N):
if math.isnan(a[i]):
continue
pl = 0.0 if math.isnan(lo[i - 1]) else lo[i - 1]
pu = 0.0 if math.isnan(up[i - 1]) else up[i - 1]
lo[i] = lo[i] if (lo[i] > pl or c[i - 1] < pl) else pl
up[i] = up[i] if (up[i] < pu or c[i - 1] > pu) else pu
if math.isnan(a[i - 1]):
dirn = 1
elif is_upper[i - 1]:
dirn = -1 if c[i] > up[i] else 1
else:
dirn = 1 if c[i] < lo[i] else -1
is_upper[i] = dirn == 1
res[i] = 1.0 if dirn == -1 else 0.0
return res
def above_daily_sma(d, c, n=50):
"""그 봉의 '어제까지 끝난 일봉 종가 > 일봉 50일선' (일봉 종가 = 그날 마지막 봉 종가)."""
days, dc = [], []
for i in range(len(d)):
if not days or d[i][:10] != days[-1]:
days.append(d[i][:10]); dc.append(c[i])
else:
dc[-1] = c[i]
up = []
for k in range(len(dc)):
if k + 1 < n:
up.append(0.0)
else:
up.append(1.0 if dc[k] > sum(dc[k + 1 - n:k + 1]) / n else 0.0)
pos = {x: k for k, x in enumerate(days)}
return [up[pos[x[:10]] - 1] if pos[x[:10]] >= 1 else 0.0 for x in d]
def vol_weight(c, win, ann, target=0.5):
r = [0.0] + [c[i] / c[i - 1] - 1 for i in range(1, len(c))]
cs = [0.0]; cs2 = [0.0]
for x in r:
cs.append(cs[-1] + x); cs2.append(cs2[-1] + x * x)
w = [1.0] * len(c)
for t in range(win, len(c)):
s = cs[t + 1] - cs[t + 1 - win]; s2 = cs2[t + 1] - cs2[t + 1 - win]
v = math.sqrt(max(s2 / win - (s / win) ** 2, 0.0)) * math.sqrt(ann)
w[t] = min(1.0, target / v) if v > 1e-9 else 1.0
return w
def simulate(c, want, fee):
"""want[i] > 0 이면 들고 있고 싶다(값 = 살 때 비중). 산 뒤에는 수량 그대로, 0 이 되면 판다."""
cash, units, n_tr = 1.0, 0.0, 0
E, wts = [], []
for i in range(len(c)):
eq = cash + units * c[i]
cur = units * c[i] / eq if eq > 0 else 0.0
t = want[i]
new = 0.0 if t <= 0 else (t if cur == 0 else cur)
if abs(new - cur) > 1e-12:
eq -= fee * abs(new - cur) * eq
units = new * eq / c[i]; cash = eq - units * c[i]; n_tr += 1
E.append(eq); wts.append(new)
g = [1.0] + [E[i] / E[i - 1] for i in range(1, len(E))]
return g, wts, n_tr
def stats(g, ppy):
eq, peak, mdd = 1.0, 1.0, 0.0
for x in g:
eq *= x; peak = max(peak, eq); mdd = min(mdd, eq / peak - 1)
return eq ** (ppy / len(g)) - 1, mdd, eq
def run(name, k, eval_start, fee=0.001, a=START, b=END, keep=False, atr_n=14, factor=2.0):
S = series(name, k, a, b)
d, h, l, c = S["d"], S["h"], S["l"], S["c"]
bpd = 24 // k
w = vol_weight(c, 7 * bpd, bpd * 365.0)
st = supertrend_up(h, l, c, n=atr_n, factor=factor)
fl = above_daily_sma(d, c)
g, wts, n_tr = simulate(c, [st[i] * fl[i] * w[i] for i in range(len(c))], fee)
W = next(i for i, x in enumerate(d) if x >= eval_start)
cg, mdd, mult = stats(g[W:], S["ppy"])
ret = [1.0] + [c[i] / c[i - 1] for i in range(1, len(c))]
hc, hm, hmult = stats(ret[W:], S["ppy"])
expo = sum(wts[W:]) / len(wts[W:])
fc, fm, _ = stats([1 + expo * (x - 1) for x in ret[W:]], S["ppy"])
r = dict(cagr=cg, mdd=mdd, end=mult * SEED, trades=n_tr, hold_cagr=hc, hold_mdd=hm, hold_end=hmult * SEED,
expo=expo, fix_cagr=fc, fix_mdd=fm, start=d[W], last=d[-1])
if keep:
r.update(d=d[W:], g=g[W:], ret=ret[W:], wts=wts[W:], c=c[W:])
return r
def won(x):
"""원 → '1억 1,066만원' · '1,956만원'"""
m = int(round(x / 1e4))
if m >= 10000:
return "%d억 %s만원" % (m // 10000, format(m % 10000, ",")) if m % 10000 else "%d억원" % (m // 10000)
return format(m, ",") + "만원"
def pct(x):
return "%.1f%%" % (x * 100)
def main():
eval_start = series("KRW-BTC_1h.csv", 4)["d"][400] # 4시간봉 400봉 워밍업 뒤부터 잰다
print("비트코인 슈퍼트렌드 봇 · ATR 14 · 배수 2 · 일봉 50일선 · 살 때 비중 0.5÷7일 변동성 · 편도 0.1%")
print("기간 %s ~ %s (UTC) · 1,000만원\n" % (eval_start, END))
print("[1] 차트 시간봉만 바꾼다 — 설정은 그대로")
res = {}
for k in TFS:
for ex, f in (("바이낸스", "BTCUSDT_1h.csv"), ("업비트", "KRW-BTC_1h.csv")):
res[(k, ex)] = r = run(f, k, eval_start, keep=(k in (1, 4)))
b, u = res[(k, "바이낸스")], res[(k, "업비트")]
lab = "%d시간봉" % k if k < 24 else "일봉"
print(" %-6s 바이낸스 %s (연 %s · 가장 깊은 골짜기 %s · 사고판 횟수 %d번) | 업비트 %s (연 %s · %s · %d번)"
% (lab, won(b["end"]), pct(b["cagr"]), pct(b["mdd"]), b["trades"], won(u["end"]), pct(u["cagr"]), pct(u["mdd"]), u["trades"]))
for ex in ("바이낸스", "업비트"):
r = res[(4, ex)]
print(" 그냥 보유 %s %s (연 %s · 가장 깊은 골짜기 %s)" % (ex, won(r["hold_end"]), pct(r["hold_cagr"]), pct(r["hold_mdd"])))
b4, b1 = res[(4, "바이낸스")], res[(1, "바이낸스")]
print(" 1시간봉은 4시간봉보다 %.1f배 자주 사고팔았다(바이낸스 %d번 대 %d번)" % (b1["trades"] / b4["trades"], b1["trades"], b4["trades"]))
print("\n[2] 같은 평균 비중을 늘 들고 있었다면(매 봉 맞춤 · 비용 0 — 이 계좌에 유리한 계산)")
for k in (1, 4, 6, 8):
for ex in ("바이낸스", "업비트"):
r = res[(k, ex)]
print(" %d시간봉 %s 봇 평균 비중 %.0f%% → 고정 비중 계좌 연 %s · 가장 깊은 골짜기 %s (봇 연 %s · %s)"
% (k, ex, r["expo"] * 100, pct(r["fix_cagr"]), pct(r["fix_mdd"]), pct(r["cagr"]), pct(r["mdd"])))
print("\n[3] 수수료를 바꾸면 (바이낸스)")
for fee in (0.0, 0.0005, 0.001, 0.0012, 0.0015, 0.0025):
r1 = run("BTCUSDT_1h.csv", 1, eval_start, fee=fee); r4 = run("BTCUSDT_1h.csv", 4, eval_start, fee=fee)
print(" 편도 %.2f%% 1시간봉 연 %s · 4시간봉 연 %s (%s)" % (fee * 100, pct(r1["cagr"]), pct(r4["cagr"]), won(r4["end"])))
print("\n[4] 최근 2년만 (2024-10-18 16:00 UTC ~) — 같은 계좌를 그날부터 다시 잰다")
for ex in ("바이낸스", "업비트"):
row = []
for k in (1, 4):
r = res[(k, ex)]
i0 = next(i for i, x in enumerate(r["d"]) if x >= "2024-10-18T16:00:00")
_, m1, e1 = stats(r["g"][i0 + 1:], 1); _, m2, e2 = stats(r["ret"][i0 + 1:], 1)
row.append("%d시간봉 봇 %s(골짜기 %s)" % (k, won(e1 * SEED), pct(m1)))
print(" %s %s · 그냥 보유 %s(골짜기 %s)" % (ex, " · ".join(row), won(e2 * SEED), pct(m2)))
print("\n[5] 바이낸스 4시간봉 봇이 사고판 기록")
r = res[(4, "바이낸스")]
tr, i, eq = [], 0, 1.0
eqs = []
for x in r["g"]:
eq *= x; eqs.append(eq)
w = r["wts"]
while i < len(w):
if w[i] > 0 and (i == 0 or w[i - 1] == 0):
j = i
while j + 1 < len(w) and w[j + 1] > 0:
j += 1
ex = j + 1 if j + 1 < len(w) else j
tr.append((r["d"][i], r["c"][i], w[i], r["d"][ex], r["c"][ex], eqs[ex] / (eqs[i - 1] if i > 0 else 1.0)))
i = j + 1
else:
i += 1
best = max(tr, key=lambda x: x[5])
loss = sorted(x[5] - 1 for x in tr if x[5] <= 1)
print(" 산 뒤 판 것 %d번 · 계좌가 늘어난 것 %d번 · 줄어든 것 %d번(한 번에 가장 크게 줄어든 것 %s)"
% (len(tr), sum(1 for x in tr if x[5] > 1), len(loss), pct(loss[0])))
print(" 계좌를 가장 많이 늘린 한 번: %s 종가 %s달러에 계좌의 %.0f%%로 사서 → %s 종가 %s달러에 팔았다 · 계좌 %.3f배"
% (best[0], format(round(best[1]), ","), best[2] * 100, best[3], format(round(best[4]), ","), best[5]))
print(" 해마다(바이낸스 4시간봉 봇 대 그냥 보유):")
for y in range(2018, 2027):
idx = [k for k, x in enumerate(r["d"]) if x[:4] == str(y)]
if not idx:
continue
b0 = idx[0] - 1 if idx[0] > 0 else 0
bot = eqs[idx[-1]] / eqs[b0] - 1
hold = r["c"][idx[-1]] / r["c"][b0] - 1
print(" %d 봇 %+.1f%% 그냥 보유 %+.1f%%" % (y, bot * 100, hold * 100))
print("\n[6] 1시간봉에 맞게 선을 고쳐 주면? — ATR 길이 56(4시간봉 14 × 4)")
for fa in (2.0, 4.0):
row = []
for ex, f in (("바이낸스", "BTCUSDT_1h.csv"), ("업비트", "KRW-BTC_1h.csv")):
r = run(f, 1, eval_start, atr_n=56, factor=fa)
row.append("%s %s (연 %s · 골짜기 %s · %d번)" % (ex, won(r["end"]), pct(r["cagr"]), pct(r["mdd"]), r["trades"]))
print(" 1시간봉 ATR 56 · 배수 %d %s" % (fa, " | ".join(row)))
print(" (비교: 4시간봉 ATR 14 · 배수 2 바이낸스 %s · 업비트 %s)" % (won(res[(4, "바이낸스")]["end"]), won(res[(4, "업비트")]["end"])))
print("\n[7] 다른 거래소·다른 시대 — 비트스탬프 2014-01 ~ 2017-09 (편도 0.1%)")
bs = {}
for k in TFS:
bs[k] = r = run("BTCUSD_1h.csv", k, "2014-01-01", a="2013-06-01", b="2017-09-30T23:59:59")
lab = "%d시간봉" % k if k < 24 else "일봉"
print(" %-6s 연 %s · 가장 깊은 골짜기 %s · 사고판 횟수 %d번" % (lab, pct(r["cagr"]), pct(r["mdd"]), r["trades"]))
print(" 그냥 보유(4시간봉 기준) 연 %s · 가장 깊은 골짜기 %s" % (pct(bs[4]["hold_cagr"]), pct(bs[4]["hold_mdd"])))
print("\n끝.")
if __name__ == "__main__":
main()
알고랩 Strategy Lab — 전략을 검증하고, 검증한 것만 자동매매로 옮깁니다. 4시간마다 봉이 끝날 때 판정하고 그 자리에서 주문하는 일은 사람보다 봇이 잘합니다. 알고랩 자동매매 살펴보기 · 전략 검증 전체 보기
과거 데이터를 돌려 본 결과이며 미래 수익을 보장하지 않습니다. 투자 판단과 책임은 본인에게 있습니다.