async def exchange_balances_extra_df( self, # type: HummingbotApplication ex_balances: Dict[str, Decimal], ex_avai_balances: Dict[str, Decimal]): total_col_name = f"Total ({RateOracle.global_token_symbol})" allocated_total = Decimal("0") rows = [] for token, bal in ex_balances.items(): if bal == Decimal(0): continue avai = Decimal(ex_avai_balances.get( token.upper(), 0)) if ex_avai_balances is not None else Decimal(0) allocated = f"{(bal - avai) / bal:.0%}" rate = await RateOracle.global_rate(token) rate = Decimal("0") if rate is None else rate global_value = rate * bal allocated_total += rate * (bal - avai) rows.append({ "Asset": token.upper(), "Total": round(bal, 4), total_col_name: smart_round(global_value), "Allocated": allocated, }) df = pd.DataFrame( data=rows, columns=["Asset", "Total", total_col_name, "Allocated"]) df.sort_values(by=["Asset"], inplace=True) return df, allocated_total
def active_positions_df(self) -> pd.DataFrame: columns = ["Symbol", "Type", "Fee Tier", "Amount", "Upper Price", "Lower Price", ""] data = [] if len(self.active_positions) > 0: for position in self.active_positions: amount = self._base_token_amount if position in self.active_buys else self._quote_token_amount data.append([ position.trading_pair, "Buy" if position in self.active_buys else "Sell", position.fee_tier, f"{smart_round(Decimal(str(amount)), 8)}", smart_round(Decimal(str(position.upper_price)), 8), smart_round(Decimal(str(position.lower_price)), 8), "[In range]" if self._last_price >= position.lower_price and self._last_price <= position.upper_price else "[Out of range]" ]) return pd.DataFrame(data=data, columns=columns)
async def format_status(self) -> str: """ Returns a status string formatted to display nicely on terminal. The strings composes of 4 parts: markets, assets, profitability and warnings(if any). """ if self._arb_proposals is None: return " The strategy is not ready, please try again later." # active_orders = self.market_info_to_active_orders.get(self._market_info, []) columns = ["Exchange", "Market", "Sell Price", "Buy Price", "Mid Price"] data = [] for market_info in [self._market_info_1, self._market_info_2]: market, trading_pair, base_asset, quote_asset = market_info buy_price = await market.get_quote_price(trading_pair, True, self._order_amount) sell_price = await market.get_quote_price(trading_pair, False, self._order_amount) # check for unavailable price data buy_price = smart_round(Decimal(str(buy_price)), 8) if buy_price is not None else '-' sell_price = smart_round(Decimal(str(sell_price)), 8) if sell_price is not None else '-' mid_price = smart_round(((buy_price + sell_price) / 2), 8) if '-' not in [buy_price, sell_price] else '-' data.append([ market.display_name, trading_pair, sell_price, buy_price, mid_price ]) markets_df = pd.DataFrame(data=data, columns=columns) lines = [] lines.extend(["", " Markets:"] + [" " + line for line in markets_df.to_string(index=False).split("\n")]) assets_df = self.wallet_balance_data_frame([self._market_info_1, self._market_info_2]) lines.extend(["", " Assets:"] + [" " + line for line in str(assets_df).split("\n")]) lines.extend(["", " Profitability:"] + self.short_proposal_msg(self._arb_proposals)) warning_lines = self.network_warning([self._market_info_1]) warning_lines.extend(self.network_warning([self._market_info_2])) warning_lines.extend(self.balance_warning([self._market_info_1])) warning_lines.extend(self.balance_warning([self._market_info_2])) if len(warning_lines) > 0: lines.extend(["", "*** WARNINGS ***"] + warning_lines) return "\n".join(lines)
async def market_trades_report( self, # type: HummingbotApplication connector, days: float, market: str): trades: List[Trade] = await connector.get_my_trades(market, days) g_sym = RateOracle.global_token_symbol if not trades: self._notify(f"There is no trade on {market}.") return data = [] amount_g_col_name = f" Amount ({g_sym})" columns = ["Time", " Side", " Price", "Amount", amount_g_col_name] trades = sorted(trades, key=lambda x: (x.trading_pair, x.timestamp)) fees = {} # a dict of token and total fee amount fee_usd = 0 for trade in trades: time = f"{datetime.fromtimestamp(trade.timestamp / 1e3).strftime('%Y-%m-%d %H:%M:%S')} " side = "buy" if trade.side is TradeType.BUY else "sell" usd = await RateOracle.global_value( trade.trading_pair.split("-")[0], trade.amount) data.append([ time, side, smart_round(trade.price), smart_round(trade.amount), round(usd) ]) for fee in trade.trade_fee.flat_fees: if fee[0] not in fees: fees[fee[0]] = fee[1] else: fees[fee[0]] += fee[1] fee_usd += await RateOracle.global_value(fee[0], fee[1]) lines = [] df: pd.DataFrame = pd.DataFrame(data=data, columns=columns) lines.extend([f" {market.upper()}"]) lines.extend( [" " + line for line in df.to_string(index=False).split("\n")]) self._notify("\n" + "\n".join(lines)) fee_text = ",".join(k + ": " + f"{v:.4f}" for k, v in fees.items()) self._notify( f"\n Total traded: {g_sym} {df[amount_g_col_name].sum():.0f} " f"Fees: {fee_text} ({g_sym} {fee_usd:.2f})")
async def start_trade_monitor(trade_monitor): from hummingbot.client.hummingbot_application import HummingbotApplication hb = HummingbotApplication.main_application() trade_monitor.log("Trades: 0, Total P&L: 0.00, Return %: 0.00%") total_trades = 0 return_pcts = [] pnls = [] quote_asset = "" while True: if hb.strategy_task is not None and not hb.strategy_task.done(): if all(market.ready for market in hb.markets.values()): trades: List[TradeFill] = hb._get_trades_from_session(int(hb.init_time * 1e3), config_file_path=hb.strategy_file_name) if len(trades) > total_trades: total_trades = len(trades) market_info: Set[Tuple[str, str]] = set((t.market, t.symbol) for t in trades) for market, symbol in market_info: quote_asset = symbol.split("-")[1] # Note that the qiote asset of the last pair is assumed to be the quote asset of P&L for simplicity cur_trades = [t for t in trades if t.market == market and t.symbol == symbol] cur_balances = await hb.get_current_balances(market) perf = await calculate_performance_metrics(market, symbol, cur_trades, cur_balances) return_pcts.append(perf.return_pct) pnls.append(perf.total_pnl) avg_return = sum(return_pcts) / len(return_pcts) if len(return_pcts) > 0 else s_decimal_0 total_pnls = sum(pnls) # Note that this sum doesn't handles cases with different multiple pairs for simplisity trade_monitor.log(f"Trades: {total_trades}, Total P&L: {smart_round(total_pnls)} {quote_asset}, Return %: {avg_return:.2%}") # Here we write the P&L to a file data_set = {} data_set['trades']=total_trades data_set['total_pnl']=str(smart_round(total_pnls))+" " +quote_asset data_set['return']=str(avg_return) with open('data/totals.json', 'w') as outfile: json.dump(data_set, outfile) return_pcts.clear() pnls.clear() await asyncio.sleep(2) # sleeping for longer to manage resources
async def format_status(self) -> str: """ Returns a status string formatted to display nicely on terminal. The strings composes of 4 parts: market, assets, spread and warnings(if any). """ if not self._connector_ready: return "UniswapV3 connector not ready." columns = ["Exchange", "Market", "Current Price"] data = [] market, trading_pair, base_asset, quote_asset = self._market_info data.append([ market.display_name, trading_pair, smart_round(Decimal(str(self._last_price)), 8) ]) markets_df = pd.DataFrame(data=data, columns=columns) lines = [] lines.extend(["", " Markets:"] + [" " + line for line in markets_df.to_string(index=False).split("\n")]) # See if there're any active positions. if len(self.active_positions) > 0: df = self.active_positions_df() lines.extend(["", " Positions:"] + [" " + line for line in df.to_string(index=False).split("\n")]) else: lines.extend(["", " No active positions."]) assets_df = self.wallet_balance_data_frame([self._market_info]) lines.extend(["", " Assets:"] + [" " + line for line in str(assets_df).split("\n")]) warning_lines = self.network_warning([self._market_info]) warning_lines.extend(self.balance_warning([self._market_info])) if len(warning_lines) > 0: lines.extend(["", "*** WARNINGS ***"] + warning_lines) return "\n".join(lines)
def report_performance_by_market( self, # type: HummingbotApplication market: str, trading_pair: str, perf: PerformanceMetrics, precision: int): lines = [] base, quote = trading_pair.split("-") lines.extend([f"\n{market} / {trading_pair}"]) trades_columns = ["", "buy", "sell", "total"] trades_data = [ [ f"{'Number of trades':<27}", perf.num_buys, perf.num_sells, perf.num_trades ], [ f"{f'Total trade volume ({base})':<27}", smart_round(perf.b_vol_base, precision), smart_round(perf.s_vol_base, precision), smart_round(perf.tot_vol_base, precision) ], [ f"{f'Total trade volume ({quote})':<27}", smart_round(perf.b_vol_quote, precision), smart_round(perf.s_vol_quote, precision), smart_round(perf.tot_vol_quote, precision) ], [ f"{'Avg price':<27}", smart_round(perf.avg_b_price, precision), smart_round(perf.avg_s_price, precision), smart_round(perf.avg_tot_price, precision) ], ] trades_df: pd.DataFrame = pd.DataFrame(data=trades_data, columns=trades_columns) lines.extend(["", " Trades:"] + [ " " + line for line in trades_df.to_string(index=False).split("\n") ]) assets_columns = ["", "start", "current", "change"] assets_data = [ [f"{base:<17}", "-", "-", "-"] if market in DERIVATIVES else # No base asset for derivatives because they are margined [ f"{base:<17}", smart_round(perf.start_base_bal, precision), smart_round(perf.cur_base_bal, precision), smart_round(perf.tot_vol_base, precision) ], [ f"{quote:<17}", smart_round(perf.start_quote_bal, precision), smart_round(perf.cur_quote_bal, precision), smart_round(perf.tot_vol_quote, precision) ], [ f"{trading_pair + ' price':<17}", smart_round(perf.start_price), smart_round(perf.cur_price), smart_round(perf.cur_price - perf.start_price) ], [f"{'Base asset %':<17}", "-", "-", "-"] if market in DERIVATIVES else # No base asset for derivatives because they are margined [ f"{'Base asset %':<17}", f"{perf.start_base_ratio_pct:.2%}", f"{perf.cur_base_ratio_pct:.2%}", f"{perf.cur_base_ratio_pct - perf.start_base_ratio_pct:.2%}" ], ] assets_df: pd.DataFrame = pd.DataFrame(data=assets_data, columns=assets_columns) lines.extend(["", " Assets:"] + [ " " + line for line in assets_df.to_string(index=False).split("\n") ]) perf_data = [[ "Hold portfolio value ", f"{smart_round(perf.hold_value, precision)} {quote}" ], [ "Current portfolio value ", f"{smart_round(perf.cur_value, precision)} {quote}" ], [ "Trade P&L ", f"{smart_round(perf.trade_pnl, precision)} {quote}" ]] perf_data.extend([ "Fees paid ", f"{smart_round(fee_amount, precision)} {fee_token}" ] for fee_token, fee_amount in perf.fees.items()) perf_data.extend([[ "Total P&L ", f"{smart_round(perf.total_pnl, precision)} {quote}" ], ["Return % ", f"{perf.return_pct:.2%}"]]) perf_df: pd.DataFrame = pd.DataFrame(data=perf_data) lines.extend(["", " Performance:"] + [ " " + line for line in perf_df.to_string( index=False, header=False).split("\n") ]) self._notify("\n".join(lines)) with open('data/history.txt', 'w') as outfile: outfile.write("\n".join(lines))