avatarDiego Degese

Summary

This article discusses a strategy for trading 0DTE options using credit spreads, specifically focusing on the SPY ETF, and presents a backtest analysis using data from June 2021 to July 2023.

Abstract

The article begins by explaining the concept of credit spreads, which involve simultaneously selling and buying options contracts on the same underlying asset but with different strike prices. It then delves into the specifics of trading 0DTE options, which are options contracts that expire on the same day they are opened. The author provides examples of Call Credit Spreads and Put Credit Spreads, outlining their advantages and disadvantages. The article then moves on to discuss the backtest analysis, which involves trading credit spreads on SPY with 0DTE options. The results of the backtest are presented, showing a high win rate and overall profitability. However, the author cautions that trading and investing carry inherent risks and past performance may not predict future outcomes.

Opinions

  • The author believes that trading 0DTE options using credit spreads can be an effective strategy for generating income and limiting risk.
  • The author suggests that credit spreads offer several advantages, including limited risk, income generation, and a higher probability of profit compared to other strategies.
  • The author acknowledges that credit spreads also have disadvantages, such as limited profit potential and margin requirements.
  • The author emphasizes the importance of risk management in trading strategies, noting that the defined parameters for opening bearish or bullish trades based on percentage changes contributed to the strategy's success.
  • The author encourages readers to do more tests on this strategy and welcomes input and feedback for potential improvements or areas that require further clarification.
  • The author cautions that trading and investing carry inherent risks and past performance may not predict future outcomes.
  • The author provides a disclaimer that the information in the article is for educational purposes only and should not be construed as investment advice.

How I Achieved Over 80% Win Rate Using 0DTE Options and the Credit Spread Strategy on SPY 🤯🤩

Using Put Credit Spread and Call Credit Spread Strategies with Same-Day Expiration Options

In the never-ending quest to beat the market, I am always developing new ways to increase earnings and lower risks. Trading 0DTE options using Credit Spreads is one of the approaches. This article aims to go further into the mechanics of this strategy, examining its advantages and disadvantages. Additionally, we will perform a backtest analysis using data from June 2021 to July 2023 to evaluate the performance of this approach.

You cannot read the rest of my article? This already happened to me, and I decided to become a Medium member for less than a Starbucks coffee per month. Don’t miss out — become a member now!

What Is a Credit Spread?

Before entering into the specifics of trading 0DTE options, it’s essential to understand the concept of credit spreads. Credit spreads are versatile options trading strategies that involve simultaneously selling and buying options contracts on the same underlying asset but with different strike prices. The primary goal of a credit spread is to generate a net credit (receive a premium) when initiating the trade.

Call Credit Spread (Bearish)

A Call Credit Spread is executed when a trader sells an out-of-the-money (OTM) call option and simultaneously buys a further OTM call option with a higher strike price. This strategy is employed when the trader expects the underlying asset’s price to remain below the lower strike price at expiration.

Example 1: Let’s say you are trading SPY, which is currently priced at $400. You decide to implement a Call Credit Spread with the following components:

  • Sell a SPY Call Option with a strike price of $410 with a premium of $10.
  • Buy a SPY Call Option with a strike price of $420 with a premium of $5.

In this scenario, you receive a net credit of $5 ($10 premium received — $5 premium paid). Your maximum profit is limited to this credit, and you profit if SPY closes below $410 at expiration.

Example 2: If SPY closes above $420 at expiration, your maximum loss is capped at $5 (the difference between the two strike prices minus the net credit received).

Put Credit Spread (Bullish)

A Put Credit Spread, on the other hand, involves selling an OTM put option and simultaneously buying a further OTM put option with a lower strike price. This strategy is used when we anticipate that the underlying asset’s price will remain above the higher strike price at expiration.

Example 1 Suppose you are trading SPY at $400 and decide to implement a Put Credit Spread with these components:

  • Sell SPY Put Option with a strike price of $390 with a premium of $8.
  • Buy SPY Put Option with a strike price of $380 with a premium of $4.

