AlgoBulls logo

Contact Us

Bull Call Ratio Backspread Strategy: Position for Strong Upside with Defined Risk

/img/blogs/blog_bullCallRatio/thumbnail

Expecting a strong upward move in the market? The Bull Call Ratio Backspread strategy is designed for scenarios where the underlying asset is likely to rally sharply. By combining a greater number of long call options with fewer short calls, this strategy allows traders to benefit from significant upside moves while maintaining controlled downside risk through structured position sizing, predefined exits and disciplined risk management.

In this blog, we’ll break down the mechanics of the Bull Call Ratio Backspread, discuss entry and exit criteria, outline key risk management considerations and explain how this strategy performs under different market conditions.


Understanding the Bull Call Ratio Backspread Strategy

The Bull Call Ratio Backspread is a multi-leg options strategy constructed using call options. It is typically established for a net credit or small net debit and is designed to profit from a strong bullish breakout accompanied by rising volatility.

The strategy benefits from:

  • sharp upward price movement

  • volatility expansion

  • limited or manageable downside risk (depending on structure)

Structure of a Bull Call Ratio Backspread

The classic structure involves:

  • Sell 1 At-the-Money (ATM) Call Option

  • Buy 2 Out-of-the-Money (OTM) Call Options

(Ratios can vary, but 1:2 is the most common.)


How the Bull Call Ratio Backspread Strategy Works

1. Entry Criteria

Eligible Markets: The Bull Call Ratio Backspread is best suited for markets where a strong bullish move and potential volatility expansion are expected. It performs particularly well when the underlying is likely to break out sharply to the upside.

Ideal instruments include:

  • Indices: NSE’s NIFTY 50, FIN NIFTY, and US-based indices such as the S&P 500 (SPX) and Nasdaq 100 (QQQ).

  • Stocks: Liquid large-cap stocks with deep options markets, such as AAPL, MSFT, NFLX, and JNJ.

Trade Trigger & Signal Conditions: To improve trade quality and avoid entering during low-momentum phases, the Bull Call Ratio Backspread is initiated only when bullish breakout conditions are confirmed in the underlying.

Primary entry conditions:

  • The underlying closes above the previous 15-minute high with a small buffer to avoid false breakouts.

  • The underlying price remains above the 20-period EMA, indicating bullish intraday trend support.

  • No active position is currently open in the strategy.

This dual-filter approach ensures the strategy participates primarily in environments with fresh upside momentum and supportive trend structure, which are critical for backspread profitability.

Strike Price Selection: The Bull Call Ratio Backspread is typically constructed by selling an ATM call and buying multiple OTM calls for leveraged upside exposure. Strike selection plays a critical role in shaping the payoff profile:

  • Closer OTM Long Calls: Results in a higher probability of profit on moderate upward moves but may reduce the net credit (or increase the debit).

  • Farther OTM Long Calls: May allow entry at a net credit and delivers stronger convex payoff on sharp rallies, but requires a more significant upward move to realize full profitability.

Expiry Selection: Expiry choice influences both the sensitivity to time decay and the ability to capture large directional moves:

  • Weekly Expiry: Suitable for short-term breakout trades where an immediate sharp move is anticipated. However, rapid time decay and gamma risk must be monitored.

  • Monthly Expiry: Provides more time for the bullish move to materialize, with smoother position behavior and reduced time decay pressure.

Lot Size & Positioning: Position sizing should align with the trader’s risk tolerance and capital allocation. While the strategy offers unlimited upside potential, the downside risk (if structured for a net debit) is limited to the net premium paid. Proper sizing ensures the trade remains within acceptable drawdown limits during sideways or mildly bearish conditions.

Timeframes: The Bull Call Ratio Backspread can be deployed across multiple timeframes, typically ranging from 1 to 60 minutes for systematic setups.

  • Lower timeframes enable precise breakout entries and active trade management.

  • Higher timeframes are better suited for capturing larger directional moves.

For intraday breakout strategies, the 1-minute timeframe can be effective when combined with strict entry filters and disciplined risk controls.


2. Exit Rules & Re-Entry Strategy

The Bull Call Ratio Backspread follows well-defined exit and re-entry rules to manage risk while remaining responsive to strong directional moves.

The strategy exits an active position under the following scenarios:

  • Profit Target Reached:
    The position is closed when the predefined profit target is achieved based on the net premium or mark-to-market gains. This allows profits from sharp bullish moves to be systematically locked in rather than left exposed to reversals.

  • Stop-Loss Triggered:
    If the strategy’s net premium or mark-to-market loss breaches the configured stop-loss threshold, all legs are exited to contain downside risk. This is particularly important in scenarios where the underlying remains range-bound or moves mildly against the expected bullish direction.

  • Underlying Price Adverse Movement:
    The position may be exited if the underlying fails to show the expected bullish follow-through or moves below a predefined support or invalidation level. This helps avoid capital being tied up in stagnant or weakening market conditions.

Re-Entry Logic

