Errors¶
errors ¶
The exception hierarchy.
A library must never kill the host process. Six places used to raise
SystemExit — the data loaders, the panel builder, the alignment step — which
is fine for a script and unusable from anything else: an import of nullres
could terminate a notebook, a web request, or another library's test run,
with no chance to catch it.
The smell was already visible from inside. robustness.cross_symbol has to
survive a symbol whose data is missing, so it carried
except (SystemExit, ValueError) — catching the interpreter's own shutdown
signal to keep a loop going. That is what a missing exception type looks like.
Three failure modes are worth distinguishing, because a caller responds differently to each:
ConfigError You asked for something that does not exist or does
not parse. Nothing will fix it but editing the
config or the call.
DataUnavailableError The data is not here. It might be a symbol that
never listed, a month the archive does not publish,
or a cache that has not been filled yet. Fetching
more may fix it.
InsufficientDataError The data is here and there is not enough of it to
measure anything. Widen the date range, shorten the
windows, or lower `min_train`.
ConfigError and InsufficientDataError also subclass ValueError, because
that is what they were before this module existed and callers that already
catch ValueError should keep working. New code should catch NullresError,
or one of the three.
Each type carries the exit code the CLI returns for it, so the mapping lives
with the error rather than in a table in cli.py that drifts from it.
NullresError ¶
Bases: Exception
Base for every error this package raises deliberately.
Catching this catches everything nullres considers a handled failure. It
does not catch bugs — an index mismatch between a position series and its
bars stays a bare ValueError, because there is no configuration that
causes it and no caller that should recover from it.
ConfigError ¶
Bases: NullresError, ValueError
A config value, override, or name that cannot be honoured.
Unknown TOML keys, unknown strategies, unknown intervals, malformed
--set overrides. The distinguishing property is that no amount of data
or compute changes the answer.
DataUnavailableError ¶
Bases: NullresError
Required market data could not be obtained.
Deliberately NOT a ValueError: nothing was wrong with what you asked
for, the bytes are simply not there. That distinction is what lets
cross_symbol record "no data for this symbol" as a per-symbol note and
carry on, rather than treating it as a bad request.
InsufficientDataError ¶
Bases: NullresError, ValueError
There is data, but not enough of it to measure anything.
Raised by the splitters when the folds would be too small to mean
anything, and by pipeline.prepare when alignment leaves too few bars.
Reporting a Sharpe off eighty bars would be worse than refusing.