Esempio n. 1
0
    def empty_between(cls, q0: 'Quote', q1: 'Quote') -> List['Quote']:
        """
        Returns empty quotes between `q0` and `q1`.
        """
        resolution = q0.resolution
        if q1.resolution != q1.resolution:
            raise Exception('Quote resolutions must be equal')

        missing_interval = q1.start_date - q0.end_date
        if missing_interval == 0:
            return []
        elif missing_interval < 0:
            raise Exception('Quotes must be in ascending order')

        ohlc = [q0.close] * 4
        quotes = []
        domain = Interval.intersection(
            [q0.domain.get_gt(), q1.domain.get_lt()])
        assert domain.is_finite
        for span in resolution.iterate(domain, start_open=domain.start_open):
            q = Quote(ohlc, date=span.start, volume=0.0, resolution=resolution)
            quotes.append(q)

        if quotes[-1].end_date > q1.start_date:
            raise Exception(
                f'Unregular quote distance between filled quote {quotes[-1]} and {q1}'
            )
        return quotes
Esempio n. 2
0
    def _update_extension_interval(self):
        if not self._extension_interval_stale:
            return
        self._extension_interval_stale = False
        if self._extension_stale:
            self._update_extension_if_needed()

        if self.start and self.start_valid and self.end and self.end_valid:
            self.extension_interval = Interval.union([self.start_func.domain, self.end_func.domain])
        elif self.start and self.start_valid:
            self.extension_interval = Interval.intersection([self.start_func.domain, self.curve.domain.get_lt()])
        elif self.end and self.end_valid:
            self.extension_interval = Interval.intersection([self.end_func.domain, self.curve.domain.get_gt()])
        else:
            self.extension_interval = Interval.empty()
        self.update_extension_interval()
        if (self.start and not self.extension_interval.is_negative_infinite) or (self.end and not self.extension_interval.is_positive_infinite):
            if self.raise_on_empty:
                raise Exception('Unable to extend func')
Esempio n. 3
0
    def missing_domains(cls, quotes, domain=None):
        # TODO: optimise by recursively dividing quotes
        # in half and checking if the quotes are
        # contiguous. Then collect domains between
        # contiguous quotes.
        quotes_len = len(quotes)
        if quotes_len == 0:
            if domain is None:
                return []
            else:
                return [domain]

        if domain is None:
            domain = cls.list_domain(quotes)
        else:
            domain = Interval.parse(domain)
        if domain.is_empty:
            return []

        missing_list = []
        head = Interval.intersection([domain, quotes[0].domain.get_lt()])
        if not head.is_empty:
            missing_list.append(head)

        for i in range(1, quotes_len):
            q0 = quotes[i - 1]
            q1 = quotes[i]
            if q0.end_date != q1.start_date:
                if q0.end_date > q1.start_date:
                    continue
                missing = Interval(q0.domain.end,
                                   q1.domain.start,
                                   start_open=not q0.domain.end_open,
                                   end_open=not q1.domain.start_open)
                missing_list.append(missing)

        tail = Interval.intersection([domain, quotes[-1].domain.get_gt()])
        if not tail.is_empty:
            missing_list.append(tail)

        return missing_list
Esempio n. 4
0
    def sample_points(self, domain=None, min_step=MIN_STEP, step=None):
        min_step = self.resolve_min_step(min_step)
        if domain is None:
            domain = self.domain
        else:
            domain = Interval.intersection([self.domain, domain])
        if domain.is_empty:
            return []
        elif not domain.is_finite:
            raise Exception(
                "Cannot sample points on an infinite domain {}. Specify a finite domain."
                .format(domain))
        x_start, x_end = domain
        x_end_bin = round(x_end / min_step) if min_step is not None else x_end
        if domain.start_open:
            points = []
        else:
            points = [(x_start, self.y(x_start))]
        if step is not None:
            x = x_start + step
            while x <= x_end:
                y = self.y(x)
                points.append((x, y))
                x += step
        elif min_step is not None and min_step > 0:
            x = self.x_next(x_start, min_step=min_step, limit=x_end)
            while x is not None and x <= x_end:
                y = self.y(x)
                points.append((x, y))
                x_bin = round(x / min_step) if min_step is not None else x
                if x_bin == x_end_bin:
                    break
                x1 = self.x_next(x, min_step=min_step, limit=x_end)
                if x1 is not None:
                    x1_bin = round(x1 /
                                   min_step) if min_step is not None else x1
                    if x1_bin <= x_bin:
                        raise Exception(
                            'Next x value {} should be greater than the previous x value {} by at least the minimum step of {}'
                            .format(x1, x, min_step))
                x = x1

            if not domain.end_open and points[-1][0] != x_end:
                points.append((x_end, self.y(x_end)))
        else:
            raise Exception("Bad functions sample parameters.")

        return points
