비트코인 · 터틀 트레이딩 · 돌파 매매 · 실측 재현 페이지

비트코인 돌파 매매,
다 살까 나눠 살까

비트코인 일봉 종가가 직전 20일 최고가를 넘으면 사고, 직전 10일 최저가 아래로 내려가면 파는 규칙 — '터틀 트레이딩'으로 알려진 돌파 규칙입니다. 같은 신호로 1,000만원 계좌 둘을 2018년 1월 1일부터 2026년 10월 16일까지 굴렸습니다. ① 한 번에 다 — 신호가 나면 전액 산다 ② 나눠 사기 — 처음엔 조금만 사고, 오를 때마다 같은 양을 더 산다(터틀 원조의 사이징·더 사기·손절 그대로). 종가로 판단해 다음 날 시가에 체결했고, 편도 수수료 0.1%를 뗐습니다.

-30.67%나눠 산 계좌가 가장 크게 줄어든 폭 — 한 번에 다 산 계좌는 -53.95% (바이낸스)
1억 2,513만원나눠 산 계좌의 끝 잔고 — 한 번에 다 산 계좌는 1억 3,952만원 (바이낸스 · 1,000만원 시작)
2,544만원나눠 산 계좌의 평균 비트코인 비중(30.4%)을 늘 들고 있던 계좌 — 가장 크게 줄어든 폭 -35.71%

설정 그대로

항목값
사는 신호일봉 종가 > 직전 20일 최고가 → 다음 날 시가에 산다
파는 신호종가 < 직전 10일 최저가 → 다음 날 시가에 전부 판다
하루 움직임 N지난 20일 평균 변동폭(와일더 ATR 20)
처음 한 번에 사는 양계좌 평가액 × 1% ÷ N 개 — 값이 N 만큼 떨어지면 계좌가 1% 줄어드는 양(1%어치가 아닙니다). 2026-10-16 바이낸스 종가로 1,000만원 계좌라면 약 3,648,000원어치
더 사기종가 ≥ 마지막으로 산 값 + N 의 절반 → 같은 양을 한 번 더 · 처음 산 것까지 최대 4번
손절종가 < 마지막으로 산 값 − 2N → 다음 날 시가에 전부 판다(10일 최저가를 기다리지 않음)
현금모자라면 남은 현금만큼만 산다(빚 없음 · 계좌 100% 까지)

비트코인 · 바이낸스 (BTCUSDT · 달러 계좌를 1,000만원 배수로 환산)

계좌연 수익가장 크게 줄어든 폭1,000만원 →2024-01 부터
나눠 사기연 33.31%-30.67%1억 2,513만원연 7.82% / -27.80%
한 번에 다연 34.97%-53.95%1억 3,952만원연 11.93% / -38.02%
같은 비중연 11.21%-35.71%2,544만원연 9.44% / -19.40%
그냥 보유연 22.84%-81.18%6,100만원연 24.61% / -52.97%

나눠 사기 거래 46번 중 손해 32번 · 가장 큰 거래 2020-10-11 → 2021-03-25 +353.13% · 처음 한 번에 산 양이 계좌의 3분의 1 미만이었던 거래 34번 / 46번

비트코인 · 업비트 (KRW-BTC)

계좌연 수익가장 크게 줄어든 폭1,000만원 →2024-01 부터
나눠 사기연 48.96%-30.27%3억 3,183만원연 24.59% / -23.48%
한 번에 다연 35.17%-72.48%1억 4,137만원연 15.82% / -32.30%
같은 비중연 11.88%-43.29%2,683만원연 10.08% / -18.77%
그냥 보유연 22.25%-86.81%5,847만원연 25.25% / -49.94%

한계 — 먼저 읽어 주세요

받아가기

돌리는 법: zip 을 풀고 python run_turtle.py

그대로 돌린 출력

구간 2018-01-01 ~ 2026-10-16 · 편도 수수료 0.1% · 원금 1,000만원(달러 계좌는 같은 배수로 환산)

