Multi-Asset Portfolio Strategies: Beyond Equities
Diversify across equities, derivatives, commodities, and currencies to build robust all-weather portfolios for Indian markets.
Equity-only portfolios suffer in bear markets. Multi-asset portfolios—combining stocks, options, commodities, currencies—provide true diversification, reducing volatility while maintaining returns.
This guide builds multi-asset strategies for Indian markets, leveraging NSE equities, Nifty derivatives, MCX commodities, and currency futures.
Asset Class Characteristics in India
Correlation Matrix (2020-2024)
| Asset | Nifty 50 | Gold | USD/INR | Crude |
|---|---|---|---|---|
| Nifty 50 | 1.00 | -0.15 | -0.30 | 0.40 |
| Gold | -0.15 | 1.00 | 0.60 | 0.20 |
| USD/INR | -0.30 | 0.60 | 1.00 | 0.35 |
| Crude | 0.40 | 0.20 | 0.35 | 1.00 |
Key Insights:
- Gold negatively correlated with Nifty (hedge)
- USD/INR rises when Nifty falls (FII outflows)
- Crude positively correlated (India net importer)
import pandas as pd
import numpy as np
from scipy.optimize import minimize
class MultiAssetPortfolio:
"""
Multi-asset portfolio optimization
"""
def __init__(self, asset_returns: pd.DataFrame):
self.returns = asset_returns
self.mean_returns = asset_returns.mean()
self.cov_matrix = asset_returns.cov()
def optimize_weights(self, target_return: float = None) -> np.array:
"""
Optimize asset weights for maximum Sharpe ratio
"""
n_assets = len(self.mean_returns)
# Objective: Negative Sharpe (minimize negative = maximize positive)
def neg_sharpe(weights):
portfolio_return = np.dot(weights, self.mean_returns) * 252
portfolio_std = np.sqrt(np.dot(weights.T, np.dot(self.cov_matrix * 252, weights)))
sharpe = portfolio_return / portfolio_std
return -sharpe
# Constraints
constraints = [
{'type': 'eq', 'fun': lambda w: np.sum(w) - 1} # Weights sum to 1
]
if target_return:
constraints.append({
'type': 'eq',
'fun': lambda w: np.dot(w, self.mean_returns) * 252 - target_return
})
# Bounds (0 to 1 for long-only)
bounds = tuple((0, 1) for _ in range(n_assets))
# Initial guess
init_weights = np.array([1/n_assets] * n_assets)
# Optimize
result = minimize(
neg_sharpe,
init_weights,
method='SLSQP',
bounds=bounds,
constraints=constraints
)
return result.x
# Example: Optimize across 4 assets
asset_returns = pd.DataFrame({
'Nifty50': np.random.randn(1000) * 0.015 + 0.0005,
'Gold': np.random.randn(1000) * 0.010 + 0.0003,
'USDINR': np.random.randn(1000) * 0.008 + 0.0002,
'Crude': np.random.randn(1000) * 0.025 + 0.0004
})
portfolio = MultiAssetPortfolio(asset_returns)
optimal_weights = portfolio.optimize_weights()
print("Optimal Weights:")
for asset, weight in zip(asset_returns.columns, optimal_weights):
print(f" {asset}: {weight:.1%}")