Esempio n. 5
0
 def sample_points(self, domain=None, min_step=MIN_STEP, step=None):
     min_step = self.resolve_min_step(min_step)
     if domain is None:
         domain = self.domain
     else:
         domain = Interval.intersection([self.domain, domain])
     if domain.is_empty:
         return []
     elif domain.is_infinite:
         raise Exception(
             "Cannot sample points on an infinite domain. Specify a finite domain."
         )
     self.scan(domain.start)
     self.scan(domain.end)
     return super().sample_points(domain=domain,
                                  min_step=min_step,
                                  step=step)
Esempio n. 6
0
    def _domain_indexes(self, domain):
        """
        Turn a domain into start and end indexes (inclusive and exclusive respectively).
        """
        points_len = len(self._points)
        if domain.is_superset_of(self.domain):
            return 0, points_len

        domain = Interval.intersection([domain, self.domain])
        if domain.is_empty:
            return 0, 0

        if domain.is_negative_infinite:
            start_i = 0
        else:
            i = max(0, int(math.floor(self.x_index(domain.start))))
            while i < points_len:
                x = self._points[i][0]
                if x >= domain.end:
                    # i -= 1
                    break
                if domain.contains(x):
                    break
                i += 1
            start_i = i

        if domain.is_positive_infinite:
            end_i = points_len
        else:
            i = min(points_len, int(math.ceil(self.x_index(domain.end))))
            while i >= 0:
                x = self._points[i][0]
                if x <= domain.start:
                    # i += 1
                    break
                if domain.contains(x):
                    break
                i -= 1
            end_i = i + 1

        return start_i, end_i
Esempio n. 7
0
    def sample_points(self, domain=None, min_step=None, step=None):
        domain = Interval.parse(domain, default_inf=True)

        if self.domain.is_empty:
            return []

        if self.interval is not None and (
            (min_step is not None and min_step > self.interval) or
            (step is not None and step != self.interval)):
            # Irregular sampling
            return super().sample_points(domain=domain,
                                         min_step=min_step,
                                         step=step)

        if domain is None or domain.is_superset_of(self.domain):
            # Sample all
            return list(self._points)

        # Sample some
        domain = Interval.intersection([self.domain, domain])
        if domain.is_empty:
            return []
        i0, i1 = self._domain_indexes(domain)
        return self._points[i0:i1]
Esempio n. 8
0
 def get_domain(self):
     domains = list(map(lambda f: f.domain, self.funcs))
     if self.is_union:
         return Interval.union(domains)
     else:
         return Interval.intersection(domains)
