"""
Option Date Utilities
=====================
These are a collection of functions for determining
when the current options cycle expires (3rd Friday of most months)
and for calculating historical option expiration dates.
.. tip:: If you need to automate looking up the current option
cycle expiration, then please checkout using the script:
::
/opt/sa/analysis_engine/scripts/print_next_expiration_date.py
2018-10-19
"""
import datetime
import pandas.tseries.offsets as pd_bday
import analysis_engine.holidays as hdays
import spylunking.log.setup_logging as log_utils
log = log_utils.build_colorized_logger(name=__name__)
[docs]def get_options_for_years(
years=[
'2014',
'2015',
'2016',
'2016',
'2017',
'2018',
'2019',
'2020',
'2021',
'2022',
]):
"""get_options_for_years
:param years: number of years back
:param months: number of months to build year
"""
entities = []
months = [
'01',
'02',
'03',
'04',
'05',
'06',
'07',
'08',
'09',
'10',
'11',
'12'
]
option_expirations = {
}
opts = []
for year in years:
for month in months:
target_date_str = str(month + '-01-' + year)
target_date = datetime.datetime.strptime(
target_date_str,
'%m-%d-%Y')
option_expiration_date = option_expiration(
target_date)
option_expiration_str = option_expiration_date.strftime(
'%m-%d-%Y')
option_expirations[option_expiration_str] = option_expiration_date
opts.append(option_expiration_date.strftime(
'%m-%d-%Y'))
# end of for all months
# end of building option expiration dates
now = datetime.datetime.now() + datetime.timedelta(days=0)
num_legs = 20
num_done = 1
last_exp_date = 0
date_format = '%m-%d-%Y'
str_output = now.strftime(date_format)
log.info(f'current date={str_output}')
entities.append(str_output)
for option_exp in opts:
option_exp_date = datetime.datetime.strptime(
option_exp,
date_format)
if option_exp_date >= now:
if num_legs > 0:
if (last_exp_date == 0):
delta = (option_exp_date - now).days
else:
delta = (option_exp_date - last_exp_date).days
entities.append(str(delta))
entities.append(option_exp_date.strftime('%m-%d-%Y'))
entities.append('Leg ' + str(num_done))
else:
break
num_legs -= 1
num_done += 1
last_exp_date = option_exp_date
# end of processing
return entities
# end of get_options_for_years
[docs]def historical_options(
years=[
'2014',
'2015',
'2016',
'2017',
'2018',
'2019',
'2020',
'2021',
'2022',
'2023',
'2024',
'2025',
'2026',
'2027',
'2028'
]):
"""historical_options
:param years: years to build
"""
entities = []
months = [
'01',
'02',
'03',
'04',
'05',
'06',
'07',
'08',
'09',
'10',
'11',
'12'
]
option_expirations = {
}
opts = []
for year in years:
for month in months:
target_date_str = str(month + '-01-' + year)
target_date = datetime.datetime.strptime(
target_date_str,
'%m-%d-%Y')
option_expiration_date = option_expiration(
target_date)
option_expiration_str = option_expiration_date.strftime(
'%m-%d-%Y')
option_expirations[option_expiration_str] = option_expiration_date
opts.append(option_expiration_date.strftime(
'%m-%d-%Y'))
# end of for all months
# end of building option expiration dates
now = datetime.datetime.strptime('01-01-2009', '%m-%d-%Y')
num_legs = 400
num_done = 1
date_format = '%m-%d-%Y'
for option_exp in opts:
option_exp_date = datetime.datetime.strptime(option_exp, date_format)
if option_exp_date >= now:
if num_legs > 0:
entities.append(option_exp_date.strftime('%m-%d-%Y'))
else:
break
num_legs -= 1
num_done += 1
# end of processing
return entities
# end of historical_options
[docs]def get_options_between_dates(
start_date,
end_date):
"""get_options_between_dates
:param start_date: start date
:param end_date: end date
"""
valid_options = []
for rec in historical_options():
opt_date = datetime.datetime.strptime(
str(rec),
'%m-%d-%Y').date()
if start_date <= opt_date <= end_date:
valid_options.append(opt_date.strftime('%Y-%m-%d'))
return valid_options
# end of get_options_between_dates
[docs]def option_expiration(
date=None):
"""option_expiration
:param date: date to find the current expiration
"""
cur_date = date
if not cur_date:
cur_date = datetime.datetime.now()
while (not (cur_date.weekday() == 4 and 14 < cur_date.day < 22)):
cur_date = cur_date + datetime.timedelta(days=1)
if hdays.is_holiday(
date=cur_date):
test_date = cur_date - datetime.timedelta(days=1)
if cur_date.weekday() == 0:
test_date = cur_date - datetime.timedelta(days=3)
if hdays.is_holiday(
date=test_date):
test_date = cur_date - datetime.timedelta(days=4)
if hdays.is_holiday(
date=test_date):
test_date = cur_date - datetime.timedelta(days=5)
cur_date = test_date
# end of if this date is a holiday and go back
return cur_date
# end of option_expiration
[docs]def get_options_for_today():
"""get_options_for_today
Get a list of option expiration nodes where the last cell
has the current option cycle's expiration date.
"""
cur_date = datetime.datetime.now()
cycle_exps = historical_options()
previous_exp = None
valid_option_exps = []
for idx, org_exp_date_str in enumerate(cycle_exps):
log.debug(f'cycle={idx} expiration={org_exp_date_str}')
exp_date = datetime.datetime.strptime(
org_exp_date_str,
'%m-%d-%Y')
exp_date_str = exp_date.strftime(
'%Y-%m-%d')
cycle_start_date = exp_date - pd_bday.BDay(19)
if previous_exp:
cycle_start_date = previous_exp + pd_bday.BDay(1)
cycle_start_date_str = cycle_start_date.strftime(
'%m-%d-%Y')
valid_option_exps.append({
'exp_date': exp_date,
'exp_date_str': exp_date_str,
'cycle_start': cycle_start_date,
'cycle_start_str': cycle_start_date_str
})
if cur_date < exp_date:
break
previous_exp = exp_date
# end of for all historical options
return valid_option_exps
# end of get_options_for_today