Skip to content
Back to skills

Portfolio Management Expert

ASecurity

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'.

  • 11 stars
  • 0 votes
  • 1 copy
  • 3 views
  • Added September 10, 2026
businesspythongoapisecurityperformance

Works with

  • api

Security analysis

A100/100

Scanned September 10, 2026

npx -y skills add luokai0/ai-agent-skills-by-luo-kai --skill portfolio-management-expert --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Portfolio Management Expert?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Portfolio Management Expert
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/luokai0-portfolio-management-expert/badge)](https://www.skillsdirectory.com/skills/luokai0-portfolio-management-expert)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
author: luo-kai
name: portfolio-management-expert
description: 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'.
license: MIT
metadata:
  author: luokai25
  version: "1.0"
  category: finance
---

# 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

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.