Implied Risk Premia for Factors

Theory, Estimation, and Applications

Core Question

Given observed portfolio weights \(\bm{w}\) and estimated covariance matrix \(\bm{Q}\), what expected returns \(\bm{\mu}^*\) would rationalize this allocation as optimal?

Project Components

ComponentStatusDescription
BRISMA Risk ModelCompleteCovariance estimation (Q_emp, Q_shrink, Q_garch)
Inverse OptimizationCompleteMV, MRAR, Omega inverse methods
Factor PremiaCompleteOLS, Fama-MacBeth, GLS extraction
Bantleon CalibrationCompleteM1, M2, Hybrid lambda methods

The Pipeline

Portfolio Weights
w
+
Covariance
Q
-->
Inverse
Optimization
-->
Implied Returns
mu*
-->
Cross-Sectional
Regression
-->
Factor Premia
pi

1. The Core Problem

1.1 Forward vs. Inverse Optimization

DirectionGivenFindChallenge
ForwardExpected returns \(\bm{\mu}\), covariance \(\bm{Q}\)Optimal weights \(\bm{w}^*\)Requires return forecasts
InverseObserved weights \(\bm{w}\), covariance \(\bm{Q}\)Implied returns \(\bm{\mu}^*\)Requires utility assumption

1.2 Why Implied Returns?

Key Insight

Implied returns extract the market's collective wisdom embedded in current prices and allocations, avoiding the need for subjective return forecasts.

Applications:

  • Black-Litterman Prior: Use implied returns as equilibrium prior, blend with views
  • Client Analysis: Understand what returns a client implicitly assumes
  • Consistency Check: Verify if assumed returns match market consensus
  • Factor Premia: Extract systematic risk compensation from cross-section

1.3 Comparison of Approaches

ApproachProsCons
Historical ReturnsData-driven, objectiveBackward-looking, noisy
Analyst ForecastsForward-lookingSubjective, costly
Implied ReturnsInternally consistentRequires utility assumption

2. Mean-Variance Framework

2.1 The Utility Function

An investor with mean-variance preferences maximizes:

\[U_{MV}(\bm{w}) = \bm{w}'\bm{\mu} - \frac{\lambda}{2}\bm{w}'\bm{Q}\bm{w}\]

where:

  • \(\bm{w} \in \R^n\): Portfolio weights (column vector, \(\sum w_i = 1\))
  • \(\bm{\mu} \in \R^n\): Expected returns (column vector)
  • \(\bm{Q} \in \R^{n \times n}\): Covariance matrix (symmetric, positive semi-definite)
  • \(\lambda > 0\): Risk aversion parameter

2.2 Interpretation

