book
Checkout our new book! Hands on AI Trading with Python, QuantConnect, and AWS Learn More arrow

Option Strategies

Reverse Conversion

Introduction

A Reverse Conversion, or Reversal, is the inverse of a conversion and also a special case of a protective collar. It consist of shorting one lot of the underlying security, buying a call, and selling a put with lower strike price. However, the strategy now serves as an delta-neutral arbitration from Option mispricing instead of a hedge strategy. Note that it only attains a true profit when the risk-free return is greater than the risk-free interest rate.

Implementation

Follow these steps to implement the reverse conversion strategy:

  1. In the initialize method, set the start date, set the end date, subscribe to the underlying Equity, and create an Option universe.
  2. Select Language:
    def initialize(self) -> None:
        self.set_start_date(2017, 4, 1)
        self.set_end_date(2017, 4, 30)
        self.set_cash(100000)
    
        self.universe_settings.asynchronous = True
        option = self.add_option("GOOG", Resolution.MINUTE)
        self._symbol = option.symbol
        option.set_filter(lambda universe: universe.include_weeklys().conversion(30, -5))

    The conversion filter narrows the universe down to just the two contracts you need to form a reverse conversion.

  3. In the on_data method, select the strike and expiry of the contracts in the strategy legs.
  4. Select Language:
    def on_data(self, slice: Slice) -> None:
        if self.portfolio.invested:
            return
    
        # Get the OptionChain
        chain = slice.option_chains.get(self._symbol, None)
        if not chain:
            return
    
        # Select an expiry date and ATM strike price
        expiry = max([x.expiry for x in chain])
        strike = sorted(chain, key = lambda x: abs(x.strike - chain.underlying.price))[0].strike
  5. In the on_data method, select the contracts and place the orders.
  6. Approach A: Call the OptionStrategies.reverse_conversion method with the details of each leg and then pass the result to the buy method.

    Select Language:
    reverse_conversion = OptionStrategies.reverse_conversion(self._symbol, strike, expiry)
    self.buy(reverse_conversion, 1)

    Approach B: Create a list of Leg objects and then call the combo_market_order, combo_limit_order, or combo_leg_limit_order method.

    Select Language:
    # Select the call and put contracts
    call = [x for x in chain if x.right == OptionRight.CALL and x.expiry == expiry and x.strike == strike][0]
    put = [x for x in chain if x.right == OptionRight.PUT and x.expiry == expiry and x.strike == strike][0]
    
    legs = [
        Leg.create(call.symbol, 1),
        Leg.create(put.symbol, -1),
        Leg.create(chain.underlying.symbol, -chain.underlying.symbol_properties.contract_multiplier)
    ]
    self.combo_market_order(legs, 1)

Strategy Payoff

This is a fixed payoff, delta-neutral strategy. The payoff is

CT=(STK)+PT=(KST)+PayoffT=(S0ST+CTPTC0+P0)×mfee=(S0KC0+P0)×mfee whereCT=Call value at time TPT=Put value at time TST=Underlying asset price at time TK=Strike pricePayoffT=Payout total at time TS0=Underlying asset price when the trade openedC0=Call price when the trade opened (credit received)P0=Put price when the trade opened (debit paid)m=Contract multiplierT=Time of expiration

The following chart shows the payoff at expiration:

reverse conversion strategy payoff

The payoff is only dependent on the strike price and the initial asset prices.

If the Option is American Option, there is a risk of early assignment on the contract you sell.

Example

The following table shows the price details of the assets in the algorithm:

AssetPrice ($)Strike ($)
Call10.30832.50
Put7.40832.50
Underlying Equity at position opens832.26-

Therefore, the payoff is

PayoffT=(S0KC0+P0)×mfee=(832.26832.5010.30+7.40)×1001.00×3=317.00

So, the strategy loses $317.

The following algorithm implements a reverse conversion Option strategy:

Select Language:
class ReverseConversionOptionStrategy(QCAlgorithm):
    def initialize(self) -> None:
        self.set_start_date(2017, 4, 1)
        self.set_end_date(2017, 4, 23)
        self.set_cash(100000)
        
        equity = self.add_equity("GOOG", Resolution.MINUTE)
        option = self.add_option("GOOG", Resolution.MINUTE)
        self.symbol = option.symbol

        # set our strike/expiry filter for this option chain
        option.set_filter(lambda universe: universe.include_weeklys().conversion(30, -5))

    def on_data(self, data: Slice) -> None:
        # avoid extra orders
        if self.portfolio.invested: return

        # Get the OptionChain of the self.symbol
        chain = data.option_chains.get(self.symbol, None)
        if not chain: return

        # choose the furthest expiration date within 30 days from now on
        expiry = sorted(chain, key = lambda x: x.expiry)[-1].expiry
        
        # select ATM strike price
        strike = sorted(chain, key = lambda x: abs(x.Strike - chain.underlying.price))[0].strike

        # Order Strategy
        reverse_conversion = OptionStrategies.reverse_conversion(self.symbol, strike, expiry)
        self.buy(reverse_conversion, 1)

    def on_end_of_day(self, symbol: Symbol) -> None:
        if symbol.value == "GOOG":
            self.log(f"{self.time}::{symbol}::{self.securities[symbol].price}")

You can also see our Videos. You can also get in touch with us via Discord.

Did you find this page helpful?

Contribute to the documentation: