# Sector-Specific Weight Calibration

`D18-F10-A08` · Fundamental Analysis and Valuation → Sector-Specific Equity Scoring · archetype `record-transform` · difficulty 5/5 · verification **verified**

Full page: https://docs.thefintechbuilder.com/fundamental-analysis-and-valuation/sector-specific-equity-scoring/sector-specific-weight-calibration/
Agent skill: `npx skills add IslamBaraka90/Fintech-Algorithms-Library` — https://docs.thefintechbuilder.com/guides/agent-skill/

## Install and import

```bash
npm install fintech-algorithms
```

```ts
import { sectorSpecificWeightCalibration } from "fintech-algorithms/fundamental-analysis-and-valuation/sector-specific-equity-scoring/sector-specific-weight-calibration";
```

## Signature

```ts
sectorSpecificWeightCalibration(data)
```

Fits component weights by projected gradient descent on a logistic model of the labelled outcome, keeping the weights nonnegative and summing to 1 at every step and pulling them back toward the declared base weights with a ridge term. Splits the history in time and keeps the fitted weights only when they beat the base weights on the held-out Brier score.

## Parameters

| Name | Type | Required | Notes |
| --- | --- | --- | --- |
| `data` | `RecordValue` | yes | A plain object. `framework` must be the string `sector-weight-calibration-teaching-v1`. `component_names` is an array of at least two unique nonempty strings; `base_weights` is an object keyed by exactly those names, nonnegative and summing to 1. `feature_rows` is an array of at least twelve rows, each a numeric array aligned to `component_names` with every score in [0, 100]; `labels` and `observation_dates` must match it in length, labels being 0 or 1 and dates being strictly increasing `YYYY-MM-DD` strings. `train_end_index` splits the rows in time. `learning_rate`, `logit_slope` and `iterations` must be positive, `ridge_penalty` nonnegative. · min_rows: 12, min_training_rows: 8, min_validation_rows: 4, max_iterations: 5000 |

## Returns

`{ state: string; method: string; component_names: string[]; base_weights: Record<string, number>; candidate_weights: Record<string, number>; selected_weights: Record<string, number>; candidate_intercept: number; selected_intercept: number; base_train_brier: number; base_validation_brier: number; candidate_train_brier: number; candidate_validation_brier: number; selected_validation_brier: number; weight_shift_l1: number; train_rows: number; validation_rows: number; coverage_ratio: number; reason: string }`

`candidate_weights` and `candidate_intercept` are the fitted values; `selected_weights` and `selected_intercept` are those same values when the candidate validation Brier score is at or below the base one, and otherwise the base weights with a zero intercept. The four Brier fields report train and validation loss for base and candidate, and `selected_validation_brier` repeats whichever was chosen. `weight_shift_l1` is the summed absolute move from base to candidate, and `train_rows` and `validation_rows` record the split sizes. `state` is `calibrated-improved` or `retain-base-weights`. `method` is `nonnegative-simplex-logloss-v1` and `coverage_ratio` is 1.

## Errors

- When data is not a plain object, or a feature value is not a finite number — throws TypeError
- When an observation date is not a YYYY-MM-DD string — throws TypeError
- When framework is not sector-weight-calibration-teaching-v1 — throws RangeError
- When component_names is not at least two unique nonempty strings — throws RangeError
- When feature_rows holds fewer than 12 observations, or labels or observation_dates do not match its length — throws RangeError
- When a feature row does not match component_names in length, or a score falls outside [0, 100] — throws RangeError
- When a label is not 0 or 1, or observation_dates is not strictly increasing — throws RangeError
- When train_end_index leaves fewer than 8 training or 4 validation rows — throws RangeError
- When base_weights does not match component_names, is negative, or does not sum to 1 within 1e-9 — throws RangeError
- When learning_rate, logit_slope or iterations is not positive, ridge_penalty is negative, or iterations exceeds 5000 — throws RangeError

## Complexity

Time `O(i * n * k + i * k log k) for i iterations, n rows and k components`, space `O(n * k)`.

## Worked example

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

`data`:

```json
{
  "framework": "sector-weight-calibration-teaching-v1",
  "component_names": ["quality", "resilience", "cash_conversion"],
  "base_weights": {
    "quality": 0.4,
    "resilience": 0.35,
    "cash_conversion": 0.25
  },
  "feature_rows": [
    [82, 65, 78],
    [74, 60, 70],
    [45, 72, 55]
  ],
  "labels": [1, 1, 0, 1, 0, 1],
  "observation_dates": [
    "2024-01-01",
    "2024-02-01",
    "2024-03-01",
    "2024-04-01",
    "2024-05-01",
    "2024-06-01"
  ],
  "train_end_index": 12,
  "learning_rate": 0.08,
  "ridge_penalty": 0.2,
  "logit_slope": 5,
  "iterations": 600
}
```

### Call

```ts
sectorSpecificWeightCalibration(data)
```

### Returns

object with 18 fields: state, method, component_names, base_weights, candidate_weights, selected_weights, candidate_intercept, selected_intercept, …

```json
{
  "state": "retain-base-weights",
  "method": "nonnegative-simplex-logloss-v1",
  "component_names": ["quality", "resilience", "cash_conversion"],
  "base_weights": {
    "quality": 0.4,
    "resilience": 0.35,
    "cash_conversion": 0.25
  },
  "candidate_weights": {
    "quality": 0.7551696860135335,
    "resilience": 0,
    "cash_conversion": 0.24483031398646643
  },
  "selected_weights": {
    "quality": 0.4,
    "resilience": 0.35,
    "cash_conversion": 0.25
  },
  "candidate_intercept": -0.40266157235699845,
  "selected_intercept": 0,
  "base_train_brier": 0.14500903499442555,
  "base_validation_brier": 0.10197248987791843,
  "candidate_train_brier": 0.10051624085395794,
  "candidate_validation_brier": 0.10310568321068389,
  "selected_validation_brier": 0.10197248987791843,
  "weight_shift_l1": 0.710339372027067
}
```

Showing 14 of 18 fields.

## Other exports

`calculate`, `bankFundamentalScore`, `insuranceFundamentalScore`, `reitFundamentalScore`, `utilityFundamentalScore`, `earlyStageLiquidityAndRunwayScore`, `cyclicalAndCommodityCycleNormalization`, `holdingCompanyLookThroughScore`, `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.

## Verification and provenance

Tier: **verified** (via D).

The worked example below is the figure published in this algorithm's article, replayed and asserted by the test suite on every build. The arithmetic cannot drift without the build failing.

Both tiers guarantee the signature. Full explanation: https://docs.thefintechbuilder.com/guides/verification/

Generated from the docs.json payload shipped inside fintech-algorithms@0.13.0.
The signature and parameter list are checked against the compiled implementation at build time,
so a description that contradicts the code fails the build rather than reaching this file.

## Links

- Article (how it works, step by step): https://thefintechbuilder.com/fundamental-analysis-and-valuation/sector-specific-equity-scoring/sector-specific-weight-calibration/
- Implementation source: https://github.com/IslamBaraka90/Fintech-Algorithms-Library/blob/main/src/fundamental-analysis-and-valuation/sector-specific-equity-scoring/sector-specific-weight-calibration/impl.ts
- Package on npm: https://www.npmjs.com/package/fintech-algorithms
- Domain index for agents: https://docs.thefintechbuilder.com/fundamental-analysis-and-valuation/llms.txt
