Advanced Portfolio Construction Techniques › Integrating Multiple Techniques

Michael BrenndoerferDecember 18, 20253 min read
Quantitative FinanceAll chapters
Part 9 of 15Portfolio Theory and Investment Analysis
Chapter 51Advanced Portfolio Construction Techniques › Integrating Multiple Techniques
Reading section 7 of 11 · Integrating Multiple Techniques · 3 minSection 7 of 11 · 3 min

Book contents

Section 7 of 11 · 3 min read

Advanced Portfolio Construction Techniques › Integrating Multiple TechniquesOne section · Sections in this chapter7 / 11 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

In practice, you can combine multiple techniques rather than relying on any single approach. The techniques we have studied are not mutually exclusive; they address different aspects of the portfolio construction problem and can be layered together. Your workflow might proceed as follows:

  1. Start with Black-Litterman to generate stable expected returns that blend market equilibrium with proprietary views
  2. Use shrinkage for covariance estimation to reduce the impact of sampling noise
  3. Apply risk budgeting to set target risk allocations across asset classes or risk factors
  4. Incorporate practical constraints such as position limits, turnover caps, and sector restrictions
  5. Account for transaction costs in rebalancing decisions to avoid excessive trading
In[34]:
Code
def integrated_portfolio_optimization(
    returns,
    market_weights,
    views_P=None,
    views_Q=None,
    views_confidence=None,
    risk_budget=None,
    min_weight=0.0,
    max_weight=0.4,
    prev_weights=None,
    max_turnover=0.2,
    transaction_cost=0.001,
):
    """
    Integrated portfolio construction combining multiple techniques.
    """
    n = returns.shape[1]

    # Step 1: Estimate covariance with shrinkage
    lw = LedoitWolf().fit(returns)
    cov = lw.covariance_ * 12

    # Step 2: Black-Litterman expected returns
    delta = 2.5
    tau = 0.05
    pi = delta * cov @ market_weights

    if views_P is not None and views_Q is not None:
        omega = (
            np.diag(views_confidence)
            if views_confidence is not None
            else np.eye(len(views_Q)) * 0.01
        )
        mu, _ = black_litterman(pi, cov, views_P, views_Q, omega, tau)
    else:
        mu = pi

    # Step 3: Risk-aware optimization
    def objective(w):
        # Expected return component
        ret = w @ mu

        # Risk component with risk budgeting penalty
        port_var = w @ cov @ w
        port_vol = np.sqrt(port_var + 1e-10)

        if risk_budget is not None:
            rc = w * (cov @ w) / port_vol
            rc_pct = rc / port_vol
            risk_penalty = 10 * np.sum((rc_pct - risk_budget) ** 2)
        else:
            risk_penalty = 0

        # Transaction cost penalty
        if prev_weights is not None:
            tc_penalty = transaction_cost * np.sum(np.abs(w - prev_weights))
        else:
            tc_penalty = 0

        return -(ret - 2.5 * port_var - risk_penalty - tc_penalty)

    # Constraints
    constraints = [{"type": "eq", "fun": lambda w: np.sum(w) - 1}]

    if prev_weights is not None and max_turnover is not None:
        constraints.append(
            {
                "type": "ineq",
                "fun": lambda w: (
                    max_turnover - 0.5 * np.sum(np.abs(w - prev_weights))
                ),
            }
        )

    bounds = [(min_weight, max_weight) for _ in range(n)]

    w0 = prev_weights if prev_weights is not None else np.ones(n) / n
    result = minimize(
        objective,
        w0,
        method="SLSQP",
        constraints=constraints,
        bounds=bounds,
        options={"maxiter": 1000},
    )

    return result.x, mu, cov


# Define parameters
risk_budget_target = np.array([0.18, 0.22, 0.22, 0.18, 0.20])
min_w_int, max_w_int = 0.05, 0.35
max_turn_int = 0.15
tc_cost = 0.001

# Apply integrated approach
w_integrated, mu_integrated, cov_integrated = integrated_portfolio_optimization(
    returns,
    w_mkt,
    views_P=P,
    views_Q=Q,
    views_confidence=[0.02**2, 0.01**2],
    risk_budget=risk_budget_target,
    min_weight=min_w_int,
    max_weight=max_w_int,
    prev_weights=prev_weights,
    max_turnover=max_turn_int,
    transaction_cost=tc_cost,
)
Out[35]:
Console
Integrated Portfolio Construction
============================================================

Techniques combined:
  • Black-Litterman expected returns
  • Ledoit-Wolf shrinkage covariance
  • Risk budgeting targets
  • Position limits (5% - 35%)
  • Turnover constraint (15%)
  • Transaction cost penalty (10bp)

Asset            Weight   Risk Contrib       Change
------------------------------------------------------------
Asset A          21.12%         17.93%       +1.12%
Asset B          21.75%         21.99%       +1.75%
Asset C          18.64%         22.15%       -1.36%
Asset D          20.55%         17.94%       +0.55%
Asset E          17.94%         19.98%       -2.06%

Total turnover: 3.42%
Portfolio expected return: 7.39%
Portfolio volatility: 12.40%