Last active
January 11, 2021 10:20
-
-
Save s-tlm/cc72336b3b38c658703177b6a6ed8b04 to your computer and use it in GitHub Desktop.
Complete MACD implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import pandas as pd | |
| from matplotlib import pyplot as plt | |
| import os | |
| # Class setup | |
| class MovingAverage(): | |
| def __init__(self, closing_prices): | |
| self.data = pd.DataFrame(closing_prices) | |
| def EMA(self, averaging_length=50): | |
| ret = self.data.ewm( | |
| span=averaging_length, | |
| adjust=False).mean() | |
| return ret.rename(columns={'Close': 'EMA'}) | |
| def MACD(self, a=12, b=26, c=9): | |
| MACD_line = self.EMA(a) - self.EMA(b) | |
| signal_line = MACD_line.ewm(span=c, adjust=False).mean() | |
| histogram = MACD_line - signal_line | |
| return MACD_line, signal_line, histogram | |
| # Importing stock data | |
| DATA_DIR = ('X:\\MY_DIR\\ANZ.AX.csv') | |
| STOCK_SYM = os.path.basename(DATA_DIR).split('.csv')[0] # reads the stock ticker symbol from the file name | |
| df = pd.read_csv( | |
| DATA_DIR, | |
| index_col='Date', # dates parsed as index | |
| parse_dates=True, | |
| dayfirst=True # DD/MM formatting | |
| ) | |
| df = df.asfreq('B') # B for Business calendar (no weekends) | |
| df = df.fillna(method='ffill') # fills any missing day's data with previous day's | |
| closing_prices = df.Close # takes column labelled 'Close' | |
| buy = pd.DataFrame(index=closing_prices.index, columns=['Buy']) # an empty data-frame to store buy signals | |
| sell = pd.DataFrame(index=closing_prices.index, columns=['Sell']) # an empty data-frame to store sell signals | |
| # Executing class and variables | |
| MACD_indicator = MovingAverage(closing_prices) | |
| MACD_line, signal_line, histogram = MACD_indicator.MACD() | |
| COOLDOWN_PERIOD = 30 | |
| cooldown = 0 | |
| # Generating buy and sell signals | |
| for i in range(1, len(closing_prices)): | |
| cooldown -= 1 | |
| if i == 1: | |
| if MACD_line['EMA'].iloc[i] > signal_line['EMA'].iloc[i]: | |
| high = 'MACD' | |
| else: | |
| high = 'SIGNAL' | |
| elif MACD_line['EMA'].iloc[i] > signal_line['EMA'].iloc[i]: | |
| if high == 'SIGNAL': # MACD crossed signal - bottom to top BUY | |
| if MACD_line['EMA'].iloc[i] < 0 and cooldown <= 0: | |
| buy.iloc[i] = closing_prices[i] # BUY | |
| cooldown = COOLDOWN_PERIOD | |
| high = 'MACD' | |
| elif MACD_line['EMA'].iloc[i] < signal_line['EMA'].iloc[i]: | |
| if high == 'MACD': # MACD crossed signal - top to bottom SELL | |
| if MACD_line['EMA'].iloc[i] > 0: | |
| sell.iloc[i] = closing_prices[i] # SELL | |
| high = 'SIGNAL' | |
| # Plotting results | |
| plt.rcParams["figure.figsize"] = [16,9] | |
| plt.rcParams["lines.linewidth"] = 0.75 | |
| fig, (ax1, ax2) = plt.subplots(2) | |
| ax1.plot(closing_prices, label = 'Closing Prices') | |
| ax1.plot(buy, 'g^', label = 'Buy') | |
| ax1.plot(sell, 'rv', label = 'Sell') | |
| # ax1.plot(MACD_indicator.EMA(12), 'r', label = '12 day EMA') # uncomment if you wish to plot the 12 day EMA | |
| # ax1.plot(MACD_indicator.EMA(26), 'y', label = '26 day EMA') # uncomment if you wish to plot the 26 day EMA | |
| ax1.legend(loc='lower left') | |
| ax2.plot(MACD_line, label = 'MACD Line') | |
| ax2.plot(signal_line, label = 'Signal Line') | |
| histogram_y = [histogram['EMA'].iloc[i] for i in range(0, len(histogram))] | |
| ax2.bar(histogram.index, histogram_y, color=['g' if histogram_y[i] > 0 else 'r' for i in range(0,len(histogram_y))], width = 1, label = 'Histogram') | |
| ax2.legend(loc='lower left') | |
| ax1.title.set_text(STOCK_SYM) | |
| ax1.set(xlabel='Date', ylabel='($) AUD') | |
| ax2.set(xlabel='Date', ylabel='($) AUD') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment