Using Python to calculate days between news highs for a stock.

When it comes to swing trading stock options a trader needs to choose an option expiration date for their contracts. Choosing this date has often been brought with confusion and many traders often choose expiration’s that are too short on time.

One thing is for sure, when the options expire the contract is over. If you are an option buyer and your stock options expire out of the money, you lose. If you are an options seller, you may want your option contracts to expire out of the money. Regardless of which leg of the option game you play picking the correct expiration is probably one of the more challenging tasks related to options trading.

For me personally, I play both legs of the game. I sell option contracts on slower moving stocks and I buy long calls on the S&P 500 and Dow Jones Industrial ETFs. I wrote a Python program that tells me how many days it takes for a stock or ETF to reach new highs, from high to high. When I look at the chart that is produced I can get an idea on the average days to a new high and the longest number of days in the last 240 trading days that it took to reach a new high. This greatly helps me choose my expiration dates on options where I can’t afford premiums for longer expirations.

What I ended up finding out is that for DIA and SPY new highs are achieved on average every ten days with around fifty days being the longest. This tells me my expiration should be no shorter than fifty days.

I find it best to trade long LEAP options well into the money v.s. picking the shortest amount of time for expiration. The information output from this code is not intended to beused as a way to pick the shortest expiration possible. LEAPs are more expensive but more time means more opportunity for profits.

This code uses the alpaca.markets API.

from datetime import datetime, timedelta,timezone
import matplotlib.pyplot as plt
import requests
import sys
import mykeys
import statistics

start = datetime.now(timezone.utc) - timedelta(days=240)
start = start.isoformat('T')

end = datetime.now(timezone.utc) - timedelta(minutes=20)
end = end.isoformat('T')

endpoint = "https://data.alpaca.markets/v2"

symbol = sys.argv[1]

endpoint_bars = f"/stocks/{symbol}/bars"

path_str = f"/stocks/snapshots"

query = {"start":start, "end":end , "timeframe":"1Day", "limit": 240}

headers_str = {'APCA-API-KEY-ID': mykeys.KEY, 'APCA-API-SECRET-KEY': mykeys.SECRET_KEY,'Accept': 'application/json'}

try:
    response = requests.get(f"{endpoint}{endpoint_bars}",
            params=query,
            headers=headers_str
            )
    json = response.json()
    print(json)
except Exception as e:
    print(e)

bars = json["bars"]



start_data = []

start_data.append(0)

time_data = []

high_data = []

close_data = []

dip_data = []

data = []

last_high = bars[0]["h"]

last_low = bars[0]["l"]

start_date = bars[0]["t"]

start_close = bars[0]["c"]

day_counter = 0





for i,bar in enumerate(bars):
    t = bar["t"]
    c = bar["c"]
    h = bar["h"]
    l = bar["l"]
    v = bar["v"]
    
    datetime_obj =  datetime.strptime(t, '%Y-%m-%dT%H:%M:%SZ')
    
    dt = f"{datetime_obj.month}-{datetime_obj.day}-{datetime_obj.year}"
    
        

    if not start_date:
        start_date = t
        start_close = c
        last_low = l
        day_counter = day_counter + 1
        

    elif start_date != '' and c > last_high:
        
        dip = 100 - ((last_high / c) * 100)

        time_data.append(dt)
        dip_data.append(dip)
        high_data.append(h)
        close_data.append(c)
        data.append(day_counter)
        print(dt,h,day_counter,dip,last_low)       
        start_date = ''
        start_close = 0
        day_counter = 0
        last_high = h
      
    elif (i == (len(bars) - 1)):
        day_counter = day_counter + 1
        dip = 100 - ((c / high_data[-1]) * 100)
        time_data.append("CURRENT SWING")
        dip_data.append(dip)
        high_data.append(h)
        close_data.append(c)
        data.append(day_counter)
        print("CURRENT SWING",dt,h,day_counter,dip,last_low)
        start_date = ''
        start_close = 0
        day_counter = 0
        last_high = h
       
        
    else:
        if l < last_low:
            last_low = l
        day_counter = day_counter + 1




plt.rcParams.update({
    "lines.color": "white",
    "patch.edgecolor": "white",
    "text.color": "white",
    "axes.facecolor": "black",
    "axes.edgecolor": "lightgray",
    "axes.labelcolor": "white",
    "xtick.color": "white",
    "ytick.color": "white",
    "grid.color": "lightgray",
    "figure.facecolor": "black",
    "figure.edgecolor": "black",
    "savefig.facecolor": "black",
    "savefig.edgecolor": "black"})


#plt.xticks(rotation='vertical')

fig, axs = plt.subplots(1, 1,figsize=(14,8))

l = len(data) - 1

time_data.reverse()
high_data.reverse()
data.reverse()

axs.set_title(f"Days To New Highs For Symbol {symbol} ",color='white')
axs.set_facecolor('#000000')

axs.barh(time_data,data)

rects = axs.patches

labels = [f"label{i}" for i in range(len(rects))]

for i,rect in enumerate(rects):
    # Get X and Y placement
    x_value = rect.get_width()
    
    y_value = rect.get_y() + rect.get_height() / 2

    # Number of points between bar and label. Change to your liking.
    space = 5
    # Vertical alignment for positive values
    ha = 'left'

    # If value of bar is negative: Place label left of bar
    if x_value < 0:
        # Invert space to place label to the left
        space *= -1
        # Horizontally align label at right
        ha = 'right'


    label = f"{high_data[i]} - {data[i]} days."
    
    if (i == 0):
        text_color = "red"
    else:
        text_color = "green"

    plt.annotate(
        label,                      # Use `label` as label
        (x_value, y_value),         # Place label at end of the bar
        xytext=(space, 0),          # Horizontally shift label by `space`
        textcoords="offset points", # Interpret `xytext` as offset in points
        va='center',                # Vertically center label
        color=text_color,
        ha=ha)                      # Horizontally align label differently for
                                    # positive and negative values.

    axs.tick_params(axis='x', colors='red')
    
    axs.tick_params(axis='y', colors='green')

    axs.grid(True,color='#292b2e')

plt.show()

Leave a Reply

Your email address will not be published. Required fields are marked *