def save_daily_portfolio_balance() -> None: balances = [] # add exchange balances for key, e in store.exchanges.storage.items(): balances.append(e.assets[jh.app_currency()]) # store daily_balance of assets into database if jh.is_livetrading(): for asset_key, asset_value in e.assets.items(): store_daily_balance_into_db({ 'id': jh.generate_unique_id(), 'timestamp': jh.now(), 'identifier': jh.get_config('env.identifier', 'main'), 'exchange': e.name, 'asset': asset_key, 'balance': asset_value, }) # add open position values for key, pos in store.positions.storage.items(): if pos.is_open: balances.append(pos.pnl) total = sum(balances) store.app.daily_balance.append(total) logger.info('Saved daily portfolio balance: {}'.format(round(total, 2)))
def handle_exception(exc_type, exc_value, exc_traceback) -> None: if issubclass(exc_type, KeyboardInterrupt): sys.excepthook(exc_type, exc_value, exc_traceback) return # handle Breaking exceptions if exc_type in [ exceptions.InvalidConfig, exceptions.RouteNotFound, exceptions.InvalidRoutes, exceptions.CandleNotFoundInDatabase ]: click.clear() print(f"{'=' * 30} EXCEPTION TRACEBACK:") traceback.print_tb(exc_traceback, file=sys.stdout) print("=" * 73) print( '\n', jh.color('Uncaught Exception:', 'red'), jh.color(f'{exc_type.__name__}: {exc_value}', 'yellow') ) return # send notifications if it's a live session if jh.is_live(): jesse_logger.error( f'{exc_type.__name__}: {exc_value}' ) if jh.is_live() or jh.is_collecting_data(): logging.error("Uncaught Exception:", exc_info=(exc_type, exc_value, exc_traceback)) else: print(f"{'=' * 30} EXCEPTION TRACEBACK:") traceback.print_tb(exc_traceback, file=sys.stdout) print("=" * 73) print( '\n', jh.color('Uncaught Exception:', 'red'), jh.color(f'{exc_type.__name__}: {exc_value}', 'yellow') ) if jh.is_paper_trading(): print( jh.color( 'An uncaught exception was raised. Check the log file at:\nstorage/logs/paper-trade.txt', 'red' ) ) elif jh.is_livetrading(): print( jh.color( 'An uncaught exception was raised. Check the log file at:\nstorage/logs/live-trade.txt', 'red' ) ) elif jh.is_collecting_data(): print( jh.color( 'An uncaught exception was raised. Check the log file at:\nstorage/logs/collect.txt', 'red' ) )
def liquidation_price(self): """ The price at which the position gets liquidated. formulas are taken from: https://help.bybit.com/hc/en-us/articles/900000181046-Liquidation-Price-USDT-Contract- """ if self.is_close: return np.nan if jh.is_livetrading(): return self._liquidation_price if self.mode == 'isolated': if self.type == 'long': return self.entry_price * (1 - self._initial_margin_rate + 0.004) elif self.type == 'short': return self.entry_price * (1 + self._initial_margin_rate - 0.004) else: return np.nan elif self.mode == 'cross': return np.nan elif self.mode == 'spot': return np.nan else: raise ValueError
def handle_thread_exception(args): """ :param args: :return: """ if args.exc_type == SystemExit: return # handle Breaking exceptions if args.exc_type in [ exceptions.ConfigException, exceptions.RouteNotFound, exceptions.InvalidRoutes, exceptions.CandleNotFoundInDatabase ]: click.clear() print('=' * 30 + ' EXCEPTION TRACEBACK:') traceback.print_tb(args.exc_traceback, file=sys.stdout) print("=" * 73) print( '\n', jh.color('Uncaught Exception:', 'red'), jh.color( '{}: {}'.format(args.exc_type.__name__, args.exc_value), 'yellow')) return # send notifications if it's a live session if jh.is_live(): jesse_logger.error('{}: {}'.format(args.exc_type.__name__, args.exc_value)) if jh.is_live() or jh.is_collecting_data(): logging.error("Uncaught Exception:", exc_info=(args.exc_type, args.exc_value, args.exc_traceback)) else: print('=' * 30 + ' EXCEPTION TRACEBACK:') traceback.print_tb(args.exc_traceback, file=sys.stdout) print("=" * 73) print( '\n', jh.color('Uncaught Exception:', 'red'), jh.color( '{}: {}'.format(args.exc_type.__name__, args.exc_value), 'yellow')) if jh.is_paper_trading(): print( jh.color( 'An uncaught exception was raised. Check the log file at:\n{}' .format('storage/logs/paper-trade.txt'), 'red')) elif jh.is_livetrading(): print( jh.color( 'An uncaught exception was raised. Check the log file at:\n{}' .format('storage/logs/live-trade.txt'), 'red')) elif jh.is_collecting_data(): print( jh.color( 'An uncaught exception was raised. Check the log file at:\n{}' .format('storage/logs/collect.txt'), 'red'))
def save_daily_portfolio_balance() -> None: balances = [] # add exchange balances for key, e in store.exchanges.storage.items(): balances.append(e.assets[jh.app_currency()]) # # store daily_balance of assets into database # if jh.is_livetrading(): # for asset_key, asset_value in e.assets.items(): # store_daily_balance_into_db({ # 'id': jh.generate_unique_id(), # 'timestamp': jh.now(), # 'identifier': jh.get_config('env.identifier', 'main'), # 'exchange': e.name, # 'asset': asset_key, # 'balance': asset_value, # }) # add open position values for key, pos in store.positions.storage.items(): if pos.is_open: balances.append(pos.pnl) total = sum(balances) store.app.daily_balance.append(total) # TEMP: disable storing in database for now if not jh.is_livetrading(): logger.info(f'Saved daily portfolio balance: {round(total, 2)}')
def test_is_livetrading(): assert jh.is_livetrading() is False
def register_custom_exception_handler() -> None: import sys import threading import traceback import logging from jesse.services import logger as jesse_logger import click from jesse import exceptions log_format = "%(message)s" os.makedirs('./storage/logs', exist_ok=True) if jh.is_livetrading(): logging.basicConfig(filename='storage/logs/live-trade.txt', level=logging.INFO, filemode='w', format=log_format) elif jh.is_paper_trading(): logging.basicConfig(filename='storage/logs/paper-trade.txt', level=logging.INFO, filemode='w', format=log_format) elif jh.is_collecting_data(): logging.basicConfig(filename='storage/logs/collect.txt', level=logging.INFO, filemode='w', format=log_format) elif jh.is_optimizing(): logging.basicConfig(filename='storage/logs/optimize.txt', level=logging.INFO, filemode='w', format=log_format) else: logging.basicConfig(level=logging.INFO) # main thread def handle_exception(exc_type, exc_value, exc_traceback) -> None: if issubclass(exc_type, KeyboardInterrupt): sys.excepthook(exc_type, exc_value, exc_traceback) return # handle Breaking exceptions if exc_type in [ exceptions.InvalidConfig, exceptions.RouteNotFound, exceptions.InvalidRoutes, exceptions.CandleNotFoundInDatabase ]: click.clear() print(f"{'=' * 30} EXCEPTION TRACEBACK:") traceback.print_tb(exc_traceback, file=sys.stdout) print("=" * 73) print('\n', jh.color('Uncaught Exception:', 'red'), jh.color(f'{exc_type.__name__}: {exc_value}', 'yellow')) return # send notifications if it's a live session if jh.is_live(): jesse_logger.error(f'{exc_type.__name__}: {exc_value}') if jh.is_live() or jh.is_collecting_data(): logging.error("Uncaught Exception:", exc_info=(exc_type, exc_value, exc_traceback)) else: print(f"{'=' * 30} EXCEPTION TRACEBACK:") traceback.print_tb(exc_traceback, file=sys.stdout) print("=" * 73) print('\n', jh.color('Uncaught Exception:', 'red'), jh.color(f'{exc_type.__name__}: {exc_value}', 'yellow')) if jh.is_paper_trading(): print( jh.color( 'An uncaught exception was raised. Check the log file at:\nstorage/logs/paper-trade.txt', 'red')) elif jh.is_livetrading(): print( jh.color( 'An uncaught exception was raised. Check the log file at:\nstorage/logs/live-trade.txt', 'red')) elif jh.is_collecting_data(): print( jh.color( 'An uncaught exception was raised. Check the log file at:\nstorage/logs/collect.txt', 'red')) sys.excepthook = handle_exception # other threads if jh.python_version() >= (3, 8): def handle_thread_exception(args) -> None: if args.exc_type == SystemExit: return # handle Breaking exceptions if args.exc_type in [ exceptions.InvalidConfig, exceptions.RouteNotFound, exceptions.InvalidRoutes, exceptions.CandleNotFoundInDatabase ]: click.clear() print(f"{'=' * 30} EXCEPTION TRACEBACK:") traceback.print_tb(args.exc_traceback, file=sys.stdout) print("=" * 73) print( '\n', jh.color('Uncaught Exception:', 'red'), jh.color(f'{args.exc_type.__name__}: {args.exc_value}', 'yellow')) return # send notifications if it's a live session if jh.is_live(): jesse_logger.error( f'{args.exc_type.__name__}: { args.exc_value}') if jh.is_live() or jh.is_collecting_data(): logging.error("Uncaught Exception:", exc_info=(args.exc_type, args.exc_value, args.exc_traceback)) else: print(f"{'=' * 30} EXCEPTION TRACEBACK:") traceback.print_tb(args.exc_traceback, file=sys.stdout) print("=" * 73) print( '\n', jh.color('Uncaught Exception:', 'red'), jh.color(f'{args.exc_type.__name__}: {args.exc_value}', 'yellow')) if jh.is_paper_trading(): print( jh.color( 'An uncaught exception was raised. Check the log file at:\nstorage/logs/paper-trade.txt', 'red')) elif jh.is_livetrading(): print( jh.color( 'An uncaught exception was raised. Check the log file at:\nstorage/logs/live-trade.txt', 'red')) elif jh.is_collecting_data(): print( jh.color( 'An uncaught exception was raised. Check the log file at:\nstorage/logs/collect.txt', 'red')) threading.excepthook = handle_thread_exception
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)