Пример #1
0
def test_first():
    funcs = [[(0, None), (1, 12), (2, None)], [(0, 1), (1, 1), (2, 1)]]
    first = Curve.first(funcs)
    assert first(-1) is None
    assert first(0) == 1
    assert first(1) == 12
    assert first(2) == 1
    assert first(3) is None

    funcs = [[(0, None), (1, 12), (2, None)], 1]
    first = Curve.first(funcs)
    assert first(-1) == 1
    assert first(0) == 1
    assert first(1) == 12
    assert first(2) == 1
    assert first(3) == 1

    first = Curve.first([
        Generic(lambda x: 1, domain=Interval(0, 2)),
        Generic(lambda x: 2, domain=Interval.gte(1))
    ])
    assert first(-1) is None
    assert first(0) == 1
    assert first(1) == 1
    assert first(2) == 1
    assert first(2.1) == 2
    assert first(3) == 2
    assert first.sample_points(Interval(0, 3), min_step=1) == [(0, 1), (1, 1),
                                                               (2, 1), (3, 2)]
Пример #2
0
def test_update_with_obj_autoremove():
    begin_update_count = 0

    def begin_update(domain):
        nonlocal begin_update_count
        begin_update_count += 1

    end_update_count = 0

    def end_update(domain):
        nonlocal end_update_count
        end_update_count += 1

    f = Curve()

    # Add and remove observer using object
    obj = T()
    f.add_observer(obj, begin=begin_update, end=end_update, autoremove=True)

    f.begin_update(Interval(1, 3))
    assert begin_update_count == 1
    f.end_update(Interval(1, 3))
    assert end_update_count == 1

    obj = None
    f.begin_update(Interval(1, 3))
    assert begin_update_count == 1
    f.end_update(Interval(1, 3))
    assert end_update_count == 1
Пример #3
0
    def end_update(self, domain):
        if domain.is_empty or self._end_update_interval.is_superset_of(domain):
            return
        self._end_update_interval = Interval.union(
            [self._end_update_interval, domain])
        if not self._end_update_interval.is_superset_of(
                self._begin_update_interval):
            # Keep collecting updates
            return

        # Updates complete
        update_interval = self._end_update_interval
        self._begin_update_interval = Interval.empty()
        self._end_update_interval = Interval.empty()
        self.set_needs_interval_update()
        for token in list(self._ordered_observer_tokens):
            _, callback_interval, _, callback, _, callback_with_interval = self._observer_data[
                token]
            if callback_interval is None or update_interval.intersects(
                    callback_interval):
                if callback is not None:
                    if callback_with_interval:
                        callback(update_interval)
                    else:
                        callback()
Пример #4
0
    def append_list(self, points):
        """
        `points` are assumed to be strictly ordered in ascending order w.r.t. to `x`.
        """
        points_len = len(self._points)
        if points_len == 0:
            return self.set(points)
        new_points_len = len(points)
        if new_points_len == 0:
            return

        if points[0][0] <= self._points[-1][0]:
            raise Exception(
                'Attempting to append points in non-ascending order')

        if self.domain.is_empty:
            domain = Interval.closed(points[0][0], points[-1][0])
        else:
            domain = Interval(self.domain.end,
                              points[-1][0],
                              start_open=True,
                              end_open=False)
        self.begin_update(domain)
        self._is_equally_spaced = self._points_equally_spaced(
            self._points, points)
        if self._force_equally_spaced and not self._is_equally_spaced:
            raise Exception(
                'Attempting to append points at non-regular intervals: {}{} + {}{}'
                .format('...' if len(self._points) > 2 else '',
                        self._points[len(self._points) - 2:], points[:2],
                        '...' if len(points) > 2 else ''))
        self._points += points
        self._did_change_points()
        self.end_update(domain)
Пример #5
0
 def get_domain(self):
     if len(self._points) == 0:
         return Interval.empty()
     return Interval(self._points[0][0],
                     self._points[-1][0],
                     start_open=False,
                     end_open=False)
