ビットコイン(BTC)は「4 年周期(Halving Cycle)」で価格が大きく動くと言われています。
本記事では、過去 3 周期(Cycle1〜3)の未来形状を Cycle4 に整列させ、未来価格を予測するモデルを Python で構築します。
さらに、log10 スケールと価格(log スケール)の二軸チャートを同期させ、
「形状」と「実際の価格」を同時に観察できる可視化を実現します。
📌 本記事で扱う内容
- yfinance を使った BTC データ取得
- 4 つのハーフィング周期の整列
- Cycle1〜3 の未来部分を Cycle4 に重ねる
- End 価格(120,000 USD)を基準に log10 方向へスケーリング
- Cycle2・3 の未来形状の平均
- Cycle1 を加えた最終未来予測
- 振幅減衰(Amplitude Decay, k=0.6)
- log10 と価格(log スケール)の二軸同期チャート
📈 完成イメージ
- Cycle1〜4 の log10 価格推移
- Cycle2・3 の未来形状(780 日目まで)の平均(赤点線)
- 最終未来予測(赤太線)
- 右軸は価格(USD, log スケール)で左軸と完全同期
BTC の長期分析に使える強力な可視化になります。
🧠 モデルの考え方
1. 過去周期の未来形状を Cycle4 に整列する
- 横方向:Cycle3 の終了日を基準に水平シフト
- 縦方向:Cycle4 の End(120,000 USD)に合わせて log10 方向に垂直シフト;end120000$の妥当性は、第一期から三期のendの値と第一期から四期の最大値の推移双方を説明する曲線から凡そ概算しました。
ここでは、割愛します。
これにより、過去周期の未来形状を Cycle4 の未来に重ねることができます。
2. Cycle2・3 の未来形状を平均する
780 日目以降の未来形状を平均し、
Cycle4 の未来の「形」を推定します。
3. Cycle1 も加えて再平均
Cycle1 の未来形状も加えることで、
より滑らかで安定した未来曲線を作ります。
4. 振幅減衰(k=0.6)
過去周期の振幅は徐々に小さくなっているため、
未来形状を 0.6 倍に減衰させます。
🧪 実装コード(全文)
コード
.py
import numpy as np
import pandas as pd
import yfinance as yf
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
# -----------------------------
# 1. BTC データ取得(4期)
# -----------------------------
periods = [
("2012-11-28", "2016-07-09"),
("2016-07-09", "2020-05-11"),
("2020-05-11", "2024-04-20"),
("2024-04-20", "2028-04-20")
]
btc_data = []
for start, end in periods:
df = yf.download("BTC-USD", start=start, end=end)
df = df[["Close"]]
df["days"] = (df.index - df.index[0]).days
btc_data.append(df)
# -----------------------------
# 2. 第四期 End の値(120000)
# -----------------------------
log_end4 = np.log10(120000)
# -----------------------------
# 3. 第三期 End 日(横軸の基準)
# -----------------------------
end3_day = btc_data[2]["days"].iloc[-1]
# -----------------------------
# 4. 四期(Cycle 4)
# -----------------------------
df4 = btc_data[3]
aligned_days4 = df4["days"].values - df4["days"].values[0]
log4 = np.log10(df4["Close"].values)
current4_day = aligned_days4[-1]
start_date4 = df4.index[0]
# -----------------------------
# 5. 一期〜三期の未来部分を取得
# -----------------------------
aligned_curves = []
aligned_curves.append((aligned_days4, log4, "Cycle 4 (x=0)"))
future_2 = None
future_3 = None
for idx in [0, 1, 2]:
df = btc_data[idx]
days = df["days"].values
logp = np.log10(df["Close"].values)
aligned_days = days - days[-1] + end3_day
mask_future = aligned_days >= current4_day
x_future = aligned_days[mask_future]
y_future = logp[mask_future] + (log_end4 - logp[-1])
aligned_curves.append((x_future, y_future, f"Cycle {idx+1} future"))
if idx == 1:
future_2 = (x_future, y_future)
if idx == 2:
future_3 = (x_future, y_future)
# -----------------------------
# 6. 未来予測(y_final_scaled)
# -----------------------------
sk = 780
mask2 = future_2[0] >= sk
mask3 = future_3[0] >= sk
x2 = future_2[0][mask2]
y2 = future_2[1][mask2]
x3 = future_3[0][mask3]
y3 = future_3[1][mask3]
min_len = min(len(x2), len(x3))
x_avg = x2[:min_len]
y_avg = (y2[:min_len] + y3[:min_len]) / 2
future_1 = aligned_curves[1]
x1_all, y1_all, _ = future_1
mask1 = x1_all >= sk
x1 = x1_all[mask1]
y1 = y1_all[mask1]
min_len2 = min(len(x_avg), len(x1))
x_final = x_avg[:min_len2]
y_final = (y_avg[:min_len2] + y1[:min_len2]) / 2
k = 0.6
y_final_scaled = log_end4 + k * (y_final - log_end4)
date_final = start_date4 + pd.to_timedelta(x_final, unit="D")
# -----------------------------
# 7. Cycle2&3 の未来部分(780日目まで)平均(赤点線)
# -----------------------------
mask2_780 = future_2[0] <= sk
mask3_780 = future_3[0] <= sk
x2_780 = future_2[0][mask2_780]
y2_780 = future_2[1][mask2_780]
x3_780 = future_3[0][mask3_780]
y3_780 = future_3[1][mask3_780]
y2_780_scaled = log_end4 + k * (y2_780 - log_end4)
y3_780_scaled = log_end4 + k * (y3_780 - log_end4)
min_len_780 = min(len(x2_780), len(x3_780))
x_red_780 = x2_780[:min_len_780]
y_red_780 = (y2_780_scaled[:min_len_780] + y3_780_scaled[:min_len_780]) / 2
date_red_780 = start_date4 + pd.to_timedelta(x_red_780, unit="D")
# -----------------------------
# 8. 描画(左:log10、右:価格×対数軸)
# -----------------------------
fig, ax1 = plt.subplots(figsize=(14, 8))
ax1.set_ylabel("log10(Price)")
ax1.set_xlabel("Date")
ax1.grid(True, linestyle="--", alpha=0.6)
ax1.xaxis.set_major_locator(mdates.MonthLocator(interval=3))
ax1.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m"))
colors = ["purple", "blue", "green", "orange"]
for i, (days, logp, label) in enumerate(aligned_curves):
dates = start_date4 + pd.to_timedelta(days, unit="D")
if "Cycle 1" in label or "Cycle 2" in label or "Cycle 3" in label:
mask = days <= sk
dates = dates[mask]
logp = logp[mask]
logp = log_end4 + k * (logp - log_end4)
ax1.plot(dates, logp, color=colors[i], alpha=0.6, label=label)
ax1.plot(date_final, y_final_scaled, color="red", linewidth=3.0,
label="Future prediction (scaled k=0.6)")
ax1.plot(date_red_780, y_red_780, color="red", linewidth=2.0, linestyle="--",
label="Avg Cycle2&3 (0–780 days, scaled)")
ax2 = ax1.twinx()
ax2.set_ylabel("Price (USD, log scale)")
ax2.set_yscale("log")
ymin, ymax = ax1.get_ylim()
ax2.set_ylim(10**ymin, 10**ymax)
plt.title("Original log10 Chart + Right Axis (Price Log Scale)", fontsize=16)
fig.legend(loc="upper left")
plt.tight_layout()
plt.show()
結果グラフ
🔍 可視化のポイント
■ log10 と価格(log スケール)の同期
左軸(log10)と右軸(価格)を完全同期させることで、
- log10 の形状
- 実際の価格の動き
を同時に観察できます。
■ Cycle2・3 の未来形状の平均(赤点線)
780 日目までの未来形状を平均し、
短期的な未来の参考曲線として利用します。
■ 最終未来予測(赤太線)
Cycle1〜3 の未来形状を統合し、
振幅減衰(k=0.6)を適用した未来予測です。
📝 まとめ
本記事では、ビットコインの 4 年周期を利用した未来予測モデルを Python で構築しました。
- 過去周期の未来形状を Cycle4 に整列
- End 価格を基準に log10 方向へスケーリング
- Cycle2・3 の未来形状を平均
- Cycle1 を加えて再平均
- 振幅減衰(k=0.6)
- log10 と価格の二軸同期チャート
これらを組み合わせることで、
Cycle4 の未来価格の「形状」を推定するモデルが完成します。
