HKUDS/Vibe-Trading · error · MissingExchangeRateError

no {base}/{self.quote_currency} rate on or before {day}{boun

Error message

no {base}/{self.quote_currency} rate on or before {day}{bound}

What it means

Even with allow_stale=True, get_rate needs at least one quote for the base currency on or before the requested day, and within max_staleness_days if provided. No candidate exists -> MissingExchangeRateError, with the staleness bound included in the message when relevant.

Source

Thrown at agent/src/entities/cashflow.py:677

                "never applied silently"
            )

        candidates = [
            entry
            for (entry_base, entry_date), entry in self.rates.items()
            if entry_base == base and entry_date <= day
        ]
        if max_staleness_days is not None:
            candidates = [
                entry
                for entry in candidates
                if (day - entry.date).days <= max_staleness_days
            ]
        if not candidates:
            bound = (
                f" within {max_staleness_days} days" if max_staleness_days is not None else ""
            )
            raise MissingExchangeRateError(
                f"no {base}/{self.quote_currency} rate on or before {day}{bound}"
            )
        best = max(candidates, key=lambda entry: entry.date)
        return best, True


def translate_cashflows(
    flows: CashFlowSeries | Iterable[CashFlow],
    rate_table: FxRateTable,
    *,
    allow_stale_rates: bool = False,
    max_staleness_days: int | None = None,
) -> CashFlowSeries:
    """Convert flows in one or more currencies into ``rate_table``'s currency.

    Each flow is converted using the FX rate quoted on **that flow's own
    settlement date** -- never a single series-level or period-end rate.
    Applying one end-of-period rate to every flow is the most common

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Source earlier rates covering the requested period and rebuild the table
  2. Increase max_staleness_days to a tolerance appropriate for the currency's quote frequency
  3. Remove or relax the bound (pass None) if some staleness is acceptable for your use case

Example fix

# before
rate, stale = table.get_rate('EUR', d, allow_stale=True, max_staleness_days=3)
# after
rate, stale = table.get_rate('EUR', d, allow_stale=True, max_staleness_days=10)
Defensive patterns

Strategy: fallback

Validate before calling

earliest = min(e.date for k, e in table.rates.items() if k[0] == base)
if day < earliest:
    raise ValueError('need earlier FX history')

Try / catch

from agent.src.entities.cashflow import MissingExchangeRateError
try:
    rate, stale = table.get_rate(base, day, allow_stale=True, max_staleness_days=N)
except MissingExchangeRateError:
    rate = fetch_rate_from_api(base, day)  # backfill then rebuild table

Prevention

When it happens

Trigger: get_rate('EUR', date(2024,1,31), allow_stale=True) when the table's earliest EUR quote is 2024-02-05; or a candidate exists but is 10 days old with max_staleness_days=7.

Common situations: Rates feed starting later than the flow history (backfilling old periods); a thinly quoted currency where gaps exceed your staleness tolerance; max_staleness_days set too tight for weekly-quoted currencies.

Related errors


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