Attempting to improve on the MACD strategy in python
In my previous post I introduced a rudimentary trading strategy based on the MACD. This strategy produced lots of spurious trading signals and would probably not be particularly effective in the wild. In this post I'll explore some attempts to improve the quality of signal produced by the MACD strategy.
Baseline results
In order to evaluate the performance of each approach, we need to have a reference. The naïve MACD strategy produces lots of bad trade signals over the test data.
Approach 1: Positivity of the MACD
We can try to filter out bad trade signals by insisting that the MACD be positive in order to trigger a trade.
import numpy as np
def macd_strategy2(ohlcv):
"""
Calculate the macd of a stock, decide whether to buy, sell, or hold based on signal behaviour
Inputs:
ohlcv: numpy array - A 5 x N matrix with rows corresponding to
o, h, l, c, v respectively
Outputs:
status: string - "BUY", "SELL", or "HOLD"
"""
typical = typical_price(ohlcv)
macd, macd_sig, macd_hist = macd(typical)
macd_hist = macd_hist[::-1] # reversed MACD histogram
macd = macd[::-1]
if macd_hist[0] > 0 and macd_hist[1] <= 0 and macd[0] >= 0:
return "BUY"
elif macd_hist[0] < 0 and macd_hist[1] >= 0:
return "SELL"
else:
return "HOLD"
This seems to filter out quite a few of the bad buy signals, however this strategy isn't applicable for sell signals.
Approach 2: Positivity of the derivative
Another potential way to filter out signals from the MACD is to look at the sign of the first derivative. In order to calculate the first derivative, we can use a rudimentary method such as a finite difference scheme:
import numpy as np
def first_deriv(signal, dt):
"""
Calculate the first derivative using finite difference method
Inputs:
signal: numpy array - A sequence of price points in time
dt: int - Bucket size in seconds
Outputs:
dx: numpy array - First derivative at each point in points
"""
dx = np.zeros(len(signal))
dx[0] = (signal[1] - signal[0]) / dt
dx[-1] = (signal[-1] - signal[-2])
for i in range(1, len(dx) - 1):
dx[i] = (signal[i + 1] - signal[i - 1]) / (2 * dt)
return dx
Then integrating this into the MACD strategy:
def macd_strategy3(ohlcv):
"""
Calculate the macd of a stock, decide whether to buy, sell, or
hold based on signal behaviour
Inputs:
ohlcv: numpy array - A 5 x N matrix with rows corresponding to
o, h, l, c, v respectively
Outputs:
status: string - "BUY", "SELL", or "HOLD"
"""
typical = ta.typical_price(ohlcv)
macd, macd_sig, macd_hist = ta.macd(typical)
dx = ta.first_deriv(typical, 1)[::-1]
macd_hist = macd_hist[::-1] # reversed MACD histogram
if macd_hist[0] > 0 and macd_hist[1] <= 0 and dx[0] > 0:
return "BUY"
elif macd_hist[0] < 0 and macd_hist[1] >= 0 and dx[0] < 0:
return "SELL"
else:
return "HOLD"
I had high hopes for this approach, but it didn't seem to have much effect at all.
Results
Neither of these approaches do a particularly good job of cleaning up the signals generated by the original MACD strategy. Usually the MACD is used in conjunction with other indicators in order to provide more reliable trading signals.
Posted Using LeoFinance