def test_making_series_input_shape(self): got = input_util.series_source_inputs_shape( source_calc_type=_DataType.Enum.CLOSE_PRICE, t=time.FromUnixSeconds(1578009600), time_spec=calc.CalcTimeSpecs(num_periods=2, period_length=time.Hours(24))) expected = get_input_shapes() assert_that( got, contains(equals_proto(expected[0]), equals_proto(expected[1])))
def get_recursive_inputs_for_ema20(t: time.Time, symbol: str) -> List[DataEntry]: return [ DataEntry( symbol=symbol, data_space=DataEntry.STOCK_DATA, data_type=DataType.EMA_20D, value=58.31, timestamp=time_util.from_time(t - time.Hours(24)), ), _make_close_price(symbol, 59.85, t) ]
def test_making_series_input_shape_account_for_trading_days(self): got = input_util.series_source_inputs_shape( source_calc_type=_DataType.Enum.CLOSE_PRICE, t=time.FromCivil(time.CivilTime(2017, 12, 26)), time_spec=calc.CalcTimeSpecs(num_periods=2, period_length=time.Hours(24))) assert_that( got, contains( equals_proto(f""" data_type: CLOSE_PRICE timestamp {{ seconds: {time.as_seconds(2017, 12, 22)} }}"""), equals_proto(f""" data_type: CLOSE_PRICE timestamp {{ seconds: {time.as_seconds(2017, 12, 26)} }}""")))
def test_making_recursive_input_shape(self): got = input_util.recursive_inputs_shape( base_calc_type=_DataType.Enum.EMA_20D, incr_calc_type=_DataType.Enum.CLOSE_PRICE, t=time.FromUnixSeconds(1578009600), time_spec=calc.CalcTimeSpecs(num_periods=20, period_length=time.Hours(24))) assert_that( got, contains( equals_proto(f""" data_type: EMA_20D timestamp {{ seconds: {time.as_seconds(2020, 1, 2)} }}"""), equals_proto(f""" data_type: CLOSE_PRICE timestamp {{ seconds: {time.as_seconds(2020, 1, 3)} }}""")))
def test_ema20_recursive_calculation(self): date = time.FromCivil(time.CivilTime(2020, 1, 1)) close_now = _make_close_price(60.84, date) ema_last = _DataEntry( symbol='TEST', data_space=_DataEntry.STOCK_DATA, data_type=data_type_pb2.DataType.EMA_20D, value=58.46, timestamp=time_util.from_time(date - time.Hours(24)), ) assert_that( ema.make_ema_20d_producer().calculate((ema_last, close_now)), equals_proto(f""" symbol: "TEST" data_space: STOCK_DATA data_type: EMA_20D value: 58.68666666666667 timestamp {{ seconds: {time.as_seconds(2020, 1, 1)} }}"""))
# EMA is computed based on previous EMA. However, it must starts somewhere, # where the first EMA need to calculated from X days of close prices. def _initial(self, inputs: calc.CalcInputs) -> float: prices = (data.value for data in inputs) return pd.DataFrame(prices).ewm(span=self._time_specs.num_periods, adjust=False).mean().iloc[-1][0] def _recur(self, inputs: calc.CalcInputs) -> float: num_periods = self._time_specs.num_periods return (SMOOTHING_FACTOR / (num_periods + 1) * inputs[1].value \ + (num_periods + 1 - SMOOTHING_FACTOR) / (num_periods + 1) * inputs[0].value) def recursive_inputs_shape(self, t: time.Time) -> calc.RecursiveInputs: return input_util.recursive_inputs_shape(self._calc_type, self._source_calc, t, self._time_specs) def source_inputs_shape(self, t: time.Time) -> calc.SourceInputs: return input_util.series_source_inputs_shape(self._source_calc, t, self._time_specs) make_ema_20d_producer: calc.CalcProducerFactory = lambda: EmaProducer( DataType.EMA_20D, calc.CalcTimeSpecs(20, time.Hours(24))) make_ema_50d_producer: calc.CalcProducerFactory = lambda: EmaProducer( DataType.EMA_50D, calc.CalcTimeSpecs(50, time.Hours(24))) make_ema_150d_producer: calc.CalcProducerFactory = lambda: EmaProducer( DataType.EMA_150D, calc.CalcTimeSpecs(150, time.Hours(24)))