Пример #6
0
    def span_interval(self, interval, start_open=False) -> Interval:
        """
        Returns the time interval which fully contains the specified interval.
        """
        interval = Interval.parse(interval, default_inf=True)
        if interval.is_empty:
            return Interval.empty()
        elif interval.start == interval.end:
            return self.span_date(interval.start, start_open=start_open)

        end_open = not start_open

        if interval.is_negative_infinite:
            start = -math.inf
        else:
            # Move outward if interval is closed but should be open
            o = not interval.start_open and start_open
            span = self.span_date(interval.start, start_open=o)
            start = span.start

        if interval.is_positive_infinite:
            end = math.inf
        else:
            # Move outward if interval is closed but should be open
            o = not interval.end_open and end_open
            span = self.span_date(interval.end, start_open=not o)
            end = span.end

        return Interval(start,
                        end,
                        start_open=start_open,
                        end_open=not start_open)
Пример #7
0
def test_interval_contains_inf():
    inf = Interval.infinite()
    assert inf.contains(math.inf) is True
    assert inf.contains(-math.inf) is True
    assert Interval.gte(0).contains(math.inf) is True
    assert Interval.gte(0).contains(-math.inf) is False
    assert Interval.lte(0).contains(math.inf) is False
    assert Interval.lte(0).contains(-math.inf) is True
Пример #8
0
 def __init__(self, y, domain=None):
     super().__init__(min_step=math.inf)
     self._value = y
     if domain is not None:
         domain = Interval.parse(domain)
     else:
         domain = Interval.infinite()
     self._const_interval = domain
Пример #9
0
 def __init__(self, min_step=None):
     self.name = None
     self._domain = None
     self._observer_data = {}
     self._ordered_observer_tokens = []
     self._begin_update_interval = Interval.empty()
     self._end_update_interval = Interval.empty()
     self.min_step = min_step
Пример #10
0
    def update_extension(self):
        if self.start:
            x = self.curve.domain.start
            if x is not None and self.curve.domain.start_open and self.curve.domain.contains(x + self.min_step):
                x += self.min_step
            y = None
            d_y = None
            if self.regression_degree is not None:
                x1 = x
                for i in range(self.regression_degree):
                    x1 = self.curve.x_next(x1, min_step=self.min_step)
                domain = Interval(x, x1)
                tangent = self.curve.regression(domain, min_step=self.min_step)
                if tangent is not None:
                    y = tangent.y(x)
                    d_y = tangent.slope
            elif self.regression_period is not None:
                domain = Interval(x, x + self.regression_period)
                tangent = self.curve.regression(domain, min_step=self.min_step)
                if tangent is not None:
                    y = tangent.y(x)
                    d_y = tangent.slope
            else:
                y = self.curve.y(x)
                d_y = self.curve.d_y(x, forward=True)

            self.start_valid = y is not None and d_y is not None
            if self.start_valid:
                self.update_extension_func(self.start_func, x, y, d_y)

        if self.end:
            x = self.curve.domain.end
            if x is not None and self.curve.domain.end_open and self.curve.domain.contains(x - self.min_step):
                x -= self.min_step
            y = None
            d_y = None
            if self.regression_degree is not None:
                x0 = x
                for i in range(self.regression_degree):
                    x0 = self.curve.x_previous(x0, min_step=self.min_step)
                domain = Interval(x0, x)
                tangent = self.curve.regression(domain, min_step=self.min_step)
                if tangent is not None:
                    y = tangent.y(x)
                    d_y = tangent.slope
            elif self.regression_period is not None:
                domain = Interval(x - self.regression_period, x)
                tangent = self.curve.regression(domain, min_step=self.min_step)
                if tangent is not None:
                    y = tangent.y(x)
                    d_y = tangent.slope
            else:
                y = self.curve.y(x)
                d_y = self.curve.d_y(x, forward=False)

            self.end_valid = y is not None and d_y is not None
            if self.end_valid:
                self.update_extension_func(self.end_func, x, y, d_y)
Пример #11
0
def test_round():
    assert Interval(1.2, 3.4).round() == (1, 3)
    assert Interval(1.2, 3.4).round(method=math.floor) == (1, 3)
    assert Interval(1.2, 3.4).round(method=math.ceil) == (2, 4)
    assert Interval.open_closed(1.2, 3.4).round() == Interval.open_closed(1, 3)
    assert Interval.closed_open(1.2, 3.4).round() == Interval.closed_open(1, 3)
    assert Interval.empty().round() == Interval.empty()
Пример #12
0
    def _did_update_extremas(self):
        self.possible_extrema = None
        self.possible_extrema_phase = None

        if len(self.extremas) == 0:
            self.extrema_interval = Interval.empty()
        else:
            self.extrema_interval = Interval(self.extrema_xs[0],
                                             self.extrema_xs[-1],
                                             start_open=False,
                                             end_open=False)