Re-entry is initiated only when fresh bullish momentum is re-established after a prior exit. Following a stop-loss, profit booking, or invalidation exit, the strategy updates its reference price and enters a cooldown phase to avoid repeated trades during choppy market conditions.

After the cooldown period, the system waits for the underlying to once again satisfy the primary breakout conditions:

  • The underlying closes above the updated previous 15-minute high with the defined buffer.

  • The price remains above the 20-period EMA, confirming continued bullish trend support.

  • No active position is currently open.

Once these conditions are met, a new Bull Call Ratio Backspread is established around the updated price zone.

This structured approach ensures that re-entries occur only when fresh upside momentum and trend alignment are present, helping the strategy avoid overtrading during range-bound or indecisive market phases.

Alternative Exit Strategies

  • Trailing Stop-Loss:
    Instead of a fixed stop-loss, a trailing stop-loss can be applied at the strategy level. As the position moves into profit during a strong rally, the stop dynamically adjusts upward to lock in gains while preserving upside participation. If the trailing threshold is breached, all open positions are exited.

  • Partial Profit Booking:
    Traders may optionally scale out of a portion of the long call exposure once predefined profit conditions are met, while keeping the remaining structure active to participate in further upside expansion.

  • Time-Based Exit:
    Positions may be closed after a predefined portion of the expiry cycle has elapsed, particularly if the expected breakout has not materialized. This helps manage theta exposure and frees capital for higher-conviction opportunities.

Figure 1: Bull Call Ratio Backspread Strategy Execution Flowchart (Values align with the first sample in the upcoming Profit & Loss Calculations section).

This section details the Python implementation of a Short Iron Butterfly strategy with fixed strike spacing and automated re-entry logic.

Selecting Instruments and Strikes for Entry

python
def strategy_select_instruments_for_entry(self, candle, instruments_bucket):
       selected_instruments, meta = [], []

       for instrument in instruments_bucket:
           self.logger.debug(
               f"Checking entry conditions for base instrument: {instrument} | "
               f"Determining ATM/OTM option instruments and verifying if CE orders are already placed."
           )

           # Skip the instrument if active order already exists
           if self.child_instrument_main_orders.get(instrument):
               continue

           # Retrieve LTP of the base instrument to setup child instruments
           base_instrument_ltp = self.broker.get_ltp(instrument)

           # Track re-entry count for this instrument
           re_entry_count = self.re_entry_count.get(instrument, 0)

           # If re-entry count exceeds the allowed limit, skip further re-entries
           if re_entry_count >= self.re_entry_limit:
               continue

           # otherwise increment re-entry count
           else:
               re_entry_count += 1

           leg_wise_list = [
               (BrokerOrderTransactionTypeConstants.BUY, OptionsStrikeDirection.ATM.value, 0),
               (BrokerOrderTransactionTypeConstants.SELL, OptionsStrikeDirection.OTM.value, self.no_of_otm_strikes_leg_sell)
           ]
           hist_data = self.get_historical_data(instrument)
           ema = talib.EMA(hist_data['close'], timeperiod=self.time_period)
           self.logger.debug(f"Latest candle close: {hist_data['close'].iloc[-1]} | Previous candle high: {hist_data['high'].iloc[-2]}")
           if hist_data['close'].iloc[-1] > hist_data['high'].iloc[-2] and self.utils.crossover(hist_data['close'], ema) == 1:
               for action, strike_direction, no_of_strikes in leg_wise_list:
                   self.options_instruments_set_up_all_expiries(instrument, 'CE', base_instrument_ltp)  # Set up option instruments for available expiries
                   child_instrument = self.get_child_instrument_details(instrument, 'CE', strike_direction, no_of_strikes)  # Retrieve ATM/OTM child instrument details for the given instrument

                   # Map the base instrument to its corresponding child instrument in the instruments' mapper. This allows tracking of relationships between base and child instruments for further processing.
                   self.instruments_mapper.add_mappings(instrument, child_instrument)

                   selected_instruments.append(child_instrument)
                   meta.append({"action": action, "base_instrument": instrument, "strike_direction": strike_direction})

       return selected_instruments, meta

Code Explanation:

1. Skipping Instruments with Active Positions

python
if self.child_instrument_main_orders.get(instrument):
    continue
  • Before evaluating entry conditions, the strategy ensures that no active orders already exist for the base instrument.

  • This prevents:

    • Overlapping positions

    • Duplicate entries

    • Uncontrolled exposure

  • Only instruments with no active position are considered for fresh entry.

2. Fetching Underlying Price Once

python
base_instrument_ltp = self.broker.get_ltp(instrument)

The latest traded price (LTP) of the base instrument is retrieved once and reused across strike calculations.

Benefits:

  • Ensures all legs are aligned to the same price snapshot
  • Reduces unnecessary broker/API calls
  • Prevents minor inconsistencies in strike selection

3. Re-Entry Control Logic

python
re_entry_count = self.re_entry_count.get(instrument, 0)

if re_entry_count >= self.re_entry_limit:
    continue
