コード例 #1
0
    def __init__(self, initial: Price):
        super().__init__(initial)
        mod: Modifier
        parent: Modifier

        # Slice 2: InitialDecay
        mod = InitialDecay(self.initial, None)
        self.timeline[TimePeriod(2)] = mod
        parent = mod

        # Slices 3-13: Decay
        for i in range(3, 14):
            time = TimePeriod(i)
            mod = SlowDecay(self.initial, parent)
            self.timeline[time] = mod
            parent = mod
コード例 #2
0
    def __init__(self, initial: 'Price', pattern_start: int):

        super().__init__(initial, pattern_start)

        def _get_pattern(value: int) -> Type[Modifier]:
            # The default:
            cls: Type[Modifier] = SlowDecay

            # Pattern takes priority:
            if value == pattern_start:
                cls = SmallProfit
            elif value == pattern_start + 1:
                cls = MediumProfit
            elif value == pattern_start + 2:
                cls = LargeProfit
            elif value == pattern_start + 3:
                cls = MediumProfit
            elif value == pattern_start + 4:
                cls = SmallProfit
            elif value >= pattern_start + 5:
                # Week finishes out with independent low prices
                cls = WideLoss
            elif value == 2:
                # Normal start-of-week pattern
                cls = InitialDecay

            return cls

        parent = None
        # Slices 2-13: Magic!
        for i in range(2, 14):
            time = TimePeriod(i)
            mod = _get_pattern(i)(self.initial, parent)
            self.timeline[time] = mod
            parent = mod
コード例 #3
0
    def __init__(self, initial: Price, length_phase1: int, length_decay1: int,
                 length_phase2: int):

        super().__init__(initial)

        if not 0 <= length_phase1 <= 6:
            raise ValueError("Phase1 length must be between [0, 6]")
        self._length_phase1 = length_phase1

        if not 2 <= length_decay1 <= 3:
            raise ValueError("Decay1 length must be 2 or 3")
        self._length_decay1 = length_decay1
        self._length_decay2 = 5 - length_decay1

        remainder = 7 - length_phase1
        if not 1 <= length_phase2 <= remainder:
            raise ValueError(f"Phase2 must be between [1, {remainder}]")
        self._length_phase2 = length_phase2
        self._length_phase3 = remainder - length_phase2

        assert (self._length_phase1 + self._length_phase2 +
                self._length_phase3 + self._length_decay1 +
                self._length_decay2) == 12

        chain: List[Modifier] = []
        decay_class: Type[Modifier]

        def _push_node(mod_cls: Type[Modifier]) -> None:
            mod = mod_cls(self.initial, chain[-1] if chain else None)
            chain.append(mod)

        # Phase 1 [0, 6]
        for _ in range(0, self._length_phase1):
            _push_node(SmallProfit)

        # Decay 1 [2, 3]
        decay_class = MediumLoss
        for _ in range(0, self._length_decay1):
            _push_node(decay_class)
            decay_class = RapidDecay

        # Phase 2 [1, 6]
        for _ in range(0, self._length_phase2):
            _push_node(SmallProfit)

        # Decay 2 [2, 3]
        decay_class = MediumLoss
        for _ in range(0, self._length_decay2):
            _push_node(decay_class)
            decay_class = RapidDecay

        # Phase 3 [0, 6]
        for _ in range(0, self._length_phase3):
            _push_node(SmallProfit)

        # Build timeline
        assert len(chain) == 12
        for i, mod in enumerate(chain):
            time = TimePeriod(i + 2)
            self.timeline[time] = mod
コード例 #4
0
 def random_price(self, time: AnyTime):
     '''Provide a random price for the given time, unless that time has data.'''
     timeslice = TimePeriod.normalize(time)
     if self.timeline[timeslice].price.is_atomic:
         return self.timeline[timeslice].price.value
     return random.randint(self.timeline[timeslice].price.lower,
                           self.timeline[timeslice].price.upper)
コード例 #5
0
 def normalize(cls, value: Any) -> Any:
     if isinstance(value, Dict):
         return {
             TimePeriod.normalize(key): price
             for key, price in value.items()
         }
     return value
コード例 #6
0
    def __init__(self, initial: 'Price', pattern_start: int):

        low = self._pattern_earliest
        high = self._pattern_latest
        if not low <= pattern_start <= high:
            raise ValueError(
                f"pattern_start must be between {low} and {high}, inclusive")

        super().__init__(initial)
        self._pattern_start = pattern_start
        self._pattern_peak = TimePeriod(pattern_start + self._peak_time)
        self._tail = 9 - pattern_start
コード例 #7
0
ファイル: multi.py プロジェクト: NikMThompson/Botnip
    def fix_price(self, time: AnyTime, price: int) -> None:
        if not self:
            assert RuntimeError("No viable models to fix prices on!")

        timeslice = TimePeriod.normalize(time)
        remove_queue = []
        for index, model in self._models.items():
            try:
                model.fix_price(timeslice, price)
            except ArithmeticError as exc:
                logging.info(f"Ruled out model: {model.name}")
                logging.debug(f"  Reason: {timeslice.name} price={price} not possible:")
                logging.debug(f"    {str(exc)}")
                remove_queue.append(index)

        for i in remove_queue:
            del self._models[i]