== 비트코인 · 바이낸스 (마지막 봉 2026-10-16)
  나눠 사기    연 33.31% · 가장 크게 줄어든 폭 -30.67% · 1,000만원 → 1억 2,513만원 · 2024-01~ 연 7.82% / -27.80% · 거래 46번 · 평균 비중 30.4%
  한 번에 다   연 34.97% · 가장 크게 줄어든 폭 -53.95% · 1,000만원 → 1억 3,952만원 · 2024-01~ 연 11.93% / -38.02% · 거래 42번
  같은 비중    연 11.21% · 가장 크게 줄어든 폭 -35.71% · 1,000만원 → 2,544만원 · 2024-01~ 연 9.44% / -19.40%
  그냥 보유    연 22.84% · 가장 크게 줄어든 폭 -81.18% · 1,000만원 → 6,100만원 · 2024-01~ 연 24.61% / -52.97%
  나눠 사기 거래 46번 중 손해 32번 · 가장 큰 손해 -7.20% · 가장 큰 거래 2020-10-11 → 2021-03-25 +353.13%
  처음 한 번에 산 양이 계좌의 3분의 1 미만이었던 거래 34번 / 46번
  2026-10-16 종가 기준 1,000만원 계좌의 처음 한 번 = 약 3,648,000원어치 (N = 종가의 2.74%)
  (원조 느린 규칙 55일 돌파·20일 청산) 나눠 사기 연 20.73% · -44.86% / 한 번에 다 연 25.97% · -47.12%

== 비트코인 · 업비트 (마지막 봉 2026-10-16)
  나눠 사기    연 48.96% · 가장 크게 줄어든 폭 -30.27% · 1,000만원 → 3억 3,183만원 · 2024-01~ 연 24.59% / -23.48% · 거래 46번 · 평균 비중 32.0%
  한 번에 다   연 35.17% · 가장 크게 줄어든 폭 -72.48% · 1,000만원 → 1억 4,137만원 · 2024-01~ 연 15.82% / -32.30% · 거래 45번
  같은 비중    연 11.88% · 가장 크게 줄어든 폭 -43.29% · 1,000만원 → 2,683만원 · 2024-01~ 연 10.08% / -18.77%
  그냥 보유    연 22.25% · 가장 크게 줄어든 폭 -86.81% · 1,000만원 → 5,847만원 · 2024-01~ 연 25.25% / -49.94%
  나눠 사기 거래 46번 중 손해 28번 · 가장 큰 손해 -7.88% · 가장 큰 거래 2019-03-21 → 2019-07-15 +170.02%
  처음 한 번에 산 양이 계좌의 3분의 1 미만이었던 거래 25번 / 46번
  2026-10-16 종가 기준 1,000만원 계좌의 처음 한 번 = 약 4,462,000원어치 (N = 종가의 2.24%)
  (원조 느린 규칙 55일 돌파·20일 청산) 나눠 사기 연 43.59% · -32.76% / 한 번에 다 연 28.50% · -67.71%

== 이더리움 · 바이낸스 (마지막 봉 2026-10-16)
  나눠 사기    연 16.41% · 가장 크게 줄어든 폭 -44.15% · 1,000만원 → 3,803만원 · 2024-01~ 연 -7.42% / -44.15% · 거래 50번 · 평균 비중 22.7%
  한 번에 다   연 21.99% · 가장 크게 줄어든 폭 -67.83% · 1,000만원 → 5,738만원 · 2024-01~ 연 -18.59% / -62.46% · 거래 47번
  같은 비중    연 10.27% · 가장 크게 줄어든 폭 -40.63% · 1,000만원 → 2,362만원 · 2024-01~ 연 4.59% / -21.23%
  그냥 보유    연 14.19% · 가장 크게 줄어든 폭 -93.97% · 1,000만원 → 3,210만원 · 2024-01~ 연 1.08% / -67.55%

== 이더리움 · 업비트 (마지막 봉 2026-10-16)
  나눠 사기    연 34.20% · 가장 크게 줄어든 폭 -37.04% · 1,000만원 → 1억 3,263만원 · 2024-01~ 연 10.33% / -29.57% · 거래 45번 · 평균 비중 28.1%
  한 번에 다   연 43.07% · 가장 크게 줄어든 폭 -65.81% · 1,000만원 → 2억 3,277만원 · 2024-01~ 연 3.50% / -53.32% · 거래 44번
  같은 비중    연 11.98% · 가장 크게 줄어든 폭 -53.82% · 1,000만원 → 2,703만원 · 2024-01~ 연 5.39% / -23.71%
  그냥 보유    연 13.74% · 가장 크게 줄어든 폭 -95.59% · 1,000만원 → 3,100만원 · 2024-01~ 연 1.59% / -64.30%

끝.

코드 전문

