예제 #1
0
 def test_frac_pips(self, frac_pips: FracPips, pair: Pair, price: Price):
     p1 = frac_pips.to_ratio_price(pair.quote.rounder)
     p2 = frac_pips.to_quote_price(pair.quote)
     p3 = frac_pips.to_pair_price(pair)
     fp = FracPips.from_price(price)
     assert isinstance(p1, BasePrice)
     assert isinstance(p2, BasePrice)
     assert isinstance(p3, BasePrice)
     assert isinstance(fp, FracPips)
     assert price == p1 == p2 == p3
     assert frac_pips == fp
예제 #2
0
 def view_set(self, xandles: Xandles):
     """Set ourselves around the candles in xandles view."""
     # DEPRECATING?....yrids should not need to know about price view.
     if self.height is None or self.scale is None:
         return
     low, high = xandles.find_view_low_high()
     if low is None or high is None:
         return
     fp_delta = high - low
     fp_pad = ceil(fp_delta / 10)
     self.top = FracPips(high + fp_pad)
     self.bot = FracPips(high - fp_pad)
     fp_height = fp_delta + (2 * fp_pad)
     self.fpp = fp_height / self.height
     self.update()
예제 #3
0
    def get_grid_list(self, fp_low: FracPips,
                      fp_high: FracPips) -> List[FracPips]:
        """Return list of fractional pips to put grid lines at.

        Args:
            fp_low: lowest price to place grid lines at or above
            fp_high: highest price to place grid lines at or below
        """
        grid_list: List[FracPips] = []
        remainder = fp_low % self.interval
        grid_fp = FracPips(fp_low - remainder)
        while grid_fp <= fp_high:
            grid_list.append(grid_fp)
            grid_fp = FracPips(grid_fp + self.interval)
        return grid_list
예제 #4
0
    def shift(self, x: int, y: int):
        """Shift GeoCandles data the given amount.

        Args:
            x: horizontal pixels where to the right is positive.
            y: vertical pixels where down is positive.
        """
        candle_slot_shift = ceil(x / self.xandles.offset)
        new_ndx = self.xandles.ndx - candle_slot_shift
        pad_adjust = Xandles.PAD * 4
        min_slots = round(
            (self.xandles.width - pad_adjust) / self.xandles.offset)
        if new_ndx < 0:
            new_ndx = 0
        pull_size = Xandles.calculate_pull_size(self.xandles.width,
                                                self.xandles.offset, new_ndx)
        candles = self.collector.grab(pull_size)
        max_ndx = len(candles) - min_slots
        if max_ndx <= 0:
            max_ndx = 1
        if new_ndx >= max_ndx:
            new_ndx = max_ndx
        self.xandles.update(candles=candles, ndx=new_ndx)
        if self.price_view:
            fp_mid, fpp = Yrids.calculate_price_view(self.xandles,
                                                     self.yrids.height)
            self.yrids.update(mid=fp_mid, fpp=fpp)
        else:
            fp_shift = round(y * self.yrids.fpp)
            new_mid = FracPips(self.yrids.mid - fp_shift)
            self.yrids.update(mid=new_mid)
        self.refresh()
예제 #5
0
 def __init__(
     self,
     height: Optional[int] = None,
     mid: Optional[FracPips] = None,
     fpp: float = PriceScale.DEFAULT_FPP,
     scale: PriceScale = PriceScale.DEFAULT,
 ):
     # ----------------------------------------------------------------------
     # User set attributes
     # ----------------------------------------------------------------------
     # the height of the view in pixels
     self.height: Optional[int] = height
     # the middle price in fractional pips
     self.mid: FracPips = None if mid is None else FracPips(mid)
     # fpp is the ratio of fractional pips to vertical pixel.
     self.fpp: float = fpp
     # the grid scale for price (how many fpp between grid lines)
     self.scale: PriceScale = scale
     # ----------------------------------------------------------------------
     # Attributes derived from update when user attributes are all set
     # ----------------------------------------------------------------------
     # The height if the scrollable area of canvas.
     self.scroll_height: Optional[int] = None
     # list of frac pips and pixel locations for grid lines.
     self.grid_list: Optional[List[Tuple[FracPips, int]]] = None
     # the price in fractional pips at top and bottom of viewable area.
     self.top: Optional[FracPips] = None
     self.bot: Optional[FracPips] = None
     # the price in fractional pips at top and bottom of scrollable area.
     self.scroll_top: Optional[FracPips] = None
     self.scroll_bot: Optional[FracPips] = None
     # ----------------------------------------------------------------------
     # Update provided we have enough info to.
     # ----------------------------------------------------------------------
     self.update()