コード例 #8
0
    def __init__(self, initial: 'Price', pattern_start: int):

        super().__init__(initial, pattern_start)

        chain: List[Modifier] = []
        decay_class: Type[Modifier]

        def _push_node(mod_cls: Type[Modifier],
                       parent_override: Optional[Modifier] = None) -> Modifier:
            if parent_override is None:
                my_parent = chain[-1] if chain else None
            else:
                my_parent = parent_override
            mod = mod_cls(self.initial, my_parent)
            chain.append(mod)
            return mod

        decay_class = WideLoss
        for _ in range(2, pattern_start):
            _push_node(decay_class)
            decay_class = SlowDecay

        # Pattern starts:
        _push_node(SmallProfit)
        _push_node(SmallProfit)

        # And then gets weird!
        # Create an unlisted parent that represents the peak shared across the next three prices.
        cap = MediumProfit(self.initial, chain[-1])
        _push_node(CappedPassthrough, cap).sub1 = True
        _push_node(Passthrough, cap)
        _push_node(CappedPassthrough, cap).sub1 = True

        # Alright, phew.
        decay_class = WideLoss
        for _ in range(0, self._tail):
            _push_node(decay_class)
            decay_class = SlowDecay

        # Build timeline
        assert len(chain) == 12
        for i, mod in enumerate(chain):
            time = TimePeriod(i + 2)
            self.timeline[time] = mod
コード例 #9
0
ファイル: multi.py プロジェクト: NikMThompson/Botnip
 def chatty_fix_price(self, time: AnyTime, price: int) -> None:
     timeslice = TimePeriod.normalize(time)
     self.fix_price(time, price)
     print(f"Added {timeslice.name} @ {price};")
     self.report()
コード例 #10
0
 def fix_price(self, time: AnyTime, price: int) -> None:
     timeslice = TimePeriod.normalize(time)
     self.timeline[timeslice].fix_price(price)
コード例 #11
0
def plot_models_range(name: str,
                      base_price: int,
                      models: Sequence[Model],
                      add_points: bool = False) -> None:

    colors = {
        TRIPLE: 'orange',
        SPIKE: 'green',
        DECAY: 'red',
        BUMP: 'purple',
    }

    _fig, ax = plt.subplots()

    # cosmetics
    ax.set_title(f"{name}'s weekly forecast: ")
    ax.set_ylabel('Turnip Price')
    ax.set_xticklabels([
        'Mon AM', 'Mon PM', 'Tue AM', 'Tue PM', 'Wed AM', 'Wed PM', 'Thu AM',
        'Thu PM', 'Fri AM', 'Fri PM', 'Sat AM', 'Sat PM'
    ])
    ax.xaxis.set_ticks(range(2, 14))
    plt.xticks(rotation=45)
    plt.grid(axis='both', which='major', ls='dotted')
    ax.set_ylim(0, 660)
    plt.tight_layout()
    plt.hlines(y=base_price, xmin=2, xmax=13, linestyles='dashed')

    if len(models) == 0:
        return

    a_model = models[0]

    continuous_priced_days = []
    continuous_priced_chunk = set()
    continuous_unpriced_days = []
    continuous_unpriced_chunk = set()
    for day in range(2, 14):
        # does this day have data?
        if a_model.timeline[TimePeriod(day)].price.is_atomic:
            # is tomorrow a valid day to have data?
            if day < 13:
                # does tomorrow have data?
                if a_model.timeline[TimePeriod(day + 1)].price.is_atomic:
                    # build onto the chunk
                    continuous_priced_chunk.update([day, day + 1])
                # chunk broken.
                else:
                    continuous_priced_chunk.update([day])
                    continuous_priced_days.append(
                        list(continuous_priced_chunk))
                    continuous_priced_chunk = set()
            else:
                # end of the week, finish the priced_days
                continuous_priced_days.append(list(continuous_priced_chunk))
        # today does not have data
        else:
            # is tomorrow a valid day to have data?
            if day < 13:
                # does it?
                if not a_model.timeline[TimePeriod(day + 1)].price.is_atomic:
                    # build the chunk
                    if day != 2:
                        # add yesterday unless today is monday_am
                        continuous_unpriced_chunk.update(
                            [day - 1, day, day + 1])
                    else:
                        continuous_unpriced_chunk.update([day, day + 1])
                # chunk broken
                else:
                    if day != 2:
                        continuous_unpriced_chunk.update(
                            [day - 1, day, day + 1])
                    else:
                        continuous_unpriced_chunk.update([day, day + 1])
                    continuous_unpriced_days.append(
                        list(sorted(continuous_unpriced_chunk,
                                    key=lambda x: x)))
                    continuous_unpriced_chunk = set()
            else:
                # end of the week, finish the unpriced_days
                continuous_unpriced_days.append(
                    list(continuous_unpriced_chunk))

    for chunk in continuous_priced_days:
        vals = [a_model.timeline[TimePeriod(day)].price.value for day in chunk]
        plt.plot(chunk,
                 vals,
                 c='black',
                 solid_capstyle='round',
                 solid_joinstyle='round')

    for chunk in continuous_unpriced_days:
        if len(chunk) == 1:
            # if this is one day of unpriced data, connect it to the neighbors.
            value = chunk[0]
            chunk = [value - 1, value, value + 1]
        for model in models:
            low_vals = [
                model.timeline[TimePeriod(day)].price.lower for day in chunk
            ]
            high_vals = [
                model.timeline[TimePeriod(day)].price.upper for day in chunk
            ]

            alpha = 1 / len(models)

            plt.fill_between(chunk,
                             low_vals,
                             high_vals,
                             alpha=alpha,
                             color=colors[model.model_type])

            if add_points:
                plt.scatter(chunk, low_vals, c='black', s=2)
                plt.scatter(chunk, high_vals, c='black', s=2)