In this instance, you receive a net credit of $4 ($8 premium received — $4 premium paid). Your maximum profit is capped at this credit, and you profit if SPY closes above $390 at expiration.

Example 2 If SPY closes below $380 at expiration, your maximum loss is limited to $6 (the difference between the two strike prices minus the net credit received).

Advantages and Disadvantages of Credit Spreads

Credit spreads offer several advantages and disadvantages that we should consider before incorporating them into our trading strategies.

Advantages

Limited Risk: Credit spreads limit the potential losses to a predetermined amount, making them a risk-controlled strategy. Traders can define their maximum loss upfront, providing peace of mind.

Income Generation: These spreads generate a net credit when initiated, providing traders with an immediate cash inflow. This can be especially appealing in low-volatility market environments.

Probability of Profit: Credit spreads often have a higher probability of profit compared to other strategies. Traders can profit even if the underlying asset’s price moves modestly in the anticipated direction.

Versatility: Credit spreads can be tailored to various market conditions, including bullish, bearish, or neutral outlooks.

Disadvantages:

Limited Profit Potential: While credit spreads offer limited risk, they also cap potential profits. Traders can only profit up to the net credit received.

Margin Requirements: Trading options, including credit spreads, may require traders to maintain a margin account, potentially tying up more capital than other strategies.

Assignment Risk: There is a risk of early assignment, particularly for American-style options. If the short leg of the spread is assigned early, it can lead to unexpected losses.

Commissions and Fees: Traders should account for transaction costs, including commissions and fees, which can impact the profitability of credit spreads.

Now that we have a solid understanding of credit spreads, let’s shift our focus to 0DTE options and how they can be integrated into this strategy.

What Does 0DTE Mean?

0DTE stands for “0 Days to Expiration.” It refers to options contracts that are set to expire at the close of the trading session on the same day they are opened. These options have no time value remaining and are entirely comprised of intrinsic value. They are also commonly known as “same-day expiration” or “same-day expiry” options.

What Are 0DTE Options?

0DTE options, also known as “same-day expiration” options, are a specific subset of options contracts. These contracts have a very short lifespan, expiring on the same day they are issued. While most standard options contracts have expiration dates that are days, weeks, or even months in the future, 0DTE options are unique in that they offer a quick, high-stakes trading opportunity.

0DTE options come in two main varieties:

0DTE Weekly Options: These options expire on the same day of the week as they are issued. For example, if an option is issued on a Friday, it will expire later that same day.

0DTE Daily Options: These options expire on the same trading day they are issued. For traders who are looking for short-term opportunities and quick decisions, daily options are particularly appealing.

How Do 0DTE Options Work?

0DTE options are attractive because of their quick turnover and large profits or losses that can occur in a single trading session. To understand how they work, it’s important to consider the following:

Intraday Trading: 0DTE options are exclusively intraday trading instruments. Traders must open and close their positions within the same trading day.

High Theta: The time decay of options, measured by theta, is extremely high for 0DTE options. This means the value of these options erodes rapidly as the trading day progresses.

Leveraged Gains and Losses: Due to their rapid time decay and leverage, 0DTE options can amplify both gains and losses. Small price movements in the underlying asset can lead to significant changes in the option value.

Time Sensitivity: Timing is critical when trading 0DTE options. Traders must closely monitor the market and make quick decisions based on their analysis of the underlying asset’s price movement.

If you enjoy reading my articles, please don’t forget to hit the follow button — Diego Degese

When Do 0DTE Options Expire?

Understanding the expiration time of 0DTE options is crucial to effectively execute any trading strategy involving these contracts. 0DTE options expire on the same trading day they are issued, and their expiration time may vary depending on the exchange and market in which they are traded.

For instance, if you are trading on the CBOE (Chicago Board Options Exchange), 0DTE options typically expire at 4:00 PM (Eastern Time) on the trading day. It’s essential to be aware of the specific expiration time for the market you are trading in, as it can influence your trading decisions.

What Happens If the Option Isn’t Exercised Before It Expires?

