I have purshased the course on Machine Lerning for Options Trading. They have used the data of SPY. For the same program I have used the data of RELIANCE from yfinance and NSE Options data. I am getting error in MTM function. Below are the code snippet.
# Function to get the premium for an option contract
def get_premium(options_strategy, options_data):
# Create to condition to assure we choose the correct option strike price
strike = options_strategy['Strike Price']
# Create to condition to assure we choose the correct option type
option_type = options_strategy['Option Type']
# Return the last price of the option that complies with the above conditions
if option_type == 'CE':
return options_data[options_data['STRIKE'] == strike].C_LAST
if option_type == 'PE':
return options_data[options_data['STRIKE'] == strike].P_LAST
return 0
def setup_call_spread(options_data, strike_difference=20):
# Create a dataframe
call_spread = pd.DataFrame(columns=['Option Type', 'Strike Price', 'position', 'premium'])
underlying_price = options_data['UNDERLYING_LAST'][0]
# Calculate ATM strike price
atm_strike_price = strike_difference * (round(underlying_price / strike_difference))
# Set up first leg of the spread
call_spread.loc['0'] = ['CE', atm_strike_price, 1, np.nan]
# Append premium for the leg
call_spread['premium'] = call_spread.apply(lambda r: get_premium(r, options_data), axis=1)
# Define price deviation for next leg of spread
deviation = round(call_spread.premium.sum()*4 / strike_difference) * strike_difference
# Set up next leg of the spread
call_spread.loc['1'] = ['CE', atm_strike_price + deviation, -1, np.nan]
# Append respective premiums for the legs
call_spread['premium'] = call_spread.apply(lambda r: get_premium(r, options_data), axis=1)
return call_spread
# Create dataframes for round trips, storing trades, and mtm
round_trips_details = pd.DataFrame()
trades = pd.DataFrame()
mark_to_market = pd.DataFrame()
# Function for calculating mtm
def add_to_mtm(mark_to_market, option_strategy, trading_date):
option_strategy['Date'] = trading_date
mark_to_market = pd.concat([mark_to_market, option_strategy])
return mark_to_market
# Initialise current position, number of trades and cumulative pnl to 0
current_position = 0
trade_num = 0
cum_pnl = 0
# Set exit flag to False
exit_flag = False
# Set start date for backtesting
start_date = data.index[0] #.strftime('%Y-%m-%d')
#start_date = start_date.date() #.strftime('%Y-%m-%d')
for i in data.loc[start_date:].index:
if (current_position == 0) & (data.loc[i, 'signal'] != 0):
# Set up option spread strategy
try:
options_data_daily = options_data.loc[i]
except:
continue
# If signal is 1 we will set up bull call spread
if data.loc[i, 'signal'] == 1:
spread = setup_call_spread(options_data_daily, 10)
else:
continue
# Check that the last price of any of the leg of the spread should be greater than 0
if (spread.premium.isna().sum() > 0) or ((spread.premium == 0).sum() > 0):
print(
f"\x1b[31mStrike price not liquid so we will ignore this trading opportunity {i}\x1b[0m")
continue
# Populate the trades dataframe
trades = spread.copy()
trades['entry_date'] = i
trades.rename(columns={'premium': 'entry_price'}, inplace=True)
# Calculate net premium
net_premium = round((spread.position * spread.premium).sum(), 1)
# Compute SL and TP for the trade
premium_sign = np.sign(net_premium)
sl = net_premium * \
(1 - config['stop_loss_percentage']*premium_sign/100)
tp = net_premium * \
(1 + config['take_profit_percentage']*premium_sign/100)
# Update current position
current_position = data.loc[i, 'signal']
# Update mark_to_market dataframe
mark_to_market = add_to_mtm(mark_to_market, spread, i)
# Increase number of trades by 1
trade_num += 1
print("-"*30)
# Print trade details
print(
f"Trade No: {trade_num} | Entry | Date: {i} | Premium: {net_premium*-1} | Position: {current_position}")
elif current_position != 0:
# Update net premium
try:
options_data_daily = options_data.loc[i]
except:
continue
spread['premium'] = spread.apply(
lambda r: get_premium(r, options_data_daily), axis=1)
net_premium = (spread.position * spread.premium).sum()
# Update mark_to_market dataframe
mark_to_market = add_to_mtm(mark_to_market, spread, i)
# Exit the trade if any of the exit condition is met
if data.loc[i, 'signal'] != current_position:
exit_type = 'Expiry or Signal Based'
exit_flag = True
elif net_premium < sl:
exit_type = 'SL'
exit_flag = True
elif net_premium > tp:
exit_type = 'TP'
exit_flag = True
if exit_flag:
# Check that the data is present for all strike prices on the exit date
if spread.premium.isna().sum() > 0:
print(
f"Data missing for the required strike prices on {i}, Not adding to trade logs.")
current_position = 0
continue
# Append the trades dataframe
trades['exit_date'] = i
trades['exit_type'] = exit_type
trades['exit_price'] = spread.premium
# Add the trade logs to round trip details
round_trips_details = pd.concat([round_trips_details, trades])
# Calculate net premium at exit
net_premium = round((spread.position * spread.premium).sum(), 1)
# Calculate net premium on entry
entry_net_premium = (trades.position * trades.entry_price).sum()
# Calculate pnl for the trade
trade_pnl = round(net_premium - entry_net_premium, 1)
# Calculate cumulative pnl
cum_pnl += trade_pnl
cum_pnl = round(cum_pnl, 1)
# Print trade details
print(
f"Trade No: {trade_num} | Exit Type: {exit_type} | Date: {i} | Premium: {net_premium} | PnL: {trade_pnl} | Cum PnL: {cum_pnl}")
# Update current position to 0
current_position = 0
# Set exit flag to false
exit_flag = False
# Calculate net premium based on positions
mark_to_market['net_premium'] = mark_to_market.position * \
mark_to_market.premium
# Strategy analytics
analytics = pd.DataFrame()
analytics['change_in_pnl'] = mark_to_market.groupby(
'Date').net_premium.sum().diff()
ana