else:
    re_entry_count += 1
  • This mechanism limits how many times the strategy can re-enter per base instrument.

  • Logic flow:

    • If the re-entry limit is already reached → skip instrument

    • Otherwise → increment counter and proceed

  • This ensures:

    • Controlled re-entry frequency

    • Avoidance of repeated entries during choppy conditions

    • Systematic capital protection

  • Unlike the earlier implementation, this version increments the re-entry counter only when conditions are about to be evaluated, making it slightly more conservative.

4. Leg Definition in a Data-Driven Format

python
leg_wise_list = [
    (BUY, ATM, 0),
    (SELL, OTM, self.no_of_otm_strikes_leg_sell)
]
  • This structure defines all legs programmatically instead of hardcoding each leg’s logic.

  • Each tuple specifies:

    • Transaction type (BUY / SELL)

    • Strike direction (ATM / OTM)

    • Strike distance

  • This design:

    • Makes the strategy modular

    • Allows strike adjustments without rewriting logic

    • Enables easy scaling to multi-leg structures

5. Entry Condition: Breakout + EMA Confirmation

python
hist_data = self.get_historical_data(instrument)
ema = talib.EMA(hist_data['close'], timeperiod=self.time_period)

if hist_data['close'].iloc[-1] > hist_data['high'].iloc[-2] and self.utils.crossover(hist_data['close'], ema) == 1:
  • This is the core entry filter.

  • Two conditions must be satisfied:

    • Breakout Condition

      • Latest close > previous candle’s high
      • Confirms price breakout
    • EMA Crossover Confirmation

      • Close crosses above EMA
      • Confirms bullish momentum
  • This dual filter ensures:

    • Structural breakout
    • Trend confirmation
    • Reduced false signals
  • Entry is triggered only when both price action and trend alignment agree.

6. Option Chain Setup Before Strike Selection

python
self.options_instruments_set_up_all_expiries(instrument, 'CE', base_instrument_ltp)
  • Before selecting strikes, the system ensures option instruments for all expiries are initialized and cached.

  • This guarantees:

    • Valid strike availability

    • Correct expiry selection

    • Reliable instrument lookup

  • It acts as a preparation step before constructing the option legs.

7. Strike Selection via Directional Rules

python
child_instrument = self.get_child_instrument_details(
    instrument, 'CE', strike_direction, no_of_strikes
)
  • Strike selection is dynamic and based on:

    • Underlying price

    • Strike direction (ATM / OTM)

    • Number of strikes away

  • This builds the multi-leg option structure programmatically rather than manually selecting symbols.

8. Instrument Mapping and Execution Metadata

python
self.instruments_mapper.add_mappings(instrument, child_instrument)

selected_instruments.append(child_instrument)
meta.append({
    "action": action,
    "base_instrument": instrument,
    "strike_direction": strike_direction
})
  • Two outputs are prepared:

    • selected_instruments
      The actual option instruments to execute trades on.
    • Meta
      Context information for each leg, including:
      • Action (BUY / SELL)

      • Base instrument reference

      • Strike type

  • This separation allows the execution engine to:

    • Place correct order types

    • Track leg relationships

    • Maintain structured order management

Creating an Order for a Position

python
def strategy_enter_position(self, candle, instrument, meta):

   child_instrument = instrument
   base_instrument = self.instruments_mapper.get_base_instrument(child_instrument)
   current_ltp = self.broker.get_ltp(child_instrument)
   multiplier = 1 if meta["strike_direction"] == OptionsStrikeDirection.ATM.value else 2
   qty = self.number_of_lots * child_instrument.lot_size * multiplier
   _order = self.broker.OrderRegular(instrument=child_instrument, order_transaction_type=meta['action'], price=current_ltp, order_code=self.order_code, order_variety=BrokerOrderVarietyConstants.LIMIT, quantity=qty)

   # Store details of successful orders
   if check_order_placed_successfully(_order):
       self.child_instrument_main_orders.setdefault(base_instrument, {})[meta['action']] = _order
   else:

       # Protection logic incase any of the legs fail to get placed - this will help avoid having naked positions
       self.logger.critical('Order placement failed for one of the legs. Exiting position for other leg, if possible and stopping strategy.')
       self.exit_all_positions_for_base_instrument(base_instrument)
       raise ABSystemExit

   return _order

Code Explanation:

1. Dynamic Quantity Multiplier Based on Strike Role

python
multiplier = 1 if meta["strike_direction"] == OptionsStrikeDirection.ATM.value else 2
qty = self.number_of_lots * child_instrument.lot_size * multiplier
  • The strategy dynamically adjusts quantity using a multiplier tied to strike direction.

  • Logic:

    • ATM leg → multiplier = 1

    • OTM leg → multiplier = 2

  • This sizing structure creates the ratio backspread payoff profile, where the long OTM exposure is larger than the ATM leg.

  • Key benefits:

    • Maintains the intended risk–reward convexity

    • Keeps position sizing parameter-driven

    • Avoids hardcoding per-leg quantities

  • Without this multiplier logic, the strategy would lose its asymmetric payoff behaviour.

