Recently I've been playing around with Quantopian/Zipline building a library of indicators I might find useful in the future. I came across the previous implementations of ATR shared, and thought I'd share my own stab at it, both iteratively in a custom event window and using a batch transform.

Happy Hacking!

7-11

Previous Posts:

https://www.quantopian.com/posts/average-true-range-basic-implementation

https://www.quantopian.com/posts/python-classes-implementing-true-range-and-average-true-range-indicators

Clone Algorithm

19

Loading...

There was an error loading this backtest.

Backtest from
to
with
initial capital

Cumulative performance:

Algorithm
Benchmark

Custom data:

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 pandas as pd from zipline.transforms import utils as tnfs_utils class ATREventWindow(tnfs_utils.EventWindow): def __init__(self, window_length): tnfs_utils.EventWindow.__init__(self, window_length=window_length) self.atr = 0 self.alpha = 2.0 / (self.window_length + 1) def handle_add(self, event): if len(self.ticks) < 2: return if self.atr is 0: self.atr = self.true_range() else: self.atr = self.atr + self.alpha * (self.true_range() - self.atr) def true_range(self): data = list(self.ticks) high = data[-1]['high'] low = data[-1]['low'] prev_close = data[-2]['close_price'] return max(high - low, abs(high - prev_close), abs(low - prev_close)) def handle_remove(self, event): pass def __call__(self): return self.atr def _true_range(d, last_close=None): if last_close is None: last_close = d['close_price'].shift(1) return pd.Panel({'range': d['high'] - d['low'], 'range_high': (d['high'] - last_close).abs(), 'range_low': (d['low'] - last_close).abs()}).max(axis=0) def _atr(d, span=14, true_range=None): if true_range is None: true_range = _true_range(d) return pd.ewma(true_range, span=span) @batch_transform(window_length=14) def atr(d): return _atr(d) def initialize(context): context.sid = sid(26578) context.atr_window = ATREventWindow(window_length=14) def handle_data(context, data): data[context.sid].dt = data[context.sid].datetime context.atr_window.update(data[context.sid]) record(window=context.atr_window()) atrs = atr(data) if atrs is None: return record(batch=atrs.ix[-1][context.sid])

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.