# Normalized Advance/Decline Line: Cumulative (A-D)/(A+D) Breadth

> **Selected variant:** daily mover-normalized balance `(A-D)/(A+D)`, accumulated as `seed + scale × ratio` with one immutable seed and scale.

## Executive summary

This package implements one precisely named breadth series. For session (t),
let (A_t) be advancing issues and (D_t) declining issues. The daily term is

\[
p_t=\frac{A_t-D_t}{A_t+D_t}, \qquad A_t+D_t>0.
\]

With immutable seed (s) and positive display scale (k), the line is

\[
N_0=s, \qquad N_t=N_{t-1}+k p_t.
\]

The canonical package uses (s=0) and (k=100). The ratio is bounded in
([-1,1]); the cumulative line is not bounded. The implementation publishes a
line only when every expected session is causally resolved. Missing sessions,
zero movers, incomplete classification, revision conflicts, cancellations, or
methodology breaks return a diagnostic state and no plausible cumulative path.

This is not the raw cumulative A/D Line, the A/D ratio (A/D), an
unchanged-inclusive or full-universe normalization, or the Ratio-Adjusted
McClellan Oscillator.

## Learning contract

After this topic, a reader can:

- calculate daily mover-normalized breadth and its cumulative path;
- explain seed, scale, denominator, zero-denominator, and rounding behavior;
- distinguish the selected formula from nearby breadth variants;
- construct a point-in-time evidence contract for membership and classification;
- resolve corrections without future leakage and recompute the dependent suffix;
- refuse a result when the evidence is incomplete, ambiguous, or incompatible.

Prerequisites are **Net Advances** and **Cumulative Advance/Decline Line**.

## The selected variant and its neighbors

| Name | Definition | Same as this topic? | Important difference |
|---|---|---|---|
| Daily mover-normalized balance | ((A-D)/(A+D)) | Input term | Bounded directional balance among movers |
| Normalized A/D Line | (s+\sum k(A-D)/(A+D)) | Yes | This package’s recursive series |
| Raw cumulative A/D Line | (s+\sum(A-D)) | No | Absolute issue counts; population scale remains |
| A/D ratio | (A/D) | No | Asymmetric; (D=0,A>0) is undefined/infinite by policy |
| Unchanged-inclusive balance | ((A-D)/(A+D+U)) | No | Unchanged issues dilute the step |
| Full-universe balance | ((A-D)/N) | No | Excluded or missing classifications act differently |
| Ratio-Adjusted McClellan Oscillator | EMA spread of a scaled normalized input | No | Smooths an input; does not directly cumulate it |

The label “normalized A/D line” is not sufficient by itself. Persist the exact
formula, denominator policy, seed, scale, and methodology identifier.

## Boundary behavior

- **(D=0,A>0):** this topic’s denominator is (A+D=A), so (p=+1). This is
  different from the A/D ratio (A/D), whose denominator is zero.
- **(A=0,D>0):** (p=-1).
- **(A=D>0):** movers exist and (p=0). This is a resolved active balance.
- **(A+D=0):** (0/0) is undefined. The strict algorithm returns
  `incomplete: zero_movers` and publishes no path. It does not create a flat day.
- **Empty universe:** `incomplete: empty_universe`.
- **Nonzero unclassified count:** `incomplete: unclassified_issues`.
- **Coverage below the declared floor:** `incomplete: low_coverage`.

## Causal input data contract

Each record is a versioned publication event. Records arrive in non-decreasing
`available_at` order and are never silently sorted. Calendar replay uses the
declared `session_sequence` after revisions are resolved.

