The Capital Asset Pricing Model (CAPM) is the most widely taught framework in finance. Every investment management course, every CFA curriculum, every risk-adjusted return calculation in institutional portfolio management traces back to Sharpe (1964) and the equation:
E(Rᵢ) = Rƒ + βᵢ · [E(Rₘ) - Rƒ]
There is a problem with this equation for anyone operating within an Islamic finance framework. The problem is not minor and it is not resolved by simply screening out haram stocks. The problem is structural: Rƒ, the risk-free rate, is by definition the return on a riba-bearing instrument typically government bonds or overnight interbank lending rates. The entire CAPM architecture is built on this foundation.
You cannot build a Shariah-compliant asset pricing model by grafting Islamic constraints onto CAPM while leaving Rƒ intact. That is not a modification it is a cosmetic adjustment to a fundamentally incompatible framework.
The Maqasid al-Shariah Compliance Asset Pricing Model (MSCAPM) takes a different approach. It doesn't replace the risk-free rate with a different number. It replaces it with a conceptually different construct one rooted in Islamic wealth distribution logic, specifically the Maqasid al-Shariah objectives of protecting and growing wealth (hifz al-mal) and incorporates investor sentiment as an additional pricing factor. The result is an asset pricing model that is Islamic not just in its outputs but in the structure of its assumptions.
Part 1: What's Wrong with Rƒ in an Islamic Context
The risk-free rate in CAPM serves two roles simultaneously:
1. It is the return available to an investor who takes zero risk. In classical CAPM, any rational investor can earn Rƒ without bearing any systematic risk. This is the opportunity cost baseline the floor below which no rational investor would allocate to risky assets.
2. It is the pure time value of money. CAPM assumes that money has time value independent of productive activity that lending cash for a period entitles the lender to a return simply by virtue of the passage of time.
Both of these assumptions violate Islamic financial principles:
On the first: in Islamic finance, there is no truly risk-free return available. Profit (ribh) is permissible only when it accompanies risk (ghorm). A return obtained with zero risk is, by definition, riba prohibited regardless of whether it is called interest, profit, or a risk-free rate.
On the second: Islamic finance does not recognise the time value of money as an independent concept. Money has no intrinsic productive capacity. Only when money is deployed in a productive enterprise through mudarabah, musharakah, or murabahah does it earn a return, and that return is contingent on the outcome of that enterprise.
Replacing Rƒ with the hibah rate on Islamic savings accounts, or with the sukuk yield, is a partial fix at best. You are substituting a number without changing the conceptual role that number plays in the model. The MSCAPM changes the role.
Part 2: The Maqasid al-Shariah Framework
The Maqasid al-Shariah the higher objectives of Islamic law provides the conceptual foundation for the modified model. Traditionally articulated as the protection of five necessities (ad-daruriyyat al-khams), the Maqasid include:
- Protection of religion (hifz al-din)
- Protection of life (hifz al-nafs)
- Protection of intellect (hifz al-aql)
- Protection of lineage (hifz al-nasl)
- Protection of wealth (hifz al-mal)
For asset pricing, hifz al-mal the protection and growth of wealth is the operative objective. Crucially, hifz al-mal in the Islamic tradition is not individual wealth maximisation in the Markowitz sense. It encompasses:
- Zakat - the obligation to distribute 2.5% of qualifying wealth annually to prescribed beneficiaries
- Prohibition of israf - excessive consumption and wasteful accumulation
- Encouragement of productive investment - wealth must be deployed in productive, socially beneficial activity
- Prohibition of wealth concentration - hoarding (kanz) is explicitly condemned in the Quran
This gives us a different investor objective function than CAPM assumes. The MSCAPM investor is not a pure expected utility maximiser. They are constrained by and oriented toward the Maqasid objectives which introduces both a modified return requirement and a sentiment component reflecting the investor's degree of Maqasid-alignment.
Part 3: The MSCAPM Structure
The modified model replaces the CAPM equation with:
E(Rᵢ) = Rz + βᵢ · [E(Rₘ) - Rz] + γᵢ · S
Where:
Rz- the zero-beta portfolio return: the expected return on a portfolio uncorrelated with the market, but constructed from Shariah-compliant assets only. This replaces Rƒ.βᵢ- standard systematic risk coefficient (market beta), computed on the Shariah-screened market indexE(Rₘ)- expected return on the Shariah-compliant market portfolio (e.g. FTSE Bursa Malaysia Hijrah Shariah Index, or S&P/OIC COMCEC 50)γᵢ- the sentiment loading of asseti- its sensitivity to aggregate investor sentimentS- the investor sentiment factor: a composite measure of Islamic investor sentiment toward the market
The critical move is the substitution of Rz for Rƒ. Let me explain each component.
Part 4: The Zero-Beta Portfolio as Rƒ Replacement
The zero-beta portfolio approach goes back to Black (1972), who showed that CAPM can be derived without a risk-free asset by using a portfolio that has zero covariance with the market portfolio. Black's zero-beta CAPM:
E(Rᵢ) = E(Rz) + βᵢ · [E(Rₘ) - E(Rz)]
This formulation requires no risk-free asset at all only two portfolios: the market portfolio and its zero-beta counterpart. In an Islamic context, this is exactly what we need.
Constructing the zero-beta portfolio:
The zero-beta portfolio z satisfies:
Cov(Rz, Rₘ) = 0
For a Shariah-screened asset universe with covariance matrix Σ and market weights wₘ:
σz,m = wz^T · Σ · wₘ = 0
We find wz by solving:
minimise wz^T · Σ · wz (minimise variance)
subject to wz^T · Σ · wₘ = 0 (zero covariance with market)
wz^T · 1 = 1 (fully invested)
wz ≥ 0 (no short selling)
wᵢ = 0 for all non-Shariah assets
This is a standard quadratic program with linear constraints solvable with scipy.optimize.minimize or CVXPY.
The expected return E(Rz) on this portfolio becomes the Islamic analogue of the risk-free rate. It represents the minimum return available to a fully invested, Shariah-compliant investor with zero systematic risk exposure. Crucially, it is earned through productive investment in actual businesses not through lending at interest.
import numpy as np
from scipy.optimize import minimize
def find_zero_beta_portfolio(
cov_matrix: np.ndarray,
market_weights: np.ndarray,
shariah_eligible: np.ndarray,
) -> np.ndarray:
"""
Find minimum-variance portfolio with zero covariance to market.
All weights constrained to Shariah-eligible assets.
"""
n = len(market_weights)
def portfolio_variance(w):
return w @ cov_matrix @ w
def market_covariance(w):
return w @ cov_matrix @ market_weights
constraints = [
{"type": "eq", "fun": lambda w: w.sum() - 1}, # fully invested
{"type": "eq", "fun": market_covariance}, # zero beta
]
# Bounds: 0 for non-eligible, [0,1] for eligible
bounds = [(0, 0) if not shariah_eligible[i] else (0, 1) for i in range(n)]
# Initial guess: equal weight eligible assets
w0 = shariah_eligible.astype(float) / shariah_eligible.sum()
result = minimize(
portfolio_variance,
w0,
method="SLSQP",
bounds=bounds,
constraints=constraints,
options={"ftol": 1e-12, "maxiter": 1000},
)
if not result.success:
raise ValueError(f"Zero-beta portfolio optimization failed: {result.message}")
return result.x
Part 5: The Investor Sentiment Factor
The second innovation in MSCAPM is the explicit incorporation of investor sentiment as a pricing factor. This draws on the behavioural finance literature (Baker & Wurgler 2006) but reframes it within an Islamic context.
In Islamic capital markets particularly in Malaysia, the GCC, and Indonesia investor sentiment has an additional dimension beyond the standard fear/greed cycle: Shariah confidence. Investors' willingness to allocate to Islamic equities is affected by:
- Fatwas and Shariah board pronouncements
- Zakat compliance news
- Islamic economic policy announcements (Bank Negara RMiT, AAOIFI standards)
- Perception of Maqasid-alignment in corporate behaviour
The sentiment factor S is constructed as a composite index from observable proxies:
S = α₁ · Turnover_ratio
+ α₂ · IPO_volume_ratio
+ α₃ · Closed_end_fund_discount
+ α₄ · Put_call_ratio (inverted)
+ α₅ · Shariah_compliance_index_change
Where each component is standardised (z-scored) and the weights αⱼ are estimated via principal component analysis the first principal component of the proxy matrix is taken as the sentiment factor.
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
def construct_sentiment_factor(
turnover_ratio: pd.Series,
ipo_volume: pd.Series,
cef_discount: pd.Series, # closed-end fund discount
put_call_ratio: pd.Series,
shariah_index_change: pd.Series,
) -> pd.Series:
"""
Construct composite investor sentiment factor via PCA.
Returns first principal component as sentiment index S.
"""
proxies = pd.DataFrame({
"turnover": turnover_ratio,
"ipo_volume": ipo_volume,
"cef_discount": -cef_discount, # invert: high discount = negative sentiment
"put_call": -put_call_ratio, # invert: high put/call = negative sentiment
"shariah_chg": shariah_index_change,
}).dropna()
# Standardise
scaler = StandardScaler()
scaled = scaler.fit_transform(proxies)
# First principal component = sentiment factor
pca = PCA(n_components=1)
sentiment = pca.fit_transform(scaled).flatten()
print(f"Sentiment factor explains {pca.explained_variance_ratio_[0]*100:.1f}% of proxy variance")
print(f"Component loadings:")
for col, loading in zip(proxies.columns, pca.components_[0]):
print(f" {col:<15}: {loading:+.3f}")
return pd.Series(sentiment, index=proxies.index, name="sentiment_factor")
The sentiment loading γᵢ for each asset is then estimated by regressing the asset's excess returns on both the market factor and the sentiment factor:
Rᵢ - Rz = αᵢ + βᵢ · (Rₘ - Rz) + γᵢ · S + εᵢ
Part 6: Full MSCAPM Estimation
import numpy as np
import pandas as pd
from scipy.optimize import minimize
import statsmodels.api as sm
class MSCAPM:
"""
Maqasid al-Shariah Compliance Asset Pricing Model.
Replaces CAPM risk-free rate with zero-beta portfolio return.
Adds investor sentiment as a second pricing factor.
E(Rᵢ) = Rz + βᵢ·[E(Rₘ) - Rz] + γᵢ·S
"""
def __init__(
self,
returns: pd.DataFrame, # shape (T, N) - asset returns
market_returns: pd.Series, # shape (T,) - Shariah market index
shariah_eligible: np.ndarray, # shape (N,) - binary eligibility
sentiment: pd.Series, # shape (T,) - sentiment factor S
):
self.returns = returns
self.market = market_returns
self.eligible = shariah_eligible
self.sentiment = sentiment
self.asset_names = returns.columns.tolist()
self.n_assets = len(self.asset_names)
# Align all series on common index
common_idx = (returns.index
.intersection(market_returns.index)
.intersection(sentiment.index))
self.returns = returns.loc[common_idx]
self.market = market_returns.loc[common_idx]
self.sentiment = sentiment.loc[common_idx]
def estimate_zero_beta(self) -> float:
"""Estimate zero-beta portfolio return."""
cov = self.returns.iloc[:, self.eligible.astype(bool)].cov().values
mkt_w = self._market_weights_for_eligible()
n_elig = self.eligible.sum()
cov_full = np.zeros((self.n_assets, self.n_assets))
elig_idx = np.where(self.eligible)[0]
for i, ii in enumerate(elig_idx):
for j, jj in enumerate(elig_idx):
cov_full[ii, jj] = cov[i, j]
zero_beta_w = find_zero_beta_portfolio(
cov_full, mkt_w, self.eligible
)
# Expected return of zero-beta portfolio
mean_returns = self.returns.mean().values
self.rz = float(zero_beta_w @ mean_returns)
self.zero_beta_weights = zero_beta_w
return self.rz
def _market_weights_for_eligible(self) -> np.ndarray:
"""Equal-weight market portfolio over eligible assets."""
w = self.eligible.astype(float)
return w / w.sum()
def estimate_factors(self) -> pd.DataFrame:
"""
Estimate β (market) and γ (sentiment) for each asset.
OLS regression: Rᵢ - Rz = α + β·(Rₘ - Rz) + γ·S
"""
if not hasattr(self, "rz"):
self.estimate_zero_beta()
mkt_excess = self.market.values - self.rz
results = []
for asset in self.asset_names:
asset_excess = self.returns[asset].values - self.rz
X = sm.add_constant(
np.column_stack([mkt_excess, self.sentiment.values])
)
model = sm.OLS(asset_excess, X).fit()
results.append({
"asset": asset,
"alpha": model.params[0],
"beta": model.params[1],
"gamma": model.params[2],
"r2": model.rsquared,
"beta_p": model.pvalues[1],
"gamma_p": model.pvalues[2],
})
self.factor_loadings = pd.DataFrame(results).set_index("asset")
return self.factor_loadings
def expected_returns(self, sentiment_forecast: float = 0.0) -> pd.Series:
"""
Compute MSCAPM expected returns.
E(Rᵢ) = Rz + βᵢ·[E(Rₘ) - Rz] + γᵢ·S_forecast
"""
if not hasattr(self, "factor_loadings"):
self.estimate_factors()
mkt_expected = float(self.market.mean())
mkt_premium = mkt_expected - self.rz
er = {}
for asset in self.asset_names:
beta = self.factor_loadings.loc[asset, "beta"]
gamma = self.factor_loadings.loc[asset, "gamma"]
er[asset] = self.rz + beta * mkt_premium + gamma * sentiment_forecast
return pd.Series(er, name="E(R) MSCAPM")
def compare_with_capm(self, risk_free_rate: float) -> pd.DataFrame:
"""Compare MSCAPM vs standard CAPM expected returns."""
mscapm_er = self.expected_returns()
mkt_expected = float(self.market.mean())
capm_er = {}
for asset in self.asset_names:
beta = self.factor_loadings.loc[asset, "beta"]
capm_er[asset] = risk_free_rate + beta * (mkt_expected - risk_free_rate)
comparison = pd.DataFrame({
"CAPM": pd.Series(capm_er),
"MSCAPM": mscapm_er,
"Beta": self.factor_loadings["beta"],
"Gamma": self.factor_loadings["gamma"],
"Diff": mscapm_er - pd.Series(capm_er),
})
return comparison
def maqasid_alignment_score(self) -> pd.Series:
"""
Compute a simple Maqasid alignment score for each asset.
Higher gamma (positive sentiment loading) = more aligned with
Islamic investor sentiment = higher Maqasid score.
Score = normalized (1 + gamma) across assets.
"""
if not hasattr(self, "factor_loadings"):
self.estimate_factors()
gamma = self.factor_loadings["gamma"]
score = (gamma - gamma.min()) / (gamma.max() - gamma.min())
return score.rename("maqasid_alignment")
Part 7: Simulated Example Bursa Malaysia Shariah Stocks
import numpy as np
import pandas as pd
np.random.seed(42)
T = 60 # 60 months of returns
N = 8 # 8 assets
# Simulate monthly returns for Shariah-screened stocks
# Based on rough FTSE Bursa Malaysia Hijrah Shariah characteristics
asset_names = [
"TENAGA", "PETRONAS_CHEM", "DIALOG", "HARTALEGA",
"INARI", "AXIATA", "GAMUDA", "SIME_DARBY"
]
true_betas = np.array([0.85, 0.70, 1.10, 1.25, 1.40, 0.95, 1.05, 0.80])
true_gammas = np.array([0.30, 0.15, 0.45, 0.60, 0.55, 0.20, 0.35, 0.10])
market_returns = pd.Series(
np.random.normal(0.008, 0.035, T), # ~9.6% annual, 12% vol
index=pd.date_range("2021-01", periods=T, freq="ME"),
name="FBMHS"
)
sentiment = pd.Series(
np.random.normal(0, 1, T),
index=market_returns.index,
name="sentiment"
)
# Generate correlated asset returns
returns_data = {}
rz_true = 0.003 # ~3.6% annual zero-beta return
for i, asset in enumerate(asset_names):
idio_vol = np.random.uniform(0.02, 0.04)
r = (rz_true
+ true_betas[i] * (market_returns.values - rz_true)
+ true_gammas[i] * sentiment.values
+ np.random.normal(0, idio_vol, T))
returns_data[asset] = r
returns = pd.DataFrame(returns_data, index=market_returns.index)
shariah_eligible = np.ones(N, dtype=int) # all pass screen in this example
# Fit MSCAPM
model = MSCAPM(
returns=returns,
market_returns=market_returns,
shariah_eligible=shariah_eligible,
sentiment=sentiment,
)
rz = model.estimate_zero_beta()
loadings = model.estimate_factors()
er_mscapm = model.expected_returns(sentiment_forecast=0.5) # mild positive sentiment
# Compare with CAPM using OPR proxy (BNM overnight policy rate ~3%)
opr_monthly = 0.03 / 12
comparison = model.compare_with_capm(risk_free_rate=opr_monthly)
print(f"\nZero-beta portfolio return: {rz*100:.3f}% per month ({rz*1200:.2f}% annualised)")
print(f"Market expected return: {market_returns.mean()*100:.3f}% per month")
print(f"Market risk premium: {(market_returns.mean()-rz)*100:.3f}% per month\n")
print("Factor Loadings:")
print(loadings[["beta", "gamma", "r2"]].round(3).to_string())
print("\nExpected Returns Comparison (monthly):")
print(comparison[["CAPM", "MSCAPM", "Diff"]].multiply(100).round(3).to_string())
print("\nMaqasid Alignment Scores (0=lowest, 1=highest):")
print(model.maqasid_alignment_score().round(3).to_string())
Part 8: What the Model Reveals
Running this on real Shariah-compliant equity data reveals several patterns that standard CAPM misses:
The zero-beta return is typically lower than the OPR-proxy risk-free rate. This might seem paradoxical shouldn't the minimum return available to an investor without systematic risk be at least as high as the "risk-free" rate? The answer is that Rz is not guaranteed it is the expected return on a real investment portfolio with real business risk, just zero systematic risk. Some periods it will be higher than OPR; some lower. This is precisely what Islamic finance expects: there is no guaranteed return, only expected returns contingent on real economic activity.
Sentiment loadings γ are heterogeneous and significant. Stocks with stronger Maqasid credentials genuine productive activity, strong zakat compliance records, low leverage tend to have positive sentiment loadings. This means they benefit when Islamic investor sentiment is positive and suffer less when it turns negative. The sentiment factor captures a dimension of Islamic equity pricing that pure beta cannot.
The pricing difference between CAPM and MSCAPM is largest for high-beta, high-sentiment stocks. For a stock with β = 1.40 and γ = 0.60, the MSCAPM expected return under positive sentiment conditions can be materially higher than CAPM predicts. This implies that CAPM systematically underprices Maqasid-aligned growth stocks when Islamic investor sentiment is positive a potential source of alpha for funds that identify this mispricing.
Part 9: Why This Matters for Malaysian Islamic Finance
Malaysia has the most developed Islamic capital market infrastructure in the world. The Securities Commission maintains the Shariah Advisory Council list of permissible securities. Bank Negara regulates Islamic financial institutions under IFSA 2013. The FTSE Bursa Malaysia Hijrah Shariah Index provides a benchmark for Shariah-compliant portfolios.
But the pricing models used by most Malaysian fund managers are still standard CAPM sometimes with sukuk yields substituted for the risk-free rate, occasionally with Fama-French factors added, but fundamentally Western models with Islamic constraints bolted on.
The MSCAPM offers something different: a pricing model that starts from Islamic epistemological assumptions. The zero-beta portfolio replaces Rƒ with something that actually exists in a riba-free economy. The sentiment factor captures the specific dynamics of Islamic investor behaviour including the Maqasid-alignment dimension that affects how Islamic institutional investors (takaful funds, Islamic unit trusts, waqf institutions) allocate capital.
For a takaful fund manager sizing the investment portfolio to meet tabarru' obligations and generate surplus this matters practically. The expected return on the Shariah-compliant equity portfolio determines the investment income available to offset claims. Using a model that correctly prices Shariah-compliant assets, rather than one that assumes a risk-free rate that doesn't exist in the Islamic economy, gives a more accurate picture of what that portfolio can realistically be expected to deliver.
The Deeper Point
Both the fuzzy portfolio model from the previous post and the MSCAPM make the same underlying argument: the assumptions embedded in classical financial models are not neutral. They encode specific epistemological and ethical commitments about uncertainty, about the time value of money, about what constitutes risk that are in tension with Islamic financial principles.
The typical response in Islamic finance is to take the classical model and add constraints: screen out haram stocks, replace interest with hibah, add a zakat adjustment. This produces a model that is Islamically compliant in its outputs while remaining Western in its foundations.
The more interesting and intellectually honest approach which both the fuzzy semi-spread framework and the MSCAPM represent is to rebuild from foundations that are consistent with Islamic principles. Fuzzy numbers instead of probability distributions because the future is genuinely uncertain in ways that probability theory doesn't fully capture. A zero-beta portfolio instead of a risk-free rate because there is no such thing as a guaranteed return in a riba-free economy.
These are not just theological accommodations. They are epistemologically defensible positions that produce models which, I would argue, are more honest about what we actually know and don't know about financial markets Islamic or otherwise.
This post draws on the framework from "Investor Sentiment Under the Maqasid Al-Shari'ah Compliance Asset Pricing Model." The Python implementation is original. Financial examples are illustrative not investment advice. For the zero-beta portfolio construction, see Black (1972); for the sentiment factor methodology, see Baker & Wurgler (2006).