Algorithm with Aroon from TA-LIB

Hey guys,
I am working on a passive momentum algorithm and I want to use the Aroon indicator as part of that but I have no clue how the syntax works for that or how to implement it. If someone could whip up an implementation of the Aroon, I would greatly appreciate it. Thank you!

Cheers,
Josh

8 responses

Hello Joshua,

This shows the syntax but doesn't trade.

P.

94
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
import talib

def initialize(context):
context.stock  = sid(2)
context.first = True

def handle_data(context, data):

if context.first:
order_target_percent(context.stock, 1.0)
context.first = False

highPrices = history(15, '1d', 'high')
lowPrices  = history(15, '1d', 'low')

Aroon = talib.AROON(highPrices[context.stock], lowPrices[context.stock], timeperiod = 14)
AroonDown = Aroon[0][-1]
AroonUp   = Aroon[1][-1]

record(AroonUp=AroonUp, AroonDown=AroonDown)


This backtest was created using an older version of the backtester. Please re-run this backtest to see results using the latest backtester. Learn more about the recent changes.
There was a runtime error.

Thank you so much! Can you make examples for other TA-Lib functions (e.g abandoned baby)? I think having a repository of examples would help the beginners like me. Also, where did you figure out the syntax to make that script?

Also, it appears that the syntax is different when you are using a universe. Could someone do an example with a universe?

Hello Joshua,

This uses the method shown in the Quantopian docs:

import numpy as np

Aroon = ta.AROON()

def initialize(context):
set_universe(universe.DollarVolumeUniverse(floor_percentile=99.95,ceiling_percentile=100.0))

def handle_data(context, data):
results = Aroon(data)
for stock in data:
if np.isnan(results[stock][0]):
return
print results[stock]


but the candle functions are not supported that way. To use CDLABANDONEDBABY:

import talib

def initialize(context):
context.stock  = sid(2)

def handle_data(context, data):
openPrices  = history(15, '1d', 'open_price')
highPrices  = history(15, '1d', 'high')
lowPrices   = history(15, '1d', 'low')
closePrices = history(15, '1d', 'close_price')
results = talib.CDLABANDONEDBABY(openPrices[context.stock], highPrices[context.stock], \
lowPrices[context.stock], closePrices[context.stock])
print results


The attached backtest counts the occurrence of CDL3BLACKCROWS in 2012 for a universe of stocks. ('break' should read 'continue'.) I calculated that approximately the pattern appears once in every 50 years per stock with daily bars.

P.

47
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
import numpy as np
import talib

def initialize(context):
set_universe(universe.DollarVolumeUniverse(90,100))
context.PatternCount = 0

def handle_data(context, data):
Results = GetPrices(data)
if Results is None:
return
for Sid in data:
if Sid.sid not in Results[0].columns:
break
OpenPrices  = np.array(Results[0][Sid])
HighPrices  = np.array(Results[1][Sid])
LowPrices   = np.array(Results[2][Sid])
ClosePrices = np.array(Results[3][Sid])
Cdl3BlackCrows  = talib.CDL3BLACKCROWS(OpenPrices, HighPrices, LowPrices, ClosePrices)
if Cdl3BlackCrows[-1:] < 0:
context.PatternCount +=1
print context.PatternCount
#print Cdl3BlackCrows
record(PatternsFound=context.PatternCount)

@batch_transform(window_length=14, refresh_period=0)
def GetPrices(DataPanel):
OpenPrices  = DataPanel['open_price']
HighPrices  = DataPanel['high']
LowPrices   = DataPanel['low']
ClosePrices = DataPanel['close_price']
return OpenPrices, HighPrices, LowPrices, ClosePrices
This backtest was created using an older version of the backtester. Please re-run this backtest to see results using the latest backtester. Learn more about the recent changes.
There was a runtime error.

So the AroonUp and AroonDown is still the same as before

Hello Joshua,

No. AroonDown and AroonUp are now results[stock][0] and results[stock][1] respectively.

P.

Thank you so much for all your help! I am curious where you learned these complicated methods and functions so thoroughly

Hello Joshua,

They're not that complicated and I don't understand them that thoroughly! I've never really programmed in 'C' but the source code is the place to start looking with TA-Lib as there is not a great deal of documentation otherwise - see http://sourceforge.net/p/ta-lib/code/HEAD/tree/trunk/ta-lib/c/src/ta_func/

Look at a function like CDLABANDONEDBABY and you can see:

int    startIdx,
int    endIdx,
float  inOpen[],
float  inHigh[],
float  inLow[],
float  inClose[],
double optInPenetration


which tells me I need to provide Open, High, Low, Close prices in that order. I can ignore Penetration as it is optional. This gives me the line in the algo:

results = talib.CDLABANDONEDBABY(openPrices[context.stock], highPrices[context.stock], \
lowPrices[context.stock], closePrices[context.stock])


The simplest thing now is to print 'results' and see what happens. Mostly it will look like this:

[0 0 0 0 0 0 0 0 0 0 0 0 0]


but occasionally it will look like this:

[   0    0    0    0    0    0    0    0    0    0    0    0 -100]


which shows the pattern has been found with -100 denoting a 'Bearish Abandoned Baby'.

In this case 'results' has 13 entries because that is the number of bars needed to find it and if using batch_transform to get the data a window of 13 bars would be used. Of these 10 bars are used to determine whether the 11th bar is 'long' or not, and bars 11 -13 are the pattern itself. See this explanation in the source code:

/* Proceed with the calculation for the requested range.
* Must have:
* - first candle: long white (black) real body
* - second candle: doji
* - third candle: black (white) real body that moves well within the first candle's real body
* - upside (downside) gap between the first candle and the doji (the shadows of the two candles don't touch)
* - downside (upside) gap between the doji and the third candle (the shadows of the two candles don't touch)
* The meaning of "doji" and "long" is specified with TA_SetCandleSettings
* The meaning of "moves well within" is specified with optInPenetration and "moves" should mean the real body should
* not be short ("short" is specified with TA_SetCandleSettings) - Greg Morris wants it to be long, someone else want
* it to be relatively long
* outInteger is positive (1 to 100) when it's an abandoned baby bottom or negative (-1 to -100) when it's
* an abandoned baby top; the user should consider that an abandoned baby is significant when it appears in
* an uptrend or downtrend, while this function does not consider the trend
*/


And to confirm the meaning of 'long' we can look at http://sourceforge.net/p/ta-lib/code/HEAD/tree/trunk/ta-lib/c/src/ta_common/ta_global.c where we find:

    const TA_CandleSetting TA_CandleDefaultSettings[] = {
/* real body is long when it's longer than the average of the 10 previous candles' real body */
{ TA_BodyLong, TA_RangeType_RealBody, 10, 1.0 },


P.