Skip to content

Instantly share code, notes, and snippets.

@s-tlm
Last active January 11, 2021 10:20
Show Gist options
  • Select an option

  • Save s-tlm/cc72336b3b38c658703177b6a6ed8b04 to your computer and use it in GitHub Desktop.

Select an option

Save s-tlm/cc72336b3b38c658703177b6a6ed8b04 to your computer and use it in GitHub Desktop.
Complete MACD implementation
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