HKUDS/Vibe-Trading · error · ValueError

two valuations share the date {earlier[0]}; a single day can

Error message

two valuations share the date {earlier[0]}; a single day can carry only one mark

What it means

This error is raised by _normalize_valuations when two (or more) portfolio valuations in the input resolve to the same calendar date. A single day can carry only one mark because return calculations need an unambiguous ordering of valuations over time; duplicate dates make the interval between them zero-length and the period return undefined.

Source

Thrown at agent/src/quantlib/performance.py:345

    for raw_date, raw_value in raw_items:
        when = normalize_date(raw_date, field_name="valuation date")
        try:
            value = float(raw_value)
        except (TypeError, ValueError) as exc:
            raise ValueError(
                f"valuation on {when} must be numeric, got {raw_value!r}"
            ) from exc
        if not math.isfinite(value):
            raise ValueError(
                f"valuation on {when} must be finite, got {raw_value!r}; a "
                "missing mark must be fixed at the source, not carried as NaN"
            )
        resolved.append((when, value))

    resolved.sort(key=lambda item: item[0])
    for earlier, later in zip(resolved, resolved[1:], strict=False):
        if earlier[0] == later[0]:
            raise ValueError(
                f"two valuations share the date {earlier[0]}; a single day can "
                "carry only one mark"
            )
    return tuple(resolved)


def external_flows(
    flows: CashFlowSeries | Iterable[CashFlow] | None,
    *,
    external_kinds: Iterable[str] | None = None,
    internal_kinds: Iterable[str] | None = None,
) -> tuple[tuple[date, float], ...]:
    """Select the boundary-crossing flows and restate them portfolio-side.

    The returned amounts are the **negation** of ``CashFlow.amount``: the input
    is holder-perspective (a contribution is cash leaving the client, hence
    negative), the output is portfolio-perspective (a contribution is cash
    arriving, hence positive). This is the only place in the module where that

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Deduplicate valuations by date before calling the API (keep the last mark per day, e.g. dict(date -> value)).
  2. If two marks on one day are genuinely different (e.g. pre- and post-contribution), decide which one represents the official end-of-day value and drop the other.
  3. If you need to represent a flow on a valuation day, pass it as a flow, not as a second valuation.
  4. Check the input pipeline for duplicate rows or datetime-to-date coercion producing collisions.

Example fix

# before
time_weighted_return(valuations=[
    (date(2024,1,15), 100_000.0),
    (date(2024,1,15), 105_000.0),  # duplicate date -> ValueError
    (date(2024,2,15), 110_000.0),
], flows=[])

# after
merged = {d: v for d, v in [
    (date(2024,1,15), 100_000.0),
    (date(2024,1,15), 105_000.0),  # last wins
    (date(2024,2,15), 110_000.0),
]}
time_weighted_return(valuations=sorted(merged.items()), flows=[])
Defensive patterns

Strategy: validation

Validate before calling

def dedupe_valuations(valuations):
    merged = {}
    for when, value in valuations:
        d = when if isinstance(when, date) else when.date() if hasattr(when, 'date') else parse(when)
        merged[d] = value  # last mark per day wins
    return sorted(merged.items())

Type guard

def has_unique_valuation_dates(valuations) -> bool:
    ds = [normalize_date(v[0]) for v in valuations]
    return len(set(ds)) == len(ds)

Try / catch

try:
    twr = time_weighted_return(valuations, flows)
except ValueError as e:
    if 'share the date' in str(e):
        valuations = dedupe_valuations(valuations)
        twr = time_weighted_return(valuations, flows)
    else:
        raise

Prevention

When it happens

Trigger: Calling time_weighted_return, modified_dietz_return, or money_weighted_return with a valuations list containing two entries whose dates normalize to the same day, e.g. two CashFlow/valuation records on 2024-01-15 (same date given as date vs datetime vs ISO string), or the same date supplied twice from a CSV import.

Common situations: Intraday marks imported as datetimes that collapse to the same date; duplicate rows in a valuation feed; a valuation recorded at midnight boundary; merging two data sources that both contain the period-end mark.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/8cbf1b28a1d4eb6c. Report an issue: GitHub.