| Field | Contract |
|---|---|
| `event_id` | Stable event identity for one session |
| `revision`, `supersedes_revision` | Contiguous chain starting at revision 1 |
| `event_type` | `upsert` or `cancel` |
| `session_sequence`, `session_date` | Declared calendar order and date |
| `effective_at` | When the session evidence is economically effective |
| `available_at` | Earliest time this version may enter a causal result |
| `venue_id`, `universe_id`, `calendar_id`, `session` | Stable series identity |
| `comparison_basis` | Prior-value comparison rule |
| `corporate_action_policy` | Point-in-time listing continuity rule |
| `stable_id_scheme` | Stable listing/security identifier policy |
| `methodology_id` | Versioned algorithm and data-methodology identity |
| `denominator_policy` | Must be `movers` |
| `seed`, `scale` | Must match immutable invocation values |
| `roster_complete`, `classification_complete` | Evidence completeness assertions |
| `advances`, `declines`, `unchanged`, `excluded`, `unclassified` | Mutually exclusive non-negative safe integers |
| `universe_size` | Exact sum of the five classification counts |

The result is evaluated at a caller-supplied UTC cutoff. A record with
`available_at` later than that cutoff is counted as ignored future evidence and
is not otherwise interpreted. Therefore a malformed future correction cannot
alter or invalidate an earlier result.

### Corporate actions and stable identity

Splits do not ordinarily change a direction classification when comparable
prices are adjusted consistently, but symbol changes, listings, delistings,
mergers, spin-offs, and stale prior prices can change eligibility. The aggregate
counts are acceptable only after a point-in-time roster process has resolved
those events using stable identifiers and the declared comparison basis. The
algorithm does not invent that lineage from counts.

## Evidence states

| State | Meaning | Public cumulative points |
|---|---|---:|
| `resolved` | One causal, compatible, complete head for every expected session | Yes |
| `incomplete` | Missing/cancelled session, zero movers, incomplete roster/classification, partition failure, low coverage | No |
| `ambiguous` | Conflicting revision heads, revision gap, or multiple events for one session | No |
| `unsupported` | Series/methodology break, seed/scale/denominator drift, calendar conflict, or overflow | No |

Suppressing points is deliberate. A partial prefix shown as a normal line would
look authoritative even though its terminal value is not publishable.

## Resolution and calculation algorithm

1. Parse the cutoff and immutable parameters.
2. Parse only `available_at` for each event; ignore future events immediately.
3. Validate visible records and their causal availability order.
4. Resolve each event’s contiguous revision chain to one visible head.
5. Require one head for every expected calendar sequence.
6. reject cancellations, incomplete partitions, zero movers, unclassified
   issues, or coverage below the floor.
7. Require stable series identity, methodology, denominator, seed, and scale.
8. Replay sessions in declared calendar sequence.
9. Compute the ratio and contribution at full runtime precision.
10. Reject non-finite or configured overflow values; round only for display.

```text
visible = records where available_at <= cutoff
heads = resolve_contiguous_revision_chains(visible)
if evidence_state(heads) != resolved:
    return state, reasons, points=[]

line = seed
for sequence in expected_calendar_sequence:
    row = unique_head(sequence)
    movers = row.advances + row.declines
    ratio = (row.advances - row.declines) / movers
    contribution = scale * ratio
    line = checked_add(line, contribution)
    emit row, ratio, contribution, line, provenance
```

## Synthetic worked example

The fixture contains 20 synthetic sessions. The first five, with seed 0 and
scale 100, are:

| Seq. | A | D | Movers | Daily ratio | Scaled step | Line |
|---:|---:|---:|---:|---:|---:|---:|
| 1 | 60 | 30 | 90 | 0.333333 | 33.3333 | 33.3333 |
| 2 | 35 | 55 | 90 | -0.222222 | -22.2222 | 11.1111 |
| 3 | 40 | 40 | 80 | 0 | 0 | 11.1111 |
| 4 | 70 | 20 | 90 | 0.555556 | 55.5556 | 66.6667 |
| 5 | 25 | 65 | 90 | -0.444444 | -44.4444 | 22.2222 |

Sequence 3 is flat because it is an observed active balance, not because the
denominator is missing. The complete 20-session path ends at 77.7778 after
display rounding.

### Scale invariance is synthetic, not historical

For (70/30) and (700/300), the raw net values are +40 and +400, while both
normalized ratios equal +0.4. Multiplying both counts by the same positive
constant leaves the ratio unchanged. This demonstrates arithmetic only; it
does not assert that the two observations came from comparable real markets.

## Bounded Nasdaq Trader observation

