def aggregate(cls, quotes, resolution=None) -> List['Quote']: if len(quotes) == 0: return [] resolution = Duration.parse(resolution) if resolution == quotes[0].resolution: # No aggregation necessary return quotes elif resolution < quotes[0].resolution: raise Exception( 'Aggregate resolution is smaller than the quote resolution') agr_quotes: List[Quote] = [] current_start_date = None span_quotes = [] for quote in quotes: start_date = resolution.floor(quote.date) if start_date != current_start_date: if len(span_quotes) != 0: agr_quote = cls.aggregate_single(span_quotes, resolution=resolution) agr_quotes.append(agr_quote) span_quotes.clear() current_start_date = start_date if start_date == current_start_date: span_quotes.append(quote) if len(span_quotes) != 0: agr_quote = cls.aggregate_single(span_quotes, resolution=resolution) agr_quotes.append(agr_quote) return agr_quotes
def __init__(self, *ohlc, date=None, volume=None, resolution=None, res=None): ohlc = test_util.flatten(ohlc) assert len(ohlc) >= 4 if volume is None and len(ohlc) > 4: volume = float(ohlc[4]) resolution = resolution or res assert date >= 0 assert volume >= 0 assert resolution is not None super().__init__() self._start_date = date self._resolution = Duration.parse(resolution) self.open = float(ohlc[0]) self.high = float(ohlc[1]) self.low = float(ohlc[2]) self.close = float(ohlc[3]) assert self.open > 0 assert self.high > 0 assert self.low > 0 assert self.close > 0 self.volume = volume self._price_domain = None self.reset_transient_time()
def __init__(self, func, offset, duration=None): super().__init__() self.curve = Curve.parse(func) self.offset = offset self.duration = None if duration is not None: self.duration = Duration.parse(duration) if type(self.offset) != int: raise Exception( 'Offset must be an interger when duration is defined') self._observer_token = self.curve.add_observer( begin=self.begin_offset_update, end=self.end_offset_update, prioritize=True)
def empty_list(cls, price: float, resolution: Any, domain: Any) -> List['Quote']: domain = Interval.parse(domain) quotes: List[Quote] = [] if not domain.is_empty: if not domain.is_finite: raise ValueError('Must specify a finite domain') resolution = Duration.parse(resolution) ohlc = [price] * 4 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) return quotes
def aggregate_single(cls, quotes, resolution=None) -> 'Quote': if len(quotes) == 0: raise Exception('Cannot aggregate quote from empty list') o = quotes[0].open c = quotes[-1].close l = o h = o v = 0 for q in quotes: if q.low < l: l = q.low if q.high > h: h = q.high v += q.volume if resolution is not None: resolution = Duration.parse(resolution) else: resolution = quotes[0].resolution.aggregate(len(quotes)) date = resolution.floor(quotes[0].date) return Quote(o, h, l, c, date=date, volume=v, resolution=resolution)
def mock(cls, quotes, t_start=0, t_step=86400.0, volume=1): dicts = [] t_start = test_util.timestamp(t_start) t_step = Duration.parse(t_step) t = t_step.floor(t_start) for q in quotes: d = cls.normalize_data(q) if d['volume'] is None: d['volume'] = volume if d['date'] is None: d['date'] = t else: t = d['date'] if d['res'] is None: d['res'] = t_step dicts.append(d) t = t_step.next(t) return cls.parse_many(dicts)