As 0DTE options expire at the end of the trading day, they are typically European-style options. This means that they can only be exercised at expiration, unlike American-style options, which can be exercised at any time before expiration.

If you hold a 0DTE option and do not exercise it before it expires, the option will simply expire worthless, and you will lose the premium you paid to purchase it. This is a characteristic shared with all European-style options.

However, most traders in the 0DTE options market are primarily focused on trading the options themselves for their time value, rather than exercising them to acquire or dispose of the underlying asset. This approach aligns with the common goal of generating quick returns through rapid price movements in the options market.

Trading Credit Spreads on SPY with 0DTE Options:

Combining credit spreads with 0DTE options can be an interesting strategy for traders looking to benefit from short-term price movements in the SPY ETF. This approach leverages the limited risk profile of credit spreads with the rapid decay of 0DTE options to potentially achieve attractive risk-reward ratios.

Here’s how the backtested strategy works:

Identify Market Direction: Before initiating the trade, traders should have a clear view of the expected direction of the SPY ETF. Are they bullish, bearish, or neutral? This directional bias will guide whether to set up a Call Credit Spread or a Put Credit Spread.

Select Strike Prices: Choose the strike prices for the credit spread based on the anticipated price movement of SPY within the same trading day. For a bullish outlook, you’d select put strike prices below the current SPY price, and for a bearish view, you’d choose call strike prices above the current SPY price.

Open the Credit Spread: Execute the credit spread by simultaneously selling the out-of-the-money (OTM) option and buying the further OTM option. This generates a net credit, which is your potential profit.

Wait Until the Market Closes: Once the position is open, we will wait until the end of the day to check the result.

If you enjoy reading my articles, please don’t forget to hit the follow button — Diego Degese

Backtesting the Strategy

To check the effectiveness of trading credit spreads on SPY with 0DTE options, we will perform a backtest using historical data from June 2021 to July 2023. In this analysis, we focused on both Call and Put Credit Spreads, evaluating their performance under different market conditions.

Let’s break down the code step by step:

Step 1: Importing Libraries

import warnings
import numpy as np
import pandas as pd
from tqdm import tqdm

In this step, we will import the necessary Python libraries:

  • warnings: This library is used to suppress warning messages.
  • numpy (abbreviated as np): A library for numerical and mathematical operations.
  • pandas (abbreviated as pd): A library for data manipulation and analysis.
  • tqdm: A library for adding progress bars to loops and iterations.

Step 2: Defining Constants and Configuration

# Constants
DEBUG = 1
OPTIONS_FILE='../data/spy_dte_0.csv.gz'

FEES_PER_CONTRACT = 0.6
CONTRACTS = 10

HOUR_OPEN = 10
MINUTE_OPEN = 30
STRIKES = 1
DIST_BETWEEN_STRIKES = 2
MAX_CHANGE_BEARISH = -0.35
MIN_CHANGE_BULLISH = 0.35

### Configuration ###
warnings.filterwarnings("ignore")
np.set_printoptions(suppress=True)
pd.options.mode.chained_assignment = None

In this step, we will define various constants and configuration settings:

  • DEBUG: A flag to control whether debug messages will be printed (1 for enabled, 0 for disabled).
  • OPTIONS_FILE: The path to the CSV file containing options data.
  • FEES_PER_CONTRACT: The fees associated with each options contract.
  • CONTRACTS: The number of contracts used in the strategy.
  • HOUR_OPEN and MINUTE_OPEN: The hour and minute at which the trading session opens.
  • STRIKES and DIST_BETWEEN_STRIKES: Parameters used to determine strike prices for options.
  • MAX_CHANGE_BEARISH and MIN_CHANGE_BULLISH: Maximum and minimum percentage changes are used to determine whether to open bearish or bullish trades.

The code also sets up some configurations for handling warnings and formatting output.

Step 3: Defining Helper Functions

