Point = float
Pip = float
Lot = float


class Units:
    """Trading unit conversion helpers and fixed constants.

    Attributes
    ----------
    LOT_SIZE : int
        Base units per lot.
    PIP_SIZE : float
        Price delta represented by one pip.
    POINT_SIZE : float
        Price delta represented by one point.
    OPEN_COMMISSION : float
        Commission per lot when opening a position.
    MAINTAIN_BUY_COMMISSION : float
        Daily carry cost per lot for buy positions.
    MAINTAIN_SELL_COMMISSION : float
        Daily carry value per lot for sell positions.
    """

    LOT_SIZE = 100_000
    PIP_SIZE = 0.0001
    POINT_SIZE = PIP_SIZE / 10

    OPEN_COMMISSION = -6.0  # per lot, per side
    MAINTAIN_BUY_COMMISSION = -5.0  # per lot, per day
    MAINTAIN_SELL_COMMISSION = 1.25  # per lot, per day

    @staticmethod
    def pip_value(lots: Lot) -> float:
        """Convert one pip movement into account currency.

        Parameters
        ----------
        lots : Lot
            Position size in lots.

        Returns
        -------
        float
            Account-currency value of one pip movement.
        """
        return lots * Units.LOT_SIZE * Units.PIP_SIZE

    @staticmethod
    def point_value(lots: Lot) -> float:
        """Convert one point movement into account currency.

        Parameters
        ----------
        lots : Lot
            Position size in lots.

        Returns
        -------
        float
            Account-currency value of one point movement.
        """
        return lots * Units.LOT_SIZE * Units.POINT_SIZE

    @staticmethod
    def pips_to_value(pips: Pip, lots: Lot) -> float:
        """Convert pip distance to account currency.

        Parameters
        ----------
        pips : Pip
            Distance in pips.
        lots : Lot
            Position size in lots.

        Returns
        -------
        float
            Distance value in account currency.
        """
        return pips * Units.pip_value(lots)

    @staticmethod
    def points_to_value(points: Point, lots: Lot) -> float:
        """Convert point distance to account currency.

        Parameters
        ----------
        points : Point
            Distance in points.
        lots : Lot
            Position size in lots.

        Returns
        -------
        float
            Distance value in account currency.
        """
        return points * Units.point_value(lots)

    @staticmethod
    def open_commission(lots: Lot) -> float:
        """Compute opening commission in account currency.

        Parameters
        ----------
        lots : Lot
            Position size in lots.

        Returns
        -------
        float
            Opening commission amount.
        """
        return Units.OPEN_COMMISSION * lots

    @staticmethod
    def maintain_buy_commission(lots: Lot) -> float:
        """Compute daily carry for buy positions.

        Parameters
        ----------
        lots : Lot
            Position size in lots.

        Returns
        -------
        float
            Daily carry amount in account currency.
        """
        return Units.MAINTAIN_BUY_COMMISSION * lots

    @staticmethod
    def maintain_sell_commission(lots: Lot) -> float:
        """Compute daily carry for sell positions.

        Parameters
        ----------
        lots : Lot
            Position size in lots.

        Returns
        -------
        float
            Daily carry amount in account currency.
        """
        return Units.MAINTAIN_SELL_COMMISSION * lots
