HKUDS/Vibe-Trading · error · ValuationError
comps.run_comps: mixed eps_basis across the comp set {sorted
Error message
comps.run_comps: mixed eps_basis across the comp set {sorted(all_bases)} -- every peer and the target must declare the same EPS basis, or the P/E distribution mixes GAAP and adjusted earnings What it means
Every peer and the target must declare the same eps_basis; mixing basic and diluted EPS across the comp set would make the P/E distribution compare GAAP and adjusted figures inconsistently, so run_comps refuses the mixture.
Source
Thrown at agent/src/quantlib/valuation/comps.py:1182
MissingInputError: (propagated from `calendarise_metric`) if any
peer's or the target's fiscal-period data lacks a field
`calendarisation_policy` needs.
"""
if calendarisation_policy not in CALENDARISATION_POLICIES:
raise ValuationError(
f"comps.run_comps: unknown calendarisation_policy {calendarisation_policy!r}, "
f"must be one of {CALENDARISATION_POLICIES}"
)
if len(peers) == 0:
raise MissingInputError(("peers",), "comps.run_comps")
names = [peer.name for peer in peers]
if len(set(names)) != len(names):
raise ValuationError(f"comps.run_comps: duplicate peer names in {names}")
all_bases = {peer.eps_basis for peer in peers} | {target.eps_basis}
if len(all_bases) > 1:
raise ValuationError(
"comps.run_comps: mixed eps_basis across the comp set "
f"{sorted(all_bases)} -- every peer and the target must declare the "
"same EPS basis, or the P/E distribution mixes GAAP and adjusted "
"earnings"
)
peer_multiples = tuple(peer_multiple_set(peer, calendarisation_policy) for peer in peers)
distributions = {
name: multiple_distribution(name, peer_multiples) for name in MULTIPLE_NAMES
}
calendarised_target = {
"ebitda": calendarise_metric(
target.ebitda, calendarisation_policy, metric_name="ebitda", company_name=target.name
),
"ebit": calendarise_metric(
target.ebit, calendarisation_policy, metric_name="ebit", company_name=target.name
),View on GitHub (pinned to 80ffdda44c)
Solutions
- Standardize: pick one basis (usually diluted) and rebuild all peers/target with it explicitly.
- If a vendor only has basic EPS, convert or document the choice rather than mixing.
- Assert {p.eps_basis for p in peers} | {target.eps_basis} has exactly one element before run_comps.
Example fix
# before
peers = [CompPeer('A','diluted',...), CompPeer('B','basic',...)]
# after
from dataclasses import replace
peers = [replace(p, eps_basis='diluted') for p in peers] # after verifying data supports it Defensive patterns
Strategy: validation
Validate before calling
bases = {p.eps_basis for p in peers} | {target.eps_basis}
if len(bases) > 1:
raise ValueError(f'mixed eps_basis: {sorted(bases)}') Type guard
def uniform_eps_basis(target, peers):
return len({p.eps_basis for p in peers} | {target.eps_basis}) == 1 Try / catch
except ValuationError as e:
if 'mixed eps_basis' in str(e):
peers = [replace(p, eps_basis='diluted') for p in peers] Prevention
- Set eps_basis explicitly at every construction site
- Standardize on one basis in the ingestion contract
When it happens
Trigger: One peer dataclass built with eps_basis='basic' while target/others use 'diluted' — often one row built by different code or a defaulted constructor call.
Common situations: Heterogeneous data ingestion where one vendor reports basic EPS only; a peer added later with a default basis; copy-pasted fixture code diverging from the production path.
Related errors
- {model}: {name} must be a finite number, got {val!r}
- {model}: eps_basis must be one of {EPS_BASES}, got {eps_basi
- peers
- comps.run_comps: duplicate peer names in {names}
- latest valuation on {marks[-1].date} is {value!r}; a residua
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/118937db58c5401e.
Report an issue: GitHub.