Summary
Position.calculate_max_profit() in src/features/position_models.py uses max(spread_width - debit, debit) to compute max profit for BULL_CALL_SPREAD and BEAR_PUT_SPREAD. The correct formula is always spread_width - debit. The max() fallback returns a wrong value when the net debit exceeds half the spread width.
Location
src/features/position_models.py, lines 238–243:
elif self.strategy_type in [StrategyType.BULL_CALL_SPREAD, StrategyType.BEAR_PUT_SPREAD]:
spread_width = abs(self.strikes[1] - self.strikes[0])
net_credit = sum(
-qty * price for qty, price in zip(self.quantities, self.entry_prices)
)
return max(spread_width * abs(self.quantities[0]) - abs(net_credit), abs(net_credit))
Why this is wrong
For a bull call spread (debit spread), max profit is always spread_width - net_debit. Example:
- Spread width: $5.00 (500 cents), net debit paid: $4.00 (400 cents)
- Correct max profit: $1.00 (100 cents)
- Current formula:
max(500 - 400, 400) = max(100, 400) = 400 cents (wrong by 4x)
Whenever the net debit is larger than half the spread width, the formula returns the net debit itself as max profit, which is the max loss of the position — the exact opposite of what it should return.
For well-priced spreads (debit < 50% of width) the formula coincidentally returns the right answer, which is why this hasn't been caught.
Secondary observation
The spread_width variable on line 280 in the calculate_max_loss() branch for BULL_CALL_SPREAD/BEAR_PUT_SPREAD is computed but never used. Max loss for a debit spread is correctly abs(net_debit), but the dead spread_width assignment suggests this code was written with the wrong formula in mind and then partially corrected.
Correct fix
elif self.strategy_type in [StrategyType.BULL_CALL_SPREAD, StrategyType.BEAR_PUT_SPREAD]:
spread_width = abs(self.strikes[1] - self.strikes[0]) * abs(self.quantities[0])
net_debit = abs(sum(
qty * price for qty, price in zip(self.quantities, self.entry_prices)
))
return spread_width - net_debit
Summary
Position.calculate_max_profit()insrc/features/position_models.pyusesmax(spread_width - debit, debit)to compute max profit forBULL_CALL_SPREADandBEAR_PUT_SPREAD. The correct formula is alwaysspread_width - debit. Themax()fallback returns a wrong value when the net debit exceeds half the spread width.Location
src/features/position_models.py, lines 238–243:Why this is wrong
For a bull call spread (debit spread), max profit is always
spread_width - net_debit. Example:max(500 - 400, 400)=max(100, 400)= 400 cents (wrong by 4x)Whenever the net debit is larger than half the spread width, the formula returns the net debit itself as max profit, which is the max loss of the position — the exact opposite of what it should return.
For well-priced spreads (debit < 50% of width) the formula coincidentally returns the right answer, which is why this hasn't been caught.
Secondary observation
The
spread_widthvariable on line 280 in thecalculate_max_loss()branch forBULL_CALL_SPREAD/BEAR_PUT_SPREADis computed but never used. Max loss for a debit spread is correctlyabs(net_debit), but the deadspread_widthassignment suggests this code was written with the wrong formula in mind and then partially corrected.Correct fix