2. Limit Order Placement at Current LTP

python
_order = self.broker.OrderRegular(
    instrument=child_instrument,
    order_transaction_type=meta['action'],
    price=current_ltp,
    order_code=self.order_code,
    order_variety=BrokerOrderVarietyConstants.LIMIT,
    quantity=qty
)
  • Orders are submitted as LIMIT orders at the current LTP, rather than using market orders.

  • This provides:

    • Better execution control

    • Reduced slippage risk

    • More predictable fill prices across legs

  • In multi-leg option strategies, controlled execution is critical because partial or poor fills can temporarily distort the intended payoff structure.

3. Base-to-Child Instrument Mapping Context

python
base_instrument = self.instruments_mapper.get_base_instrument(child_instrument)
  • Before placing the order, the strategy resolves the base instrument corresponding to the option leg.

  • This mapping is essential for:

    • Grouping legs under a single underlying

    • Coordinated position management

    • Structured exit handling later

  • It ensures all option legs remain logically tied to their parent instrument.

4. Order Tracking Upon Successful Placement

python
if check_order_placed_successfully(_order):
    self.child_instrument_main_orders.setdefault(base_instrument, {})[meta['action']] = _order
  • Once the broker confirms successful placement, the order is stored in the strategy’s tracking structure.

  • Key design points:

    • Uses setdefault for safe dictionary initialization

    • Groups orders by base instrument

    • Indexes by action type (BUY/SELL)

  • This enables the engine to:

    • Monitor open legs

    • Manage exits cleanly

    • Detect incomplete structures

  • The structure maintains clear visibility into the live position state.

5. Fail-Safe Protection Against Partial Structures

python
else:
    self.logger.critical(
        'Order placement failed for one of the legs. Exiting position for other leg, if possible and stopping strategy.'
    )
    self.exit_all_positions_for_base_instrument(base_instrument)
    raise ABSystemExit
  • If any leg fails to place successfully, the strategy immediately triggers protective action.

  • Protective behaviour:

    • Logs a critical error

    • Attempts to exit any already-open legs

    • Raises ABSystemExit to halt execution

  • This is a crucial risk-control safeguard.

  • It prevents:

    • Partially constructed spreads

    • Unhedged directional exposure

    • Accidental naked option risk

  • By forcefully stopping after a failure, the strategy preserves its defined-risk discipline.

Exit Condition Checks

python
  def check_exit_conditions(self, base_instrument, child_leg_orders_dict):
       """
       Evaluate all exit rules for the Bull Call Ratio Backspread.

       Checks:
       • Trend Invalidation Check - handled separately in exit selection logic.
       • Target Profit - exit if spread rises beyond the profit threshold.
       • Stop-Loss - exit if spread falls beyond the stop-loss threshold.
       """

       # Retrieve current orders and latest traded prices (LTP) for both legs
       ltp_leg_buy = self.broker.get_ltp(child_leg_orders_dict[BrokerOrderTransactionTypeConstants.BUY].instrument)
       ltp_leg_sell = self.broker.get_ltp(child_leg_orders_dict[BrokerOrderTransactionTypeConstants.SELL].instrument)

       # Initialize key levels at entry:
       if not self.spread_entry:
           entry_price_leg_buy = self.child_instrument_main_orders.get(base_instrument)[BrokerOrderTransactionTypeConstants.BUY].entry_price
           entry_price_leg_sell = self.child_instrument_main_orders.get(base_instrument)[BrokerOrderTransactionTypeConstants.SELL].entry_price
           self.spread_entry = entry_price_leg_buy - 2 * entry_price_leg_sell  # spread at entry
           (multiplier, self.transaction_type) = (1, "Net Debit") if self.spread_entry > 0 else (-1, "Net Credit")
           self.stoploss_premium = self.spread_entry * (1 - multiplier * self.stoploss_percentage / 100)
           self.target_premium = self.spread_entry * (1 + multiplier * self.target_percentage / 100)

       # Current spread price
       self.spread_current = ltp_leg_buy - 2 * ltp_leg_sell

       # Target Profit and Stop-Loss Threshold Check based on spread value
       if self.spread_current > self.target_premium or self.spread_current < self.stoploss_premium:
           (threshold_name, threshold) = ("Target", self.target_premium) if self.spread_current > self.target_premium else ("Stoploss", self.stoploss_premium)
           self.logger.info(f"{threshold_name} threshold reached: Transaction Type: {self.transaction_type} | Current Net Premium: {abs(self.spread_current):.2f} | {threshold_name} Threshold: {abs(threshold):.2f} - Exiting positions...")
           self.spread_entry = None
           return True

       return False

Code Explanation:

1. Leg-wise LTP Retrieval

python
ltp_leg_buy = self.broker.get_ltp(child_leg_orders_dict[BUY].instrument)
ltp_leg_sell = self.broker.get_ltp(child_leg_orders_dict[SELL].instrument)
  • The strategy first retrieves the latest traded prices (LTP) of both option legs — the long call and the short call.

  • This ensures:

    • Real-time mark-to-market evaluation
    • Accurate spread valuation
    • Proper exit timing
  • Unlike structure-based exits, this logic is purely spread-value driven.

