import { SECTOR, ASSET_TYPE, REGIME } from '../config/constants.js'; import type { MarketContext, AssetType } from '../types.js'; interface InflatedOverrides { gates: Record; thresholds: Record; } export class MarketRegime { private marketPE: number; private techPE: number; private reitYield: number; private igSpread: number; private rateRegime: string; private volatilityRegime: string; constructor(marketContext: Partial) { const b = marketContext?.benchmarks ?? ({} as 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: AssetType, sector?: string): InflatedOverrides { 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: {} }; } private _stock(sector?: string): InflatedOverrides { if (sector === SECTOR.REIT) { return { gates: {}, 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: {}, }; } 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: {}, }; } private _etf(): InflatedOverrides { return { gates: { maxExpenseRatio: 0.75 }, thresholds: { minYield: 0.5 } }; } private _bond(): InflatedOverrides { const spreadMultiplier = this.rateRegime === REGIME.HIGH ? 0.9 : 0.8; return { gates: {}, thresholds: { minSpread: +(this.igSpread * spreadMultiplier).toFixed(2) }, }; } }