在绘图上放置一个标记

数据挖掘 Python matplotlib
2022-02-11 16:45:18

我想在情节上放置一个呼叫标记。每当较小的移动平均线 (21) 越过较长的移动平均线 (34) 时,看涨期权应该是“买入”,而每当较小的移动平均线穿过较长的移动平均线时,看涨期权应该是“卖出”。

我有一列平均价格。我使用该rolling()函数计算了 21 天和 34 天的滚动平均值,并使用 matplotlib 绘制了所有三列的线图:平均价格、sma_21 和 sma_34。我想在情节上放置一个标记。

如果较小的移动平均线 (21) 与较长的移动平均线 (34) 交叉,我需要放置这个制造商“^”,如果较小的移动平均线穿过较长的移动平均线,我需要放置这个制造商“v”。

averageprice = [
    2352.6, 2410.26, 2443.31, 2525.78, 2506.58, 2530.69, 2530.49, 2545.01,
    2605.4, 2593, 2577.65, 2554.74, 2549.69, 2552.85, 2568.84, 2577.2,
    2693.18, 2624.95, 2543.44, 2513.28, 2487.48, 2464.89, 2469.41, 2427.94,
    2402.96, 2430.5, 2427.14, 2412.24, 2403.02, 2388.78, 2357.33, 2345.89,
    2342.52, 2361.01, 2368.46, 2366.9, 2354.42, 2348.75, 2343.49, 2426.54,
    2478.13, 2453.34, 2449.5, 2396.18, 2402.63
]
avg_p = df['Average Price'] 
sma21 = avg_p.rolling(window = 21).mean() 
sma34 = avg_p.rolling(window = 34).mean()
avg_p.plot() 
x = df.index 
f = sma21 
g = sma34 
plt.plot(x, f) 
plt.plot(x, g) 
idx = np.argwhere(np.diff(np.sign(f - g))).flatten() 
plt.plot(x[idx], f[idx], '^') 
plt.show() 

我使用此代码获取交点并放置标记

idx = np.argwhere(np.diff(np.sign(f - g))).flatten()

并得到这样的情节:

在此处输入图像描述

我需要得到看起来像这样的标记:

在此处输入图像描述

2个回答

根据一些标准,我能够为每个点生成以下标记:

基于正弦高于余弦的标记

我制作了一个虚拟的 Pandas 数据框,使用正弦和余弦得到很好地相互交叉的线条;还使索引本身成为一列(带有reset_index)只是为了使以后的绘图更容易。

df = pd.DataFrame.from_dict(dict(sin=np.sin(np.linspace(0, 2*np.pi, 50)),
                             cos=np.cos(np.linspace(0, 2*np.pi, 50))))
df.index.name = "index"
df.reset_index(inplace=True)
df.head(5)

  index sin        cos
0   0   0.000000    1.000000
1   1   0.063424    0.997987
2   2   0.126592    0.991955
3   3   0.189251    0.981929
4   4   0.251148    0.967949

我创建了一个包含您想要的标准的新列,因此如果一行高于或低于另一行:

df["criteria"] = df.sin > df.cos    # where sin values are higher than cos values

这将允许我们选择使用哪种样式(例如,哪种标记)来绘制哪些点。

最终图本身由两部分组成(请注意,我们重复使用相同的ax对象,因此所有图都出现在同一张图上)

  1. 可以添加基础数据本身来创建简单的线条(这些是您的移动平均列)。

    ax = df.sin.plot(c="gray", figsize=(10, 6))    # plots the sine curve in gray
    df.cos.plot(c="cyan", ax=ax)                   # re-uses the ax object - important!
    
  2. 标记,基于我们的criteria专栏。我们过滤满足我们标准的点并用某个标记绘制它们,然后过滤符合标准的点(使用否定选择器:)~虽然我们使用了plot上面的基本线,但我们现在需要使用scatter这种情节:

    df[df.criteria].plot(kind="scatter", x="index", y="sin",
                         c="green", marker="^", ax=ax, label="higher")
    
    df[~df.criteria].plot(kind="scatter", x="index", y="sin",
                         c="red", marker="v", ax=ax, label="lower");
    

    请注意,我们继续使用相同的ax对象。

我们还可以添加图例,它默认使用 Pandas 列名称或label在每个绘图方法中传递的名称:

plt.legend()="lower");    # adds legend for all plots

您可以在matplotlib 文档中看到有一个marker参数,但似乎您不能简单地指定 Pandas 数据框的一列来为每个单独的点提供标记。

只需找到这两个数据的交集并施加大于和小于的条件,然后找到它们的索引并绘制它。

ndf = pd.read_csv('Nifty50.csv')
ndf.Date = pd.to_datetime(ndf['Date'])

fig, ax = plt.subplots(figsize=(15, 5))
ndf['roll21'] = ndf['Close'].rolling(21).mean()
ndf['roll34'] = ndf['Close'].rolling(34).mean()
ndf.dropna()

def whenCrosses(values):
    l=[]
    were = values[0]
    flag = True
    for i, ele in enumerate(values):
        if were==ele:
            l.append(0)
        else:
            l.append(1)
            were = ele
    return l

ndf['buy'] = ndf['roll34']<ndf['roll21']
ndf['sell'] = ndf['roll34']>ndf['roll21']

ndf['buy_change'] = np.array(whenCrosses(ndf.buy.values.reshape(1, len(ndf.buy)).flatten()))
ndf['sell_change'] = np.array(whenCrosses(ndf.sell.values.reshape(1, len(ndf.sell)).flatten()))

ndf['buy'] = ndf['buy_change'].where(ndf['buy']==True)
ndf['buy'] = ndf['roll21'].where(ndf['buy']==1)

ndf['sell'] = ndf['sell_change'].where(ndf['sell']==True)
ndf['sell'] = ndf['roll21'].where(ndf['sell']==1)

ax.plot(ndf.Date, ndf.Close, 'r')
ax.plot(ndf.Date, ndf.roll34, 'b', label='34_SMA')
ax.plot(ndf.Date, ndf.roll21, 'g', label='21_SMA')
ax.plot(ndf.Date, ndf.buy, "g^")
ax.plot(ndf.Date, ndf.sell, "kv")

ax.set_xlabel('Date')
plt.legend(loc=2)
plt.tight_layout()
plt.xticks(plt.xticks()[0], df.index.date, rotation=45)
plt.show()

你应该得到- 在此处输入图像描述