Contract Checks

The keeks.checks module is the contract harness for contributors, on the scikit-learn check_estimator pattern: each check runs a contributor’s implementation against the documented contract of its base class - the bets a binary strategy sizes, the weights an allocator returns, the draws a joint-return model samples - and fails with the first violation it meets, so an implementation can be verified without running a simulator.

Contract checks for strategies and joint-return models, on the check_estimator pattern.

The strategy contracts are enforced at the base classes: a concrete evaluate returning a contract-violating vector fails loudly at its own call site. A contributor implementing keeks.binary_strategies.BaseStrategy, keeks.allocation.BaseAllocationStrategy, or keeks.allocation.models.JointReturnModel has nonetheless had no way to verify an implementation against the documented contract without running a simulator. The checks here are that harness: each runs the contract’s probes and raises - ValueError naming the expectation and the received value for a contract violation, TypeError for a subject outside the check’s ABC - and passes silently when everything holds.

Examples

>>> from keeks import FixedWeights, check_allocation_strategy
>>> check_allocation_strategy(FixedWeights([0.25, 0.75]))
keeks.checks.check_allocation_strategy(strategy: BaseAllocationStrategy) → None[source]

Verify an allocator against the documented weight contract.

Runs the contract probes: evaluate at a positive bankroll returns a valid long-only weight vector (one finite weight per option, each within [0, 1], summing to no more than one within PROBABILITY_SUM_TOLERANCE); a nonpositive bankroll returns all zeros - there is nothing left to allocate - with one weight per option at every bankroll.

Parameters:

strategy (BaseAllocationStrategy) – The allocation strategy to check.

Raises:
  • TypeError – If strategy is not a keeks.allocation.BaseAllocationStrategy subclass.

  • ValueError – If any probe violates the contract.

Examples

>>> from keeks import BaseAllocationStrategy, check_allocation_strategy
>>> class _OverBudget(BaseAllocationStrategy):
...     def evaluate(self, current_bankroll):
...         return (0.6, 0.6)
>>> check_allocation_strategy(_OverBudget())
Traceback (most recent call last):
    ...
ValueError: Strategy weights must sum to no more than one; got (0.6, 0.6)
keeks.checks.check_model(model: JointReturnModel) → None[source]

Verify a joint-return model against the documented sampling contract.

Runs the contract probes: sample(n_samples, rng) returns a finite (n_samples, N) matrix of joint simple returns with N >= 1; the same generator state produces the same draws (the house reproducibility contract); every sample count carries one column per option; and moments(), when the model knows them, returns a shape (N,) mean and (N, N) covariance - None is the documented answer for a model without closed-form moments.

Parameters:

model (JointReturnModel) – The joint-return model to check.

Raises:

Examples

>>> from keeks import binary_bets_model, check_model
>>> check_model(binary_bets_model([(0.55, 2.0, 1.0), (0.30, 2.5, 1.0)]))

A model that ignores its generator breaks reproducibility:

>>> import numpy as np
>>> from keeks.allocation.models import JointReturnModel
>>> class _DriftingModel(JointReturnModel):
...     def sample(self, n_samples, rng):
...         return np.random.default_rng().uniform(size=(n_samples, 2))
>>> check_model(_DriftingModel())
Traceback (most recent call last):
    ...
ValueError: sample must be deterministic given a generator's state - the same generator state must produce the same draws (the house reproducibility contract), but two identically-seeded generators diverged
keeks.checks.check_strategy(strategy: BaseStrategy) → None[source]

Verify a binary strategy against the documented BaseStrategy contract.

Runs the contract probes: evaluate returns a single finite bankroll fraction within [0, 1] across a probability grid; a nonpositive bankroll returns exactly 0.0 - there is nothing left to stake; get_max_safe_bet stays a fraction within [0, 1] and answers 0.0 for a nonpositive bankroll; and the optional simulator hooks update_bankroll and record_settlement, when defined, are callable - the shapes the simulators resolve getattr-style.

Parameters:

strategy (BaseStrategy) – The binary strategy to check.

Raises:
  • TypeError – If strategy is not a keeks.binary_strategies.BaseStrategy subclass.

  • ValueError – If any probe violates the contract.

Examples

>>> from keeks import KellyCriterion, check_strategy
>>> check_strategy(KellyCriterion(payoff=2.0, loss=1.0, transaction_cost_rate=0.01))

A contract violation raises with the expectation and the received value:

>>> class _Reckless(KellyCriterion):
...     def evaluate(self, probability, current_bankroll):
...         return 1.5
>>> check_strategy(_Reckless(payoff=2.0, loss=1.0, transaction_cost_rate=0.01))
Traceback (most recent call last):
    ...
ValueError: evaluate(0.0, 1000.0) must return a bankroll fraction between 0 and 1, got 1.5