英文:
Matplotlib plot market between ticks (X axis)
问题
I'm calculating 2 moving averages from a stock price and finding if they crossed over. When they crossover, I want to show in the graph a marker on top of it.
To find the crossovers, I'm using this code:
idxs = np.argwhere(np.diff(df_status)).flatten()
where df_status is a list with -1, 0 and 1 from the two moving averages. The idxs gives me the index position from df_status where the crossover happened.
The problem is when the cross is between 2 dates, as seen in the picture below:
How can I move the marker to be centered on the crossover than in the date that it was detected?
Code to reproduce:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
data = [
["2019-12-16", 4.39, 4.02, 5.11],
["2019-12-17", 4.42, 4.08, 5.09],
["2019-12-18", 4.2, 4.11, 5.06],
["2019-12-19", 4.57, 4.18, 5.04],
["2019-12-20", 4.85, 4.27, 5.03],
["2019-12-23", 4.95, 4.36, 5.01],
["2019-12-26", 5.8, 4.54, 5.01],
["2019-12-27", 6.0, 4.74, 5.01],
["2019-12-30", 5.9, 4.92, 5.0],
["2020-01-02", 6.02, 5.11, 5.00]
]
columns = ["day", "price", "SMA_10", "SMA_100"]
df = pd.DataFrame(data, columns=columns)
df['status_SMA_10_SMA_100'] = np.sign(df['SMA_10'] - df['SMA_100'])
idxs = np.argwhere(np.diff(df['status_SMA_10_SMA_100'])).flatten() # get crossovers
fig = plt.figure(figsize=[15, 8])
ax = fig.gca()
plt.grid(True)
plt.plot(df['day'], df['price'])
plt.plot(df['day'], df['SMA_10'])
plt.plot(df['day'], df['SMA_100'])
for marker in idxs:
ax.plot(df['day'][marker + 1], df['SMA_100'][marker + 1], marker='o', markersize=35, alpha=.5)
plt.show()
In this code, the crossover is at index 8, but the crossover happens in the graph between indexes 8 and 9. How can I position the marker between the two X ticks?
英文:
I'm calculating 2 moving averages from a stock price and finding if they crossed over. When they crossover, I want to show in the graph a marker on top of it.
To find the crossovers, I'm using this code:
idxs = np.argwhere(np.diff(df_status)).flatten()
where df_status is a list with -1, 0 and 1 from the two moving averages. The idxs gives me the index position from df_status where the crossover happened.
The problem is when the cross is between 2 dates, as seen in the picture below:
How can I move the marker to be centered on the crossover than in the date that it was detected?
Code to reproduce:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
data = [
["2019-12-16", 4.39, 4.02, 5.11],
["2019-12-17", 4.42, 4.08, 5.09],
["2019-12-18", 4.2, 4.11, 5.06],
["2019-12-19", 4.57, 4.18, 5.04],
["2019-12-20", 4.85, 4.27, 5.03],
["2019-12-23", 4.95, 4.36, 5.01],
["2019-12-26", 5.8, 4.54, 5.01],
["2019-12-27", 6.0, 4.74, 5.01],
["2019-12-30", 5.9, 4.92, 5.0],
["2020-01-02", 6.02, 5.11, 5.00]
]
columns = ["day", "price", "SMA_10", "SMA_100"]
df = pd.DataFrame(data, columns=columns)
df['status_SMA_10_SMA_100'] = np.sign(df['SMA_10'] - df['SMA_100'])
idxs = np.argwhere(np.diff(df['status_SMA_10_SMA_100'])).flatten() # get crossovers
fig = plt.figure(figsize=[15, 8])
ax = fig.gca()
plt.grid(True)
plt.plot(df['day'], df['price'])
plt.plot(df['day'], df['SMA_10'])
plt.plot(df['day'], df['SMA_100'])
for marker in idxs:
ax.plot(df['day'][marker], df['SMA_100'][marker], marker='o', markersize=35, alpha=.5)
ax.plot(df['day'][marker + 1], df['SMA_100'][marker], marker='o', markersize=35, alpha=.5)
plt.show()
In this code, the crossover is at index 8, but the crossover happen in the graph between indexes 8 and 9. How can I position the marker between the two X ticks?
答案1
得分: 2
IIUC,要找到交叉点 'SMA_10' 和 'SMA_100',请尝试以下代码:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
data = [
["2019-12-16", 4.39, 4.02, 5.11],
["2019-12-17", 4.42, 4.08, 5.09],
["2019-12-18", 4.2, 4.11, 5.06],
["2019-12-19", 4.57, 4.18, 5.04],
["2019-12-20", 4.85, 4.27, 5.03],
["2019-12-23", 4.95, 4.36, 5.01],
["2019-12-26", 5.8, 4.54, 5.01],
["2019-12-27", 6.0, 4.74, 5.01],
["2019-12-30", 5.9, 4.92, 5.0],
["2020-01-02", 6.02, 5.11, 5.00]
]
columns = ["day", "price", "SMA_10", "SMA_100"]
df = pd.DataFrame(data, columns=columns)
df['status_SMA_10_SMA_100'] = np.sign(df['SMA_10'] - df['SMA_100'])
idxs = np.argwhere(np.diff(df['status_SMA_10_SMA_100'])).flatten() # 获取交叉点
fig = plt.figure(figsize=[15, 8])
ax = fig.gca()
plt.grid(True)
plt.plot(df['day'], df['price'])
plt.plot(df['day'], df['SMA_10'])
plt.plot(df['day'], df['SMA_100'])
s = (df['SMA_10'] - df['SMA_100']).reset_index().set_index(0)
xmarker = s.reindex(s.index.union([0])).interpolate(method='index').loc[0.00].values
ymarker = df['SMA_10'].reindex(df.index.union(xmarker)).interpolate(method='index').loc[xmarker].values
ax.plot(xmarker, ymarker, marker='o', markersize='35', alpha=.5)
# for marker in idxs:
# ax.plot(df['day'][marker], df['SMA_100'][marker], marker='o', markersize=35, alpha=.5)
# ax.plot(df['day'][marker + 1], df['SMA_100'][marker], marker='o', markersize=35, alpha=.5)
plt.show()
输出结果:
英文:
IIUC, to find crossover 'SMA_10' and 'SMA_100' try this:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
data = [
["2019-12-16", 4.39, 4.02, 5.11],
["2019-12-17", 4.42, 4.08, 5.09],
["2019-12-18", 4.2, 4.11, 5.06],
["2019-12-19", 4.57, 4.18, 5.04],
["2019-12-20", 4.85, 4.27, 5.03],
["2019-12-23", 4.95, 4.36, 5.01],
["2019-12-26", 5.8, 4.54, 5.01],
["2019-12-27", 6.0, 4.74, 5.01],
["2019-12-30", 5.9, 4.92, 5.0],
["2020-01-02", 6.02, 5.11, 5.00]
]
columns = ["day", "price", "SMA_10", "SMA_100"]
df = pd.DataFrame(data, columns=columns)
df['status_SMA_10_SMA_100'] = np.sign(df['SMA_10'] - df['SMA_100'])
idxs = np.argwhere(np.diff(df['status_SMA_10_SMA_100'])).flatten() # get crossovers
fig = plt.figure(figsize=[15, 8])
ax = fig.gca()
plt.grid(True)
plt.plot(df['day'], df['price'])
plt.plot(df['day'], df['SMA_10'])
plt.plot(df['day'], df['SMA_100'])
s = (df['SMA_10'] - df['SMA_100']).reset_index().set_index(0)
xmarker = s.reindex(s.index.union([0])).interpolate(method='index').loc[0.00].values
ymarker = df['SMA_10'].reindex(df.index.union(xmarker)).interpolate(method='index').loc[xmarker].values
ax.plot(xmarker, ymarker, marker='o', markersize='35', alpha=.5)
# for marker in idxs:
# ax.plot(df['day'][marker], df['SMA_100'][marker], marker='o', markersize=35, alpha=.5)
# ax.plot(df['day'][marker + 1], df['SMA_100'][marker], marker='o', markersize=35, alpha=.5)
plt.show()
Output:
答案2
得分: 1
使用 @ScottBoston 的建议,我提出了这个解决方案,可以处理单个和多个交叉点:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
def getAxisPositionForCrosses(index_position, df):
qtt_points = 10
ma1 = [np.nan] * qtt_points
ma1[0] = df.loc[index_position]['SMA_10']
ma1[qtt_points - 1] = df.loc[index_position + 1]['SMA_10']
ma2 = [np.nan] * qtt_points
ma2[0] = df.loc[index_position]['SMA_100']
ma2[qtt_points - 1] = df.loc[index_position + 1]['SMA_100']
df_cross = pd.DataFrame({'ma1': ma1, 'ma2': ma2})
df_cross = df_cross.interpolate(method='index')
df_cross['diff'] = df_cross['ma1'] >= df_cross['ma2']
idxs_crosses = np.argwhere(np.diff(df_cross['diff'])).flatten()
x_cross = index_position + 1/idxs_crosses[0]
return {'x': x_cross, 'y': df_cross.loc[idxs_crosses[0]]['ma2']}
data = [
["2019-12-17", 8.54, 8.73, 8.68],
["2019-12-18", 8.4, 8.69, 8.66],
["2019-12-19", 8.41, 8.66, 8.65],
["2019-12-20", 8.09, 8.6, 8.62],
["2019-12-23", 8.4, 8.58, 8.61],
["2019-12-26", 8.25, 8.54, 8.58],
["2019-12-27", 8.42, 8.53, 8.58],
["2019-12-30", 8.78, 8.55, 8.59],
["2020-01-02", 8.97, 8.6, 8.61],
["2020-01-03", 9.27, 8.68, 8.65]
]
columns = ["day", "price", "SMA_10", "SMA_100"]
df = pd.DataFrame(data, columns=columns)
df['status_SMA_10_SMA_100'] = np.sign(df['SMA_10'] - df['SMA_100'])
# 获取交叉点
idxs = np.argwhere(np.diff(df['status_SMA_10_SMA_100'])).flatten()
cross_x = []
cross_y = []
for index in idxs:
cross = getAxisPositionForCrosses(index, df)
cross_x.append(cross['x'])
cross_y.append(cross['y'])
fig = plt.figure(figsize=[15, 8])
ax = fig.gca()
plt.grid(True)
plt.plot(df['day'], df['price'])
plt.plot(df['day'], df['SMA_10'])
plt.plot(df['day'], df['SMA_100'])
ax.plot([cross_x], [cross_y], marker='o', markersize='35', alpha=.5)
plt.show()
英文:
Using @ScottBoston suggestion, I came up with this solution that works with single and multiple crossovers:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
def getAxisPositionForCrosses(index_position, df):
qtt_points = 10
ma1 = [np.nan] * qtt_points
ma1[0] = df.loc[index_position]['SMA_10']
ma1[qtt_points - 1] = df.loc[index_position + 1]['SMA_10']
ma2 = [np.nan] * qtt_points
ma2[0] = df.loc[index_position]['SMA_100']
ma2[qtt_points - 1] = df.loc[index_position + 1]['SMA_100']
df_cross = pd.DataFrame({'ma1': ma1, 'ma2': ma2})
df_cross = df_cross.interpolate(method='index')
df_cross['diff'] = df_cross['ma1'] >= df_cross['ma2']
idxs_crosses = np.argwhere(np.diff(df_cross['diff'])).flatten()
x_cross = index_position + 1/idxs_crosses[0]
return {'x': x_cross, 'y': df_cross.loc[idxs_crosses[0]]['ma2']}
data = [
["2019-12-17", 8.54, 8.73, 8.68],
["2019-12-18", 8.4, 8.69, 8.66],
["2019-12-19", 8.41, 8.66, 8.65],
["2019-12-20", 8.09, 8.6, 8.62],
["2019-12-23", 8.4, 8.58, 8.61],
["2019-12-26", 8.25, 8.54, 8.58],
["2019-12-27", 8.42, 8.53, 8.58],
["2019-12-30", 8.78, 8.55, 8.59],
["2020-01-02", 8.97, 8.6, 8.61],
["2020-01-03", 9.27, 8.68, 8.65]
]
columns = ["day", "price", "SMA_10", "SMA_100"]
df = pd.DataFrame(data, columns=columns)
df['status_SMA_10_SMA_100'] = np.sign(df['SMA_10'] - df['SMA_100'])
# get crossovers
idxs = np.argwhere(np.diff(df['status_SMA_10_SMA_100'])).flatten()
cross_x = []
cross_y = []
for index in idxs:
cross = getAxisPositionForCrosses(index, df)
cross_x.append(cross['x'])
cross_y.append(cross['y'])
fig = plt.figure(figsize=[15, 8])
ax = fig.gca()
plt.grid(True)
plt.plot(df['day'], df['price'])
plt.plot(df['day'], df['SMA_10'])
plt.plot(df['day'], df['SMA_100'])
ax.plot([cross_x], [cross_y], marker='o', markersize='35', alpha=.5)
plt.show()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论