Пример #13
0
 def get_range(self, domain=None, **kwargs):
     points = self.sample_points(domain=domain, **kwargs)
     low = None
     high = None
     for p in points:
         if low is None or p[1] < low:
             low = p[1]
         if high is None or p[1] > high:
             high = p[1]
     if low is None or high is None:
         return Interval.empty()
     return Interval(low, high)
Пример #14
0
def test_duplicate_multiple_nested_function_update():
    points = Points([])
    f = (points * 0.5 + points * 0.5) * 2

    points.append((0, 1))
    assert f.is_updating is False
    assert f.domain == Interval.point(0)
    assert f.y(0) == 2

    points.append((1, 1))
    assert f.is_updating is False
    assert f.domain == Interval(0, 1)
    assert f.y(1) == 2
Пример #15
0
def test_sample_infinite():
    f = Constant(1)
    with pytest.raises(Exception):
        f.sample_points()

    with pytest.raises(Exception):
        f.sample_points(domain=Interval.infinite())

    with pytest.raises(Exception):
        f.sample_points(domain=Interval.gte(0))

    with pytest.raises(Exception):
        f.sample_points(domain=Interval.lte(0))
Пример #16
0
def test_span_interval():
    assert Duration('1h').span_interval(Interval.open(3600, 2 * 3600),
                                        start_open=False) == span(
                                            3600, 2 * 3600, start_open=False)
    assert Duration('1h').span_interval(Interval.open(3600, 2 * 3600),
                                        start_open=True) == span(
                                            3600, 2 * 3600, start_open=True)
    assert Duration('1h').span_interval(Interval.closed(3600, 2 * 3600),
                                        start_open=False) == span(
                                            3600, 3 * 3600, start_open=False)
    assert Duration('1h').span_interval(Interval.closed(3600, 2 * 3600),
                                        start_open=True) == span(
                                            0, 2 * 3600, start_open=True)
Пример #17
0
    def reset(self, domain=None):
        points_len = len(self._points)
        if points_len == 0:
            return
        if domain is None:
            return self.set([])
        domain = Interval.parse(domain)

        if not self.domain.intersects(domain):
            return

        if domain.is_superset_of(self.domain):
            self.set([])
            return

        remove_start_i, remove_end_i = self._domain_indexes(domain)
        if remove_start_i == remove_end_i:
            # Nothing to remove
            return
        head = self._points[:remove_start_i]
        tail = self._points[remove_end_i:]
        if len(head) != 0 and domain.contains(head[-1][0]):
            del head[-1]
        if len(tail) != 0 and domain.contains(tail[0][0]):
            del tail[0]
        head_len = len(head)
        tail_len = len(tail)
        if head_len + tail_len == 0:
            self.set([])
            return
        points = head + tail

        update_start = self._points[0][0]
        update_start_open = False
        if head_len != 0:
            update_start = head[-1][0]
            update_start_open = True

        update_end = self._points[-1][0]
        update_end_open = False
        if tail_len != 0:
            update_end = tail[0][0]
            update_end_open = True

        update_domain = Interval(update_start,
                                 update_end,
                                 start_open=update_start_open,
                                 end_open=update_end_open)

        self.set(points, update_domain=update_domain)
Пример #18
0
def test_duplicate_function_update():
    points = Points([])
    f = points + points

    points.append((0, 1))
    assert points.is_updating is False
    assert f.is_updating is False
    assert f.domain == Interval.point(0)
    assert f.y(0) == 2

    points.append((1, 1))
    assert points.is_updating is False
    assert f.is_updating is False
    assert f.domain == Interval(0, 1)
    assert f.y(1) == 2
Пример #19
0
def test_max():
    f = Curve.max([Points([(0, -1), (1, 0), (2, 1)]), 0])
    assert f.domain == Interval.closed(0, 2)
    assert f.y(-1) is None
    assert f.y(0) == 0
    assert f.y(1) == 0
    assert f.y(2) == 1
    assert f.y(3) is None

    f = Curve.max([0, Points([(0, -1), (1, 0), (2, 1)])])
    assert f.domain == Interval.closed(0, 2)
    assert f.y(-1) is None
    assert f.y(0) == 0
    assert f.y(1) == 0
    assert f.y(2) == 1
    assert f.y(3) is None
