My aim is to first create two plots (which I correctly created), each of them representing the CDF of the number of Puts and Calls still open in the market. For each plot, I also wanted to draw the vertical line representing the 40% and 80% percentile.
However, the final aim is to merge the two plot and also add the respective vertical lines for both sides (here is the problem). This is what I did:
Creation of the two single plots (FIRST CALL):
plt.figure(figsize=(14, 6)) # Adjusting figure size
plt.bar(CALL.index, CALL['CDF'], width=0.5, color='lightgreen') # Using DataFrame index as x-axis ticks
plt.xlabel('STRIKE')
plt.ylabel('CDF')
plt.title('Cumulative Distribution Function (CDF) for CALL')
plt.xticks(CALL.index, CALL['STRIKE'], rotation=90) # Setting x-axis ticks to the Strike values with rotation
plt.grid(True)
# Find the nearest value to 40% in the 'Percentile' column
nearest_40_percentile_idx = (CALL['Percentile'] - 0.4).abs().idxmin()
nearest_40_percentile_strike = CALL.loc[nearest_40_percentile_idx, 'STRIKE']
# Add a vertical line at the corresponding 'Strike' value for 40th percentile
plt.axvline(x=nearest_40_percentile_idx, color='red', linestyle='--', label=f'Nearest to 40% ({nearest_40_percentile_strike})')
# Find the nearest value to 80% in the 'Percentile' column
nearest_80_percentile_idx = (CALL['Percentile'] - 0.8).abs().idxmin()
nearest_80_percentile_strike = CALL.loc[nearest_80_percentile_idx, 'STRIKE']
# Add a vertical line at the corresponding 'Strike' value for 80th percentile
plt.axvline(x=nearest_80_percentile_idx, color='blue', linestyle='--', label=f'Nearest to 80% ({nearest_80_percentile_strike})')
# Show legend
plt.legend()
plt.show()
The one of the PUT is basically the same, just with the df's name changed.
Now, I tried to merge them and plot the vertical lines in this way, but the graph is a mess:
res = pd.concat([CALL, PUT])
# Set different colors for CALL and PUT bars
colors = {1: 'lightgreen', 2: 'orange'}
# Plot the bar chart
plt.figure(figsize=(16, 6))
sns.barplot(x='Strike', y='CDF', data=res, hue='hue', palette=colors)
# Calculate the nearest strike values to the 40th and 80th percentiles for both CALL and PUT
nearest_40_percentile_idx_call = (CALL['Percentile'] - 0.4).abs().idxmin()
nearest_40_percentile_strike_call = CALL.loc[nearest_40_percentile_idx_call, 'Strike']
nearest_40_percentile_idx_put = (PUT['Percentile'] - 0.4).abs().idxmin()
nearest_40_percentile_strike_put = PUT.loc[nearest_40_percentile_idx_put, 'Strike']
# Add vertical lines at the corresponding strike values for the 40th and 80th percentiles
plt.axvline(x=nearest_40_percentile_idx_call, color='blue', linestyle='--', label=f'40% for CALL ({nearest_40_percentile_strike_call})')
plt.axvline(x=nearest_40_percentile_idx_put, color='green', linestyle='--', label=f'40% for PUT ({nearest_40_percentile_strike_put})')
# Set labels and title
plt.xlabel('Strike')
plt.ylabel('Cumulative Distribution Function (CDF)')
plt.title('CDF for CALL and PUT')
# Rotate x-axis labels for better readability
plt.xticks(rotation=60)
# Show legend
plt.legend()
# Show the plot
plt.show()
Any suggestion?
SOLUTION
The idea is to sorte all the strikes, which represent the x-axis and then, by defining the corresponding value of the strike in which I'd like to plot the vertical line, to find the corresponding index and then plot the line in that index.