Nasdaq Trader’s official Daily Market Files page describes annual downloadable
files of Nasdaq market statistics. Its field-definition page lists Nasdaq
Advances, Declines, and Unchanged among the year-to-date fields. On 2026-07-23,
the official `daily2026.csv` returned these provider observations:

| Date | Advances | Declines | Unchanged | Author-derived ratio | Author-derived zero-seed, scale-100 path |
|---|---:|---:|---:|---:|---:|
| 2026-03-02 | 2,443 | 2,431 | 228 | 0.002462 | 0.2462 |
| 2026-03-03 | 1,359 | 3,542 | 190 | -0.445419 | -44.2957 |
| 2026-03-04 | 3,368 | 1,509 | 224 | 0.381177 | -6.1780 |
| 2026-03-05 | 1,430 | 3,454 | 195 | -0.414414 | -47.6195 |
| 2026-03-06 | 1,461 | 3,384 | 238 | -0.396904 | -87.3099 |

The three counts are provider observations. Every ratio and path value in the
last two columns is author-derived arithmetic. This table is an explanatory
observation, not strict `resolved` output: the free CSV does not provide the
stable roster/exclusion partition, publication timestamps, revision lineage,
or enough evidence to prove constant universes and causal availability. No
relationship to index return and no predictive claim is inferred.

## Revisions, suffixes, and series breaks

A visible revision replaces its earlier version only through a contiguous
chain. Recompute the revised session and every later point because each suffix
depends on the changed prefix. A cancellation makes the history incomplete. A
same-revision conflict makes it ambiguous. A future revision is ignored at an
earlier cutoff.

Changing the seed translates the whole line; changing scale multiplies all
steps. Either change creates a different series and cannot be spliced into the
old history. Denominator, universe, calendar, comparison basis, corporate-action
policy, stable-ID scheme, or methodology changes are also explicit series
breaks. Start a new segment rather than drawing a continuous line.

## Precision and overflow

Counts must be safe integers in both implementations. Ratios and cumulative
values are retained at runtime floating-point precision. Display rounding never
feeds back into the recurrence. The caller may set `max_abs_line`; exceeding it
returns `unsupported: line_overflow` with no points. For very long audited
histories, a decimal or rational implementation may be preferable, but it must
retain the same state and evidence contract.

## Implementation and validation

- [Python implementation](./implementations/python/normalized_ad_line.py)
- [TypeScript implementation](./implementations/typescript/normalizedAdLine.ts)
- [Shared fixture](./datasets/normalized-ad-line-fixtures.json)
- [Python tests](./tests/test_normalized_ad_line.py)
- [TypeScript tests](./tests/normalizedAdLine.test.ts)

Tests cover formula parity, active balance, zero movers, missing sessions,
coverage, unclassified issues, cancellations, visible and future revisions,
conflicts, causal cutoff isolation, suffix recomputation, series breaks,
immutability, no silent sorting, invalid inputs, and overflow.

## Visual explanations

- [Causal calculation flow](./visuals/mermaid/calculation-flow.md)
- [Scale-invariance comparison](./visuals/static/scale-invariance.svg)
- [Resolved path and publication gate](./visuals/static/normalized-line-path.svg)
- [Interactive guided lab](./visuals/animated/normalized-ad-line-playground.html)
- [Visual plan](./visuals/VISUAL-PLAN.md)

## Limitations and safe interpretation

Normalization reduces sensitivity to mover population size. It does not repair
survivorship bias, historical membership, stale comparisons, missing records,
low coverage, or revision lineage. The cumulative level is seed- and
scale-dependent. A rising or falling line describes accumulated breadth under
the selected contract; it does not predict price, establish causality, or prove
a profitable trading rule.

## Related topics

- **Net Advances** supplies (A-D).
- **Advance/Decline Ratio** uses (A/D), not this bounded balance.
- **Cumulative Advance/Decline Line** accumulates raw counts.
- **Absolute Breadth Index** discards direction.
- **Ratio-Adjusted McClellan Oscillator** smooths normalized breadth rather than
  accumulating it directly.

See [REFERENCES.md](./REFERENCES.md) for evidence roles and limitations.
