이어 가기
절차
실행 순서
- 1
**DOL** (Degree of Operating Leverage) = % ΔOP / % ΔSales = (Sales − VC) / (Sales − VC − FC). 고정비 비중 클수록 DOL 큼 — 매출 1% 변동 → 영업이익 N% 변동.
- 2
**DFL** (Degree of Financial Leverage) = % ΔNI / % ΔOP = OP / (OP − Interest). 이자비용 비중 클수록 DFL 큼.
- 3
**DCL** (Degree of Combined Leverage) = DOL × DFL = % ΔNI / % ΔSales. 매출 1% 변동 → 순이익 N% 변동.
- 4
Mandelker-Rhee (1984): DOL × DFL 가 stock beta 에 직접 영향. 고-DCL 회사가 system risk 높음.
- 5
Dugan-Shriver (1992): DOL 표준 추정 — 5 년 회귀법 (% ΔOP = α + β × % ΔSales). 본 recipe 의 추정 방법.
- 6
Faff-Brooks (1998): 사이클 회사 (조선·반도체·정유) 의 DCL 평균 3-5, 안정 회사 (통신·소비재) 1-1.5.
- 7
매출 −10% 충격 시 영업이익 = −10% × DOL, 순이익 = −10% × DCL.
- 8
침체 시나리오 (매출 -20%) 에서 ROE 가 어떻게 변할지 직접 추정.
- 9
`metric : str` — 5 metric 이름
- 10
`value : float`
- 11
`salesShockPct : float` — −20% ~ +20%
- 12
`opChangePct`, `niChangePct : float` — DOL/DCL 곱한 추정 변화율
학술 근거
레버리지 분석은 corporate finance 기본 — 매출 변동이 이익에 어떻게 증폭되는지 측정.
- DOL (Degree of Operating Leverage) = % ΔOP / % ΔSales = (Sales − VC) / (Sales − VC − FC). 고정비 비중 클수록 DOL 큼 — 매출 1% 변동 → 영업이익 N% 변동.
- DFL (Degree of Financial Leverage) = % ΔNI / % ΔOP = OP / (OP − Interest). 이자비용 비중 클수록 DFL 큼.
- DCL (Degree of Combined Leverage) = DOL × DFL = % ΔNI / % ΔSales. 매출 1% 변동 → 순이익 N% 변동.
학술 검증:
- Mandelker-Rhee (1984): DOL × DFL 가 stock beta 에 직접 영향. 고-DCL 회사가 system risk 높음.
- Dugan-Shriver (1992): DOL 표준 추정 — 5 년 회귀법 (% ΔOP = α + β × % ΔSales). 본 recipe 의 추정 방법.
- Faff-Brooks (1998): 사이클 회사 (조선·반도체·정유) 의 DCL 평균 3-5, 안정 회사 (통신·소비재) 1-1.5.
매크로 충격 시뮬레이션:
- 매출 −10% 충격 시 영업이익 = −10% × DOL, 순이익 = −10% × DCL.
- 침체 시나리오 (매출 -20%) 에서 ROE 가 어떻게 변할지 직접 추정.
공개 호출 방식
import dartlab
import polars as pl
import numpy as np
c = dartlab.Company("005930")
is_df = c.show("IS", freq="Y")
years = ["2025", "2024", "2023", "2022", "2021"]
def fetchSeries(df: pl.DataFrame, snake: str, years: list[str]) -> list[float]:
row = df.filter(pl.col("snakeId") == snake).select(years)
return row.to_numpy()[0].tolist() if row.height > 0 else [0.0] * len(years)
sales = fetchSeries(is_df, "sales", years)
op = fetchSeries(is_df, "operating_profit", years)
ni = fetchSeries(is_df, "net_income", years)
interest = fetchSeries(is_df, "interest_expense", years)
# 1) 회귀 추정 — % ΔOP / % ΔSales (5 년 시계열)
salesPct = [(sales[i] - sales[i+1]) / sales[i+1] for i in range(len(sales)-1) if sales[i+1] != 0]
opPct = [(op[i] - op[i+1]) / op[i+1] for i in range(len(op)-1) if op[i+1] != 0]
niPct = [(ni[i] - ni[i+1]) / ni[i+1] for i in range(len(ni)-1) if ni[i+1] != 0]
dolRegression = np.polyfit(salesPct, opPct, 1)[0] if len(salesPct) >= 2 else None
dclRegression = np.polyfit(salesPct, niPct, 1)[0] if len(salesPct) >= 2 else None
# 2) 단년도 algebraic (가장 최근)
dolAlgebraic = (op[0] / sales[0]) and ((op[0] - op[1]) / op[1]) / ((sales[0] - sales[1]) / sales[1]) if sales[1] != 0 and op[1] != 0 else None
dflAlgebraic = op[0] / (op[0] - abs(interest[0])) if (op[0] - abs(interest[0])) != 0 else None
dclAlgebraic = (dolAlgebraic or 0) * (dflAlgebraic or 0)
# 3) 매크로 충격 시나리오
shocks = [-0.20, -0.10, -0.05, 0.05, 0.10, 0.20]
scenarios = []
for shock in shocks:
scenarios.append({
"salesShockPct": shock * 100,
"opChangePct": shock * (dolRegression or 0) * 100,
"niChangePct": shock * (dclRegression or 0) * 100,
"salesProjected": sales[0] * (1 + shock),
"opProjected": op[0] * (1 + shock * (dolRegression or 0)),
"niProjected": ni[0] * (1 + shock * (dclRegression or 0)),
})
leverageTable = pl.DataFrame({
"metric": ["DOL_regression", "DOL_algebraic", "DFL_algebraic", "DCL_regression", "DCL_algebraic"],
"value": [dolRegression, dolAlgebraic, dflAlgebraic, dclRegression, dclAlgebraic],
})
scenarioTable = pl.DataFrame(scenarios) 호출 동작
c.show("IS", freq="Y")— 5 년 손익계산서.- snakeId 로 4 항목 추출 (sales, operating_profit, net_income, interest_expense).
- DOL / DCL — 5 년 회귀 추정 (
np.polyfit1 차). - DFL — 단년도 algebraic (OP / (OP − |Interest|)).
- 매크로 충격 시나리오 — 매출 ±5%, ±10%, ±20% 시 OP / NI 추정.
대표 반환 형태
leverageTable : pl.DataFrame:
metric : str— 5 metric 이름value : float
scenarioTable : pl.DataFrame:
salesShockPct : float— −20% ~ +20%opChangePct,niChangePct : float— DOL/DCL 곱한 추정 변화율salesProjected,opProjected,niProjected : float— 절대값 추정
한계
interest_expensesnakeId 가용성 — 한국 일부 회사 IS 에서 영업외비용 통합 표기. 별도 추출 필요.- 회귀 5 점 — 5 년 시계열로 1 차 회귀 신뢰성 약함. 분기 시계열 (20 점) 권장하나 본 recipe 는 연간 표준.
- 단년도 algebraic 노이즈 — 단년도 % ΔOP/% ΔSales 가 1 회 사이클 시 무한대. 회귀 추정 우선.
- DOL 정의 변형 —
(Sales − VC) / (Sales − VC − FC)정의는 변동비/고정비 분리 필요. dartlab 에서 직접 X — 회귀 + algebraic 으로만 추정. - 시나리오 선형성 가정 — DOL 큰 회사도 매출 −50% 같은 극단 충격에서는 비선형 (적자 전환). 본 recipe 시나리오 ±20% 한정.
한국 / 미국 시장 차이
- 한국: 사이클 산업 (조선·반도체·정유·해운) 비중 큼. KOSPI 200 평균 DCL 약 2.5 (S&P 500 의 1.5 대비). 본 recipe 가 한국 시장에서 특히 의미.
- 미국: 서비스·플랫폼 회사 비중 커 평균 DCL 낮음. 다만 IT (반도체·하드웨어) 회사 사이클 효과 강함.
연계 절차
- 본 recipe → DOL/DFL/DCL + 시나리오 표.
- DCL > 3 = 사이클 회사 → 매크로 시나리오 (
engines.recipe.creditDistressDual의 침체 가정) 와 결합. - DOL 변동 → 고정비 구조 변화 (CAPEX 사이클·M&A 효과) 점검.
- DFL 큰 회사 →
engines.recipe.distressFilter의 부채비율·유동성 게이트 강화. - ROE 변동의 5 동인 (
engines.recipe.dupontDriver) 중 financialLeverage 변화와 DFL 변화 일치 검증.
기본 검증
- DOL × DFL ≈ DCL 항등식 (algebraic) 5%p 이내 일치 확인.
- 회귀 R² 점검 — 0.7 이하면 5 년 회귀 신뢰성 낮음 (회사 사이클 큼 또는 외부 충격).
- DOL 5 이상 + DFL 2 이상 → DCL 10 이상 — 매출 −10% 시 NI −100% (적자 전환) 위험.
- 시나리오는 추정 — 실제 충격 시 비선형 효과 (적자 시 세금 환급, 운영 효율 변화 등) 별도.
- “DCL 1.5 = 안전” 단정 X — 산업 평균 (회사가 속한 산업 평균 DCL) 대비로 해석.
런타임
실행 환경별 호환성
| 환경 | 상태 | 비고 / 제한 |
|---|---|---|
| Local Python | supported | — |
| Server | supported | — |
| MCP | unknown | — |
| Web AI | unknown | — |
| Pyodide | limited |
|