def get_vertical_option_kind(df, max_change_bearish, min_change_bullish):

    changes = 100 * (df['close_underlying'].values / df['close_underlying'].values[0] - 1)
    
    change = changes[-1]
    min_change = min(changes)
    max_change = max(changes)
    
    if change < max_change_bearish and max_change < min_change_bullish:
        return 'C' # Sell Call Vertical
    elif change > min_change_bullish and min_change > max_change_bearish:
        return 'P' # Sell Put Vertical
    else:
        return ''

def get_vertical_strikes(df, kind, strikes, dist_between_strikes):

    if kind == 'P':
        sell_strike = int(df['close_underlying'].values[0]) - strikes
        buy_strike  = sell_strike - dist_between_strikes
    else:
        sell_strike = int(df['close_underlying'].values[0]) + strikes
        buy_strike  = sell_strike + dist_between_strikes

    return (buy_strike, sell_strike)

def get_vertical_result(df, kind, buy_strike, sell_strike):

    # Open Vertical
    df = df.sort_values('date', ascending=True)

    stock_price = df['close_underlying'].values[0]
    buy_price   = df[(df['strike'] == buy_strike)  & (df['kind'] == kind)]['close'].values[0]
    sell_price  = df[(df['strike'] == sell_strike) & (df['kind'] == kind)]['close'].values[0]

    open_cost  = -100 * buy_price
    open_cost +=  100 * sell_price
    open_cost *= CONTRACTS

    if DEBUG:
        tqdm.write(f' OPEN {kind} ({stock_price:6.2f}): SELL {sell_strike} @ {sell_price:6.2f} -  BUY {buy_strike} @ {buy_price:6.2f} - TOTAL: {(-buy_price + sell_price):6.2f}')

    # Close Vertical (Prices are 0 if they are OTM/ATM or the difference between the strike and the underlying's close price if they are ITM)
    stock_price = df['close_underlying'].values[-1]
    sell_price = 0 if (kind == 'P' and buy_strike <= stock_price) or (kind == 'C' and buy_strike >= stock_price) else abs(buy_strike - stock_price)
    buy_price = 0 if (kind == 'P' and sell_strike <= stock_price) or (kind == 'C' and sell_strike >= stock_price) else abs(sell_strike - stock_price)

    if DEBUG:
        tqdm.write(f'CLOSE {kind} ({stock_price:6.2f}):  BUY {sell_strike} @ {buy_price:6.2f} - SELL {buy_strike} @ {sell_price:6.2f} - TOTAL: {(-buy_price + sell_price):6.2f}')

    close_cost = -100 * buy_price
    close_cost += 100 * sell_price
    close_cost *= CONTRACTS

    if DEBUG:
        tqdm.write(f'**************** Processed Date: {df["date"].dt.date.values[0]} - Result: {open_cost + close_cost:8.2f} ****************')

    return open_cost + close_cost

Then. we define some helper functions that perform various calculations and operations related to the trading strategy. These functions include:

  • get_vertical_option_kind: Determines whether to open a Call or Put vertical spread based on changes in the underlying asset's price.
  • get_vertical_strikes: Calculates the strike prices for the vertical spread.
  • get_vertical_result: Calculates the result after opening and closing the vertical spread.

These functions play a crucial role in executing and evaluating the trading strategy.

Step 4: Reading the Data

### Read File ###
df = pd.read_csv(OPTIONS_FILE, header=0)
df['date'] = pd.to_datetime(df['date'])

In this step, the code reads the options data from the CSV file specified in OPTIONS_FILE into a pandas DataFrame (df). It also converts the 'date' column to datetime format for date manipulation.

Step 5: Getting Expiration Dates

### Get all the expiration dates ###
expirations = df['expire_date'].unique().tolist()

This code extracts all unique expiration dates from the DataFrame and stores them in a list called expirations. These dates represent the various expiration dates of the options contracts in the dataset.

Step 6: Calculating Profit and Loss (P&L) by Day

