timmy gist felülvizsgálása 10 months ago. Revízióhoz ugrás
1 file changed, 161 insertions
macd_calculator.py(fájl létrehozva)
| @@ -0,0 +1,161 @@ | |||
| 1 | + | # import shutil | |
| 2 | + | ||
| 3 | + | # import matplotlib | |
| 4 | + | ||
| 5 | + | import matplotlib.pyplot as plt | |
| 6 | + | import numpy as np | |
| 7 | + | import pandas as pd | |
| 8 | + | from matplotlib import rcParams | |
| 9 | + | ||
| 10 | + | import error_printer | |
| 11 | + | from stock_data_downloader import StockDataDownloader | |
| 12 | + | ||
| 13 | + | error_printer.configure_icecream() | |
| 14 | + | ||
| 15 | + | ||
| 16 | + | rcParams["font.family"] = "sans-serif" | |
| 17 | + | # rcParams["font.sans-serif"] = ["SimHei"] # 或其他支持中文的字型 | |
| 18 | + | rcParams["font.sans-serif"] = ["STHeiti", "PingFang"] | |
| 19 | + | ||
| 20 | + | ||
| 21 | + | class MACDCalculator: | |
| 22 | + | def __init__(self, stock_data: pd.DataFrame): | |
| 23 | + | """ | |
| 24 | + | 初始化 MACDCalculator 類的實例。 | |
| 25 | + | ||
| 26 | + | 參數: | |
| 27 | + | stock_data (pd.DataFrame): 包含股票資料的 DataFrame。 | |
| 28 | + | """ | |
| 29 | + | self.stock_data = stock_data | |
| 30 | + | ||
| 31 | + | def calculate_macd(self) -> tuple[pd.Series, pd.Series, pd.Series, pd.Series]: | |
| 32 | + | """ | |
| 33 | + | 計算股票資料的 MACD 指標。 | |
| 34 | + | ||
| 35 | + | 返回: | |
| 36 | + | tuple[pd.Series, pd.Series, pd.Series, pd.Series]: 包含快線 EMA、慢線 EMA、MACD 線和訊號線的元組。 | |
| 37 | + | """ | |
| 38 | + | ||
| 39 | + | short_ema = self.stock_data["Close"].ewm(span=12, adjust=False).mean() # 計算股票收盤價的快速指數移動平均線(EMA) | |
| 40 | + | long_ema = self.stock_data["Close"].ewm(span=26, adjust=False).mean() # 計算股票收盤價的慢速指數移動平均線(EMA) | |
| 41 | + | macd = short_ema - long_ema # 計算 MACD 線 | |
| 42 | + | signal_line = macd.ewm(span=9, adjust=False).mean() # 計算訊號線 | |
| 43 | + | return short_ema, long_ema, macd, signal_line # 返回短期EMA、長期EMA、MACD、訊號線 | |
| 44 | + | ||
| 45 | + | def find_golden_crosses(self, macd: pd.Series, signal_line: pd.Series) -> np.ndarray: | |
| 46 | + | """ | |
| 47 | + | 找到 MACD 線和訊號線的黃金交叉點。 | |
| 48 | + | ||
| 49 | + | 參數: | |
| 50 | + | macd (pd.Series): MACD 線。 | |
| 51 | + | signal_line (pd.Series): 訊號線。 | |
| 52 | + | ||
| 53 | + | 返回: | |
| 54 | + | np.ndarray: 包含黃金交叉點索引的 NumPy 陣列。 | |
| 55 | + | """ | |
| 56 | + | crosses = (macd.shift(1) < signal_line.shift(1)) & (macd > signal_line) | |
| 57 | + | cross_indices = np.where(crosses)[0] | |
| 58 | + | return cross_indices | |
| 59 | + | ||
| 60 | + | def find_death_crosses(self, macd: pd.Series, signal_line: pd.Series) -> np.ndarray: | |
| 61 | + | """ | |
| 62 | + | 找到 MACD 線和訊號線的死亡交叉點。 | |
| 63 | + | ||
| 64 | + | 參數: | |
| 65 | + | macd (pd.Series): MACD 線。 | |
| 66 | + | signal_line (pd.Series): 訊號線。 | |
| 67 | + | ||
| 68 | + | 返回: | |
| 69 | + | np.ndarray: 包含死亡交叉點索引的 NumPy 陣列。 | |
| 70 | + | """ | |
| 71 | + | crosses = (macd.shift(1) > signal_line.shift(1)) & (macd < signal_line) | |
| 72 | + | cross_indices = np.where(crosses)[0] | |
| 73 | + | return cross_indices | |
| 74 | + | ||
| 75 | + | def get_golden_cross_dates(self, golden_crosses: np.ndarray) -> list: | |
| 76 | + | """ | |
| 77 | + | 獲取黃金交叉點的日期。 | |
| 78 | + | ||
| 79 | + | 參數: | |
| 80 | + | golden_crosses (np.ndarray): 包含黃金交叉點索引的 NumPy 陣列。 | |
| 81 | + | ||
| 82 | + | 返回: | |
| 83 | + | list: 包含黃金交叉點日期的列表。 | |
| 84 | + | """ | |
| 85 | + | cross_dates = [] | |
| 86 | + | for cross_index in golden_crosses: | |
| 87 | + | cross_date = str(self.stock_data.index[cross_index])[:10] | |
| 88 | + | cross_dates.append(cross_date) | |
| 89 | + | return cross_dates | |
| 90 | + | ||
| 91 | + | def get_death_cross_dates(self, death_crosses: np.ndarray) -> list: | |
| 92 | + | """ | |
| 93 | + | 獲取死亡交叉點的日期。 | |
| 94 | + | ||
| 95 | + | 參數: | |
| 96 | + | death_crosses (np.ndarray): 包含死亡交叉點索引的 NumPy 陣列。 | |
| 97 | + | ||
| 98 | + | 返回: | |
| 99 | + | list: 包含死亡交叉點日期的列表。 | |
| 100 | + | """ | |
| 101 | + | cross_dates = [] | |
| 102 | + | for cross_index in death_crosses: | |
| 103 | + | cross_date = str(self.stock_data.index[cross_index])[:10] | |
| 104 | + | cross_dates.append(cross_date) | |
| 105 | + | return cross_dates | |
| 106 | + | ||
| 107 | + | def plot_macd(self): | |
| 108 | + | # 從實例中獲取資料 | |
| 109 | + | short_ema, long_ema, macd, signal_line = self.calculate_macd() | |
| 110 | + | ||
| 111 | + | # 定義顏色變數 | |
| 112 | + | macd_color = (243 / 255, 158 / 255, 55 / 255) # 橙色 | |
| 113 | + | signal_line_color = (38 / 255, 128 / 255, 218 / 255) # 藍色 | |
| 114 | + | positive_bar_color = (247 / 255, 65 / 255, 84 / 255) # 紅色 | |
| 115 | + | negative_bar_color = (51 / 255, 184 / 255, 90 / 255) # 綠色 | |
| 116 | + | ||
| 117 | + | plt.figure(figsize=(10, 5)) | |
| 118 | + | plt.plot(macd.index, macd, label="MACD線", color=macd_color) | |
| 119 | + | plt.plot(signal_line.index, signal_line, label="訊號線", color=signal_line_color) | |
| 120 | + | ||
| 121 | + | # 繪製 MACD 柱狀圖,使用顏色變數 | |
| 122 | + | bar_colors = [positive_bar_color if v >= 0 else negative_bar_color for v in macd - signal_line] | |
| 123 | + | plt.bar(macd.index, macd - signal_line, color=bar_colors) | |
| 124 | + | ||
| 125 | + | plt.legend() | |
| 126 | + | plt.show() | |
| 127 | + | ||
| 128 | + | ||
| 129 | + | # 檢查目前程式是否被作為主程式執行 | |
| 130 | + | if __name__ == "__main__": | |
| 131 | + | # 建立 StockDataDownloader 實例 | |
| 132 | + | downloader = StockDataDownloader(months=1) | |
| 133 | + | ||
| 134 | + | # 下載股票資料 | |
| 135 | + | stock_data = downloader.download_stock_data("00929.TW") | |
| 136 | + | ||
| 137 | + | # 建立 MACDCalculator 實例 | |
| 138 | + | macd_calculator = MACDCalculator(stock_data) | |
| 139 | + | ||
| 140 | + | # 計算 MACD 指標 | |
| 141 | + | short_ema, long_ema, macd, signal_line = macd_calculator.calculate_macd() | |
| 142 | + | ||
| 143 | + | # 找到黃金交叉點和死亡交叉點 | |
| 144 | + | golden_crosses = macd_calculator.find_golden_crosses(macd, signal_line) | |
| 145 | + | death_crosses = macd_calculator.find_death_crosses(macd, signal_line) | |
| 146 | + | ||
| 147 | + | # 獲取黃金交叉點和死亡交叉點的日期 | |
| 148 | + | golden_cross_dates = macd_calculator.get_golden_cross_dates(golden_crosses) | |
| 149 | + | death_cross_dates = macd_calculator.get_death_cross_dates(death_crosses) | |
| 150 | + | ||
| 151 | + | # 列印結果 | |
| 152 | + | # print("短期EMA: ", short_ema) | |
| 153 | + | # print("長期EMA: ", long_ema) | |
| 154 | + | # print("MACD: ", macd) | |
| 155 | + | # print("訊號線: ", signal_line) | |
| 156 | + | # print("黃金交叉點: ", golden_crosses) | |
| 157 | + | # print("死亡交叉點: ", death_crosses) | |
| 158 | + | print("黃金交叉日期: ", golden_cross_dates) | |
| 159 | + | print("死亡交叉日期: ", death_cross_dates) | |
| 160 | + | ||
| 161 | + | macd_calculator.plot_macd() # 繪製 MACD 圖表 | |
Újabb
Régebbi