예제 #6
0
 def test_price(self, value, subclass, pips, frac_pips):
     if subclass is ValueError:
         with pytest.raises(ValueError):
             Price(value)
     else:
         price = Price(value)
         assert price.pips == pips
         assert FracPips.from_price(price) == frac_pips
         assert isinstance(price, BasePrice)
         assert isinstance(price, subclass)
예제 #7
0
class TestFracPips:
    @pytest.mark.parametrize(
        "frac_pips,pair,price",
        (
            (FracPips(112345), Pair.AUD_USD, Price("1.12345")),
            (FracPips(100123), Pair.USD_JPY, Price("100.123")),
        ),
    )
    def test_frac_pips(self, frac_pips: FracPips, pair: Pair, price: Price):
        p1 = frac_pips.to_ratio_price(pair.quote.rounder)
        p2 = frac_pips.to_quote_price(pair.quote)
        p3 = frac_pips.to_pair_price(pair)
        fp = FracPips.from_price(price)
        assert isinstance(p1, BasePrice)
        assert isinstance(p2, BasePrice)
        assert isinstance(p3, BasePrice)
        assert isinstance(fp, FracPips)
        assert price == p1 == p2 == p3
        assert frac_pips == fp
예제 #8
0
class Const:
    DEFAULT_FPP = 10.0  # initial frac pips per pixel value before data loaded.
    FP_MAX: FracPips = FracPips(1_000_000)
    FP_MIN: FracPips = FracPips(0)
    MIN_FPP = 0.01  # lowest allowed value for fpp
    ONE_THIRD = float(1) / float(3)
    PRICE_PAD: FracPips = FracPips(10_000)
    PRICE_VIEW_PAD = 25
    TAIL_PADDING = 50  # num pixels to pad to right of candles when tailing.
    TIME_CANVAS_HEIGHT = 42
    PRICE_CANVAS_WIDTH = 80  # 110
    MIN_TIME_GRID_WIDTH = 120
예제 #9
0
    def update(
        self,
        height: Optional[int] = None,
        mid: Optional[FracPips] = None,
        fpp: Optional[float] = None,
        scale: Optional[PriceScale] = None,
    ) -> bool:
        """Update Yrids with specified values, resolve if possible.

        All the args are optional, and if left as None they will stay the
        same as they already were.

        Args:
            height: height of view in in pixels.
            mid: frac pips price of mid point of view.
            fpp: ratio of frac pips per pixel
            scale: price scale object indicating frac pips between price grid lines.
        """
        if height is not None:
            self.height = height
        if mid is not None:
            self.mid = mid
        if fpp is not None:
            self.fpp = fpp
        if scale is not None:
            self.scale = scale
        if not self.can_resolve():
            return False
        self.scroll_height = self.height * 3
        fp_view_delta = round((self.height / 2) * self.fpp)
        fp_scroll_delta = round((self.height / 2) * self.fpp * 3)
        self.top = FracPips(self.mid + fp_view_delta)
        self.bot = FracPips(self.mid - fp_view_delta)
        self.scroll_top = FracPips(self.mid + fp_scroll_delta)
        self.scroll_bot = FracPips(self.mid - fp_scroll_delta)
        self.grid_list = []
        for fp in self.scale.get_grid_list(self.scroll_bot, self.scroll_top):
            y = self.fp_to_y(fp)
            self.grid_list.append((fp, y))
        return True
예제 #10
0
 def calculate_price_view(cls, xandles: Xandles,
                          height: int) -> Tuple[FracPips, float]:
     """Calculate the price_view fp_mid and fpp from Xandles and pixel height.
     
     Args:
         xandles: must be loaded with candles we can get prices from.
         height: height of view area price view will cover.
     Returns:
         frac pip price of mid point of view, Frac pips per pixel ratio
     """
     low, high = xandles.find_view_low_high()
     fp_mid = FracPips(round((high + low) / 2))
     fp_delta = high - low
     fp_pad = ceil(fp_delta / 10)
     fp_height = fp_delta + (2 * fp_pad)
     fpp = fp_height / height
     return fp_mid, fpp
예제 #11
0
    def find_view_low_high(
            self) -> Tuple[Optional[FracPips], Optional[FracPips]]:
        """Return the lowest and highest price in view as frac pips.

        If there are no prices in the view, then return None, None instead.
        """
        if not self.candles:
            return None, None
        high = FracPips(0)
        low = FracPips(1_000_000)
        for candle in self.iter_view_candles():
            candle_high = candle.high_fp
            candle_low = candle.low_fp
            if candle_high > high:
                high = candle_high
            if candle_low < low:
                low = candle_low
        if low > high:
            return None, None
        return low, high
예제 #12
0
 def c_fp(self) -> FracPips:
     """Closing price as Fractional Pips."""
     return FracPips.from_price(self.c)
예제 #13
0
 def l_fp(self) -> FracPips:
     """Low price as Fractional Pips."""
     return FracPips.from_price(self.l)
예제 #14
0
 def h_fp(self) -> FracPips:
     """High price as Fractional Pips."""
     return FracPips.from_price(self.h)
예제 #15
0
 def o_fp(self) -> FracPips:
     """Open price as Fractional Pips."""
     return FracPips.from_price(self.o)
예제 #16
0
 def y_to_fp(self, y: int) -> FracPips:
     """Convert y pixel coordinate to price in frac pips."""
     return FracPips(self.scroll_top - round(y * self.fpp))
예제 #17
0
 def price_to_y(self, price: Price) -> int:
     """Convert Price to y pixel coordinate."""
     return self.fp_to_y(FracPips.from_price(price))
예제 #18
0
class PriceScale:
    """For finding where to put price grid lines on scale."""

    NUM_GRID = 6

    MIN_PIXEL = 80

    DEFAULT_FPP: float = 1.0
    DEFAULT: "PriceScale" = None

    # Different numbers of pips we might have between each grid line.
    INTERVALS = (
        FracPips(10),
        FracPips(25),
        FracPips(50),
        FracPips(100),
        FracPips(250),
        FracPips(500),
        FracPips(1000),
        FracPips(2500),
        FracPips(5000),
        FracPips(10_000),
        FracPips(25_000),
        FracPips(50_000),
        FracPips(100_000),
        FracPips(250_000),
        FracPips(500_000),
        FracPips(1_000_000),
        FracPips(2_500_000),
        FracPips(5_000_000),
        FracPips(10_000_000),
        FracPips(25_000_000),
        FracPips(50_000_000),
        FracPips(100_000_000),
        FracPips(250_000_000),
        FracPips(500_000_000),
    )

    def __init__(self, fpp: float):
        """Set up PriceScale based on fractional pips per pixel.

        The self.interval attribute is loaded with the smallest fractional
        pip value from self.INTERVALS which will result in the grid lines
        being at least self.MIN_PIXEL pixels away from each other. If there
        is no such interval we just pick the biggest.

        Args:
            fpp: fractional pips per pixel.
        """
        self.interval: FracPips = self.INTERVALS[-1]
        for interval in self.INTERVALS:
            pixels: float = float(interval) / fpp
            if pixels >= self.MIN_PIXEL:
                self.interval = interval
                break

    def __repr__(self):
        return f"<Scale {self.interval}>"

    def get_grid_list(self, fp_low: FracPips,
                      fp_high: FracPips) -> List[FracPips]:
        """Return list of fractional pips to put grid lines at.

        Args:
            fp_low: lowest price to place grid lines at or above
            fp_high: highest price to place grid lines at or below
        """
        grid_list: List[FracPips] = []
        remainder = fp_low % self.interval
        grid_fp = FracPips(fp_low - remainder)
        while grid_fp <= fp_high:
            grid_list.append(grid_fp)
            grid_fp = FracPips(grid_fp + self.interval)
        return grid_list