Example #1
0
 def check_max_reward(self, max_reward: float) -> ModelStep:
     """
     Returns whether the profit upper bound is acceptably high.
     :param max_reward: highest profit to sell for: res_line - sup_line at 0.5t
     """
     return ModelStep(passed=max_reward / self.period_low > 0.15 / 100,
                      value=f'{100 * max_reward / self.period_low:.2f}%',
                      step_id=Breakout1ModelSteps.MAX_REWARD)
Example #2
0
 def check_range_change_2(self, range_change_2: float) -> ModelStep:
     """
     Returns whether the range decreased from [0.31t, 0.65t] to [0.66t, 0.85t].
     :param range_change_2: change in price range between [0.66, 0.85t] and [0.66t, 0.85t]
     """
     return ModelStep(
         passed=range_change_2 / self.period_low < 0.1,
         value=f'{100 * range_change_2 / self.period_low:0.2f}%',
         step_id=Breakout1ModelSteps.RANGE_CHANGE_2)
Example #3
0
 def check_dist_from_res(self, dist_from_res: float) -> ModelStep:
     """
     Returns whether the price exceeded the resistance line by at least 10% of the period's range.
     :param dist_from_res: difference between the resistance line and the symbol's recent high
     """
     return ModelStep(
         passed=dist_from_res >= 0.1 * self.period_range,
         value=f'{100 * dist_from_res / self.period_range:.2f}%',
         step_id=Breakout1ModelSteps.BREAKS_RESISTANCE)
Example #4
0
 def check_dist_to_sup(self, dist_to_sup: float) -> ModelStep:
     """
     Returns whether the price dipped to slightly above or just barely below the support.
     :param dist_to_sup: difference between the symbol's recent low and the support line
     """
     return ModelStep(passed=self.period_range * -15 / 100 <= dist_to_sup <=
                      self.period_range * 20 / 100,
                      value=f'{100 * dist_to_sup / self.period_range:.2f}%',
                      step_id=Breakout1ModelSteps.DIPS_TO_SUPPORT)
Example #5
0
 def check_high_volume_drop_ratio(
         self, high_volume_drop_ratio: float) -> ModelStep:
     """
     Returns whether the price drops too often when volume increases.
     :param high_volume_drop_ratio: when a minute's volume is higher than usual, the pct of occurrences
         that see price drop
     """
     self.set_val('high_volume_drop_ratio', high_volume_drop_ratio)
     return ModelStep(passed=high_volume_drop_ratio > 1.5,
                      value=f'{high_volume_drop_ratio}:1',
                      step_id=Breakout1ModelSteps.HIGH_VOL_DROP_RATIO)
Example #6
0
    def check_strongest_high_volume_dip(
            self, strongest_high_volume_dip: float) -> ModelStep:
        """
        Returns whether any single minute with atypically high volume drops in price too steeply.
        :param strongest_high_volume_dip: strongest minute-resolution price drop that is accompanied by
            higher-than-usual volume
        """

        return ModelStep(
            passed=strongest_high_volume_dip < self.avg_minute_range +
            (1.7 * self.stdev_minute_range),
            value=
            f'{(strongest_high_volume_dip - self.avg_minute_range) / self.stdev_minute_range:.0f} '
            f'stdevs',
            step_id=Breakout1ModelSteps.STRONGEST_HIGH_VOL_DIP)
Example #7
0
    def check_ema_minute_volume(
            self, ema_minute_volume: float,
            med_ema_volume_prev_7_periods: float) -> ModelStep:
        """
        Returns whether this period's moving-average volume is higher than the median of the moving-average volume
        during the same period on the previous 7 days.
        :param ema_minute_volume: average minute's volume exponentially weighted by time
        :param med_ema_volume_prev_7_periods: median of: moving-average volume during the same period on each of
            the last 7 days
        """

        return ModelStep(
            passed=ema_minute_volume > 1.2 * med_ema_volume_prev_7_periods,
            value=
            f'{100 * ema_minute_volume / med_ema_volume_prev_7_periods:.1f}%',
            step_id=Breakout1ModelSteps.EMA_MINUTE_VOLUME)
 def add_step(self,
              step: ModelStep = None,
              passed: bool = None,
              value: str = None,
              step_id: ModelSteps = None) -> None:
     """
     Adds a step in the calculation of model output.
     Parameters: either a single ModelStep, or:
         passed: bool,
         value: str,
         step_id: ModelSteps
     """
     if step is not None:
         self.steps.append(step)
     elif passed is not None and value is not None and step_id is not None:
         self.steps.append(
             ModelStep(passed=passed, value=value, step_id=step_id))
     else:
         raise ValueError(
             'Invalid arguments passed to model\'s output.add_step()')
Example #9
0
    def _check_ema_volume_excitement(self,
                                     output: Breakout1ModelOutput) -> bool:
        ema_volumes = [ema(output.minute_volumes)]
        prev_date = self.time().now().date()
        for i in range(7):
            # Load the previous day's data
            prev_date = self.time().get_prev_mkt_day(prev_date)
            day_data = self.mongo().load_symbol_day(output.symbol, prev_date)
            if not SymbolDay.validate_candles(day_data.candles):
                output.steps.append(
                    ModelStep(
                        passed=False,
                        value=
                        f'missing needed data on {prev_date.strftime(DATE_FORMAT)}',
                        step_id=Breakout1ModelSteps.EMA_MINUTE_VOLUME))
                return False

            # Aggregate the day's second-resolution candles into minute resolution
            prev_period_start = datetime.combine(prev_date,
                                                 output.period.start_time)
            prev_period_end = datetime.combine(prev_date,
                                               output.period.end_time)
            prev_second_candles = [
                candle for candle in day_data.candles
                if prev_period_start <= candle.moment <= prev_period_end
            ]
            prev_minute_candles = aggregate_minute_candles(prev_second_candles)

            # Calculate the previous day's moving-average volume
            ema_volumes.append(
                ema([candle.volume for candle in prev_minute_candles]))

        # Calculate the median ema volume of the same period on each of the past 7 days
        med_ema_volume_prev_7_periods = median(ema_volumes)
        # Calculate the ema volume of this period today
        ema_minute_volume = ema(output.minute_volumes)
        # Perform next step: ema minute volume check
        output.steps.append(
            output.check_ema_minute_volume(ema_minute_volume,
                                           med_ema_volume_prev_7_periods))
        return output.steps[-1].passed