Example #1
0
def _create_price_watermark(
    plot: plt.Subplot,
    name: str,
    price: int,
    va_top: bool,
    pattern: Optional["models.PricePatterns"],
) -> None:
    y_text_offset = 5

    if va_top:
        vertical_alignment = "top"
        y_text_offset *= -1
    else:
        vertical_alignment = "bottom"

    if pattern is None:
        pattern_color = colors.CURRENT_PRICE_COLOR
    else:
        pattern_color = colors.PATTERN_COLORS[pattern]

    # Create a dotted line line at the break-even point that matches the price
    # progression
    price_line = mlines.Line2D(
        [0, 4],
        [price, price],
        color=pattern_color,
        linewidth=2,
        linestyle="--",
    )
    plot.add_line(price_line)

    plot.annotate(
        f"{name}: {price}",
        (2, price),
        textcoords="offset points",
        xytext=(0, y_text_offset),
        horizontalalignment="center",
        verticalalignment=vertical_alignment,
        color=pattern_color,
        fontsize=LABEL_SIZE,
        bbox={
            "boxstyle": "Square,pad=0.3",
            "facecolor": colors.color(0, 0, 0, alpha=0.08),
            "edgecolor": "none",
            "linewidth": 0,
        },
    )
def _add_cursor(plot_prices: plt.Subplot, current_period: int) -> None:
    # Create a shaded region for the current period
    rect = patches.Rectangle(
        (current_period - 0.5, 0),
        1,
        701,
        linewidth=0,
        color=colors.CURRENT_PRICE_COLOR,
        alpha=0.1,
    )

    # Add the patch to the Axes
    plot_prices.add_patch(rect)

    # Create a line at the head of the current price period
    current_period_line = mlines.Line2D(
        [current_period - 0.5, current_period - 0.5],
        [0, 700],
        color=colors.CURRENT_PRICE_COLOR,
    )
    plot_prices.add_line(current_period_line)
def _create_pattern_line(
    price_plot: plt.Subplot,
    spike_breakdown: List[float],
    spike_pattern: models.PotentialPattern,
    spike_color: List[float],
) -> None:
    """Create a dashed line on the max price for periods with a potential spike"""
    # get highest possible price for each period

    first_period = spike_pattern.spike.start
    last_period = spike_pattern.spike.end
    high_price = spike_pattern.prices_summary.max

    period_highs: List[Optional[int]] = [
        high_price for _ in range(first_period, last_period + 1)
    ]
    price_periods: List[float] = [
        p for p in range(first_period, last_period + 1)
    ]

    # Instead of using a plot, we are just going to draw the line directly.
    # Create a line at the head of the current price period
    current_period_line = mlines.Line2D(
        [first_period - 0.5, last_period + 0.5],
        [high_price, high_price],
        color=spike_color,
        linestyle="--",
        linewidth=4,
        # We want this line to be always visible so our alpha floor is going to be .1
        alpha=max(utils.chance_alpha(spike_pattern.chance), 0.1),
    )
    price_plot.add_line(current_period_line)

    y_annotation_distance = 10

    for period in price_periods:
        if period == 11.5:
            continue

        try:
            chance = spike_breakdown[int(period)]
        except TypeError:
            # If this is period '11.5', then we don't need to annotate it, that value
            # is just here for line continuation
            continue

        # We need to render the numbers ABOVE the spike patter so that they don't
        # get illegible as the spike placement becomes more certain.
        price_plot.annotate(
            utils.format_chance(chance),
            (period, high_price),
            textcoords="offset points",
            xytext=(0, y_annotation_distance),
            ha="center",
            va="bottom",
            fontsize=LABEL_SIZE,
            color=spike_color,
        )

    # Annotate the total chance of this spike
    price_plot.annotate(
        utils.format_chance(spike_pattern.chance),
        (first_period - 0.5 - 0.1, high_price),
        ha="right",
        va="center",
        fontsize=LABEL_SIZE,
        color="white",
        alpha=0.75,
        bbox={
            "boxstyle": "Circle,pad=0.6",
            "facecolor": colors.color(*spike_color),
            "edgecolor": spike_color,
            "linewidth": 0,
        },
    )

    # Add a label to the daily chances for clarity
    middle = first_period + (last_period - first_period) / 2
    middle_price = next(p for p in period_highs if p)

    price_plot.annotate(
        "daily:",
        (middle, middle_price + y_annotation_distance * 2.5),
        textcoords="offset points",
        xytext=(0, y_annotation_distance),
        ha="center",
        va="bottom",
        fontsize=LABEL_SIZE * 1.1,
        color=spike_color,
    )