The anchored family

Start from consensus and move it by a fixed, versioned rule

The anchored family treats consensus as the anchor and the model as information about where consensus is wrong. Nothing is learned per company: one shipped coefficient set moves every subject by the same rule, so a published number is always the consensus plus terms that can be read off.

Inputs and outputs

flowchart TB
    subgraph IN["Point-in-time inputs"]
        direction LR
        M["Model forecast m<br>latest before as_of"]
        C["Consensus c<br>latest before as_of"]
        C0["Earlier consensus c₋₃₀<br>one lookback window back"]
    end

    subgraph SG["Two signals"]
        direction LR
        G["Gap Δ<br>(m − c) / |c|<br>where consensus is wrong"]
        R["Revision r<br>c / c₋₃₀ − 1<br>where analysts are heading"]
    end

    Q["Eligibility gate<br>missing input, stale model,<br>stale consensus, gap too wide"]
    S["Versioned coefficient set<br>a, b_Δ, b_r, age limits,<br>maximum gap, fitted_through"]
    F["Frozen linear rule<br>ŝ = a + b_Δ Δ + b_r r<br>same for every company"]

    E["eligible<br>eligibility_reason<br>refusal, never a fallback"]
    X["expected_surprise<br>ŝ, actual vs consensus"]
    L["anchored_level<br>ŷ = c × (1 + ŝ)"]
    K["contribution_*<br>a, b_Δ Δ and b_r r,<br>summing to ŝ"]
    V["parameters_version<br>audit trail"]

    M --> G
    C --> G
    C --> R
    C0 --> R
    G --> Q
    R --> Q
    S -.-> Q
    S -.-> F
    Q -->|refused| E
    Q -->|publishable| F
    F --> X & L & K & V

    classDef input fill:#eef3fb,stroke:#4c72b0,color:#1f2d3d
    classDef signal fill:#f6f6f6,stroke:#8c8c8c,color:#222222
    classDef rule fill:#fff4e8,stroke:#dd8452,color:#222222
    classDef output fill:#edf6ef,stroke:#55a868,color:#1f3d27
    class M,C,C0 input
    class G,R,Q signal
    class F,S rule
    class X,L,K,E,V output
    style IN fill:#f8fafd,stroke:#c7d4ea
    style SG fill:#fafafa,stroke:#d0d0d0
Figure 1: What the anchored estimate reads, the two signals it forms, the gate it passes, and what it returns.
  • Consensus is the anchor. The published level is consensus moved by terms that can each be read off, so a customer can see why it differs.
  • Three reads of the panel, nothing more. The model now, consensus now and consensus one lookback window earlier, each read strictly before the reading moment. Actual history is not needed at publication; it was used once, when the coefficient set was fitted.
  • Nothing is learned per company. One frozen set moves every subject by the same rule. A retrained set is a new version, and parameters_version names it on every row.
  • The gate runs before the rule. It checks the inputs’ presence and age and the size of the gap. Missing or stale inputs, or a gap wide enough to look like a data break, return a reason instead of a number.
  • Compared with the Bayesian posterior: that method learns per-company weights from actual history and returns an interval; this one applies a fixed, externally fitted rule and returns a consensus-relative surprise.

Consensus gap

ConsensusGap measures the gap \(\Delta\): how far the model’s forecast \(m\) sits from consensus \(c\), as a fraction of consensus. Symbols follow the notation page.

\[ \Delta=\frac{m-c}{\lvert c\rvert}. \]

  • Nothing to fit: fit reads nothing and returns the same configuration.
  • Missing values: The gap is missing where either side is missing, or where consensus is zero and the ratio has no meaning.
  • Role: The building block of the anchored estimate, and a signal in its own right when only the comparison with consensus is needed.

Anchored estimate

AnchoredEstimate publishes the expected surprise \(\hat s\), the fraction by which the reported actual \(y\) is expected to differ from consensus, and the anchored level \(\hat y\) it implies. The revision \(r\) is the relative change in consensus since \(c_{-30}\), the consensus read over the lookback window earlier:

\[ \hat s=a+b_\Delta\,\Delta+b_r\,r,\qquad r=\frac{c}{c_{-30}}-1,\qquad \hat y=c\,(1+\hat s). \]

  • Customary beat, \(a\): The surprise when the model agrees with consensus, \(\Delta=0\), and consensus has not moved, \(r=0\). Companies beat consensus on average, so \(a\) is positive.
  • Gap weight, \(b_\Delta\): The fraction of the gap \(\Delta\) that carries into \(\hat s\). Both shipped sets keep it well below one.
  • Revision weight, \(b_r\): How strongly the revision \(r\) carries into \(\hat s\). A company without a prior consensus \(c_{-30}\) contributes no revision term.
  • Attribution: The three terms \(a\), \(b_\Delta\Delta\) and \(b_r r\) are published as contribution_customary_beat, contribution_gap and contribution_revision, and they sum to \(\hat s\).

Reading policy

publish_anchored is the publication boundary. It anchors the panel, measures the revision, applies the estimate and returns one row per subject.

  • Reading moment: Every value is read strictly before as_of.
  • Revision: The current and the prior consensus are read 30 days apart, and neither may be older than 60 days at its own read.
  • Training window: A reading date on or before the set’s fitted_through raises PanelError; it does not return individual refusal rows.
  • Fields: The published numbers are selectable. A feed that must not carry level fields publishes expected_surprise alone.

Eligibility

Each subject passes an ordered gate before the rule runs: missing input, a stale model, a stale consensus, or a gap too wide to be information. A refused subject keeps its row and its reason. Anchored eligibility gives the checks, the limits each coefficient set sets, and what raises instead.

Coefficient sets

Two sets ship, fitted on the same window. A retrained set is a new version, never an edit, so every published row names the set it came from in parameters_version.

Anchored parameters lists the values, limits and training dates for both sets.

Prior work records where the numbers came from.

Further reading