2. One-Time Spread Entry Initialization

python
if not self.spread_entry:
    entry_price_leg_buy = ...
    entry_price_leg_sell = ...
    self.spread_entry = entry_price_leg_buy - 2 * entry_price_leg_sell
  • The system computes and stores the initial spread value at entry, but only once per trade cycle.

  • For a 1×2 call backspread:

    • Long leg contributes positively
    • Two short legs contribute negatively
  • So the spread is calculated as:

    • Spread = Buy Price − 2 × Sell Price

    • This becomes the baseline reference for all future exit checks.

  • Why store once?

    • Anchors stop-loss and target to original entry

    • Prevents threshold drift

    • Ensures each re-entry starts fresh

3. Automatic Net Debit / Net Credit Detection

python
(multiplier, self.transaction_type) =
    (1, "Net Debit") if self.spread_entry > 0
    else (-1, "Net Credit")
  • The strategy dynamically determines whether the structure is entered as:

    • Net Debit (typical backspread case)

    • Net Credit (possible depending on strikes)

  • This is an important robustness feature.

  • Why it matters:

    • Profit direction differs for debit vs credit

    • Threshold math must adapt automatically

    • Same code supports multiple payoff regimes

  • The multiplier normalizes later calculations.

4. Construction of Stop-Loss and Target Thresholds

python
self.stoploss_premium = spread_entry * (1 - multiplier * stoploss%)
self.target_premium   = spread_entry * (1 + multiplier * target%)
  • Thresholds are derived directly from the entry spread value.

  • Because the multiplier adjusts sign:

    • Works correctly for both debit and credit structures

    • Maintains consistent risk logic

    • Avoids hardcoding comparison directions

  • Interpretation:

    • For a typical net debit backspread:

      • Profit occurs when spread value rises

      • Loss occurs when spread value falls

  • The formula automatically aligns with this behaviour.

5. Real-Time Spread Monitoring

python
self.spread_current = ltp_leg_buy - 2 * ltp_leg_sell
  • The system continuously recomputes the live spread value using current market prices.

  • This represents the true mark-to-market value of the entire strategy.

  • Why this is important:

    • Captures full multi-leg dynamics

    • More accurate than monitoring legs independently

    • Reflects real exit cost

  • This is the core trade-level risk monitor.

6. Unified Target and Stop-Loss Check

python
if self.spread_current > self.target_premium
   or self.spread_current < self.stoploss_premium:
  • A single conditional checks both exit scenarios.

  • Exit triggers when either:

    • Spread exceeds target threshold → profit booked

    • Spread falls below stop-loss threshold → risk capped

  • This keeps the logic:

    • Clean

    • Symmetric

    • execution-efficient

7. Resetting Spread State After Exit

python
self.spread_entry = None
  • After an exit, the entry reference is cleared.

  • This is crucial because it:

    • Prepares the system for clean re-entry

    • Prevents stale thresholds

    • Ensures the next trade recalibrates properly

  • Without this reset, future exits could be misaligned.

Validation in Short Call Butterfly

python
def validate_parameters(self):
       """ Validates required strategy parameters. """
       check_argument(
           self.strategy_parameters, "extern_function", lambda x: len(x) >= 5,
           err_message=(
               "Need 5 parameters for this strategy: \n"
               "(1) NUMBER_OF_OTM_STRIKES_SELL_LEG \n"
               "(2) TARGET_PERCENTAGE \n"
               "(3) STOPLOSS_PERCENTAGE \n"
               "(4) RE_ENTRY_LIMIT \n"
               "(5) TIME_PERIOD \n"
           )
       )

       # Validate numeric strategy parameters
       for param in (self.re_entry_limit, self.no_of_otm_strikes_leg_sell, self.time_period):
           check_argument(param, "extern_function", is_positive_int, "Value should be a positive integer")

       # Validate percentage strategy parameters
       for param in (self.target_percentage, self.stoploss_percentage):
           check_argument(param, "extern_function", is_nonnegative_int_or_float, "Value should be >0")

Code Explanation:

The validate_parameters function ensures all required strategy inputs are present and logically valid before any trading logic executes. This prevents runtime failures and protects the integrity of the strategy configuration.

Failure Case 1: Missing Required Strategy Parameters

python
self.strategy_parameters = {
    "NUMBER_OF_OTM_STRIKES_SELL_LEG": 2,
    "TARGET_PERCENTAGE": 20,
    "STOPLOSS_PERCENTAGE": 10
    # Missing RE_ENTRY_LIMIT and TIME_PERIOD
}

validate_parameters()

Error:

python
Need 5 parameters for this strategy

Reason:

The strategy requires at least five configuration parameters:

  • NUMBER_OF_OTM_STRIKES_SELL_LEG
  • TARGET_PERCENTAGE
  • STOPLOSS_PERCENTAGE
  • RE_ENTRY_LIMIT
  • TIME_PERIOD

