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
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)
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