- Authors
- Name

はじめに
投資を始めると「どのETFを買うか?」に集中しがちですが、長期的にリターンを決定するのは資産配分とリバランスです。リバランスとは、ポートフォリオの資産比率が目標から乖離した際に、元の比率に戻す作業です。
本記事では、リバランスの理論からPython自動化まで、開発者視点で実践的に解説します。
リバランスが必要な理由
比率ドリフトの例
# 初期ポートフォリオ(目標比率)
portfolio = {
"韓国株式(KODEX 200)": 0.30, # 30%
"米国株式(VOO)": 0.40, # 40%
"債券(TLT)": 0.20, # 20%
"金(GLD)": 0.10 # 10%
}
# 1年後(株式上昇、債券下落の場合)
# 韓国株式: 30% -> 28% (-2%)
# 米国株式: 40% -> 48% (+8%) ← 目標超過!
# 債券: 20% -> 16% (-4%) ← 目標未達!
# 金: 10% -> 8% (-2%)
# リバランスなしで放置すると:
# - 株式比率76%で過度なリスクエクスポージャー
# - 本来意図した分散投資効果が失われる
リバランスの効果
1. リスク管理: 特定資産への偏りを防止
2. 安く買い/高く売り: 上昇した資産を売り、下落した資産を買う逆張り効果
3. 規律の維持: 感情的な投資判断を防止
4. 長期リターンの改善: ボラティリティ対比リターン(シャープレシオ)の向上
リバランス戦略
1. 時間ベースリバランス(Calendar Rebalancing)
# 決められた周期でリバランス
# メリット: シンプルで実行しやすい
# デメリット: 市場状況と無関係に実行
# 四半期リバランス(最も一般的)
REBALANCE_SCHEDULE = "quarterly" # monthly, quarterly, semi-annually, annually
# 推奨周期:
# - 月次: 取引コストが低い場合(手数料無料証券会社)
# - 四半期: ほとんどの投資家に適切
# - 半期/年次: 税金効率を重視する場合
2. 閾値ベースリバランス(Threshold Rebalancing)
# 目標比率から一定範囲を超えたらリバランス
# メリット: 大きな変動に即時対応
# デメリット: 市場急変時に頻繁な取引が発生
THRESHOLD = 0.05 # 5%乖離時にリバランス
def needs_rebalancing(current_weights: dict, target_weights: dict, threshold: float) -> bool:
"""リバランスの必要性を判断"""
for asset, target in target_weights.items():
current = current_weights.get(asset, 0)
if abs(current - target) > threshold:
return True
return False
# 例: 米国株式が40% -> 46%(6%乖離)→ リバランス必要!
3. ハイブリッド戦略(最も推奨)
# 四半期チェック + 5%閾値の組み合わせ
# - 毎四半期ポートフォリオを確認
# - 5%以上乖離した資産があればリバランス
# - 乖離がなければ次の四半期まで待機
def hybrid_rebalancing_check(
current_weights: dict,
target_weights: dict,
threshold: float = 0.05,
last_rebalance_date: str = None,
max_interval_days: int = 180 # 6ヶ月
) -> dict:
"""ハイブリッドリバランス戦略"""
from datetime import datetime, timedelta
needs_rebal = False
reason = ""
# 閾値チェック
for asset, target in target_weights.items():
current = current_weights.get(asset, 0)
drift = abs(current - target)
if drift > threshold:
needs_rebal = True
reason = f"{asset}: {current:.1%}(目標 {target:.1%}、乖離 {drift:.1%})"
break
# 最大間隔チェック
if last_rebalance_date and not needs_rebal:
last_date = datetime.strptime(last_rebalance_date, "%Y-%m-%d")
if (datetime.now() - last_date).days > max_interval_days:
needs_rebal = True
reason = f"最大リバランス間隔{max_interval_days}日を超過"
return {
"needs_rebalancing": needs_rebal,
"reason": reason
}
Pythonリバランス計算機
基本計算
def calculate_rebalancing(
portfolio: dict,
target_weights: dict,
total_value: float
) -> dict:
"""リバランス取引の計算"""
trades = {}
for asset, target_weight in target_weights.items():
current_value = portfolio.get(asset, {}).get("value", 0)
target_value = total_value * target_weight
diff = target_value - current_value
trades[asset] = {
"current_value": current_value,
"current_weight": current_value / total_value if total_value > 0 else 0,
"target_value": target_value,
"target_weight": target_weight,
"trade_amount": diff,
"action": "買い" if diff > 0 else "売り" if diff < 0 else "維持"
}
return trades
# 使用例
portfolio = {
"KODEX 200": {"value": 2800000, "price": 35000},
"VOO": {"value": 4800000, "price": 550000},
"TLT": {"value": 1600000, "price": 85000},
"GLD": {"value": 800000, "price": 260000}
}
target_weights = {
"KODEX 200": 0.30,
"VOO": 0.40,
"TLT": 0.20,
"GLD": 0.10
}
total_value = sum(a["value"] for a in portfolio.values())
trades = calculate_rebalancing(portfolio, target_weights, total_value)
for asset, trade in trades.items():
if trade["action"] != "維持":
print(f"{asset}: {trade['action']} {abs(trade['trade_amount']):,.0f}ウォン")
print(f" 現在: {trade['current_weight']:.1%} → 目標: {trade['target_weight']:.1%}")
キャッシュフロー活用リバランス
def cash_flow_rebalancing(
portfolio: dict,
target_weights: dict,
total_value: float,
new_cash: float
) -> dict:
"""新規資金でのリバランス(売却を最小化)"""
new_total = total_value + new_cash
# 各資産の不足分を計算
shortfalls = {}
for asset, target_weight in target_weights.items():
current_value = portfolio.get(asset, {}).get("value", 0)
target_value = new_total * target_weight
shortfall = max(0, target_value - current_value)
shortfalls[asset] = shortfall
total_shortfall = sum(shortfalls.values())
# 新規資金を不足分の比率で配分
allocations = {}
for asset, shortfall in shortfalls.items():
if total_shortfall > 0:
allocation = new_cash * (shortfall / total_shortfall)
else:
allocation = new_cash * target_weights[asset]
allocations[asset] = round(allocation)
return allocations
# 例: 100万ウォン追加投資
allocations = cash_flow_rebalancing(portfolio, target_weights, total_value, 1000000)
print("新規資金の配分:")
for asset, amount in allocations.items():
print(f" {asset}: {amount:,}ウォン購入")
# 売却なしで新規資金のみで比率調整!
税金効率化戦略
Tax-Loss Harvesting
def tax_loss_harvesting(
holdings: list,
threshold_loss_pct: float = -0.05
) -> list:
"""損失ポジションを売却して税金を節約"""
harvest_candidates = []
for holding in holdings:
gain_pct = (holding["current_price"] - holding["avg_cost"]) / holding["avg_cost"]
if gain_pct < threshold_loss_pct:
harvest_candidates.append({
"asset": holding["asset"],
"loss_amount": (holding["current_price"] - holding["avg_cost"]) * holding["quantity"],
"gain_pct": gain_pct,
"action": "売却後、類似ETFで代替"
})
return harvest_candidates
# 韓国の場合:
# - 国内株式ETF: 非課税(売買差益)
# - 海外ETF: 譲渡所得税22%(250万ウォン控除)
# - 配当所得税: 15.4%
#
# Tax-Loss Harvestingは海外ETFに効果的
資産配分モデル例
ポートフォリオモデル
# 1. 保守的ポートフォリオ(安定志向)
conservative = {
"韓国債券(KOSEF 国債10年)": 0.40,
"米国債券(TLT)": 0.20,
"韓国株式(KODEX 200)": 0.15,
"米国株式(VOO)": 0.15,
"金(GLD)": 0.10
}
# 2. バランス型ポートフォリオ(一般的)
balanced = {
"韓国株式(KODEX 200)": 0.25,
"米国株式(VOO)": 0.30,
"先進国(VEA)": 0.10,
"債券(AGG)": 0.25,
"金(GLD)": 0.10
}
# 3. 積極的ポートフォリオ(成長志向)
aggressive = {
"米国株式(VOO)": 0.35,
"NASDAQ(QQQ)": 0.20,
"韓国株式(KODEX 200)": 0.15,
"新興国(VWO)": 0.10,
"債券(AGG)": 0.15,
"金(GLD)": 0.05
}
# 4. オールウェザー(All Weather)- レイ・ダリオ
all_weather = {
"米国株式(VOO)": 0.30,
"米国長期債(TLT)": 0.40,
"米国中期債(IEF)": 0.15,
"金(GLD)": 0.075,
"コモディティ(DBC)": 0.075
}
自動化:リバランスアラートボット
#!/usr/bin/env python3
"""rebalance_checker.py — リバランス必要性チェックスクリプト"""
import json
from datetime import datetime
def check_and_notify():
# ポートフォリオデータ(実際には証券会社APIまたは手動入力)
portfolio = {
"KODEX 200": {"value": 2800000, "shares": 80},
"VOO": {"value": 4800000, "shares": 8},
"TLT": {"value": 1600000, "shares": 18},
"GLD": {"value": 800000, "shares": 3}
}
target = {
"KODEX 200": 0.30,
"VOO": 0.40,
"TLT": 0.20,
"GLD": 0.10
}
total = sum(a["value"] for a in portfolio.values())
# ドリフト確認
alerts = []
for asset, target_w in target.items():
current_w = portfolio[asset]["value"] / total
drift = current_w - target_w
if abs(drift) > 0.05:
direction = "超過" if drift > 0 else "不足"
alerts.append(
f"警告: {asset}: 現在 {current_w:.1%}(目標 {target_w:.1%}、{abs(drift):.1%} {direction})"
)
if alerts:
message = f"リバランスアラート({datetime.now().strftime('%Y-%m-%d')})\n\n"
message += "\n".join(alerts)
message += f"\n\n総資産: {total:,.0f}ウォン"
print(message)
# ここにTelegram/Slack通知を連携
else:
print("ポートフォリオ正常 — リバランス不要")
if __name__ == "__main__":
check_and_notify()
# crontabで毎週月曜日にチェック
# 0 9 * * 1 python3 /path/to/rebalance_checker.py
まとめ
ETFリバランスの重要ポイント:
- ハイブリッド戦略を推奨: 四半期チェック + 5%閾値の組み合わせ
- キャッシュフローの活用: 新規投資資金で不足資産を購入(売却を最小化)
- 税金効率: 海外ETFはTax-Loss Harvestingを考慮
- 自動化: Pythonスクリプトでドリフトをモニタリング
- 規律の維持: 感情を排除し、ルールベースで実行
クイズ(7問)
Q1. リバランスの核心的な目的は? ポートフォリオの資産比率を目標配分に戻し、リスクを管理して分散投資効果を維持すること
Q2. 時間ベース vs 閾値ベースリバランスの違いは? 時間ベース: 決められた周期で実行。閾値ベース: 目標から一定比率乖離した時に実行
Q3. キャッシュフローリバランスのメリットは? 売却なしで新規資金のみで比率を調整し、取引コストと税金を最小化
Q4. Tax-Loss Harvestingとは? 損失が出たポジションを売却して税金控除を受け、類似ETFで代替購入する戦略
Q5. オールウェザーポートフォリオで債券比率が高い理由は? 経済環境(成長/後退 x インフレ/デフレ)に関係なく安定したリターンを追求するため
Q6. 韓国で海外ETFの譲渡所得税の基本控除額は? 250万ウォン(超過分に対して22%課税)
Q7. リバランスにおける「安く買い/高く売り」効果とは? 上昇した資産(高値)を売り、下落した資産(安値)を買うため、自然と逆張り投資が実現される