If fewer than five parameters are provided, the strategy cannot safely initialize its execution logic.

Failure Case 2: Invalid integer configuration values

python
self.re_entry_limit = 0
self.no_of_otm_strikes_leg_sell = -1
self.time_period = "20"

validate_parameters()

Error:

python
Value should be a positive integer

Reason:

The following parameters must be strictly positive integers (> 0):

  • re_entry_limit

  • no_of_otm_strikes_leg_sell

  • time_period

Invalid cases include:

  • Zero values

  • Negative numbers

  • Non-integer types

These fields control structural behaviour (re-entry count, strike distance, EMA window), so invalid values would break core strategy logic.

Failure Case 3: Invalid percentage inputs

python
elf.target_percentage = -5
self.stoploss_percentage = "ten"

validate_parameters()

Error:

python
Value should be >0

Reason:

The following parameters must be non-negative numeric values:

  • target_percentage

  • stoploss_percentage

Invalid inputs include:

  • Negative percentages

  • Non-numeric values

These parameters directly drive risk and profit thresholds, so improper values would distort exit logic and risk management.

💡 Want to see the complete strategy? Check out the full implementation here.

Ideal Market Conditions for Bull Call Ratio Backspread

When to Use

The Bull Call Ratio Backspread works best when a strong bullish move accompanied by potential volatility expansion is expected. The strategy is designed to benefit from sharp upside momentum, making it most effective when the underlying is likely to break out decisively rather than remain range-bound.

Typical scenarios include:

  • Post-Consolidation Bullish Breakouts: After a prolonged period of price compression or range-bound movement, when the market is poised for an upside breakout with expanding momentum.

  • Event-Driven Upside Moves: Around catalysts such as earnings releases, economic data announcements, or policy decisions where a positive surprise could trigger a sharp bullish move and volatility expansion.

  • Strong Trend Continuation Phases: During established uptrends when the underlying shows signs of fresh momentum or breakout from a pullback, indicating potential for accelerated upside.

  • Low-to-Rising Volatility Environments: Markets transitioning from low implied volatility to expanding volatility regimes, where the convex payoff of the backspread benefits from both price acceleration and potential IV expansion.


Interpreting the Bull Call Ratio Backspread Payoff Structure

The following payoff diagram illustrates the profit and loss dynamics of a Bull Call Ratio Backspread strategy. The values used correspond to those depicted in the flowchart.

Figure 2: Profit and Loss Diagram

The green curve represents the profit zone of the strategy. In a Bull Call Ratio Backspread, the position begins to generate meaningful gains when the underlying price breaks out strongly above the higher long call strike. Unlike range-bound premium strategies, this structure is specifically designed to capture sharp upside momentum rather than benefit from price stability. As the rally strengthens, the two long calls increasingly drive the payoff, resulting in a convex upside profile.

The strategy offers uncapped profit potential on the upside, with gains expanding as the underlying continues to move higher. The dotted green line marks the target profit level, where traders may choose to exit systematically to secure profits during favourable market moves.

The red curve indicates the loss region, primarily concentrated between the short strike and the long strike. The maximum loss typically occurs near the higher strike at expiry, where the short call retains value while the long calls have not yet provided sufficient offset. Importantly, the downside exposure remains predefined, as highlighted by the red dashed stop-loss line, helping maintain disciplined risk control.

Key dashed markers highlight the important price reference points:

  • Upper breakeven marks the level where the payoff transitions from loss to profit on the upside.

  • Short strike (K1) identifies where the sold call begins to introduce downside pressure.

  • Long strike (K2) indicates the activation zone where the purchased calls start contributing positively.

  • Target profit and stop-loss thresholds outline the active risk management boundaries applied during execution.

Profit and Loss Calculations for Low and High Risk Versions

1. Low-Risk Bull Call Ratio Backspread

The following example illustrates a low-risk Bull Call Ratio Backspread constructed on a liquid US large-cap stock, AAPL. The setup is designed to benefit from a sharp upside move while keeping downside risk limited to the net premium paid.

Key Parameters

  • Target Profit (target_percentage): 50% of the net debit

  • Stop-Loss (stoploss_percentage): 30% of the net debit

  • Instrument: AAPL (Apple Inc.)

  • Expiration Type: Nearest Monthly Expiry

  • Strike Selection:

    • Leg One: ATM (Sell Call) - $180

    • Leg Two: OTM (Buy Call - Quantity 2) - $185

(1:2 ratio backspread structure)

  • Re-entry Levels

    • Re-Entry Trigger: Fresh breakout above the recent high

    • Trend Filter: Price crosses above 20 EMA

Calculations

(Assume a simple 1:1 relationship between the AAPL stock underlying and the spread for illustration.)

  • Total Premium Collected: $4.50 (ATM Call) = $4.50

  • Total Premium Paid: $2.75 (OTM Call) × 2 = $5.50

  • Net Premium Paid: $5.50 - $4.50 = $1

  • Target Profit (0.5 x Net Premium Paid):
    1 x 0.50 = $0.50

