Holding-Company Look-Through Score
Install and import#
npm install fintech-algorithmsimport { holdingCompanyLookThroughScore } from "fintech-algorithms/fundamental-analysis-and-valuation/sector-specific-equity-scoring/holding-company-look-through-score";Signature#
holdingCompanyLookThroughScore(data)Looks through a holding company to its subsidiaries by scaling each holding's equity value, debt and dividends by the parent's ownership ratio, then bridges to parent NAV using parent cash, debt and other liabilities. Scores the NAV buffer, look-through leverage, dividend cover of parent interest, concentration, valuation freshness and listed coverage.
Parameters#
| Name | Type | Notes |
|---|---|---|
data | RecordValue | A plain object. framework must be the string holding-company-lookthrough-teaching-v1. weights must be an object holding exactly nav_buffer, lookthrough_leverage, parent_coverage, diversification, freshness and listed_coverage. holdings must be an array of at least two objects, each with a unique nonempty id, an ownership_ratio in (0, 1], nonnegative equity_value, debt and dividends_to_parent, and boolean listed and stale flags. parent_cash, parent_debt and other_parent_liabilities must be nonnegative and parent_interest_expense strictly positive. parent_market_cap is optional; when present it must be nonnegative.min_holdings: 2 |
Returns#
{ state: string; method: string; holding_ledger: Array<{ id: string; ownership_ratio: number; attributable_equity_value: number; attributable_debt: number; attributable_dividends: number; listed: boolean; stale: boolean }>; gross_asset_value: number; net_asset_value: number; attributable_subsidiary_debt: number; lookthrough_leverage: number; parent_interest_coverage: number; concentration_hhi: number; fresh_value_coverage: number; listed_value_coverage: number; discount_to_nav: number | null; component_scores: Record<string, number>; weights: Record<string, number>; look_through_score: number; coverage_ratio: number; reason: string }
holding_ledger restates each holding with its ownership-scaled equity value, debt and dividends. gross_asset_value is the summed attributable stake plus parent_cash; net_asset_value deducts parent_debt and other_parent_liabilities. lookthrough_leverage divides parent plus attributable subsidiary debt by the look-through enterprise value, and is 1 when that value is not positive. parent_interest_coverage divides attributable dividends by parent_interest_expense. concentration_hhi is the sum of squared value shares, and fresh_value_coverage and listed_value_coverage are the value shares of holdings not flagged stale and flagged listed. discount_to_nav is 1 less market cap over NAV, or null when parent_market_cap is absent or NAV is not positive. component_scores holds six band scores on a 0-100 scale and look_through_score is their weighted sum. state is nonpositive-nav-review when NAV is zero or negative, otherwise the band of the score: strong-review-band at 75 or more, mixed-review-band at 50 or more, weak-review-band below that. method is holding-company-lookthrough-score-v1 and coverage_ratio is 1.
Errors#
- When data is not a plain object, or a holding entry is not an object — throws TypeError
- When a holding id is not a nonempty string, or listed or stale is not a boolean — throws TypeError
- When framework is not holding-company-lookthrough-teaching-v1 — throws RangeError
- When holdings is not an array of at least two records — throws RangeError
- When two holdings share an id — throws RangeError
- When an ownership_ratio is outside (0, 1] — throws RangeError
- When gross asset value is not positive — throws RangeError
- When weights does not hold exactly the six component names, or its values do not sum to 1 within 1e-9 — throws RangeError
- When a parent balance required to be nonnegative is negative, or parent_interest_expense is not positive — throws RangeError
Complexity: time O(n),
space O(n).
Worked example#
executed Captured by running this function on the input its own test provides. Real output of real code — but not asserted against a published figure.
Input#
{
"framework": "holding-company-lookthrough-teaching-v1",
"holdings": [
{
"id": "listed-bank",
"ownership_ratio": 0.62,
"equity_value": 920,
"debt": 540,
"dividends_to_parent": 32,
"listed": true,
"stale": false
},
{
"id": "private-logistics",
"ownership_ratio": 0.8,
"equity_value": 410,
"debt": 180,
"dividends_to_parent": 18,
"listed": false,
"stale": false
},
{
"id": "listed-utility",
"ownership_ratio": 0.35,
"equity_value": 680,
"debt": 390,
"dividends_to_parent": 21,
"listed": true,
"stale": true
}
],
"parent_cash": 95,
"parent_debt": 260,
"other_parent_liabilities": 45,
"parent_interest_expense": 24,
"parent_market_cap": 760,
"weights": {
"nav_buffer": 0.22,
"lookthrough_leverage": 0.22,
"parent_coverage": 0.18,
"diversification": 0.14,
"freshness": 0.12,
"listed_coverage": 0.12
}
}Call#
holdingCompanyLookThroughScore(data)Returns#
object with 17 fields: state, method, holding_ledger, gross_asset_value, net_asset_value, attributable_subsidiary_debt, lookthrough_leverage, parent_interest_coverage, …
{
"state": "mixed-review-band",
"method": "holding-company-lookthrough-score-v1",
"holding_ledger": [
{
"id": "listed-bank",
"ownership_ratio": 0.62,
"attributable_equity_value": 570.4,
"attributable_debt": 334.8,
"attributable_dividends": 19.84,
"listed": true,
"stale": false
},
{
"id": "private-logistics",
"ownership_ratio": 0.8,
"attributable_equity_value": 328,
"attributable_debt": 144,
"attributable_dividends": 14.4,
"listed": false,
"stale": false
},
{
"id": "listed-utility",
"ownership_ratio": 0.35,
"attributable_equity_value": 237.99999999999997,
"attributable_debt": 136.5,
"attributable_dividends": 7.35,
"listed": true,
"stale": true
}
],
"gross_asset_value": 1231.3999999999999,
"net_asset_value": 926.3999999999999,
"attributable_subsidiary_debt": 615.3,
"lookthrough_leverage": 0.47398061406833814,
"parent_interest_coverage": 1.7329166666666669,
"concentration_hhi": 0.3791097100943457,
"fresh_value_coverage": 0.7905667018655403,
"listed_value_coverage": 0.7113692361844421,
"discount_to_nav": 0.17962003454231423,
"component_scores": {
"nav_buffer": 92.05240647501488,
"lookthrough_leverage": 39.115419095924864,
"parent_coverage": 24.43055555555556,
"diversification": 71.30895331236762,
"freshness": 47.64167546638509,
"listed_coverage": 58.767033740634595
},
"weights": {
"nav_buffer": 0.22,
"lookthrough_leverage": 0.22,
"parent_coverage": 0.18,
"diversification": 0.14,
"freshness": 0.12,
"listed_coverage": 0.12
}
}Showing 14 of 17 fields.
Other exports#
This module also exports
calculate, bankFundamentalScore, insuranceFundamentalScore, reitFundamentalScore, utilityFundamentalScore, earlyStageLiquidityAndRunwayScore, cyclicalAndCommodityCycleNormalization, sectorSpecificWeightCalibration, unsupportedScopeAndCoverageDecision. Every module additionally exports run as an alias of its
primary function, and a meta object carrying its catalog id, domain, family,
shape and article URL.
Diagrams#
How it works#
This page states the contract — how to call it correctly. The article explains the concept: why it works, and where it breaks.
References#
- IFRS 10 Consolidated Financial Statements — International Accounting Standards Board
- IFRS 12 Disclosure of Interests in Other Entities — International Accounting Standards Board
- IAS 28 Investments in Associates and Joint Ventures — International Accounting Standards Board
- Evidence boundary