pnl = []
df_trend = df[(df.date.dt.hour < HOUR_OPEN) | ((df.date.dt.hour == HOUR_OPEN) & (df.date.dt.minute < MINUTE_OPEN))]
df_cost = df[(df.date.dt.hour > HOUR_OPEN) | ((df.date.dt.hour == HOUR_OPEN) & (df.date.dt.minute >= MINUTE_OPEN))]
df_open = df_cost[(df_cost.date.dt.hour == HOUR_OPEN) & (df_cost.date.dt.minute == MINUTE_OPEN)]

for expiration in tqdm(expirations):

    try:
        kind = get_vertical_option_kind(df_trend[df_trend['expire_date'] == expiration], MAX_CHANGE_BEARISH, MIN_CHANGE_BULLISH)

        if kind == '':
            if DEBUG:
                tqdm.write(f'**************** Processed Date: {expiration} - Result: -- NA -- ****************')

            continue

        (buy_strike, sell_strike) = get_vertical_strikes(df_open[df_open['expire_date'] == expiration], kind, STRIKES, DIST_BETWEEN_STRIKES)
        result = get_vertical_result(df_cost[df_cost['expire_date'] == expiration], kind, buy_strike, sell_strike)

        pnl.append([expiration, result])

    except Exception as ex:
        continue

In this part, the code iterates through each expiration date stored in expirations. Within the loop, it does the following:

  • Calls the get_vertical_option_kind function to determine whether to open a Call or Put vertical spread based on market conditions.
  • Calculates the strike prices for the vertical spread using the get_vertical_strikes function.
  • Calculates the cost of opening and closing the vertical spread using the get_vertical_cost function.

The calculated costs and other information are appended to the pnl list.

Step 7: Generating Results

# Calculate Net Result
df_result = pd.DataFrame(pnl, columns=['expire_date','gross_result'])
df_result['net_result'] = df_result['gross_result'] - CONTRACTS * FEES_PER_CONTRACT * 2 # Let them expire
df_result['wins'] = np.where(df_result['net_result'] > 0, 1, 0)
df_result['losses'] = np.where(df_result['net_result'] < 0, 1, 0)

In this step, the code creates a DataFrame df_result to store the calculated results. It calculates the net result by subtracting fees for opening and closing the contracts. It also categorizes each result as a win or loss based on whether the net result is positive or negative.

Step 8: Displaying Results

# Show the parameters
print(f' PARAMETERS '.center(70, '*'))
print(f'* Hour Open: {HOUR_OPEN}')
print(f'* Minute Open: {MINUTE_OPEN}')
print(f'* Strikes From Price: {STRIKES}')
print(f'* Distance Between Strikes: {DIST_BETWEEN_STRIKES}')
print(f'* Max % Change To Open A Bearish Trade: {MAX_CHANGE_BEARISH}')
print(f'* Min % Change To Open A Bullish Trade: {MIN_CHANGE_BULLISH}')

# Show the Total Result
print(f' SUMMARIZED RESULT '.center(70, '*'))
print(f'* Trading Days: {len(df_result)}')
print(f'* Gross PnL: $ {df_result["gross_result"].sum():.2f}')
print(f'* Net PnL: $ {df_result["net_result"].sum():.2f}')
print(f'* Win Rate: {100 * (df_result["wins"].sum() / (df_result["wins"].sum() + df_result["losses"].sum())):.2f} %')

# Show The Monthly Result
print(f' MONTHLY DETAIL RESULT '.center(70, '*'))
df_monthly = df_result[['expire_date','gross_result','net_result','wins','losses']]
df_monthly['year_month'] = df_monthly['expire_date'].str[0:7]
df_monthly = df_monthly.drop('expire_date', axis=1)
df_monthly = df_monthly.groupby(['year_month']).sum()

print(df_monthly)

Finally, the code prints out the summarized results of the trading strategy, including parameters, total results, and monthly detailed results. These results provide insights into the performance of the strategy over the specified time period.

Results

***************************** PARAMETERS *****************************
* Hour Open: 10
* Minute Open: 30
* Strikes From Price: 1
* Distance Between Strikes: 2
* Max % Change To Open A Bearish Trade: -0.35
* Min % Change To Open A Bullish Trade: 0.35
************************* SUMMARIZED RESULT **************************
* Trading Days: 130
* Gross PnL: $ 32510.10
* Net PnL: $ 30950.10
* Win Rate: 80.77 %
*********************** MONTHLY DETAIL RESULT ************************
            gross_result  net_result  wins  losses
