InitialRiskPositionSizer#

class qf_lib.backtesting.position_sizer.initial_risk_position_sizer.InitialRiskPositionSizer(broker: Broker, data_provider: DataProvider, order_factory: OrderFactory, signals_register: SignalsRegister, initial_risk: float, max_target_percentage: float = None, tolerance_percentage: float = 0.0)[source]#

Bases: PositionSizer

Sizes positions from risk per trade and the signal’s fraction_at_risk (typically ATR-based).

For each signal:

target_percentage = (initial_risk / fraction_at_risk) * suggested_exposure.value

Optionally capped by max_target_percentage.

Parameters:
  • broker (Broker)

  • data_provider (DataProvider)

  • order_factory (OrderFactory)

  • signals_register (SignalsRegister)

  • initial_risk (float) – Maximum portfolio fraction you are willing to lose if the stop is hit on one trade. For example 0.02 means 2% of portfolio at risk per position.

  • max_target_percentage (float, optional) – Upper cap on absolute target weight. None disables the cap.

  • tolerance_percentage (float) – Passed to OrderFactory.target_percent_orders.

Examples

size_signals sizes from initial_risk / fraction_at_risk (then applies exposure sign). With portfolio 100,000, price 100, initial_risk=0.05, and fraction_at_risk=0.02:

>>> sizer = InitialRiskPositionSizer(
...     broker, data_provider, order_factory, BacktestSignalsRegister(), initial_risk=0.05)
>>> signal = Signal(ticker, Exposure.LONG, fraction_at_risk=0.02, last_available_price=100.0, creation_time=now)
>>> orders = sizer.size_signals([signal], use_stop_losses=False)
>>> orders[0].quantity
2500.0

The same signal with max_target_percentage=1.0 caps leverage at 100% of portfolio (1,000 shares):

>>> capped_sizer = InitialRiskPositionSizer(
...     broker, data_provider, order_factory, BacktestSignalsRegister(),
...     initial_risk=0.05, max_target_percentage=1.0)
>>> capped_sizer.size_signals([signal], use_stop_losses=False)[0].quantity
1000.0