Exit when spread profit reaches +$0.50

  • Stop-Loss (0.3 x Net Premium Paid):

1 x 0.30 = $0.30

Max possible loss capped at -$0.30.

  • Maximum Profit Calculation:
    Maximum Profit: Unlimited
    To calculate your exact profit at any stock price above the higher strike (K2) at expiration:

Profit = (S−K2) − Max Loss

Alternatively, broken down by individual legs (for a 2:1 ratio):

Profit = [2 × (S−K2)] − (S−K1) + Net Premium

where:

  • K1 = short strike

  • K2 = long strike

  • S = spot at expiry
    It occurs when the underlying rallies sharply above the higher long call strike ($185), where the two long calls begin to dominate the payoff.

  • Maximum Loss Calculation:

    Maximum Loss = K2 - K1 + net debit paid = $5 + $1 = $6
    The maximum loss occurs if the stock price is exactly at the higher strike (K₂) at expiration. In this scenario, both long calls expire worthless while the short call remains in the money, resulting in the deepest loss for the position.

  • Breakeven Points:

    • Upper Breakeven: Long Strike + Maximum Loss = 185 + 6 = $191

    (Downside risk is already limited to the debit paid.)

Spot PriceP&L With Target/Stop-lossP&L Without Target/Stop-loss
180Exit at $0.70 = –$0.30 (Capped)–$1 (Net Debit Loss)
185Exit at $0.70 = –$0.30 (Capped)–$6 (Maximum Loss)
191Exit at $1 = $0 (Breakeven)$0
195Exit at $1.50 = +$0.50 (Target Profit)$4

2. High-Risk Bull Call Ratio Backspread

The following diagram represents the payoff behaviour of a high-risk Bull Call Ratio Backspread position at expiry.

Figure 3: Profit and Loss Diagram - High Risk Version

The following example illustrates a high-risk Bull Call Ratio Backspread constructed on the BANK NIFTY Index, designed to capitalize on sharp bullish breakouts while maintaining defined downside risk.

This setup is particularly suited for high-volatility environments where strong directional moves are expected and the convex payoff of the backspread can be effectively captured

Key Parameters

  • Target Profit (target_percentage): 60% of the net debit

  • Stop-Loss (stoploss_percentage): 40% of the net debit

  • Instrument: BANK NIFTY Index

  • Expiration Type: Nearest Weekly Expiry

  • Strike Selection:

    • Leg One: ATM (Sell Call) - 48,000

    • Leg Two: OTM (Buy Call × 2) - 48,500

(1:2 ratio backspread structure)

  • Re-Entry Levels

    • Re-Entry Trigger: Breakout above the recent high

    • Trend Filter: Price crosses above 20 EMA

Calculations

(Assume a 1:1 relationship between the BANKNIFTY spot price and the option spread for illustration.)

  • Total Premium Collected: ₹220 (ATM Call) = ₹220

  • Total Premium Paid: ₹150 (OTM Call) × 2 = ₹300

    Net Premium Paid: 300 - 220 = ₹80

  • Target Profit (0.6 × Net Premium Paid)
    80 x 0.60 = ₹48
    Exit when spread profit reaches +₹48 profit

  • Stop-Loss (0.4 × Net Premium Paid)
    80 x 0.40 = ₹32
    Maximum loss capped at −₹32

  • Maximum Profit Calculation
    Maximum Profit: Unlimited
    At expiration above the higher strike (K₂ = 48,500), the two long calls begin to dominate the payoff, producing accelerating upside gains.
    Profit Formula
    Profit = [2 x (S - K2)] - (S - K1) - Net Debit
    where:

    • K1 = short strike

    • K2 = long strike

    • S = spot at expiry

  • Maximum Loss Calculation
    Maximum Loss = (K2 - K1) + Net Debit = 500 + 80 = ₹580
    The maximum loss occurs if BANK NIFTY expires exactly at the higher strike (K₂ = 48,500). In this scenario, both long calls expire worthless while the short call remains in the money, producing the deepest loss.

  • Breakeven Point
    Upper Breakeven = K2 + Maximum Loss = 48,500 + 580 = ₹49,080
    Beyond this level, the strategy enters the profit zone.
    (Downside risk remains limited to the debit paid.)

Spot PriceP&L With Target/Stop-lossP&L Without Target/Stop-loss
48,000Exit at ₹48 = −₹32 (Capped)−₹40 (Net Debit Loss)
48,500Exit at ₹48 = −₹32 (Capped)−₹580 (Maximum Loss)
49,080Exit near ₹0 (Breakeven)₹0
49,000Exit at ₹128 = +₹48 (Target Profit)₹420

The low-risk version of the Bull Call Ratio Backspread focuses on controlled exposure with smaller debit outlay and tighter risk management, making it suitable for more measured market conditions.

In contrast, the high-risk variant increases sensitivity to sharp upside moves by using wider strikes and more aggressive parameters. While this enhances the potential for accelerated gains during strong breakouts, it also increases mark-to-market volatility and the likelihood of drawdowns if momentum fails to materialize.

