# Portfolio Management Expert

> Expert-level portfolio management and asset allocation. Use when working with portfolio construction, asset allocation, rebalancing, diversification, factor exposure, ETF selection, retirement planning, or long-term wealth building. Also use when the user mentions 'asset allocation', 'rebalancing', 'diversification', 'ETF', 'index fund', '60/40 portfolio', 'modern portfolio theory', 'passive investing', 'wealth management', or 'retirement portfolio'.

- Skill: `luokai0/portfolio-management-expert` (Agent Skill)
- Install (CLI): `npx skillmds@latest add luokai0/portfolio-management-expert`
- Raw SKILL.md: https://api.skillmd.com/api/skills/luokai0/portfolio-management-expert/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- License: MIT
- Author: luokai0 (https://skillmd.com/u/luokai0)
- Updated: 2026-09-08
- Page: https://skillmd.com/skills/luokai0/portfolio-management-expert

---


# Portfolio Management Expert

You are a world-class portfolio manager with deep expertise in asset allocation, portfolio construction, rebalancing strategies, factor investing, ETF selection, tax efficiency, and long-term wealth building frameworks.

## Before Starting

1. **Goal** — Wealth building, income generation, capital preservation, or retirement?
2. **Horizon** — Short term (<3 years), medium (3-10), or long term (10+ years)?
3. **Risk tolerance** — Conservative, moderate, or aggressive?
4. **Account type** — Taxable, IRA, 401k, or institutional?
5. **Starting point** — Building from scratch or optimizing existing portfolio?

---

## Core Expertise Areas

- **Asset Allocation**: strategic, tactical, dynamic allocation models
- **Portfolio Construction**: mean-variance, risk parity, factor tilts
- **Rebalancing**: calendar, threshold, tax-efficient rebalancing
- **ETF & Fund Selection**: expense ratios, tracking error, liquidity
- **Factor Investing**: value, momentum, quality, low volatility tilts
- **Tax Efficiency**: asset location, tax-loss harvesting, turnover
- **Retirement Planning**: safe withdrawal rates, sequence risk, glide paths
- **Performance Attribution**: factor exposure, alpha, benchmark comparison

---

## Asset Allocation Frameworks

### Strategic Asset Allocation Models
```python
def asset_allocation_models():
    return {
        'Conservative': {
            'US Bonds':          0.40,
            'International Bonds':0.10,
            'US Stocks':         0.25,
            'International Stocks':0.15,
            'Cash':              0.10,
            'expected_return':   '4-5% annually',
            'expected_vol':      '6-8%',
            'best_for':          'Capital preservation, near retirement'
        },
        'Moderate_60_40': {
            'US Stocks':           0.40,
            'International Stocks':0.20,
            'US Bonds':            0.30,
            'International Bonds': 0.10,
            'expected_return':     '6-7% annually',
            'expected_vol':        '10-12%',
            'best_for':            'Balanced growth and stability'
        },
        'Growth': {
            'US Stocks':           0.50,
            'International Stocks':0.30,
            'Emerging Markets':    0.10,
            'US Bonds':            0.10,
            'expected_return':     '7-9% annually',
            'expected_vol':        '14-16%',
            'best_for':            'Long horizon, high risk tolerance'
        },
        'Aggressive': {
            'US Stocks':           0.50,
            'International Stocks':0.30,
            'Emerging Markets':    0.15,
            'Alternatives':        0.05,
            'expected_return':     '8-10% annually',
            'expected_vol':        '16-20%',
            'best_for':            '20+ year horizon, maximum growth'
        },
        'All_Weather': {
            'US Stocks':           0.30,
            'Long Term Bonds':     0.40,
            'Intermediate Bonds':  0.15,
            'Gold':                0.075,
            'Commodities':         0.075,
            'expected_return':     '5-6% annually',
            'expected_vol':        '7-9%',
            'best_for':            'All economic environments (Ray Dalio)'
        },
        'Golden_Butterfly': {
            'US Total Market':     0.20,
            'US Small Cap Value':  0.20,
            'Long Term Bonds':     0.20,
            'Short Term Bonds':    0.20,
            'Gold':                0.20,
            'expected_return':     '6-7% annually',
            'expected_vol':        '8-10%',
            'best_for':            'Balanced across economic regimes'
        }
    }
```

### Dynamic Asset Allocation
```python
def tactical_allocation(vix, yield_curve_slope, momentum_signal):
    """
    Adjust allocation based on market conditions.
    Base: 60% stocks / 40% bonds
    """
    stock_weight = 0.60
    bond_weight  = 0.40

    # Reduce stocks in high volatility
    if vix > 30:
        stock_weight -= 0.15
        bond_weight  += 0.15
    elif vix > 20:
        stock_weight -= 0.05
        bond_weight  += 0.05

    # Reduce stocks when yield curve inverted (recession signal)
    if yield_curve_slope < 0:
        stock_weight -= 0.10
        bond_weight  += 0.10

    # Momentum overlay
    if momentum_signal < 0:
        stock_weight -= 0.10
        bond_weight  += 0.10

    # Normalize
    total = stock_weight + bond_weight
    return {
        'stocks': round(max(0.20, stock_weight / total), 2),
        'bonds':  round(min(0.80, bond_weight  / total), 2)
    }

def lifecycle_glide_path(age, retirement_age=65):
    """
    Age-based asset allocation glide path.
    Classic rule: 110 - age = stock allocation
    Modern rule: 120 - age (longer life expectancy)
    """
    years_to_retirement = retirement_age - age

    # Aggressive accumulation phase
    if years_to_retirement > 30:
        stocks = 0.90
        bonds  = 0.10
    elif years_to_retirement > 20:
        stocks = 0.80
        bonds  = 0.20
    elif years_to_retirement > 10:
        stocks = 0.70
        bonds  = 0.30
    elif years_to_retirement > 5:
        stocks = 0.60
        bonds  = 0.40
    elif years_to_retirement > 0:
        stocks = 0.50
        bonds  = 0.50
    else:
        # In retirement - sequence of returns risk
        stocks = 0.40
        bonds  = 0.60

    return {
        'age':                age,
        'years_to_retirement': years_to_retirement,
        'stocks':             stocks,
        'bonds':              bonds,
        'rationale':          f"{'Accumulation' if years_to_retirement > 0 else 'Distribution'} phase"
    }
```

---

## Portfolio Construction
```python
import numpy as np
import pandas as pd
from scipy.optimize import minimize

def efficient_frontier(returns, n_portfolios=1000, risk_free=0.05):
    """Generate efficient frontier by simulating random portfolios."""
    n_assets  = returns.shape[1]
    results   = []

    for _ in range(n_portfolios):
        weights = np.random.dirichlet(np.ones(n_assets))
        port_ret = np.sum(returns.mean() * weights) * 252
        port_vol = np.sqrt(weights @ (returns.cov() * 252) @ weights)
        sharpe   = (port_ret - risk_free) / port_vol
        results.append({
            'return':  round(port_ret * 100, 2),
            'vol':     round(port_vol * 100, 2),
            'sharpe':  round(sharpe, 3),
            'weights': weights.round(4).tolist()
        })

    df = pd.DataFrame(results)
    max_sharpe = df.loc[df['sharpe'].idxmax()]
    min_vol    = df.loc[df['vol'].idxmin()]

    return {
        'max_sharpe_portfolio': max_sharpe.to_dict(),
        'min_vol_portfolio':    min_vol.to_dict(),
        'frontier':             df
    }

def black_litterman(market_weights, returns, views, view_confidences,
                    risk_aversion=2.5, tau=0.05):
    """
    Black-Litterman model for incorporating investor views
    into portfolio optimization.
    views: dict of {asset_index: expected_return}
    """
    cov     = returns.cov() * 252
    n       = len(market_weights)

    # Implied equilibrium returns
    pi      = risk_aversion * cov @ market_weights

    # View matrix P and view vector Q
    k       = len(views)
    P       = np.zeros((k, n))
    Q       = np.zeros(k)
    Omega   = np.zeros((k, k))

    for i, (asset_idx, view_return) in enumerate(views.items()):
        P[i, asset_idx] = 1
        Q[i]            = view_return
        Omega[i, i]     = view_confidences[i]

    # BL posterior returns
    tau_cov = tau * cov
    M1      = np.linalg.inv(np.linalg.inv(tau_cov) + P.T @ np.linalg.inv(Omega) @ P)
    M2      = np.linalg.inv(tau_cov) @ pi + P.T @ np.linalg.inv(Omega) @ Q
    bl_returns = M1 @ M2

    return {
        'equilibrium_returns': dict(enumerate(pi.round(4))),
        'bl_posterior_returns': dict(enumerate(bl_returns.round(4)))
    }

def risk_parity_weights(returns):
    """Equal risk contribution portfolio."""
    n   = returns.shape[1]
    cov = returns.cov() * 252

    def risk_contribution_error(weights):
        weights    = np.array(weights)
        port_var   = weights @ cov @ weights
        mrc        = cov @ weights
        rc         = weights * mrc / port_var
        target     = np.ones(n) / n
        return np.sum((rc - target) ** 2)

    result = minimize(
        risk_contribution_error,
        x0=np.ones(n)/n,
        method='SLSQP',
        bounds=[(0.01, 1)] * n,
        constraints=[{'type': 'eq', 'fun': lambda w: np.sum(w) - 1}]
    )
    return result.x.round(4)
```

---

## Rebalancing Strategies
```python
def rebalancing_analysis(current_weights, target_weights,
                          portfolio_value, threshold=0.05):
    """
    Determine if rebalancing is needed and calculate trades.
    Threshold rebalancing: rebalance when any asset drifts > 5%
    """
    current_weights = np.array(current_weights)
    target_weights  = np.array(target_weights)
    drift           = current_weights - target_weights
    max_drift       = np.max(np.abs(drift))
    needs_rebalance = max_drift > threshold

    trades = []
    if needs_rebalance:
        for i, (cur, tgt) in enumerate(zip(current_weights, target_weights)):
            trade_value = (tgt - cur) * portfolio_value
            trades.append({
                'asset':        i,
                'current_pct':  round(cur * 100, 2),
                'target_pct':   round(tgt * 100, 2),
                'drift':        round((cur - tgt) * 100, 2),
                'trade_value':  round(trade_value, 2),
                'action':       'BUY' if trade_value > 0 else 'SELL'
            })

    return {
        'needs_rebalance': needs_rebalance,
        'max_drift':       round(max_drift * 100, 2),
        'trades':          trades
    }

def tax_efficient_rebalance(current_weights, target_weights,
                             portfolio_value, positions):
    """
    Tax-efficient rebalancing — minimize capital gains.
    Prefer selling losers, rebalance using new contributions.
    """
    trades    = []
    tax_alpha = 0

    for pos in positions:
        cur_weight = pos['current_weight']
        tgt_weight = pos['target_weight']
        drift      = cur_weight - tgt_weight

        if abs(drift) < 0.03:
            continue

        cost_basis  = pos['cost_basis']
        cur_price   = pos['current_price']
        unrealized  = (cur_price - cost_basis) / cost_basis

        if drift > 0:  # overweight, need to sell
            if unrealized < 0:
                action   = 'SELL (tax loss harvest)'
                tax_alpha += abs(unrealized * drift * portfolio_value) * 0.25
            elif unrealized < 0.15:
                action = 'SELL (small gain, acceptable)'
            else:
                action = 'HOLD (large gain, defer if possible)'
        else:
            action = 'BUY (underweight)'

        trades.append({
            'asset':      pos['name'],
            'drift':      round(drift * 100, 2),
            'unrealized': round(unrealized * 100, 2),
            'action':     action
        })

    return {'trades': trades, 'estimated_tax_alpha': round(tax_alpha, 2)}
```

---

## ETF Selection Framework
```python
def etf_comparison(etfs):
    """
    Score ETFs for selection based on key criteria.
    """
    scored = []
    for etf in etfs:
        score = 0

        # Expense ratio (lower is better)
        if etf['expense_ratio'] < 0.05:   score += 3
        elif etf['expense_ratio'] < 0.15: score += 2
        elif etf['expense_ratio'] < 0.30: score += 1

        # AUM / liquidity
        if etf['aum_billions'] > 10:   score += 3
        elif etf['aum_billions'] > 1:  score += 2
        elif etf['aum_billions'] > 0.1: score += 1

        # Bid-ask spread
        if etf['bid_ask_spread_pct'] < 0.02:  score += 2
        elif etf['bid_ask_spread_pct'] < 0.10: score += 1

        # Tracking error vs index
        if etf.get('tracking_error', 1) < 0.10:  score += 2
        elif etf.get('tracking_error', 1) < 0.30: score += 1

        scored.append({**etf, 'score': score})

    return sorted(scored, key=lambda x: x['score'], reverse=True)

def core_etf_universe():
    """Reference ETF universe for portfolio construction."""
    return {
        'US_Total_Market':        ['VTI', 'ITOT', 'SCHB'],
        'US_Large_Cap':           ['VOO', 'IVV', 'SPY'],
        'US_Small_Cap':           ['VB', 'IJR', 'SCHA'],
        'US_Small_Cap_Value':     ['VBR', 'IJS', 'VIOV'],
        'International_Dev':      ['VXUS', 'IXUS', 'VEA'],
        'Emerging_Markets':       ['VWO', 'IEMG', 'EEM'],
        'US_Total_Bond':          ['BND', 'AGG', 'SCHZ'],
        'US_Short_Bond':          ['BSV', 'SHY', 'SCHO'],
        'US_Long_Bond':           ['BLV', 'TLT', 'VGLT'],
        'TIPS_Inflation':         ['VTIP', 'SCHP', 'TIP'],
        'International_Bond':     ['BNDX', 'IAGG'],
        'Gold':                   ['GLD', 'IAU', 'GLDM'],
        'Real_Estate_REIT':       ['VNQ', 'SCHH', 'IYR'],
        'Commodities':            ['DJP', 'PDBC', 'GSG'],
        'Factor_Value':           ['VTV', 'VLUE', 'IVE'],
        'Factor_Momentum':        ['MTUM', 'QMOM'],
        'Factor_Quality':         ['QUAL', 'DGRW'],
        'Factor_Low_Vol':         ['USMV', 'SPLV'],
    }
```

---

## Retirement Planning
```python
def safe_withdrawal_analysis(portfolio_value, annual_withdrawal,
                               stock_pct=0.60, years=30):
    """
    Monte Carlo simulation for retirement withdrawal sustainability.
    Based on Trinity Study and modern research.
    """
    withdrawal_rate = annual_withdrawal / portfolio_value

    # Historical return assumptions
    stock_return = 0.10  # nominal
    bond_return  = 0.04
    stock_vol    = 0.16
    bond_vol     = 0.07
    inflation    = 0.03

    port_return  = stock_pct * stock_return + (1-stock_pct) * bond_return
    port_vol     = stock_pct * stock_vol    + (1-stock_pct) * bond_vol
    real_return  = port_return - inflation

    np.random.seed(42)
    simulations  = 10000
    successes    = 0

    for _ in range(simulations):
        balance  = portfolio_value
        annual_w = annual_withdrawal

        for year in range(years):
            ret    = np.random.normal(real_return, port_vol)
            balance = balance * (1 + ret) - annual_w
            annual_w *= (1 + inflation)  # inflation-adjust withdrawal
            if balance <= 0:
                break
        else:
            successes += 1

    success_rate = successes / simulations

    return {
        'withdrawal_rate':   round(withdrawal_rate * 100, 2),
        'annual_withdrawal': annual_withdrawal,
        'success_rate':      round(success_rate * 100, 1),
        'sustainability':    'Safe'     if success_rate > 0.95 else
                             'Moderate' if success_rate > 0.85 else
                             'Risky',
        'recommendation':    '4% rule is generally safe for 30-year horizon'
                             if withdrawal_rate <= 0.04 else
                             'Consider reducing withdrawal rate'
    }

def sequence_of_returns_risk(portfolio_value, annual_withdrawal,
                              bad_start_returns=[-0.30, -0.20, -0.10]):
    """
    Illustrate sequence of returns risk in early retirement.
    Bad returns early are far more damaging than bad returns late.
    """
    results = {}

    for scenario, early_returns in [
        ('Bad early returns', bad_start_returns),
        ('Good early returns', [-r for r in bad_start_returns])
    ]:
        balance  = portfolio_value
        balances = [balance]

        for year in range(20):
            if year < len(early_returns):
                ret = early_returns[year]
            else:
                ret = 0.07  # normal returns after

            balance = balance * (1 + ret) - annual_withdrawal
            balance = max(0, balance)
            balances.append(round(balance, 0))

        results[scenario] = {
            'final_balance': balances[-1],
            'depleted':      balances[-1] == 0
        }

    return results

def retirement_number(annual_expenses, withdrawal_rate=0.04,
                       inflation_rate=0.03, years_to_retirement=20,
                       current_savings=0, annual_contribution=0):
    """Calculate the retirement number and savings needed."""
    target_portfolio = annual_expenses / withdrawal_rate

    # Future value of current savings
    fv_savings = current_savings * (1.07 ** years_to_retirement)

    # Future value of annual contributions
    fv_contributions = annual_contribution * (
        ((1.07 ** years_to_retirement) - 1) / 0.07
    )

    projected_portfolio = fv_savings + fv_contributions
    shortfall = target_portfolio - projected_portfolio

    # Additional annual savings needed
    if shortfall > 0:
        additional_needed = shortfall * 0.07 / ((1.07**years_to_retirement) - 1)
    else:
        additional_needed = 0

    return {
        'retirement_number':     round(target_portfolio, 0),
        'projected_portfolio':   round(projected_portfolio, 0),
        'shortfall':             round(max(0, shortfall), 0),
        'additional_annual':     round(additional_needed, 0),
        'on_track':              projected_portfolio >= target_portfolio
    }
```

---

## Performance Attribution
```python
def brinson_attribution(portfolio_weights, benchmark_weights,
                         portfolio_returns, benchmark_returns,
                         sector_benchmark_returns):
    """
    Brinson-Hood-Beebower performance attribution.
    Decomposes excess return into allocation and selection effects.
    """
    results = []
    total_allocation   = 0
    total_selection    = 0
    total_interaction  = 0

    for sector in portfolio_weights.keys():
        pw  = portfolio_weights[sector]
        bw  = benchmark_weights[sector]
        pr  = portfolio_returns[sector]
        br  = benchmark_returns[sector]
        sbr = sector_benchmark_returns[sector]

        allocation   = (pw - bw) * (sbr - sum(
            benchmark_weights[s] * benchmark_returns[s]
            for s in benchmark_weights
        ))
        selection    = bw * (pr - br)
        interaction  = (pw - bw) * (pr - br)

        total_allocation  += allocation
        total_selection   += selection
        total_interaction += interaction

        results.append({
            'sector':      sector,
            'allocation':  round(allocation * 100, 3),
            'selection':   round(selection * 100, 3),
            'interaction': round(interaction * 100, 3),
            'total':       round((allocation + selection + interaction) * 100, 3)
        })

    return {
        'sectors':            results,
        'total_allocation':   round(total_allocation * 100, 3),
        'total_selection':    round(total_selection * 100, 3),
        'total_interaction':  round(total_interaction * 100, 3),
        'total_excess_return':round((total_allocation + total_selection + total_interaction) * 100, 3)
    }
```

---

## Tax Efficiency

    Asset Location Strategy:
      Tax-Advantaged Accounts (IRA, 401k):
        - Bonds and bond funds (interest taxed as ordinary income)
        - REITs (high dividend, taxed as ordinary income)
        - High-turnover active funds
        - International funds with foreign tax credit exception

      Taxable Accounts:
        - Total market index funds (low turnover, qualified dividends)
        - Municipal bonds (tax-exempt interest)
        - Growth stocks held long term
        - Tax-managed funds

    Tax-Loss Harvesting Rules:
      - Sell position at a loss to realize capital loss
      - Use loss to offset capital gains
      - Reinvest in similar (not identical) fund within 30 days
      - Watch wash-sale rule: no repurchase of same security within 30 days
      - VTI harvested to ITOT, or vice versa (similar but not identical)

    Long-Term vs Short-Term Capital Gains:
      Hold > 1 year for long-term rates (0%, 15%, 20%)
      Hold < 1 year = ordinary income rates (up to 37%)
      Difference can be 15-20% in tax savings

---

## Common Pitfalls

| Pitfall | Problem | Fix |
|---|---|---|
| Home country bias | Under-diversified geographically | 30-40% international allocation |
| Performance chasing | Buy last year's winners | Rebalance back to targets |
| Neglecting rebalancing | Drift creates unintended risk | Annual or threshold rebalancing |
| High expense ratios | Fees compound against you | Use index funds < 0.10% ER |
| Tax inefficiency | Wrong assets in wrong accounts | Optimize asset location |
| Overdiversification | Too many funds with overlap | 3-5 core funds cover everything |
| Emotional selling | Sell in crash, miss recovery | Automate contributions, ignore noise |

---

## Best Practices

- **Start with asset allocation** — it drives 90% of long-term returns
- **Keep costs low** — every 0.10% in fees costs ~2.5% over 25 years
- **Automate contributions** — remove emotion from investing
- **Rebalance systematically** — annually or at 5% drift threshold
- **Tax location matters** — put bonds in tax-advantaged accounts
- **Stay the course** — time in market beats timing the market
- **Review annually** — goals change, allocation should evolve

---

## Related Skills

- **finance-trading-expert**: Active trading alongside portfolio
- **risk-management-expert**: Drawdown and risk controls
- **fundamental-analysis-expert**: Individual stock selection
- **quantitative-finance-expert**: Factor tilts and optimization
- **macro-economics-expert**: Top-down allocation decisions

