通道线、均线交叉、葛兰碧Granville买卖八法标注
#股票均线系统应用
import akshare as ak
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 获取股票数据
def get_stock_data(stock_code, start_date, end_date):
stock_df = ak.stock_zh_a_hist(symbol=stock_code, period="daily", start_date=start_date, end_date=end_date, adjust="qfq")
stock_df['日期'] = pd.to_datetime(stock_df['日期'])
stock_df.set_index('日期', inplace=True)
return stock_df
# 计算均线
def calculate_ma(data, ma_periods=[5, 10, 20, 30, 60, 120]):
for period in ma_periods:
data[f'MA{period}'] = data['收盘'].rolling(window=period).mean()
return data
# 识别均线多头排列
def identify_bullish_arrangement(data, ma_periods=[5, 10, 20, 30, 60, 120]):
ma_columns = [f'MA{period}' for period in ma_periods]
data['bullish_arrangement'] = (data[ma_columns].diff(axis=1).iloc[:, 1:] > 0).all(axis=1)
return data
# 识别均线交叉信号
def identify_ma_cross(data, short_ma=5, long_ma=20):
data['ma_cross'] = np.where(data[f'MA{short_ma}'] > data[f'MA{long_ma}'], 1, -1)
data['ma_cross_signal'] = data['ma_cross'].diff()
return data
# 计算葛兰碧八大法则买卖点
def granville_rules(data):
close = data['收盘']
ma = data['MA20']
data['buy_signal'] = 0
data['sell_signal'] = 0
# 法则 1: 均线从下降逐渐走平且略向上方抬头,而股价从均线下方向上方突破,为买进信号
data.loc[(ma.shift(1) < ma) & (close > ma) & (close.shift(1) <= ma.shift(1)), 'buy_signal'] = 1
# 法则 2: 股价位于均线之上运行,回档时未跌破均线后又再度上升时为买进时机
data.loc[(close > ma) & (close.shift(1) < ma) & (close > close.shift(1)), 'buy_signal'] = 1
# 法则 3: 股价位于均线之上运行,回档时跌破均线,但短期均线继续呈上升趋势,此时为买进时机
data.loc[(close < ma) & (close.shift(1) > ma) & (ma.shift(1) < ma), 'buy_signal'] = 1
# 法则 4: 股价位于均线以下运行,突然暴跌,距离均线太远,极有可能向均线靠近(物极必反,下跌反弹),此时为买进时机
data.loc[(close < ma) & ((ma - close) / ma > 0.1), 'buy_signal'] = 1
# 法则 5: 股价位于均线之上运行,连续数日大涨,离均线愈来愈远,说明近期内购买股票者获利丰厚,随时都会产生获利回吐的卖压,应暂时卖出持股
data.loc[(close > ma) & ((close - ma) / ma > 0.1), 'sell_signal'] = 1
# 法则 6: 均线从上升逐渐走平,而股价从均线上方向下跌破均线时说明卖压渐重,应卖出所持股票
data.loc[(ma.shift(1) > ma) & (close < ma) & (close.shift(1) >= ma.shift(1)), 'sell_signal'] = 1
# 法则 7: 股价位于均线下方运行,反弹时未突破均线,且均线跌势减缓,趋于水平后又出现下跌趋势,此时为卖出时机
data.loc[(close < ma) & (close.shift(1) > ma) & (ma.shift(1) > ma), 'sell_signal'] = 1
# 法则 8: 股价反弹后在均线上方徘徊,而均线却继续下跌,宜卖出所持股票
data.loc[(close > ma) & (ma.shift(1) > ma), 'sell_signal'] = 1
return data
# 计算均线通道策略
def calculate_ma_channel(data, ma_period=20):
ma = data[f'MA{ma_period}']
std = data['收盘'].rolling(window=ma_period).std()
data['upper_channel'] = ma + 2 * std
data['lower_channel'] = ma - 2 * std
return data
# 绘制图形
def plot_data(data, ma_periods, stock_code): # 添加 stock_code 参数
plt.figure(figsize=(16, 10))
plt.plot(data['收盘'], label='Close Price')
for period in ma_periods:
plt.plot(data[f'MA{period}'], label=f'MA{period}')
plt.plot(data['upper_channel'], label='Upper Channel', linestyle='--', color='r')
plt.plot(data['lower_channel'], label='Lower Channel', linestyle='--', color='g')
# 绘制均线交叉信号
buy_cross = data[data['ma_cross_signal'] == 2].index
sell_cross = data[data['ma_cross_signal'] == -2].index
plt.scatter(buy_cross, data.loc[buy_cross, '收盘'], marker='^', color='g', label='MA Cross Buy Signal')
plt.scatter(sell_cross, data.loc[sell_cross, '收盘'], marker='v', color='r', label='MA Cross Sell Signal')
# 绘制葛兰碧八大法则买卖点
buy_points = data[data['buy_signal'] == 1].index
sell_points = data[data['sell_signal'] == 1].index
plt.scatter(buy_points, data.loc[buy_points, '收盘'], marker='o', color='b', label='Granville Buy Signal')
plt.scatter(sell_points, data.loc[sell_points, '收盘'], marker='x', color='m', label='Granville Sell Signal')
plt.title(f'Stock Price with MA and Channel - Stock Code: {stock_code}') # 修改标题
plt.xlabel('Date')
plt.ylabel('Price')
plt.legend()
plt.grid(True)
plt.show()
if __name__ == "__main__":
stock_code = "600938" # 贵州茅台
start_date = "20241201"
end_date = "20250523"
ma_periods=[5, 10, 20, 30]
# 获取数据
stock_data = get_stock_data(stock_code, start_date, end_date)
# 计算均线
stock_data = calculate_ma(stock_data)
# 识别均线多头排列
stock_data = identify_bullish_arrangement(stock_data)
# 识别均线交叉信号
stock_data = identify_ma_cross(stock_data)
# 计算葛兰碧八大法则买卖点
stock_data = granville_rules(stock_data)
# 计算均线通道策略
stock_data = calculate_ma_channel(stock_data)
# 绘制图形
plot_data(stock_data, ma_periods, stock_code) # 传递 stock_code 参数