A visual comparison below highlights how the risk–reward profile shifts between the two approaches.

Comparing Bull Call Ratio Backspread and Bear Put Ratio Backspread

The Bull Call Ratio Backspread and the Bear Put Ratio Backspread are convex multi-leg options strategies designed to benefit from strong directional moves accompanied by potential volatility expansion. Their payoff structures are mirror images of each other, but they are deployed under opposite market expectations.

The Bull Call Ratio Backspread is structured to profit from sharp upside breakouts, whereas the Bear Put Ratio Backspread is designed to benefit from strong downward moves in the underlying.

FeatureBull Call Ratio BackspreadBear Put Ratio Backspread
Option Types UsedSell 1 ATM Call, Buy 2 OTM CallsSell 1 ATM Put, Buy 2 OTM Puts
Strategy BiasBullish convexBearish convex
Market ExpectationStrong upside breakoutSharp downside move
Initial Trade TypeUsually small debit (can be credit)Usually small debit (can be credit)
Payoff ShapeConvex upside (hockey stick)Convex downside (inverted hockey stick)
Max Profit ScenarioLarge upward moveLarge downward move
Max Loss ScenarioNear the long strike regionNear the long strike region
Figure 4: Bull Call Ratio Backspread vs. Bear Put Ratio Backspread Mind Tree

Which One Is Right for You?

If you expect a strong bullish move and prefer a debit-based strategy with significant upside potential, the Bull Call Ratio Backspread may be more suitable. This strategy typically involves selling fewer lower-strike calls and buying more higher-strike calls, resulting in limited downside risk and unlimited profit potential on the upside. You benefit most when the underlying makes a sharp upward move beyond the higher strike.

If you anticipate only a mild bullish move or expect the price to stay within a range, this strategy may be less effective, since profits depend on a meaningful upward breakout. While the initial setup may result in a small net debit (or sometimes a credit), the key objective is to capture convex upside with controlled risk.

The Bull Call Ratio Backspread offers defined or near-defined risk with strong positive convexity. Choose this strategy if you are positioning for a significant bullish expansion in price while keeping downside risk limited.

Customize the Strategy with Your Own Parameters!

Traders can fine-tune strike selection, expiry choice, stop-loss levels, and profit targets based on risk tolerance.

👉 For testing on the Phoenix platform of AlgoBulls, head over to our site now!

👉 A Jupyter notebook for this strategy is coming soon. Meanwhile, check out All Available Notebooks for Testing Custom Strategies!


Final Thoughts

The Bull Call Ratio Backspread works best as an actively managed structure rather than a set-and-forget position. It is designed to capitalize on sharp upside momentum while keeping downside exposure controlled through its built-in hedge.

This setup performs most efficiently when supported by clear exit rules and price-based supervision. Defined profit objectives, protective loss limits and disciplined re-entry criteria help the strategy stay aligned with the intended bullish thesis while avoiding unnecessary risk.

Instead of waiting passively for expiry, the focus is on responsive, rule-driven trade management that reacts quickly when momentum strengthens or the setup weakens.

Key Risk-Mitigation Techniques

✔ Incorporated in the Strategy

Target profit & hard stop-loss:

The strategy exits automatically once the position reaches predefined profit or loss thresholds. This ensures consistent execution, protects capital during adverse moves, and helps secure gains when the underlying rallies sharply.

Price and trend invalidation exit:

In addition to P&L-based exits, the strategy continuously monitors key underlying price and trend conditions. If the underlying fails to sustain the breakout (e.g., falls back below the recent high reference) or closes below the 20 EMA, indicating loss of bullish momentum, the position is exited promptly, even if the profit target or stop-loss has not been reached. This trend-based exit helps protect against theta decay, failed breakouts, and weakening trend conditions.

Re-entry logic:

If a position exits due to a target hit, stop-loss, or price-level trigger, and the underlying continues to trend upward, the strategy can re-initiate using an updated ATM reference. This enables continued participation in sustained bullish momentum while maintaining controlled exposure.

✔ Additional Enhancements

High-frequency P&L tracking:

Monitoring profit and loss at a finer interval than the primary candle timeframe (for example, frequent checks within a 1-minute setup) allows faster defensive exits, especially when price stalls near critical zones.

Position refinement:

Strike ratios, spread spacing, and lot sizing can be dynamically adjusted based on volatility and momentum conditions. In higher-volatility environments, wider strike spacing can better accommodate large directional moves while preserving the strategy’s positive convexity. Strike selection may also be automated using implied volatility or momentum filters to keep the structure aligned with prevailing market conditions.

Disclaimer

The information provided in this article is for educational and informational purposes only and does not constitute financial, investment, or legal advice. The views and opinions expressed are based on the interpretation by the author of this article 'Bull Call Ratio Backspread Strategy: Position for Strong Upside with Defined Risk'. While we strive for accuracy, readers are advised to consult with regulatory authorities, financial experts, or legal professionals before making any trading or investment decisions. AlgoBulls is not responsible for any direct or indirect implications arising from the use of this information.