feat: dealer flow, mirror portfolio (M21), options convexity, FINRA short interest, alert producers, vendor gate
CI / Test & Type-Check (push) Canceled after 0s

Snapshot of in-progress module work across multiple slices:

- Dealer Flow: dealerExposureEngine, dealerMapService, dealerMapExplain,
  dealerMapIntegrity, dealerMapReplay, dealerStudyEngine, hanStyleLevels
- Mirror Portfolio (M21): fundRepository, captureIngest, mirrorAlertProducers,
  fund holdings strip, live book, position capture ingest
- Options: BSM, NormalizedOptionSurface types, OptionsChainRouter,
  ConvexityGate, option legs panel
- Alert producers: vixLevel, rotation, thesis, unlock, portfolioRisk,
  mirror (fund_capture, fund_13f, mirror_diff)
- FINRA short interest adapter + queue integration
- SEC company tickers adapter + ingest (symbol search index seed)
- Vendor gate (rate-limit-first data plane, ADR-0009)
- CUSIP registry, reverse 13F refresh, stock float service
- LRU cache, portfolio backtest engine
- Frontend: dealer-flow, funds, journal, lab, monitor, plan, portfolio,
  reports, screener, strategies, theses, guided-start, exits, more pages
- Volume profile, workspace profile, visibility-aware poll
- ADRs 0010 (mirror math not advice), 0011 (symbol search index)
- VENDOR_INTEGRATIONS.md, END_USER_TEST.md
- .gitignore: exclude DBs, .DS_Store, local config, agent scratch
This commit is contained in:
Investor Flow Build
2026-08-10 13:36:26 -04:00
parent 04fc11b2fd
commit ac94acf9e3
229 changed files with 32617 additions and 3934 deletions
+34 -13
View File
@@ -13,14 +13,15 @@ export type DeriskingStrategyId =
| 'thesis_based_partial'
| 'option_protected_collar'
| 'regime_cut'
| 'correlation_driven';
| 'correlation_driven'
| 'dividend_at_risk';
export interface DeriskingStrategy {
id: DeriskingStrategyId;
name: string;
description: string;
alfredFraming: string;
requiresOptionsSleeve: boolean;
requiresOptionsSleeve?: boolean; // true if this strategy requires options unlock
}
export const DERISKING_STRATEGIES: DeriskingStrategy[] = [
@@ -29,21 +30,18 @@ export const DERISKING_STRATEGIES: DeriskingStrategy[] = [
name: 'Scale Out at Targets',
description: 'Reduce partial position size as price reaches predefined profit targets. This adds flexibility — some position remains if the thesis continues to play out.',
alfredFraming: 'Winners have flexibility. Scaling out at targets locks in some gains while leaving room for further upside.',
requiresOptionsSleeve: false,
},
{
id: 'stop_trail_ema21_50',
name: 'Stop-Trail EMA 21/50',
description: 'Trail a stop above the 21-day or 50-day EMA. This adapts the stop to volatility, allowing the position to breathe while protecting gains.',
alfredFraming: 'Trailing stops adapt to changing conditions. A static stop ignores new information.',
requiresOptionsSleeve: false,
},
{
id: 'thesis_based_partial',
name: 'Thesis-Based Partial Reduction',
description: 'If the thesis is weakening but not fully invalidated, consider reducing position size rather than fully exiting. This acknowledges uncertainty without abandoning the thesis entirely.',
alfredFraming: 'When the thesis weakens but is not broken, flexibility means adjusting size — not all or nothing.',
requiresOptionsSleeve: false,
},
{
id: 'option_protected_collar',
@@ -57,14 +55,18 @@ export const DERISKING_STRATEGIES: DeriskingStrategy[] = [
name: 'Regime-Cut Reduction',
description: 'When the market regime shifts to trending-down, consider reducing exposure across the portfolio. This is a macro-level derisking response to changed conditions.',
alfredFraming: 'When the tide turns, reduce exposure. Fighting a regime shift is a common way winners become losers.',
requiresOptionsSleeve: false,
},
{
id: 'correlation_driven',
name: 'Correlation-Driven Reduction',
description: 'When multiple positions become highly correlated, consider reducing the most correlated ones. Concentrated correlation creates hidden portfolio risk.',
alfredFraming: 'When everything moves together, you do not have diversification — you have one bet wearing many masks.',
requiresOptionsSleeve: false,
},
{
id: 'dividend_at_risk',
name: 'Dividend at Risk',
description: 'When a dividend-paying stock shows signs of a potential cut — high payout ratio, declining yield, or skipped ex-date — consider reducing exposure before the cut is announced.',
alfredFraming: 'Dividend cuts usually arrive after the warning signs are visible. The market often prices a cut before it is announced.',
},
];
@@ -80,8 +82,10 @@ export interface DeriskingInput {
thesisStatus?: 'intact' | 'weakening' | 'broken';
currentRegime?: 'trending-up' | 'trending-down' | 'range-bound';
portfolioCorrelation?: number; // 0-1, how correlated this position is with others
optionsUnlockState?: number; // 0-4, from ConvexityGate
profitTargets?: number[]; // price levels
dividendYield?: number;
payoutRatio?: number;
optionsUnlockState?: number; // 0 = locked, 3+ = unlocked for option strategies
}
export interface DeriskingSuggestion {
@@ -152,13 +156,14 @@ function evaluateStrategy(
}
case 'option_protected_collar': {
const hasOptionsSleeve = (input.optionsUnlockState ?? 0) >= 3;
// Gated by options unlock state (0 = locked, 3+ = unlocked)
const hasOptionsUnlock = (input.optionsUnlockState ?? 0) >= 3;
return {
strategy: strat,
applicable: hasOptionsSleeve && inProfit,
reason: hasOptionsSleeve
? 'Options insurance sleeve is unlocked. A collar may define downside risk while partially financing protection.'
: 'Options insurance sleeve is not unlocked. Collar strategy requires the insurance sleeve tier.',
applicable: inProfit && hasOptionsUnlock,
reason: !hasOptionsUnlock
? 'Option collar requires options unlock level 3 or higher.'
: 'A collar may define downside risk while partially financing protection.',
details: strat.alfredFraming,
};
}
@@ -186,5 +191,21 @@ function evaluateStrategy(
details: strat.alfredFraming,
};
}
case 'dividend_at_risk': {
const dy = input.dividendYield;
const pr = input.payoutRatio;
const atRisk = (dy !== undefined && dy < 0.005) || (pr !== undefined && pr > 0.95);
return {
strategy: strat,
applicable: atRisk,
reason: atRisk
? (dy !== undefined && dy < 0.005
? `Dividend yield is very low (${(dy * 100).toFixed(2)}%). This may indicate a recent cut or unsustainable payout.`
: `Payout ratio is very high (${((pr ?? 0) * 100).toFixed(0)}%). Earnings may not cover the dividend.`)
: 'Dividend fundamentals appear healthy.',
details: strat.alfredFraming,
};
}
}
}