def test_pnl_percentage(): set_up(zero_fee=True) # 1x leverage trade = CompletedTrade({ 'type': 'long', 'exchange': 'Sandbox', 'entry_price': 10, 'exit_price': 12, 'take_profit_at': 20, 'stop_loss_at': 5, 'qty': 1, 'orders': [], 'symbol': 'BTC-USD', 'opened_at': jh.now_to_timestamp(), 'closed_at': jh.now_to_timestamp(), 'leverage': 1, }) assert trade.pnl_percentage == 20 # 2x leverage trade = CompletedTrade({ 'type': 'long', 'exchange': 'Sandbox', 'entry_price': 10, 'exit_price': 12, 'take_profit_at': 20, 'stop_loss_at': 5, 'qty': 1, 'orders': [], 'symbol': 'BTC-USD', 'opened_at': jh.now_to_timestamp(), 'closed_at': jh.now_to_timestamp(), 'leverage': 2, }) assert trade.pnl_percentage == 40
def test_trade_size(): trade = CompletedTrade({ 'type': 'long', 'exchange': 'Sandbox', 'entry_price': 10, 'exit_price': 20, 'take_profit_at': 20, 'stop_loss_at': 5, 'qty': 1, 'orders': [], 'symbol': 'BTC-USD', 'opened_at': jh.now_to_timestamp(), 'closed_at': jh.now_to_timestamp() }) assert trade.size == 10
def test_risk_percentage(): set_up(zero_fee=True) trade = CompletedTrade({ 'type': 'long', 'exchange': 'Sandbox', 'entry_price': 10, 'exit_price': 12, 'take_profit_at': 20, 'stop_loss_at': 5, 'qty': 1, 'orders': [], 'symbol': 'BTC-USD', 'opened_at': jh.now_to_timestamp(), 'closed_at': jh.now_to_timestamp() })
def test_holding_period(): trade = CompletedTrade({ 'type': 'long', 'exchange': 'Sandbox', 'entry_price': 10, 'exit_price': 20, 'take_profit_at': 20, 'stop_loss_at': 5, 'qty': 1, 'orders': [], 'symbol': 'BTC-USD', 'opened_at': 1552309186171, 'closed_at': 1552309186171 + 60000 }) # 1 minute == 60 seconds assert trade.holding_period == 60
def test_PNL_percentage(): no_fee() trade = CompletedTrade({ 'type': 'long', 'exchange': 'Sandbox', 'entry_price': 10, 'exit_price': 12, 'take_profit_at': 20, 'stop_loss_at': 5, 'qty': 1, 'orders': [], 'symbol': 'BTCUSD', 'opened_at': jh.now(), 'closed_at': jh.now() }) assert trade.PNL_percentage == 20
def test_risk_percentage(): no_fee() trade = CompletedTrade({ 'type': 'long', 'exchange': 'Sandbox', 'entry_price': 10, 'exit_price': 12, 'take_profit_at': 20, 'stop_loss_at': 5, 'qty': 1, 'orders': [], 'symbol': 'BTC-USD', 'opened_at': jh.now_to_timestamp(), 'closed_at': jh.now_to_timestamp() }) assert trade.risk_percentage == round((((10 - 5) / 1) * 10), 2)
def test_R(): no_fee() trade = CompletedTrade({ 'type': 'long', 'exchange': 'Sandbox', 'entry_price': 10, 'exit_price': 12, 'take_profit_at': 20, 'stop_loss_at': 5, 'qty': 1, 'orders': [], 'symbol': 'BTC-USD', 'opened_at': jh.now_to_timestamp(), 'closed_at': jh.now_to_timestamp() }) assert trade.risk_reward_ratio == 2
def test_pnl_with_fee(): # set fee (0.20%) config['env']['exchanges']['Sandbox']['fee'] = 0.002 trade = CompletedTrade({ 'type': 'long', 'exchange': 'Sandbox', 'entry_price': 10, 'exit_price': 20, 'take_profit_at': 20, 'stop_loss_at': 5, 'qty': 1, 'orders': [], 'symbol': 'BTC-USD', 'opened_at': jh.now_to_timestamp(), 'closed_at': jh.now_to_timestamp() }) assert trade.fee == 0.06 assert trade.pnl == 9.94
def test_can_add_trade_to_store(): set_up() assert store.completed_trades.trades == [] trade = CompletedTrade({ 'type': 'long', 'exchange': 'Sandbox', 'entry_price': 10, 'exit_price': 20, 'take_profit_at': 20, 'stop_loss_at': 5, 'qty': 1, 'orders': [], 'symbol': 'BTC-USD', 'opened_at': 1552309186171, 'closed_at': 1552309186171 + 60000 }) store.completed_trades.add_trade(trade) assert store.completed_trades.trades == [trade] store.reset() assert store.completed_trades.trades == []
def _log_position_update(self, order: Order, role: str) -> None: """ A log can be either about opening, adding, reducing, or closing the position. Arguments: order {order} -- the order object """ # set the trade_id for the order if we're in the middle of a trade. Otherwise, it # is done at order_roles.OPEN_POSITION if self.trade: order.trade_id = self.trade.id if role == order_roles.OPEN_POSITION: self.trade = CompletedTrade() self.trade.leverage = self.leverage self.trade.orders = [order] self.trade.timeframe = self.timeframe self.trade.id = jh.generate_unique_id() order.trade_id = self.trade.id self.trade.strategy_name = self.name self.trade.exchange = order.exchange self.trade.symbol = order.symbol self.trade.type = trade_types.LONG if order.side == sides.BUY else trade_types.SHORT self.trade.qty = order.qty self.trade.opened_at = jh.now_to_timestamp() self.trade.entry_candle_timestamp = self.current_candle[0] elif role == order_roles.INCREASE_POSITION: self.trade.orders.append(order) self.trade.qty += order.qty elif role == order_roles.REDUCE_POSITION: self.trade.orders.append(order) self.trade.qty += order.qty elif role == order_roles.CLOSE_POSITION: self.trade.exit_candle_timestamp = self.current_candle[0] self.trade.orders.append(order) # calculate average stop-loss price sum_price = 0 sum_qty = 0 if self._log_stop_loss is not None: for l in self._log_stop_loss: sum_qty += abs(l[0]) sum_price += abs(l[0]) * l[1] self.trade.stop_loss_at = sum_price / sum_qty else: self.trade.stop_loss_at = np.nan # calculate average take-profit price sum_price = 0 sum_qty = 0 if self._log_take_profit is not None: for l in self._log_take_profit: sum_qty += abs(l[0]) sum_price += abs(l[0]) * l[1] self.trade.take_profit_at = sum_price / sum_qty else: self.trade.take_profit_at = np.nan # calculate average entry_price price sum_price = 0 sum_qty = 0 for l in self.trade.orders: if not l.is_executed: continue if jh.side_to_type(l.side) != self.trade.type: continue sum_qty += abs(l.qty) sum_price += abs(l.qty) * l.price self.trade.entry_price = sum_price / sum_qty # calculate average exit_price sum_price = 0 sum_qty = 0 for l in self.trade.orders: if not l.is_executed: continue if jh.side_to_type(l.side) == self.trade.type: continue sum_qty += abs(l.qty) sum_price += abs(l.qty) * l.price self.trade.exit_price = sum_price / sum_qty self.trade.closed_at = jh.now_to_timestamp() self.trade.qty = pydash.sum_by( filter(lambda o: o.side == jh.type_to_side(self.trade.type), self.trade.orders), lambda o: abs(o.qty)) store.completed_trades.add_trade(self.trade) if jh.is_livetrading(): store_completed_trade_into_db(self.trade) self.trade = None self.trades_count += 1 if jh.is_livetrading(): store_order_into_db(order)