import { SECTOR, ASSET_TYPE, REGIME } from '../config/constants.js'; export class MarketRegime { constructor(marketContext) { const b = marketContext?.benchmarks ?? {}; this.marketPE = b.marketPE ?? 22; this.techPE = b.techPE ?? 30; this.reitYield = b.reitYield ?? 3.5; this.igSpread = b.igSpread ?? 1.0; this.rateRegime = marketContext?.rateRegime ?? REGIME.NORMAL; this.volatilityRegime = marketContext?.volatilityRegime ?? REGIME.NORMAL; } getInflatedOverrides(type, sector) { if (type === ASSET_TYPE.STOCK) return this._stock(sector); if (type === ASSET_TYPE.ETF) return this._etf(); if (type === ASSET_TYPE.BOND) return this._bond(); return { gates: {}, thresholds: {} }; } _stock(sector) { if (sector === SECTOR.REIT) { return { gates: {}, // In HIGH rate environment tighten REIT yield floor — REITs must compete harder with bonds. thresholds: { minYield: +(this.reitYield * (this.rateRegime === REGIME.HIGH ? 0.95 : 0.85)).toFixed(2), maxPFFO: 20, }, }; } if (sector === SECTOR.TECHNOLOGY) { return { gates: { maxPERatio: Math.round(this.techPE * 1.3), maxPegGate: +(this.techPE / 15).toFixed(1), }, thresholds: {}, }; } // In HIGH rate environment, compress the P/E tolerance — higher rates mean // future earnings are discounted more aggressively (lower DCF valuations). const peMultiplier = this.rateRegime === REGIME.HIGH ? 1.2 : 1.5; return { gates: { maxPERatio: Math.round(this.marketPE * peMultiplier), maxPegGate: +(this.marketPE / 12).toFixed(1), }, thresholds: {}, }; } _etf() { return { gates: { maxExpenseRatio: 0.75 }, thresholds: { minYield: 0.5 } }; } _bond() { // In HIGH rate environment demand a wider spread — the opportunity cost of holding // corporate bonds over Treasuries is higher when risk-free rate is elevated. const spreadMultiplier = this.rateRegime === REGIME.HIGH ? 0.9 : 0.8; return { gates: {}, thresholds: { minSpread: +(this.igSpread * spreadMultiplier).toFixed(2) } }; } }