예제 #1
0
    def enter_position(self,
                       type_,
                       entry_capital,
                       entry_price,
                       exit_price=0,
                       stop_loss=0):
        """
        Open position
        :param type_:
        :param entry_capital:
        :param entry_price:
        :param exit_price:
        :param stop_loss:
        :return:
        """

        if entry_capital < 0:
            raise ValueError("Error: Entry capital must be positive")
        elif entry_price < 0:
            raise ValueError("Error: Entry price cannot be negative.")
        elif self.buying_power < entry_capital:
            raise ValueError(
                "Error: Not enough buying power to enter position")
        else:
            # apply fee to price
            price_with_fee = self.apply_fee(entry_price, type_, 'Open')

            # round shares and calculate position capital
            size = rnd(entry_capital / price_with_fee)
            pos_amount = rnd(entry_price * size)

            # calculate trading fee for position
            trade_fee = rnd(pos_amount * self.fee.get(type_, 0))
            # calc buying power
            self.buying_power -= pos_amount + trade_fee

            if type_ == 'Long':
                position = LongPosition(self.number, entry_price, size,
                                        trade_fee, exit_price, stop_loss)

            elif type_ == 'Short':
                position = ShortPosition(self.number, entry_price, size,
                                         trade_fee, exit_price, stop_loss)

            else:
                raise TypeError("Invalid position type.")

            self.positions.append(position)
            self.opened_trades.append(
                OpenedTrade(type_, self.date, entry_price, size, trade_fee))
            self.number += 1
예제 #2
0
    def apply_fee(self, price, type_, direction):
        """
        Apply fee to price by position type & transaction direction

        Position types:
        * Long
        * Short

        Directions:
        * Open : Add fee to Long price, subtract fee from Short price
        * Close : Subtract fee from Long price, add fee to Short price

        :param price:
        :param type_:
        :param direction:
        :return:
        """
        sign = 1 if direction == 'Open' else -1

        # change price with fee
        fee = self.fee.get(type_, 0)
        if type_ == 'Long':
            price *= 1 + sign * fee
        elif type_ == 'Short':
            price *= 1 - sign * fee

        # round price
        return rnd(price)
예제 #3
0
    def close_position(self, position, percent, price):
        """
        close position
        :param position:
        :param percent:
        :param price:
        :return:
        """

        # TODO Change order logic to:
        # order_percent(asset, percent > 0)
        # if >0: check and buy/close if necessary
        # if 0: check and close if position exists

        if percent > 1 or percent < 0:
            raise ValueError("Error: Percent must range between 0-1.")
        elif price < 0:
            raise ValueError("Error: Current price cannot be negative.")
        else:
            # get trade fee
            # FIXME Use type by direction: buy-Long, sell-Short
            trade_fee = rnd(price * position.shares *
                            self.fee.get(position.type_, 0))

            self.closed_trades.append(
                ClosedTrade(position.type_, self.date,
                            position.shares * percent, position.entry_price,
                            price, trade_fee))
            self.buying_power += position.close(percent, price) - trade_fee