RC2_PARAM_DEFAULT
Param '<name>'requires a default value.
What it means
Every Param() needs a default as its first positional argument. The default is not a convenience — it is what the strategy runs with when nobody has tuned it, and it is where the Param’s type comes from: 20 makes an int, 2.0 a float, False a bool. Without it there is no value to backtest with and no type to build the optimizer dimension from.
Why it happens
A Param declared as a placeholder, with the intention of filling it in from the UI later:
class Placeholder(Strategy): period = Param() trade = Symbol() sizing = FixedCapital()
def execute(self): sma = SMA(self.period, on=self.trade) if sma.value > 0 and self.trade.is_flat: self.buy(self.trade)Or bounds given without a value — min/max are keywords, and none of them is the default:
class BoundsOnly(Strategy): period = Param(min=2, max=200) trade = Symbol() sizing = FixedCapital()
def execute(self): sma = SMA(self.period, on=self.trade) if sma.value > 0 and self.trade.is_flat: self.buy(self.trade)How to fix it
Lead with the value you would run today.
class WithDefault(Strategy): period = Param(20, min=2, max=200) trade = Symbol() sizing = FixedCapital()
def execute(self): sma = SMA(self.period, on=self.trade) if sma.value > 0 and self.trade.is_flat: self.buy(self.trade)If the value is not meant to be tunable at all, it doesn’t need to be a Param — a plain literal in the class body (threshold = 35) is a constant, and stays out of the optimizer grid.
Related
Param()RC2_PARAM_UNKNOWN_KWARG— a default is present, but a keyword beside it isn’t one of the five.RC2_CLASS_BODY— what the class body accepts besidesParam().