Пример #20
0
    def trim_list(cls,
                  quotes: List['Quote'],
                  domain: Any = None) -> List['Quote']:
        """
        Removes empty quotes from the start and end of the list.

        If a domain is specified, only empty quotes outside of the
        domain are removed.
        """
        if len(quotes) == 0:
            return []
        i0: Optional[int] = None
        i1: Optional[int] = None
        r = range(len(quotes))
        if domain is not None:
            domain = Interval.parse(domain)

        for i in r:
            q = quotes[i]
            if not q.is_empty or (domain is not None
                                  and domain.intersects(q.domain)):
                i0 = i
                break
        if i0 is None:
            return []

        for i in reversed(r):
            q = quotes[i]
            if not q.is_empty or (domain is not None
                                  and domain.intersects(q.domain)):
                i1 = i
                break
        assert i1 is not None
        return quotes[i0:i1 + 1]
Пример #21
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
Пример #22
0
    def __init__(self, func, start=True, end=True, uniform=True, raise_on_empty=False, min_step=MIN_STEP):
        super().__init__(min_step=min_step)
        self.curve = Curve.parse(func)

        if self.curve.domain.is_negative_infinite:
            start = False
        if self.curve.domain.is_positive_infinite:
            end = False

        self.start = start
        self.end = end
        self.start_valid = True
        self.end_valid = True
        self.uniform = uniform
        self.raise_on_empty = raise_on_empty
        self.extension_interval = Interval.empty()
        self._extension_stale = True
        self._extension_interval_stale = True
        self.curve.add_observer(begin=self.begin_extension_update, end=self.end_extension_update, prioritize=True)
        self.start_func = None
        self.end_func = None
        if self.start:
            self.start_func = self.create_extension_func(start=True)
            self.start_func.add_observer(self, begin=self.begin_update, end=self.end_update)
        if self.end:
            self.end_func = self.create_extension_func(start=False)
            self.end_func.add_observer(self, begin=self.begin_update, end=self.end_update)
Пример #23
0
    def replace(self, point, or_append=False):
        if not self.domain.contains(point[0]):
            if or_append:
                return self.append(point)
            else:
                raise Exception(
                    'Attempting to replace point outside of bounds')

        update_domain = Interval.point(point[0])
        self.begin_update(update_domain)

        nearest_i = int(math.ceil(self.x_index(point[0])))
        nearest_p = self._points[nearest_i]
        if point[0] != nearest_p[0]:
            if self._force_equally_spaced:
                raise Exception(
                    'Attempting to replace point {} between existing points. The nearest is {}.'
                    .format(point, nearest_p))
            else:
                self._points.insert(nearest_i, point)
                self._is_equally_spaced = False
        else:
            self._points[nearest_i] = point

        self._did_change_points()
        self.end_update(update_domain)
Пример #24
0
    def __init__(self,
                 min_width,
                 is_upper_trend=True,
                 min_points=None,
                 min_point_distance=0,
                 search_length_rel=None,
                 search_length_int_rel=None,
                 x_tol_rel=None,
                 x_tol_abs=None,
                 y_tol_rel=None,
                 y_tol_abs=None):
        self.min_width = min_width
        self.is_upper_trend = is_upper_trend
        self.min_points = min_points
        self.min_point_distance = min_point_distance
        self.search_length_rel = search_length_rel
        self.search_length_int_rel = search_length_int_rel
        self.x_tol_rel = x_tol_rel
        self.x_tol_abs = x_tol_abs
        self.y_tol_rel = y_tol_rel
        self.y_tol_abs = y_tol_abs
        """A list of points through which the trend line is formed."""
        self.trend_points = []
        """An unfiltered list of points from which trend points are derived."""
        self._boundary_points = []
        """A list of points which touch the trend line without the underlying trend crossing the trend."""
        self.tangent_points = []

        self._line = None
        self.search_interval = Interval.empty()
        self.reset_points_of_interest()
        self.reset_prediction()
Пример #25
0
 def domain(self):
     if self._domain is None:
         self._domain = Interval(self.start_date,
                                 self.end_date,
                                 start_open=DOMAIN_START_OPEN,
                                 end_open=not DOMAIN_START_OPEN)
     return self._domain
