microsoft/qlib · error · NotImplementedError
Implement reward calculation recipe in `reward()`.
Error message
Implement reward calculation recipe in `reward()`.
What it means
NotImplementedError from the base `Reward` class (qlib/rl/reward.py:31). `Reward.__call__` is `@final` and delegates to `reward(simulator_state)`; the base implementation intentionally raises so that subclasses must supply their own reward recipe.
Source
Thrown at qlib/rl/reward.py:31
SimulatorState = TypeVar("SimulatorState")
class Reward(Generic[SimulatorState]):
"""
Reward calculation component that takes a single argument: state of simulator. Returns a real number: reward.
Subclass should implement ``reward(simulator_state)`` to implement their own reward calculation recipe.
"""
env: Optional[EnvWrapper] = None
@final
def __call__(self, simulator_state: SimulatorState) -> float:
return self.reward(simulator_state)
def reward(self, simulator_state: SimulatorState) -> float:
"""Implement this method for your own reward."""
raise NotImplementedError("Implement reward calculation recipe in `reward()`.")
def log(self, name: str, value: Any) -> None:
assert self.env is not None
self.env.logger.add_scalar(name, value)
class RewardCombination(Reward):
"""Combination of multiple reward."""
def __init__(self, rewards: Dict[str, Tuple[Reward, float]]) -> None:
self.rewards = rewards
def reward(self, simulator_state: Any) -> float:
total_reward = 0.0
for name, (reward_fn, weight) in self.rewards.items():
rew = reward_fn(simulator_state) * weight
total_reward += rew
self.log(name, rew)View on GitHub (pinned to 79633dd950)
Solutions
- Subclass `Reward` and implement `def reward(self, simulator_state) -> float` with your calculation.
- For combining existing rewards, use `RewardCombination({name: (reward, weight)})` instead of writing a new class.
- Make sure the override signature matches exactly (`reward(self, simulator_state: SimulatorState) -> float`).
Example fix
// before
class MyReward(Reward):
pass # forgot to implement -> NotImplementedError at first env step
// after
class MyReward(Reward):
def reward(self, simulator_state: SimulatorState) -> float:
return float(simulator_state.position.abs().max()) Defensive patterns
Strategy: validation
Validate before calling
from qlib.rl.reward import Reward
def reward_implemented(reward_cls) -> bool:
return reward_cls.reward is not Reward.reward Type guard
def is_concrete_reward(r) -> bool:
from qlib.rl.reward import Reward
return isinstance(r, Reward) and type(r).reward is not Reward.reward Try / catch
try:
value = reward_fn(simulator_state)
except NotImplementedError as e:
raise TypeError(f"{type(reward_fn).__name__} must implement reward()") from e Prevention
- Assert `type(my_reward).reward is not Reward.reward` in vessel setup.
- Prefer RewardCombination over re-implementing composite rewards.
- Run a one-step rollout in CI to catch missing reward overrides immediately.
When it happens
Trigger: Instantiating `Reward()` directly, or subclassing `Reward` without overriding `reward()`, and then running a trainer/vessel that invokes the reward during rollout (the env wrapper calls it every step).
Common situations: Copy-pasting an existing reward class and renaming it while forgetting to rename/keep the `reward` method; using a reward stub during prototyping and then running full training; method signature typo (e.g. `rewards()` or wrong arg count still counts as missing override).
Related errors
- Seed iterator for training is not available.
- Seed iterator for validation is not available.
- Seed iterator for testing is not available.
- Render is not implemented in EnvWrapper.
- nfs-common is not found, please install it by execute: sudo
AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15).
Data as JSON: /api/errors/e1ac8c0e75cce6b5.
Report an issue: GitHub.