1#!/usr/bin/env python
2# -*- coding: utf-8; py-indent-offset:4 -*-
3
4###############################################################################
5#
6# Copyright (C) 2017 Christoph Giese <cgi1>
7# (based on backtrader from Daniel Rodriguez)
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program.  If not, see <http://www.gnu.org/licenses/>.
21#
22###############################################################################
23
24import backtrader as bt
25
26
27__all__ = ['Fractal']
28
29
30class Fractal(bt.ind.PeriodN):
31    '''
32    References:
33        [Ref 1] http://www.investopedia.com/articles/trading/06/fractals.asp
34
35    '''
36    lines = ('fractal_bearish', 'fractal_bullish')
37
38    plotinfo = dict(subplot=False, plotlinelabels=False, plot=True)
39
40    plotlines = dict(
41        fractal_bearish=dict(marker='^', markersize=4.0, color='lightblue',
42                             fillstyle='full', ls=''),
43        fractal_bullish=dict(marker='v', markersize=4.0, color='lightblue',
44                             fillstyle='full', ls='')
45    )
46    params = (
47        ('period', 5),
48        ('bardist', 0.015),  # distance to max/min in absolute perc
49        ('shift_to_potential_fractal', 2),
50    )
51
52    def next(self):
53        # A bearish turning point occurs when there is a pattern with the
54        # highest high in the middle and two lower highs on each side. [Ref 1]
55
56        last_five_highs = self.data.high.get(size=self.p.period)
57        max_val = max(last_five_highs)
58        max_idx = last_five_highs.index(max_val)
59
60        if max_idx == self.p.shift_to_potential_fractal:
61            self.lines.fractal_bearish[-2] = max_val * (1 + self.p.bardist)
62
63        # A bullish turning point occurs when there is a pattern with the
64        # lowest low in the middle and two higher lowers on each side. [Ref 1]
65        last_five_lows = self.data.low.get(size=self.p.period)
66        min_val = min(last_five_lows)
67        min_idx = last_five_lows.index(min_val)
68
69        if min_idx == self.p.shift_to_potential_fractal:
70            self.l.fractal_bullish[-2] = min_val * (1 - self.p.bardist)
71