# -*- coding: utf-8 -*-
"""비트코인 돌파 매매 — 한 번에 다 사기 vs 오를 때 나눠 사기(터틀 사이징) · AlgoLab 재현 코드

표준 라이브러리만 씁니다. 같은 폴더의 data_turtle/ 에 얼려 둔 일봉(2026-10-16 까지)을 읽습니다.
  python run_turtle.py

규칙(일봉 · 종가로 판단 · 다음 날 시가에 체결 · 편도 수수료 0.1%)
  사는 신호   종가 > 직전 20일 최고가
  파는 신호   종가 < 직전 10일 최저가 → 전부 판다
  N          지난 20일 평균 변동폭(와일더 ATR 20)
  한 번에    계좌 평가액 × 1% ÷ N 개 (값이 N 만큼 떨어지면 계좌가 1% 줄어드는 양)
  더 사기    종가 ≥ 마지막으로 산 값 + 0.5N 이면 같은 양을 한 번 더 · 처음 산 것까지 최대 4번
  손절       종가 < 마지막으로 산 값 − 2N → 전부 판다
  현금이 모자라면 남은 현금만큼만 산다(빚 없음)
비교
  한 번에 다  같은 사는·파는 신호, 신호가 나면 전액(더 사기·손절 없음)
  같은 비중   나눠 사기 계좌의 평균 비트코인 비중을 늘 들고 있는 계좌(매달 첫날 시가에 맞춤)
  그냥 보유   2018-01-01 종가부터 들고 있기
"""
import csv
import datetime
import os

HERE = os.path.dirname(os.path.abspath(__file__))
DATA = os.path.join(HERE, "data_turtle")
FEE = 0.001
START, END, RECENT = "2018-01-01", "2026-10-16", "2024-01-01"
SEED = 10_000_000
FILES = [("비트코인", "바이낸스", "BTCUSDT_1d.csv"), ("비트코인", "업비트", "KRW-BTC_1d.csv"),
         ("이더리움", "바이낸스", "ETHUSDT_1d.csv"), ("이더리움", "업비트", "KRW-ETH_1d.csv")]


def load(name):
    d, o, h, l, c = [], [], [], [], []
    with open(os.path.join(DATA, name), encoding="utf-8") as f:
        r = csv.reader(f)
        next(r)
        for row in r:
            if row[0][:10] > END:
                continue
            d.append(row[0][:10]); o.append(float(row[1])); h.append(float(row[2]))
            l.append(float(row[3])); c.append(float(row[4]))
    return d, o, h, l, c


def atr20(h, l, c):
    n = len(c)
    tr = [h[0] - l[0]] + [max(h[t] - l[t], abs(h[t] - c[t - 1]), abs(l[t] - c[t - 1])) for t in range(1, n)]
    N = [None] * n
    N[19] = sum(tr[:20]) / 20
    for t in range(20, n):
        N[t] = (19 * N[t - 1] + tr[t]) / 20
    return N


def channel(h, l, n_in, n_out):
    n = len(h)
    hi = [max(h[t - n_in:t]) if t >= n_in else None for t in range(n)]
    lo = [min(l[t - n_out:t]) if t >= n_out else None for t in range(n)]
    return hi, lo


def run(D, n_in=20, n_out=10, risk=0.01, max_u=4, stop=True, full=False):
    d, o, c, N = D["d"], D["o"], D["c"], D["N"]
    hi, lo = channel(D["h"], D["l"], n_in, n_out)
    i0 = D["i0"]
    cash, qty, units, last_fill, n_ent = 1.0, 0.0, 0, 0.0, 0.0
    order, cur, trades, eq, expo = None, None, [], [], []
    for t in range(i0, len(c)):
        if order is not None:
            px = o[t]
            if order[0] == "sell":
                cash += qty * px * (1 - FEE)
                cur.update(out=d[t], why=order[1], pnl=cash / cur["e0"] - 1)
                trades.append(cur)
                qty, units, cur = 0.0, 0, None
            else:
                afford = cash / (px * (1 + FEE))
                q = afford if order[1] is None else min(order[1], afford)
                if q > 0:
                    if cur is None:
                        cur = dict(inn=d[t], e0=cash + qty * px, buys=[])
                    cash -= q * px * (1 + FEE)
                    qty += q
                    units += 1
                    last_fill, n_ent = px, order[2]
                    cur["buys"].append(qty * px / (cash + qty * px))
            order = None
        e = cash + qty * c[t]
        eq.append(e)
        expo.append(qty * c[t] / e if e > 0 else 0.0)
        if t == len(c) - 1 or hi[t] is None or lo[t] is None or N[t] is None:
            continue
        if units > 0:
            if c[t] < lo[t]:
                order = ("sell", "10일 최저가")
            elif not full and stop and c[t] < last_fill - 2 * n_ent:
                order = ("sell", "2N 손절")
            elif not full and units < max_u and c[t] >= last_fill + 0.5 * n_ent:
                order = ("buy", risk * e / N[t], N[t])
        elif c[t] > hi[t]:
            order = ("buy", None if full else risk * e / N[t], N[t])
    return eq, expo, trades


