Back to Community
MACD signal

I runned a tradional MACD(12,26,9) being 100% long when signal was positive and 100% short when signal was negative.
I manually created the signal based on other codes I found and I could understand the function TALIB.MACD
Despite improvements in the strategy since it does´t beat the benchmark even without commissions is there any improvements that could be done in my code or different approaches ?
Any comments are more than welcome.

Clone Algorithm
11
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5a077cab54177a408045f5b4
There was a runtime error.
7 responses

rodrigo,

Try this with exact setup and publish it.

import talib

# -----------------------------------------  
stock, bond = symbol('AAPL'), symbol('TLT')  
Fast, Slow, Sig = 12, 26, 9  
# -----------------------------------------

def initialize(context):  
    schedule_function(trade, date_rules.every_day(), time_rules.market_open(hours=1))

def trade(context,data):  
    bars = Fast + Slow + Sig

    prices = data.history(stock, 'price', bars, '1d')  
    macd, signal, hist = talib.MACD(prices, Fast, Slow, Sig)  

    if macd[-1] > signal[-1]:  
        order_target_percent(stock, 0.8)  
        order_target_percent(bond, 0.2)  
    elif macd[-1] < signal[-1]:  
        order_target_percent(stock, 0)  
        order_target_percent(bond, 1.0)

    record(macd = macd[-1], signal = signal[-1])  
'''
100000

START  
6/1/2007  
END  
11/10/2017


Total Returns  
605.71%  
Benchmark Returns  
107.88%  
Alpha  
0.20  
Beta  
0.09  
Sharpe  
1.07  
Sortino  
1.59  
Volatility  
0.19  
Max Drawdown  
-33.48%

'''

Looks interesting, although i did wonder why @Vladimir wants @Rodrigo to publish it, rather than publishing it himself? Anyway, whatever.

I confirmed the numbers quoted by Vladimir, and also tried increasing the account size to $1MM & $10MM to check scalability. Only a small degradation in results, still substantially the same. At $10MM acct, return = 527%, alpha = 0.19, beta = 0.09, Sharpe = 1.01, MaxDD = -34.27%. Looks impressive over a 10 year test period, and a little bit of work could probably bring that DD down as well, without having to do too much curve fitting stuff. Looks like a GREAT system, huh?

OK, so what's the catch then?
Try it with almost anything other than AAPL as the "one & only" stock and you will quickly see.
For example SPY: Return = 36%, Sharpe 0.28, maxDD 36.8%; NVDA: Rtn =127%, Sharpe 0.42, maxDD=54.3%; AMZN: Rtn=100%, Sharpe=0.41, maxDD = -34.5%, and most others worse than that.

I'm NOT saying that judicious switching from stocks to bonds (TLT) based on some indicator (here MACD) isn't a good idea, but the problem here is the use of a particular kind of data mining "trick": At the end of 10 years, AFTER you already know what was the best-performing stock, use that to show how good a system looks. The problem is that, back at the start, it was not known how good AAPL would be.

So this is a kind of look-ahead bias effect. Vladimir obviously knows exactly what he is doing, but be careful Rodrigo! ;-))

Tony,

i did wonder why @Vladimir wants @Rodrigo to publish it, rather than publishing it himself?

By some, known only to Quantopian staff, reasons I do not have ability to attach my backtests to posts since April 2017.

OK, so what's the catch then?

There is no catch.
I just know that MACD Signal developed by Gerald Appel in the late seventies with default parameters (12, 26, 9) was productive for AAPL last 10 years.

Here is almost original Rodrigo's code with only bug fixes.
Rodrigo obviously knows exactly what he is doing.

import talib

def initialize(context):  
    context.stock = sid(24)  
    schedule_function(trade, date_rules.every_day(), time_rules.market_open(hours=1))

def trade(context,data):  
    prices = data.history(context.stock,'price', 47,'1d')  
    ema12 = talib.EMA(prices,12)  
    ema26 = talib.EMA(prices,26)  
    macd = ema12 - ema26  
    signal = talib.EMA(macd,9)  
    if macd[-1] > signal[-1]:  
        order_target_percent(context.stock, 1.0)  
    elif macd[-1] < signal[-1]:  
        order_target_percent(context.stock, 0.0)  
    record(macd = macd[-1], signal = signal[-1])  
'''
100000

START  
6/1/2007  
END  
11/10/2017

Returns  
669.86%  
Alpha  
0.18  
Beta  
0.38  
Sharpe  
1.07  
Drawdown  
-32.12%

'''

Using the MACD in the way you described (the classic approach) means you are employing it as a momentum indicator. Momentum indicators only work well on price time series that exhibit high positive expectancy for momentum trading (buying strength, selling weakness). Have you done any quantitative test that indicates AAPL possesses momentum properties on the daily interval?

Below is a MACD(12, 26, 9) strategy for GDXJ on the 30-minute interval.

Clone Algorithm
209
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 598ff566d2551b50de3bd455
There was a runtime error.

@Vladimir Thank you very much for your contribution. I runned the code you shared with me only changing the period to match a period I´m using as standard to compare different strategies. I honestly haven´t thought about using Bonds and it´s really interesting how volatility and Beta behave! My next steep is to test some strategies using RSI

Clone Algorithm
1
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5a0cd1abdea194428b50a33a
There was a runtime error.

Kory, you made a comment - "Have you done any quantitative test that indicates AAPL possesses momentum properties on the daily interval?". Can you highlight what test(s) one could run to check for mean reversion / momentum property ? Any reference to code in quantopian would also we very useful. thanks.