// BondFactor.jsx — 채권 리스크 요인 분석: 기준금리 · 국가/등급 스프레드 · DV01 · 기간구조 · Greeks · 팩터 익스포저. const bfMn = (v) => Math.round(v * 100).toLocaleString(); // 억 → 백만원 const bfSigned = (v) => (v > 0 ? '+' : v < 0 ? '−' : '') + Math.abs(Math.round(v * 100)).toLocaleString(); // ── ① 나라별 기준금리 ── function PolicyRates() { return (
{POLICY_RATES.map((p) => { const c = p.delta > 0 ? T.up : p.delta < 0 ? T.down : T.c500; return (
{p.country} {p.bank}
{p.rate.toFixed(2)} % {p.delta !== 0 && }
{p.asOfMove}
); })}
); } // ── ② 국가/등급별 신용스프레드 매트릭스 ── function SpreadMatrix({ pf }) { const held = new Set(pf.holds.map((h) => UMAP[h.id].country)); const all = SPREAD_MATRIX.flatMap((r) => SPREAD_GRADES.map((g) => r.spreads[g])); const mx = Math.max(...all); const heat = (v) => { const f = Math.min(1, v / mx); const r = Math.round(249 - (249 - 199) * f), g = Math.round(233 - (233 - 106) * f), b = Math.round(233 - (233 - 31) * f); return `rgb(${r},${g},${b})`; }; return (
{SPREAD_GRADES.map((g) =>
{g}
)} {SPREAD_MATRIX.map((row) =>
{row.country} {held.has(row.country) && }
{SPREAD_GRADES.map((g) => { const v = row.spreads[g]; const d = row.dod[g]; const dark = v / mx > 0.55; return
{v}bp
0 ? T.up : T.c400 }}>{d > 0 ? '+' : ''}{d}bp
; })}
)}
보유 포지션이 있는 국가 · 국채 대비 OAS, 전일대비
); } // ── ③ DV01 (포지션별 · 넷) ── function DV01Panel({ pf }) { const s = dv01Summary(pf); const firm = firmDV01(); const mx = Math.max(...s.rows.map((r) => r.dv01), 0.001); const kpis = [ { l: 'Gross DV01', v: bfMn(s.gross), sub: '보유 포지션 합', c: T.c900 }, { l: '선물 헤지', v: bfSigned(s.hedge), sub: '국채선물 매도', c: T.down }, { l: 'Net DV01', v: bfMn(s.net), sub: '금리 +1bp 시 평가손', c: T.blue }, { l: '전사 Net DV01', v: bfMn(firm.net), sub: `채권 데스크 전체 (${peopleOf('채권').length}명)`, c: T.c900 }, ]; return (
{kpis.map((k) =>
{k.l}
{k.v} 백만/bp
{k.sub}
)}
포지션별 DV01 (백만원/bp)
{s.rows.map((r) => (
{r.name} {r.country} · {r.dur}Y
{bfMn(r.dv01)}
))}
국채선물 매도 헤지
{bfSigned(s.hedge)}
); } // ── ④ 기간구조별 DV01 + Greeks ── function TenorGreeks({ pf }) { const tenors = tenorDV01(pf); const mx = Math.max(...tenors.map((t) => t.dv01), 0.001); const gk = greeksRows(pf); const gammaSum = gk.reduce((s, r) => s + r.gamma, 0); const vegaSum = gk.reduce((s, r) => s + r.vega, 0); const vegaRows = gk.filter((r) => r.vega > 0); return (
{/* 기간구조 */}
기간구조별 DV01 (백만원/bp)
{tenors.map((t) => (
0 ? T.c900 : T.c300 }}>{t.dv01 > 0 ? bfMn(t.dv01) : '—'}
0.66 ? T.blue : t.dv01 > 0 ? '#7FA8D9' : T.c200, borderRadius: '6px 6px 3px 3px', transition: 'height .3s' }} /> {t.label} {t.n}종목
))}
{/* Greeks */}
Greeks (감마·베가)
포트 감마 (Convexity)
{bfMn(gammaSum)} 백만/(100bp)²
금리 대변동 시 손익 곡률
포트 베가 (콜 내재)
0 ? T.warn : T.c900, marginTop: 5, textAlign: 'left' }}>{bfMn(vegaSum)} 백만/vol 1%p
콜러블 채권 {vegaRows.length}종목 보유
{gk.slice(0, 5).map((r, i) =>
{r.name} {r.call && 콜러블} Γ {bfMn(r.gamma)} 0 ? T.warn : T.c300, width: 58, textAlign: 'right' }}>ν {r.vega > 0 ? bfMn(r.vega) : '—'}
)}
); } // ── ⑤ 팩터별 리스크 익스포저 (관리 액션 포함) ── function BondFactorExposure({ pf }) { const dec = factorDecompose(pf).filter((d) => d.id !== 'eq'); return (
{dec.map((d) =>
)}
{dec.map((d, i) =>
{d.name} {d.code} {d.id !== 'vol' ? {d.sensLabel} → {fvEok(d.sensAmt)} : '요인 설명 후 잔차'} {Math.round(d.amt).toLocaleString()}억 {(d.frac * 100).toFixed(1)}%
)}
); } // ── 섹션 조립 (채권 포트폴리오 관리 내) ── function BondFactorSection({ pf }) { return (
① 나라별 기준금리
② 국가 × 등급별 신용스프레드
③ 팩터별 리스크 익스포저
④ DV01 — 포지션별 · Net
⑤ 기간구조 · Greeks
); } // ── 모니터링(채권) 탭용 하이라이트 ── function BondFactorHighlight({ onMore }) { const pf = React.useMemo(() => firmPortfolio('채권'), []); const m = summarize(pf); const s = dv01Summary(pf); const tenors = tenorDV01(pf); const topTenor = tenors.slice().sort((a, b) => b.dv01 - a.dv01)[0]; const dec = factorDecompose(pf).filter((d) => d.id !== 'eq').slice(0, 2); const kr = POLICY_RATES[0]; const us = POLICY_RATES[1]; const Stat = ({ l, v, u, sub, c }) => (
{l}
{v} {u}
{sub}
); return ( 채권 포트폴리오에서 상세 분석} />
팩터 기여 Top
{dec.map((d, i) =>
{d.name} {Math.round(d.amt).toLocaleString()}억 · {(d.frac * 100).toFixed(0)}%
)}
); } Object.assign(window, { BondFactorSection, BondFactorHighlight, PolicyRates, SpreadMatrix, DV01Panel, TenorGreeks, BondFactorExposure, bfMn, bfSigned });