Matplotlib 没有填满整个区域

Matplotlib not filling full area

我似乎无法弄清楚为什么 python 没有填充从 'Strike' 到 'Break Even'(红色)和 'Break Even' 到 21(绿色的)。我认为设置 'where = price>=break_even' 会允许这样做。在我执行以下代码以根据行使价为价格提供范围后发生错误。

display_range1 = strike*.9
display_range2 = strike*1.2
price = np.arange(display_range1, display_range2)

Graph Output

import pandas as pd
from pandas import DataFrame
import matplotlib
import matplotlib.pyplot as plt
import numpy as np

symbol = 'Stock'
option_type = 'Call'
expiry = 'March 17, 2020'
strike = 20.00
IV = 120.625
premium = .54
contracts = 1
break_even = strike+premium
display_range1 = strike*.9
display_range2 = strike*1.2
price = np.arange(display_range1, display_range2)


def long_call(price, strike, premium, contracts):
    P = (max(price - strike, 0) - premium)*(contracts*100)
    return P

def get_graph_value():
    graph_values = []
    for i in price:
        graph_values.append(long_call(i, strike, premium, contracts))
    return graph_values


fig, ax = plt.subplots()
ax.plot(price, get_graph_value())
ax.set(xlabel='Underlying Price ($)', ylabel='Profit/Loss ($)',
       title=str(symbol)+' '+str(option_type)+ ' Option Payoff')
ax.fill_between(price, get_graph_value(), where = price>=break_even, color='#3cb371')
ax.fill_between(price, get_graph_value(), where = price<=break_even, color ='#ff6347')
plt.axvline(break_even, color="black", label='Break Even' )
plt.axvline(strike, color="black", linestyle="--", label='Strike')
plt.legend()
plt.show()

其实你的代码没有任何问题!但是,存在分辨率问题:

where 参数允许 select 应包含 price 数组的哪些索引。现在,由于您的价格数组以 1 为步长递增,因此要包含的第一个值是 price[3],即 21。因此 fill_between 从 21 开始,就像您在图中观察到的那样。

要解决这个问题,您需要提高数据的分辨率。 在您的情况下,最好的选择是使用 and simply increase the resolution of your price variable by explicitly setting the step in numpy arange,例如

price = np.arange(display_range1, display_range2, 0.01)

如果由于某种原因无法提高 price 的分辨率,那么您可以随时通过以下方式提高 Profit/Loss 值的分辨率插值。这可能很棘手,特别是如果您的 get_graph_value 函数不是微不足道的。 幸运的是,您在此处给出的示例解决起来相当简单,因为这些值线性增加,我们可以在不通过线性插值逼近值的情况下获得更高的分辨率。 Numpy 通过提供允许计算分段线性插值的 np.interp 来覆盖您。

以下是使用 np.interp 解决分辨率问题的方法:

# ...
# nothing changes up to here:
def get_graph_value():
    graph_values = []
    for i in price:
        graph_values.append(long_call(i, strike, premium, contracts))
    # simply returning a numpy array here, makes things easier
    return np.array(graph_values)

def interpolated_values(values):
    """Do a piecewise linear interpolation between the elements of an array
    """
    # creating a 'high resolution' version of the price
    xvals = np.linspace(np.min(price), np.max(price), 1000)
    # now create 'high resolution' (interpolated) version of values
    yinterp = np.interp(xvals, price, values)
    # return both
    return xvals, yinterp

fig, ax = plt.subplots()
# ... simply replace the first fill_between call by these 2 lines:
xvals, yinterp = interpolated_values(get_graph_value())
ax.fill_between(xvals, yinterp, where = xvals>=break_even, color='#3cb371')

最后你会得到: