- Authors
- Name
- Introduction
- Why Rebalancing Is Necessary
- Rebalancing Strategies
- Python Rebalancing Calculator
- Tax-Efficient Strategies
- Asset Allocation Model Examples
- Automation: Rebalancing Alert Bot
- Conclusion

Introduction
When starting to invest, people focus on "which ETFs to buy," but in the long run, what determines returns is asset allocation and rebalancing. Rebalancing is the process of restoring your portfolio to its target ratios when asset weights have drifted from the goal.
This article covers rebalancing from theory to Python automation, taking a practical developer's perspective.
Why Rebalancing Is Necessary
Weight Drift Example
# Initial portfolio (target weights)
portfolio = {
"Korean Stocks (KODEX 200)": 0.30, # 30%
"US Stocks (VOO)": 0.40, # 40%
"Bonds (TLT)": 0.20, # 20%
"Gold (GLD)": 0.10 # 10%
}
# After 1 year (stocks up, bonds down)
# Korean Stocks: 30% -> 28% (-2%)
# US Stocks: 40% -> 48% (+8%) <- Exceeds target!
# Bonds: 20% -> 16% (-4%) <- Below target!
# Gold: 10% -> 8% (-2%)
# Without rebalancing:
# - Stock allocation rises to 76%, creating excessive risk exposure
# - The intended diversification effect is lost
Benefits of Rebalancing
1. Risk management: Prevents concentration in a single asset
2. Buy low/sell high: Contrarian effect of selling what has risen and buying what has fallen
3. Discipline: Prevents emotional investment decisions
4. Long-term return improvement: Better risk-adjusted returns (Sharpe ratio)
Rebalancing Strategies
1. Calendar Rebalancing (Time-Based)
# Rebalance at fixed intervals
# Pros: Simple and easy to execute
# Cons: Executes regardless of market conditions
# Quarterly rebalancing (most common)
REBALANCE_SCHEDULE = "quarterly" # monthly, quarterly, semi-annually, annually
# Recommended frequency:
# - Monthly: When transaction costs are low (commission-free brokerages)
# - Quarterly: Suitable for most investors
# - Semi-annual/Annual: When tax efficiency is prioritized
2. Threshold Rebalancing
# Rebalance when deviation exceeds a set range from targets
# Pros: Responds immediately to large movements
# Cons: Frequent trades during extreme market volatility
THRESHOLD = 0.05 # Rebalance when 5% drift occurs
def needs_rebalancing(current_weights: dict, target_weights: dict, threshold: float) -> bool:
"""Determine if rebalancing is needed"""
for asset, target in target_weights.items():
current = current_weights.get(asset, 0)
if abs(current - target) > threshold:
return True
return False
# Example: US stocks go from 40% -> 46% (6% drift) -> Rebalancing needed!
3. Hybrid Strategy (Most Recommended)
# Quarterly check + 5% threshold combination
# - Check portfolio every quarter
# - Rebalance if any asset drifts more than 5%
# - If no drift, wait until next quarter
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 months
) -> dict:
"""Hybrid rebalancing strategy"""
from datetime import datetime, timedelta
needs_rebal = False
reason = ""
# Threshold check
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 {target:.1%}, drift {drift:.1%})"
break
# Maximum interval check
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"Maximum rebalancing interval of {max_interval_days} days exceeded"
return {
"needs_rebalancing": needs_rebal,
"reason": reason
}
Python Rebalancing Calculator
Basic Calculation
def calculate_rebalancing(
portfolio: dict,
target_weights: dict,
total_value: float
) -> dict:
"""Calculate rebalancing trades"""
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": "Buy" if diff > 0 else "Sell" if diff < 0 else "Hold"
}
return trades
# Usage example
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"] != "Hold":
print(f"{asset}: {trade['action']} {abs(trade['trade_amount']):,.0f} KRW")
print(f" Current: {trade['current_weight']:.1%} -> Target: {trade['target_weight']:.1%}")
Cash Flow Rebalancing
def cash_flow_rebalancing(
portfolio: dict,
target_weights: dict,
total_value: float,
new_cash: float
) -> dict:
"""Rebalance using new cash (minimize selling)"""
new_total = total_value + new_cash
# Calculate shortfall for each asset
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())
# Allocate new cash proportionally to shortfalls
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
# Example: Additional 1 million KRW investment
allocations = cash_flow_rebalancing(portfolio, target_weights, total_value, 1000000)
print("New cash allocation:")
for asset, amount in allocations.items():
print(f" {asset}: Buy {amount:,} KRW")
# Adjust weights using only new cash, with no selling!
Tax-Efficient Strategies
Tax-Loss Harvesting
def tax_loss_harvesting(
holdings: list,
threshold_loss_pct: float = -0.05
) -> list:
"""Sell losing positions for tax savings"""
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": "Sell and replace with similar ETF"
})
return harvest_candidates
# For Korea:
# - Domestic stock ETFs: Tax-free (capital gains)
# - Overseas ETFs: 22% capital gains tax (2.5 million KRW exemption)
# - Dividend income tax: 15.4%
#
# Tax-Loss Harvesting is effective for overseas ETFs
Asset Allocation Model Examples
Portfolio Models
# 1. Conservative Portfolio (stability-focused)
conservative = {
"Korean Bonds (KOSEF 10Y Treasury)": 0.40,
"US Bonds (TLT)": 0.20,
"Korean Stocks (KODEX 200)": 0.15,
"US Stocks (VOO)": 0.15,
"Gold (GLD)": 0.10
}
# 2. Balanced Portfolio (general)
balanced = {
"Korean Stocks (KODEX 200)": 0.25,
"US Stocks (VOO)": 0.30,
"Developed Markets (VEA)": 0.10,
"Bonds (AGG)": 0.25,
"Gold (GLD)": 0.10
}
# 3. Aggressive Portfolio (growth-focused)
aggressive = {
"US Stocks (VOO)": 0.35,
"NASDAQ (QQQ)": 0.20,
"Korean Stocks (KODEX 200)": 0.15,
"Emerging Markets (VWO)": 0.10,
"Bonds (AGG)": 0.15,
"Gold (GLD)": 0.05
}
# 4. All Weather - Ray Dalio
all_weather = {
"US Stocks (VOO)": 0.30,
"US Long-Term Bonds (TLT)": 0.40,
"US Intermediate Bonds (IEF)": 0.15,
"Gold (GLD)": 0.075,
"Commodities (DBC)": 0.075
}
Automation: Rebalancing Alert Bot
#!/usr/bin/env python3
"""rebalance_checker.py - Rebalancing check script"""
import json
from datetime import datetime
def check_and_notify():
# Portfolio data (in practice, use brokerage API or manual input)
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())
# Check drift
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 = "over" if drift > 0 else "under"
alerts.append(
f"Warning: {asset}: currently {current_w:.1%} (target {target_w:.1%}, {abs(drift):.1%} {direction})"
)
if alerts:
message = f"Portfolio Rebalancing Alert ({datetime.now().strftime('%Y-%m-%d')})\n\n"
message += "\n".join(alerts)
message += f"\n\nTotal Assets: {total:,.0f} KRW"
print(message)
# Add Telegram/Slack notification integration here
else:
print("Portfolio normal - no rebalancing needed")
if __name__ == "__main__":
check_and_notify()
# Check every Monday with crontab
# 0 9 * * 1 python3 /path/to/rebalance_checker.py
Conclusion
Key points for ETF rebalancing:
- Hybrid strategy recommended: Quarterly check + 5% threshold combination
- Leverage cash flows: Buy underweight assets with new investment funds (minimize selling)
- Tax efficiency: Consider Tax-Loss Harvesting for overseas ETFs
- Automation: Monitor drift with Python scripts
- Maintain discipline: Remove emotions, execute by rules
Quiz (7 Questions)
Q1. What is the core purpose of rebalancing? To restore the portfolio's asset weights to target allocation, managing risk and maintaining diversification benefits.
Q2. What is the difference between time-based vs threshold-based rebalancing? Time-based: Executes at fixed intervals. Threshold-based: Executes when deviation exceeds a set percentage.
Q3. What is the advantage of cash flow rebalancing? Adjust weights using only new cash without selling, minimizing transaction costs and taxes.
Q4. What is Tax-Loss Harvesting? A strategy of selling losing positions for tax deductions and buying similar ETFs as replacements.
Q5. Why is the bond allocation high in the All Weather portfolio? To pursue stable returns regardless of the economic environment (growth/recession x inflation/deflation).
Q6. What is the basic capital gains tax exemption for overseas ETFs in Korea? 2.5 million KRW (22% tax on the excess amount).
Q7. What is the "buy low/sell high" effect in rebalancing? By selling appreciated assets (high) and buying depreciated assets (low), contrarian investing is naturally achieved.