TermMeaning
\(\bm{w}'\bm{\mu}\)Expected portfolio return
\(\frac{\lambda}{2}\bm{w}'\bm{Q}\bm{w}\)Penalty for portfolio variance
\(\lambda\)Trade-off: higher = more risk-averse

2.3 First-Order Condition

Taking the gradient with respect to \(\bm{w}\):

\[\nabla_{\bm{w}} U = \bm{\mu} - \lambda\bm{Q}\bm{w}\]

At the optimum, \(\nabla_{\bm{w}} U = \bm{0}\):

\[\bm{\mu} = \lambda\bm{Q}\bm{w}\]

This is the key relationship linking weights, covariance, and implied returns.

3. Inverse Optimization

Definition (Inverse Optimization Problem)

Given observed portfolio weights \(\bm{w}\), covariance matrix \(\bm{Q}\), and utility function \(U\), find implied expected returns \(\bm{\mu}^*\) such that \(\bm{w}\) is optimal:

\[\bm{w} = \argmax_{\bm{w}' \in \mathcal{W}} U(\bm{w}'; \bm{\mu}^*, \bm{Q})\]

3.1 Unconstrained Solution

Theorem (Unconstrained Inverse MV)

For the unconstrained mean-variance problem:

\[\bm{\mu}^* = \lambda \bm{Q} \bm{w}\]
Proof

From FOC: \(\bm{\mu} - \lambda\bm{Q}\bm{w} = \bm{0}\). Rearranging: \(\bm{\mu}^* = \lambda\bm{Q}\bm{w}\). \(\blacksquare\)

3.2 Constrained Solution (Budget Constraint)

With budget constraint \(\bm{1}'\bm{w} = 1\):

Theorem (Constrained Inverse MV)

The implied returns become:

\[\bm{\mu}^* = \lambda\bm{Q}\bm{w} + \gamma^*\bm{1}\]

where \(\gamma^*\) is the Lagrange multiplier (shadow price of budget constraint).

Interpretation of \(\gamma^*\):

  • Can be set to \(r_f\) (risk-free rate) for zero-beta interpretation
  • Can be determined by normalization (e.g., target average return)

3.3 Geometric Interpretation

The formula \(\bm{\mu}^* = \lambda\bm{Q}\bm{w}\) has a beautiful geometric meaning:

  1. \(\bm{Q}\bm{w}\) = marginal contribution to portfolio risk of each asset
  2. \(\lambda\) scales this to expected returns
  3. Assets with higher risk contribution must have higher implied returns
Key Insight

Implied return is proportional to risk contribution: \(\mu_i^* \propto (\bm{Q}\bm{w})_i\)

3.4 Alternative Utility Functions

UtilityFormulaSolution Method
Mean-Variance\(w'\mu - \frac{\lambda}{2}w'Qw\)Closed-form
MRAR (Morningstar)CRRA utilityNumerical optimization
Omega RatioLPM-basedNumerical optimization

4. Factor Models (APT)

4.1 Arbitrage Pricing Theory

Returns follow a linear \(K\)-factor structure:

\[R_i = \E[R_i] + \sum_{k=1}^{K} \beta_{ik} f_k + \epsilon_i\]

where:

  • \(f_k\): Mean-zero common factors
  • \(\beta_{ik}\): Factor loadings (sensitivities)
  • \(\epsilon_i\): Idiosyncratic risk

4.2 APT Pricing Relation

Theorem (APT)

Expected returns are linear in factor loadings:

\[\E[R_i] = r_f + \sum_{k=1}^{K} \beta_{ik} \lambda_k\]

where \(\lambda_k\) is the risk premium for factor \(k\).

In matrix form:

\[\E[\bm{R}] - r_f = \bm{B} \bm{\lambda}\]

4.3 Major Factor Models

ModelFactorsReference
CAPMMKTSharpe (1964)
Fama-French 3MKT, SMB, HMLFama & French (1993)
Carhart 4MKT, SMB, HML, UMDCarhart (1997)
Fama-French 5MKT, SMB, HML, RMW, CMAFama & French (2015)

4.4 Factor Definitions

FactorNameLongShort
MKTMarketMarket portfolioRisk-free
SMBSizeSmall capsLarge caps
HMLValueHigh B/MLow B/M
RMWProfitabilityRobustWeak
CMAInvestmentConservativeAggressive
UMDMomentumPast winnersPast losers

5. Stochastic Discount Factor Framework

5.1 SDF Definition

Definition (Stochastic Discount Factor)

A stochastic discount factor \(m\) is a random variable satisfying:

\[\E[m R_i] = 1 \quad \text{for all assets } i\]

Equivalently, for excess returns: \(\E[m R_i^e] = 0\)

Interpretation: The SDF represents marginal utility growth. Assets that pay off when marginal utility is high (bad states) are valuable and command low expected returns.

5.2 Linear SDF and Factor Models

If the SDF is linear in factors:

\[m = a + \bm{b}'\bm{f}\]

Then expected returns satisfy APT with risk premia:

\[\bm{\lambda} = -\frac{\Cov(\bm{f}, m)}{\E[m]}\]

5.3 Hansen-Jagannathan Bound

Theorem (HJ Bound)

Any admissible SDF must satisfy:

\[\frac{\sigma(m)}{\E[m]} \geq \sqrt{\bm{\mu}' \bm{\Sigma}^{-1} \bm{\mu}}\]

The RHS equals the maximum Sharpe ratio achievable from test assets.

Application

If a factor model's SDF lies below the HJ bound, the model is misspecified.

6. Bantleon Method M1 (10-Year Bond)

6.1 Concept

Method M1 extracts the risk aversion parameter \(\lambda\) from 10-year government bond yields, assuming the bond market is in equilibrium.

Method M1 Formula
\[\lambda_{M1} = \frac{\ln\left(\frac{1 + y_{10Y}}{1 + r_f}\right)}{\beta_{ref}}\]

where:

  • \(y_{10Y}\): 10-year government bond yield
  • \(r_f\): Risk-free rate (short-term)
  • \(\beta_{ref}\): Reference beta (default: 7.0)

6.2 Derivation

From the term premium equation:

\[\text{Term Premium} = \E[R_{10Y}] - r_f = \lambda \cdot \beta_{bond}\]

Assuming \(\E[R_{10Y}] \approx y_{10Y}\) and using the log approximation:

\[\ln\left(\frac{1 + y_{10Y}}{1 + r_f}\right) \approx y_{10Y} - r_f = \lambda \cdot \beta_{ref}\]

6.3 When to Use M1

ConditionUse M1?Reason
\(R^2 > 0.6\)YesMarket regime, factors explain returns well
\(R^2 < 0.3\)NoUse M2 instead
Normal yield curveYesTerm premium is positive
Inverted yield curveCautionMay produce negative lambda

6.4 Numerical Example

Example: Computing lambda_M1

Given:

  • \(y_{10Y} = 4.5\%\) (10-year bond yield)
  • \(r_f = 2.0\%\) (risk-free rate)
  • \(\beta_{ref} = 7.0\) (reference beta)

Calculation:

\[\lambda_{M1} = \frac{\ln(1.045 / 1.02)}{7.0} = \frac{\ln(1.0245)}{7.0} = \frac{0.0242}{7.0} = 0.00346\]

Result: \(\lambda_{M1} \approx 0.35\%\) per unit beta per period

7. Bantleon Method M2 (Historical Performance)

7.1 Concept

Method M2 estimates lambda from historical excess returns using exponentially-weighted averaging:

Method M2 Formula
\[\lambda_{M2} = \sum_{t=1}^{T} w_t \cdot f_t\]

where:

  • \(f_t\): Historical excess return at time \(t\)
  • \(w_t\): Exponential decay weight

7.2 Exponential Decay Weights

Weights follow exponential decay with halflife \(h\):

\[w_t = \frac{e^{-\alpha(T-t)}}{\sum_{s=1}^{T} e^{-\alpha(T-s)}}\]

where \(\alpha = \ln(2) / h\) and typically \(h = 24\) months.

7.3 Weight Visualization

Interpretation

With halflife = 24 months:

  • Recent month: weight = 1.0 (normalized)
  • 24 months ago: weight = 0.5
  • 48 months ago: weight = 0.25
  • 72 months ago: weight = 0.125

7.4 When to Use M2

ConditionUse M2?Reason
\(R^2 > 0.6\)NoUse M1 instead
\(R^2 < 0.3\)YesFactors don't explain returns, use history
High volatility regimeYesHistorical averaging smooths noise

7.5 Numerical Example

Example: Computing lambda_M2

Given: Last 4 months of excess returns (simplified):

  • \(f_1 = 2\%\), \(f_2 = -1\%\), \(f_3 = 3\%\), \(f_4 = 1\%\) (most recent)

With halflife = 2 months:

Weights (normalized): \(w_1 = 0.07, w_2 = 0.14, w_3 = 0.28, w_4 = 0.51\)

Calculation:

\[\lambda_{M2} = 0.07(0.02) + 0.14(-0.01) + 0.28(0.03) + 0.51(0.01) = 0.0151 = 1.51\%\]

8. Hybrid Method

8.1 Concept

The hybrid method blends M1 and M2 based on the explanatory power (\(R^2\)) of factor models:

Hybrid Formula
\[\mu_{hybrid} = R^2 \cdot \mu_{M1} + (1 - R^2) \cdot \mu_{M2}\]

Or equivalently for lambda:

\[\lambda_{hybrid} = R^2 \cdot \lambda_{M1} + (1 - R^2) \cdot \lambda_{M2}\]

8.2 Regime Switching Logic

\(R^2\) RangeWeight on M1Weight on M2Interpretation
\(R^2 > 0.6\)High (>60%)Low (<40%)Market regime, trust bond signal
\(0.3 \leq R^2 \leq 0.6\)MediumMediumBlend both methods
\(R^2 < 0.3\)Low (<30%)High (>70%)Historical regime, factors fail

8.3 Numerical Example

Example: Hybrid Blending

Given:

  • \(\mu_{M1} = 6\%\) (from 10Y bond method)
  • \(\mu_{M2} = 4\%\) (from historical method)
  • \(R^2 = 0.45\) (factor model explanatory power)

Calculation:

\[\mu_{hybrid} = 0.45 \times 6\% + 0.55 \times 4\% = 2.7\% + 2.2\% = 4.9\%\]

9. Lambda Calibration

9.1 Default Parameters

ParameterSymbolDefaultSource
Reference Beta\(\beta_{ref}\)7.0Bantleon calibration
Halflife (M2)\(h\)24 months2-year decay
Risk Aversion\(\lambda\)2.5 - 3.5Black-Litterman (1992)
Lookback Window\(T\)60 months5 years for betas

9.2 Estimating Risk Aversion from Market Data

From CAPM equilibrium:

\[\lambda = \frac{\E[R_{mkt}] - r_f}{\sigma^2_{mkt}}\]
Example: Lambda from Market Data

Given:

  • Market excess return: 6% annually
  • Market volatility: 16% annually

Calculation:

\[\lambda = \frac{0.06}{0.16^2} = \frac{0.06}{0.0256} = 2.34\]

9.3 Typical Lambda Values

ContextLambda RangeSource
Market equilibrium2.5 - 3.5Black & Litterman (1992)
Institutional investors2.0 - 4.0Industry practice
Individual investors1.0 - 6.0Wide range
Bantleon M10.2 - 0.5Per-period, not annualized

10. Worked Example: 2 Assets

Example: Stocks and Bonds (60/40 Portfolio)

Step 1: Setup

Portfolio weights:

\[\bm{w} = \begin{pmatrix} 0.60 \\ 0.40 \end{pmatrix} \quad \text{(60% stocks, 40% bonds)}\]

Covariance matrix (annualized):

\[\bm{Q} = \begin{pmatrix} 0.0400 & 0.0100 \\ 0.0100 & 0.0100 \end{pmatrix}\]

(Stock vol = 20%, Bond vol = 10%, correlation = 0.5)

Risk aversion: \(\lambda = 2.5\)

Step 2: Compute Q * w

\[\bm{Q}\bm{w} = \begin{pmatrix} 0.04 & 0.01 \\ 0.01 & 0.01 \end{pmatrix} \begin{pmatrix} 0.60 \\ 0.40 \end{pmatrix} = \begin{pmatrix} 0.04 \times 0.60 + 0.01 \times 0.40 \\ 0.01 \times 0.60 + 0.01 \times 0.40 \end{pmatrix} = \begin{pmatrix} 0.028 \\ 0.010 \end{pmatrix}\]

Step 3: Compute Implied Returns

\[\bm{\mu}^* = \lambda \bm{Q}\bm{w} = 2.5 \times \begin{pmatrix} 0.028 \\ 0.010 \end{pmatrix} = \begin{pmatrix} 0.070 \\ 0.025 \end{pmatrix}\]

Result

AssetWeightImplied Return
Stocks60%7.0%
Bonds40%2.5%

Portfolio implied return: \(0.60 \times 7.0\% + 0.40 \times 2.5\% = 5.2\%\)

11. Worked Example: 3 Assets with Factor Decomposition

Example: Stocks, Bonds, and Gold

Step 1: Setup

Portfolio weights:

\[\bm{w} = \begin{pmatrix} 0.50 \\ 0.30 \\ 0.20 \end{pmatrix} \quad \text{(50% stocks, 30% bonds, 20% gold)}\]

Covariance matrix:

\[\bm{Q} = \begin{pmatrix} 0.0400 & 0.0050 & 0.0020 \\ 0.0050 & 0.0100 & 0.0010 \\ 0.0020 & 0.0010 & 0.0225 \end{pmatrix}\]

Factor loadings (2 factors: Market, Bond):

\[\bm{B} = \begin{pmatrix} 1.0 & 0.1 \\ 0.2 & 0.9 \\ 0.1 & -0.2 \end{pmatrix}\]

Risk aversion: \(\lambda = 3.0\)

Step 2: Implied Asset Returns

\[\bm{Q}\bm{w} = \begin{pmatrix} 0.0217 \\ 0.0059 \\ 0.0058 \end{pmatrix}\] \[\bm{\mu}^* = 3.0 \times \bm{Q}\bm{w} = \begin{pmatrix} 0.0651 \\ 0.0177 \\ 0.0174 \end{pmatrix}\]

Step 3: Extract Factor Premia (OLS)

Cross-sectional regression: \((\bm{\mu}^* - r_f) = \bm{B}\bm{\pi}\)

With \(r_f = 2\%\):

\[\bm{\pi} = (\bm{B}'\bm{B})^{-1}\bm{B}'(\bm{\mu}^* - r_f)\]

Result

AssetImplied ReturnExcess Return
Stocks6.51%4.51%
Bonds1.77%-0.23%
Gold1.74%-0.26%
FactorPremium
Market~4.2%
Bond~0.3%

12. Factor Premia Extraction

12.1 Cross-Sectional Regression

Given implied asset returns \(\bm{\mu}^*\) and factor loadings \(\bm{B}\):

\[\bm{\pi} = (\bm{B}'\bm{B})^{-1}\bm{B}'(\bm{\mu}^* - r_f)\]

12.2 The Bridge

Implied Returns
\(\bm{\mu}^*\)
-->
Cross-Sectional
Regression
-->
Factor Premia
\(\bm{\pi}\)
-->
New Asset
Pricing

Application: Once we have factor premia \(\bm{\pi}\), we can price new assets:

\[\mu_{new} = r_f + \bm{b}_{new}'\bm{\pi}\]

12.3 Fama-MacBeth Two-Pass

Pass 1 (Time-Series): Estimate betas for each asset

\[R_{it} = \alpha_i + \bm{\beta}_i'\bm{f}_t + \epsilon_{it}\]

Pass 2 (Cross-Section): Estimate premia for each period

\[R_{it} = \gamma_{0t} + \bm{\gamma}_t'\hat{\bm{\beta}}_i + \eta_{it}\]

Result: \(\hat{\bm{\pi}} = \frac{1}{T}\sum_t \hat{\bm{\gamma}}_t\)

12.4 Shanken Correction

Standard errors must be adjusted for errors-in-variables:

\[SE_{Shanken} = SE_{FM} \times \sqrt{1 + \hat{\bm{\pi}}'\hat{\bm{\Omega}}_f^{-1}\hat{\bm{\pi}}}\]

13. Python Implementation

13.1 Inverse Optimization (Mean-Variance)

from brisma import inverse_optimize_mv

# Define inputs
weights = np.array([0.6, 0.4])  # 60/40 portfolio
cov_matrix = np.array([
    [0.04, 0.01],
    [0.01, 0.01]
])

# Compute implied returns
result = inverse_optimize_mv(
    weights=weights,
    cov_matrix=cov_matrix,
    lambda_param=2.5,
    rf_rate=0.02
)

print(result.implied_returns)
# Output: [0.09, 0.045]  (9%, 4.5% including rf)

13.2 Factor Premia Extraction

from brisma import extract_factor_premia_ols

# Implied returns from inverse optimization
implied_returns = np.array([0.08, 0.06, 0.05, 0.04])

# Factor loadings (single factor: market beta)
betas = np.array([[1.2], [0.9], [0.7], [0.4]])

# Extract factor premium
result = extract_factor_premia_ols(
    implied_returns=implied_returns,
    betas=betas,
    rf_rate=0.02
)

print(f"Factor Premium: {result.factor_premia[0]:.2%}")
print(f"R-squared: {result.r_squared:.3f}")

13.3 Full Pipeline

from brisma import BRISMA

# Load data and run full pipeline
model = BRISMA.from_excel("data/brisma_data.xlsx")
result = model.run_pipeline()

# Get implied returns
implied = model.get_implied_returns(method="mean_variance")
print(implied)

# Get factor premia
premia = model.get_factor_premia()
print(premia)

13.4 Bantleon Methods

# Method M1 (10Y Bond)
def lambda_m1(y_10y, rf, beta_ref=7.0):
    """Compute lambda from 10Y bond yield."""
    return np.log((1 + y_10y) / (1 + rf)) / beta_ref

# Method M2 (Historical with exponential decay)
def lambda_m2(returns, halflife=24):
    """Compute lambda from historical returns with exp decay."""
    T = len(returns)
    alpha = np.log(2) / halflife
    weights = np.exp(-alpha * np.arange(T-1, -1, -1))
    weights /= weights.sum()
    return np.sum(weights * returns)

# Hybrid
def lambda_hybrid(y_10y, rf, returns, r_squared, beta_ref=7.0, halflife=24):
    """Blend M1 and M2 based on R-squared."""
    lam_m1 = lambda_m1(y_10y, rf, beta_ref)
    lam_m2 = lambda_m2(returns, halflife)
    return r_squared * lam_m1 + (1 - r_squared) * lam_m2

14. BRISMA Architecture

14.1 Data Flow

Excel (brisma_data.xlsx, 4 sheets) | v load_data() --> currency_conversion --> returns | +---> estimate_iterative_covariance() --> Q_emp (empirical) | +---> estimate_factor_model() --> Q_shrink (shrinkage-adjusted) | +---> fit_garch_models() --> Q_garch (forecast) | v inverse_optimize_mv(w, Q, lambda) --> mu* (implied returns) | v extract_factor_premia_ols(mu*, B) --> pi (factor premia)

14.2 Key Modules

ModulePurpose
api.pyBRISMA facade class (main entry point)
data_loading.pyExcel data import, mapping tables
covariance.pyIterative covariance, factor model
garch_utils.pyGARCH fitting and forecasting
inverse_optimization.pyMV, MRAR, Omega inverse methods
factor_premia.pyOLS, Fama-MacBeth extraction
black_litterman.pyTactical view incorporation
portfolio_optimizer.py9 optimization functions

14.3 Three Covariance Matrices

MatrixMethodUse Case
Q_empEmpirical (historical)Baseline, backtesting
Q_shrinkFactor model + shrinkageReduced estimation error
Q_garchGARCH(1,1) forecastsForward-looking, time-varying

14.4 Test Coverage

  • Python: 173 tests across 12 modules
  • R: 18 test suites
  • R/Python equivalence: 1e-10 numerical tolerance

15. Formula Reference

NameFormulaUse
MV Utility\(U = w'\mu - \frac{\lambda}{2}w'Qw\)Investor objective
Implied Returns (MV)\(\mu^* = \lambda Qw + r_f\)Core inverse formula
Lambda M1\(\lambda = \frac{\ln((1+y_{10Y})/(1+r_f))}{\beta_{ref}}\)10Y bond method
Lambda M2\(\lambda = \sum w_t f_t\)Historical method
Hybrid\(\mu = R^2 \mu_{M1} + (1-R^2) \mu_{M2}\)Blending
Factor Premia (OLS)\(\pi = (B'B)^{-1}B'(\mu^* - r_f)\)Extraction
APT Pricing\(\E[R_i] = r_f + B_i'\pi\)New asset pricing
HJ Bound\(\frac{\sigma(m)}{\E[m]} \geq \sqrt{\mu'\Sigma^{-1}\mu}\)Model validation

16. Default Parameters

ParameterDefaultDescription
lambda_param2.5Risk aversion (Black-Litterman)
beta_ref7.0Reference beta for M1
halflife24Months for exponential decay (M2)
lookback60Months for beta estimation
rolling_window22Days for covariance
annualization11.86Periods per year (weekly data)

17. CLI Commands

# Run full pipeline
python -m brisma run data/brisma_data.xlsx -o outputs/

# Get help
python -m brisma --help

# Run specific analysis
python -m brisma analyze --method mean_variance

# Validate Bantleon methods
python python/validate_bantleon_methods.py

# Generate reports
python python/bantleon_full_report.py

Test Commands

# Python tests
pytest tests/python/ --ignore=tests/python/test_data_loading.py -v

# Single test class
pytest tests/python/test_bantleon.py::TestLambdaM1 -v

# R tests
source("run_tests.R")

References

  • Black, F., & Litterman, R. (1992). Global Portfolio Optimization. Financial Analysts Journal.
  • Fama, E. F., & French, K. R. (1993). Common risk factors in returns. Journal of Financial Economics.
  • Fama, E. F., & MacBeth, J. D. (1973). Risk, return, and equilibrium. Journal of Political Economy.
  • Hansen, L. P., & Jagannathan, R. (1991). Implications of security market data for models of dynamic economies. Journal of Political Economy.
  • Ross, S. A. (1976). The arbitrage theory of capital asset pricing. Journal of Economic Theory.
  • Shanken, J. (1992). On the estimation of beta-pricing models. Review of Financial Studies.

BRISMA Project | Bantleon InnoCheck 2025 | Last updated: January 2026