year_month
2021-06            260.0       248.0     1       0
2021-07            780.0       732.0     3       1
2021-08            440.0       416.0     2       0
2021-09           2230.1      2170.1     5       0
2021-10          -3480.0     -3540.0     2       3
2021-11          -2710.0     -2734.0     0       2
2021-12           1980.0      1920.0     4       1
2022-01            180.0       144.0     2       1
2022-02           2350.0      2314.0     3       0
2022-03           1990.0      1918.0     5       1
2022-04           2250.0      2178.0     5       1
2022-05           3390.0      3294.0     7       1
2022-06           3390.0      3282.0     7       2
2022-07           1500.0      1464.0     3       0
2022-08           2250.0      2202.0     4       0
2022-09            870.0       774.0     6       2
2022-10           1090.0      1006.0     5       2
2022-11            520.0       472.0     3       1
2022-12           1740.0      1596.0     9       3
2023-01           1620.0      1572.0     4       0
2023-02            730.0       658.0     4       2
2023-03           3460.0      3376.0     6       1
2023-04           1760.0      1700.0     5       0
2023-05           3530.0      3422.0     8       1
2023-06            390.0       366.0     2       0

This trading strategy, which involves trading options on SPY with specific parameters and rules, has shown promising results over the analyzed period. Here are some key takeaways:

Overall Profitability: The strategy has generated a gross profit of $32,510.10 over the course of 130 trading days. After accounting for fees, the net profit stands at $30,950.10.

Win Rate: The strategy exhibits a relatively high win rate of 80.77%. This suggests that a significant majority of trades have been profitable.

Monthly Performance: The strategy’s performance varies from month to month. While there are months with losses, many months have more wins than losses, contributing to the overall profitability.

Risk Management: The defined parameters for opening bearish or bullish trades based on percentage changes appear to have contributed to the strategy’s success.

Conclusion

In conclusion, the results of the backtest for the trading strategy involving options on SPY appear to be very promising. The analysis conducted here was developed in good faith, using historical data and well-defined parameters to assess the strategy’s performance over a significant period.

However, it’s essential to acknowledge that trading and investing carry inherent risks, and past performance may not necessarily predict future outcomes. Market conditions can change, and unexpected events can impact trading strategies.

Therefore, while the results look interesting, we encourage readers to do more tests on this strategy. Please, if you identify any discrepancies, potential improvements, or areas that require further clarification, we welcome your input and feedback. Open dialogue and continuous refinement are integral to successful trading strategies, and we remain open to making any necessary adjustments to enhance the accuracy and reliability of this analysis.

See you soon and Happy Trading…

If you enjoy my work, please support me on Medium by becoming a member through my referral link, and consider giving it a clap (or many?) as a small gesture of motivation. Thank you!

Download the full source code and the colab notebook of this article from here

X (Twitter): https://x.com/diegodegese LinkedIn: https://www.linkedin.com/in/ddegese Github: https://github.com/crapher

Disclaimer: Investing in the stock market involves risk and may not be suitable for all investors. The information provided in this article is for educational purposes only and should not be construed as investment advice or a recommendation to buy or sell any particular security. Always do your own research and consult with a licensed financial advisor before making any investment decisions. Past performance is not indicative of future results.

Subscribe to DDIntel Here.

Have a unique story to share? Submit to DDIntel here.

Join our creator ecosystem here.

DDIntel captures the more notable pieces from our main site and our popular DDI Medium publication. Check us out for more insightful work from our community.

DDI Official Telegram Channel: https://t.me/+tafUp6ecEys4YjQ1

Follow us on LinkedIn, Twitter, YouTube, and Facebook.

Options Strategy
Backtesting
Stock Market
Credit Spreads
Data Analysis
Recommended from ReadMedium