def same_weight(D, w):
    d, o, c, i0 = D["d"], D["o"], D["c"], D["i0"]
    cash, qty, eq = 1.0, 0.0, []
    for t in range(i0, len(c)):
        if t == i0 or d[t][:7] != d[t - 1][:7]:
            e = cash + qty * o[t]
            tq = w * e / o[t]
            dq = tq - qty
            cash -= dq * o[t] + abs(dq) * o[t] * FEE
            qty = tq
        eq.append(cash + qty * c[t])
    return eq


def stats(eq, dates):
    yrs = (datetime.date.fromisoformat(dates[-1]) - datetime.date.fromisoformat(dates[0])).days / 365.25
    pk, mdd = eq[0], 0.0
    for v in eq:
        pk = max(pk, v)
        mdd = min(mdd, v / pk - 1)
    return (eq[-1] / eq[0]) ** (1 / yrs) - 1, mdd, eq[-1] / eq[0]


def won(x):
    v = int(round(SEED * x, -4)) // 10000
    return (f"{v // 10000}억 {v % 10000:,}만원" if v % 10000 else f"{v // 10000}억원") if v >= 10000 else f"{v:,}만원"


def line(name, eq, dates):
    g, m, x = stats(eq, dates)
    j = dates.index(next(x for x in dates if x >= RECENT))
    g2, m2, _ = stats(eq[j:], dates[j:])
    return f"  {name:8s} 연 {g * 100:.2f}% · 가장 크게 줄어든 폭 {m * 100:.2f}% · 1,000만원 → {won(x)} · 2024-01~ 연 {g2 * 100:.2f}% / {m2 * 100:.2f}%"


def main():
    print(f"구간 {START} ~ {END} · 편도 수수료 {FEE * 100:.1f}% · 원금 1,000만원(달러 계좌는 같은 배수로 환산)\n")
    for coin, ex, f in FILES:
        d, o, h, l, c = load(f)
        i0 = next(i for i, x in enumerate(d) if x >= START)
        D = dict(d=d, o=o, h=h, l=l, c=c, N=atr20(h, l, c), i0=i0)
        dd = d[i0:]
        eq_t, ex_t, tr_t = run(D)
        eq_f, _, tr_f = run(D, full=True)
        w = sum(ex_t) / len(ex_t)
        eq_w = same_weight(D, w)
        bh = [x / c[i0] for x in c[i0:]]
        print(f"== {coin} · {ex} (마지막 봉 {d[-1]})")
        print(line("나눠 사기", eq_t, dd) + f" · 거래 {len(tr_t)}번 · 평균 비중 {w * 100:.1f}%")
        print(line("한 번에 다", eq_f, dd) + f" · 거래 {len(tr_f)}번")
        print(line("같은 비중", eq_w, dd))
        print(line("그냥 보유", bh, dd))
        if coin == "비트코인":
            lose = sum(t["pnl"] <= 0 for t in tr_t)
            small = sum(t["buys"][0] < 1 / 3 for t in tr_t)
            worst = min(t["pnl"] for t in tr_t)
            best = max(tr_t, key=lambda t: t["pnl"])
            print(f"  나눠 사기 거래 {len(tr_t)}번 중 손해 {lose}번 · 가장 큰 손해 {worst * 100:.2f}% · "
                  f"가장 큰 거래 {best['inn']} → {best['out']} {best['pnl'] * 100:+.2f}%")
            print(f"  처음 한 번에 산 양이 계좌의 3분의 1 미만이었던 거래 {small}번 / {len(tr_t)}번")
            t = len(c) - 1
            print(f"  {d[t]} 종가 기준 1,000만원 계좌의 처음 한 번 = 약 {round(SEED * 0.01 / D['N'][t] * c[t], -3):,.0f}원어치 "
                  f"(N = 종가의 {D['N'][t] / c[t] * 100:.2f}%)")
            eq_s2, _, _ = run(D, n_in=55, n_out=20)
            g, m, _ = stats(eq_s2, dd)
            eq_s2f, _, _ = run(D, n_in=55, n_out=20, full=True)
            g2, m2, _ = stats(eq_s2f, dd)
            print(f"  (원조 느린 규칙 55일 돌파·20일 청산) 나눠 사기 연 {g * 100:.2f}% · {m * 100:.2f}% / 한 번에 다 연 {g2 * 100:.2f}% · {m2 * 100:.2f}%")
        print()
    print("끝.")


if __name__ == "__main__":
    main()

알고랩 Strategy Lab — 전략을 검증하고, 검증한 것만 자동매매로 옮깁니다. 매일 종가를 보고 하루 움직임을 다시 재고, 살 양을 계산하는 일은 사람보다 봇이 잘합니다. 알고랩 자동매매 살펴보기 · 전략 검증 전체 보기

과거 데이터를 돌려 본 결과이며 미래 수익을 보장하지 않습니다. 투자 판단과 책임은 본인에게 있습니다.