Esempio n. 9
0
    def update_points_of_interest(self, underlying_points):
        if not self.is_ready:
            return False

        i_end = len(underlying_points)
        if i_end == 0:
            return False

        def process_points_on_trend(points_on_trend, insert_index):
            if len(points_on_trend) == 0:
                return
            closest_point = None
            closest_dist = 0
            for p in points_on_trend:
                dist = abs(self.y(p[0]) - p[1])
                if closest_point is None or dist < closest_dist:
                    closest_dist = dist
                    closest_point = p
            self.tangent_points.insert(insert_index, closest_point)

        # find intersections, tangent points and extremas
        phase = 0
        phase_point = None
        previous_phase = phase
        intersection_found = False
        intersection_insert_index = len(self.intersections)
        tangent_insert_index = len(self.tangent_points)
        points_on_trend = []
        new_extremas = []
        extrema = None
        extrema_dist = 0

        # search up to the last intersection or tangent point
        update_interval = self.search_interval
        if len(self.intersections) != 0:
            update_interval = Interval.intersection(
                [update_interval,
                 Interval.gte(self.intersections[-1][0])])
        if len(self.tangent_points) != 0:
            update_interval = Interval.intersection(
                [update_interval,
                 Interval.gt(self.tangent_points[-1][0])])

        for i in reversed(range(len(underlying_points))):
            p = underlying_points[i]
            if not update_interval.contains(p[0]):
                break

            if self.is_point_on_trend(p):
                points_on_trend.insert(0, p)
                if extrema is not None:
                    new_extremas.insert(0, extrema)
                    extrema = None
                continue
            elif len(points_on_trend) != 0:
                process_points_on_trend(points_on_trend, tangent_insert_index)
                points_on_trend = []

            phase = p[1] - self.y(p[0])
            at_intersection = previous_phase != 0 and phase * previous_phase < 0

            if at_intersection:
                # found intersection
                intersection = _line_intersection(self._line, (phase_point, p))
                if intersection is None or intersection[0] < self._line[0][0]:
                    intersection = _average_point_of_2(phase_point, p)
                self.intersections.insert(intersection_insert_index,
                                          intersection)
                intersection_found = True

                if extrema is not None:
                    new_extremas.insert(0, extrema)
                    extrema = None

            if phase > 0:
                dist = p[1]
            else:
                dist = -p[1]
            if extrema is None or dist > extrema_dist:
                extrema = p
                extrema_dist = dist

            previous_phase = phase
            phase_point = p

        if len(points_on_trend) != 0:
            process_points_on_trend(points_on_trend, tangent_insert_index)

        if extrema is not None:
            new_extremas.insert(0, extrema)
        if len(new_extremas) != 0:
            # merge extremas with existing ones
            if len(self.extremas) == 0:
                self.extremas += new_extremas
            else:
                if self.extremas[-1][0] >= update_interval.start:
                    # old extrema may be outdated
                    del self.extremas[-1]
                self.extremas += new_extremas

        if intersection_found:
            self.update_interval()

        return intersection_found
Esempio n. 10
0
def test_intersection():
    # closed, closed
    d1 = Interval(0, 2, start_open=False, end_open=False)
    d2 = Interval(1, 3, start_open=False, end_open=False)

    assert d1.contains(0)
    assert d1.contains(1)
    assert d1.contains(2)

    d = Interval.intersection([d1, d2])
    assert d.start == 1
    assert d.end == 2
    assert not d.start_open
    assert not d.end_open

    d = Interval.union([d1, d2])
    assert d.start == 0
    assert d.end == 3
    assert not d.start_open
    assert not d.end_open

    # closed, open
    d1 = Interval(0, 2, start_open=False, end_open=False)
    d2 = Interval(1, 3, start_open=True, end_open=True)

    d = Interval.intersection([d1, d2])
    assert d.start == 1
    assert d.end == 2
    assert d.start_open
    assert not d.end_open

    d = Interval.union([d1, d2])
    assert d.start == 0
    assert d.end == 3
    assert not d.start_open
    assert d.end_open

    # open, open
    d1 = Interval(0, 2, start_open=True, end_open=True)
    d2 = Interval(1, 3, start_open=True, end_open=True)

    assert not d1.contains(0)
    assert d1.contains(1)
    assert not d1.contains(2)

    d = Interval.intersection([d1, d2])
    assert d.start == 1
    assert d.end == 2
    assert d.start_open
    assert d.end_open

    d = Interval.union([d1, d2])
    assert d.start == 0
    assert d.end == 3
    assert d.start_open
    assert d.end_open

    d = Interval.intersection([Interval(0, 1), Interval(2, 3)])
    assert d.is_empty

    d = Interval.intersection([Interval(0, 1, end_open=True), Interval(1, 3, start_open=True)])
    assert d.is_empty

    d = Interval.intersection([Interval(0, 1), Interval.empty()])
    assert d.is_empty

    d = Interval.union([Interval.empty(), 1])
    assert d.start == 1
    assert d.end == 1
Esempio n. 11
0
def test_intersection_inf():
    assert Interval.intersection([Interval.gte(100), (98, 101)]) == (100, 101)
    assert Interval.intersection([Interval.point(100), Interval.open_closed(100, 101)]) == Interval.empty()