Пример #26
0
    def update_interval(self):
        len_trend_points = len(self.trend_points)
        if self._line is None:
            if len_trend_points == 1:
                self.search_interval = Interval.point(self.trend_points[0][0])
            else:
                self.search_interval = Interval.empty()
            return

        p0, p1 = self._line
        if p0[0] == p1[0]:
            # vertical line
            self.search_interval = Interval.point(p0[0])
            return

        if self.search_length_rel <= 0:
            self.search_interval = Interval.closed(p0[0], p1[0])
            return

        x_min = p0[0]
        x_max = p1[0]

        intersection = self.intersections[0] if len(
            self.intersections) != 0 else None
        if intersection is not None and intersection[0] <= x_min:
            intersection = None

        if intersection is None or len_trend_points >= self.min_points:
            # search ahead
            x_length = (x_max - x_min) * self.search_length_rel
        else:
            # not enought points to go through intersection
            x_length = intersection[0] - x_min

        # if intersection is None:
        #     # search ahead
        #     x_length = (x_max - x_min) * self.search_length_rel
        # elif len_trend_points >= self.min_points:
        #     # search ahead of intersection
        #     x_length = (intersection[0] - x_min) * self.search_length_int_rel
        # else:
        #     # not enought points to go through intersection
        #     x_length = intersection[0] - x_min

        x_max = x_min + x_length

        self.search_interval = Interval.closed_open(x_min, x_max)
Пример #27
0
def test_subset():
    d = Interval(1, 3)
    assert d.is_subset_of((0, 4))
    assert d.is_subset_of((1, 3))
    assert not d.is_subset_of(Interval.closed_open(1, 3))

    assert d.is_superset_of((2, 2))
    assert d.is_superset_of((1, 3))
    assert d.is_superset_of(Interval.closed_open(1, 3))
Пример #28
0
    def _calendar_span(self, date, start_open=False) -> Interval:
        """
        Returns the time interval which contains the specified `date`.
        """
        date = arrow.get(date)
        t = self._normalized_date(date)
        msec = timedelta(microseconds=1)
        start = date - msec
        end = date + msec
        degree = self.degree
        unit = self.unit
        sunit = type(self).singular_unit(unit)
        date_span = None

        force_agr = unit == WEEKS
        if force_agr:
            # Special case
            sunit = type(self).singular_unit(DAYS)

        # Find matching unit interval (1d, 1h, etc)
        for r0, r1 in arrow.Arrow.span_range(sunit, start, end):
            # Normalize range end
            r1 += msec
            interval = Interval(r0.float_timestamp,
                                r1.float_timestamp,
                                start_open=start_open,
                                end_open=not start_open)
            if interval.contains(t):
                if degree == 1 and not force_agr:
                    return interval
                else:
                    date_span = r0, r1
                    break

        # Expand into aggregate interval
        if self.unit == YEARS:
            start_date, end_date = self._expand_years(date_span)
        elif self.parent is not None and self.parent.unit == YEARS:
            start_date, end_date = self._expand_within_year(date_span)
        else:
            raise Exception(f'Unable to expand unit: {self.unit}')

        return Interval(self._normalized_date(start_date),
                        self._normalized_date(end_date),
                        start_open=start_open,
                        end_open=not start_open)
Пример #29
0
    def pad(self, interval, start=0, end=0, start_open=False) -> Interval:
        """
        Appends calendar lengths to the start and end of a interval.
        """
        interval = self.span_interval(interval, start_open=start_open)
        if interval.is_empty:
            return Interval.empty()

        l = interval.start
        if not interval.is_negative_infinite:
            l = self.step(l, count=start, backward=True)

        h = interval.end
        if not interval.is_positive_infinite:
            h = self.step(h, count=end)

        return Interval(l, h, start_open=start_open, end_open=not start_open)
Пример #30
0
def test_iterate_uniform():
    spans = list(
        Duration('1h').iterate(Interval.closed(2 * 3600, 4 * 3600),
                               start_open=False))
    assert len(spans) == 3
    assert spans[0] == span(2 * 3600, 3 * 3600, start_open=False)
    assert spans[1] == span(3 * 3600, 4 * 3600, start_open=False)
    assert spans[2] == span(4 * 3600, 5 * 3600, start_open=False)

    spans = list(
        Duration('1h').iterate(Interval.closed(2 * 3600, 4 * 3600),
                               backward=True,
                               start_open=False))
    assert len(spans) == 3
    assert spans[0] == span(4 * 3600, 5 * 3600, start_open=False)
    assert spans[1] == span(3 * 3600, 4 * 3600, start_open=False)
    assert spans[2] == span(2 * 3600, 3 * 3600, start_open=False)