Esempio n. 1
0
 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:
             PerformanceMetrics.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
Esempio n. 2
0
    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,
                PerformanceMetrics.smart_round(trade.price),
                PerformanceMetrics.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})")
Esempio n. 3
0
 def profitability_df(self):
     data = []
     columns = [
         "Id", f"{self.base_asset} Change", f"{self.quote_asset} Change",
         f"Unclaimed {self.base_asset}", f"Unclaimed {self.quote_asset}",
         "Total Profit/loss (%)"
     ]
     for position in self.active_positions:
         profit_data = self.calculate_profitability(position)
         data.append([
             position.token_id,
             PerformanceMetrics.smart_round(profit_data['base_change'], 8),
             PerformanceMetrics.smart_round(profit_data['quote_change'], 8),
             PerformanceMetrics.smart_round(profit_data['base_fee'], 8),
             PerformanceMetrics.smart_round(profit_data['quote_fee'], 8),
             PerformanceMetrics.smart_round(profit_data['profitability'], 8)
         ])
     return pd.DataFrame(data=data, columns=columns)
Esempio n. 4
0
    def quotes_rate_df(self):
        columns = ["Quotes pair", "Rate"]
        quotes_pair: str = f"{self._market_info_2.quote_asset}-{self._market_info_1.quote_asset}"
        data = [[
            quotes_pair,
            PerformanceMetrics.smart_round(self._rate_source.rate(quotes_pair))
        ]]

        return pd.DataFrame(data=data, columns=columns)
Esempio n. 5
0
 def active_positions_df(self) -> pd.DataFrame:
     columns = [
         "Id", "Symbol", "Fee Tier", "Range", "Current Base",
         "Current Quote", ""
     ]
     data = []
     if len(self.active_positions) > 0:
         for position in self.active_positions:
             data.append([
                 position.token_id, position.trading_pair,
                 position.fee_tier,
                 f"{PerformanceMetrics.smart_round(Decimal(str(position.lower_price)), 8)} - "
                 f"{PerformanceMetrics.smart_round(Decimal(str(position.upper_price)), 8)}",
                 PerformanceMetrics.smart_round(
                     Decimal(str(position.current_base_amount)), 8),
                 PerformanceMetrics.smart_round(
                     Decimal(str(position.current_quote_amount)), 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)
Esempio n. 6
0
    def test_smart_round(self):
        value = PerformanceMetrics.smart_round(None)
        self.assertIsNone(value)
        value = PerformanceMetrics.smart_round(Decimal("NaN"))
        self.assertTrue(value.is_nan())

        value = PerformanceMetrics.smart_round(Decimal("10000.123456789"))
        self.assertEqual(value, Decimal("10000"))
        value = PerformanceMetrics.smart_round(Decimal("100.123456789"))
        self.assertEqual(value, Decimal("100.1"))
        value = PerformanceMetrics.smart_round(Decimal("1.123456789"))
        self.assertEqual(value, Decimal("1.12"))
        value = PerformanceMetrics.smart_round(Decimal("0.123456789"))
        self.assertEqual(value, Decimal("0.1234"))
        value = PerformanceMetrics.smart_round(Decimal("0.000456789"))
        self.assertEqual(value, Decimal("0.00045"))
        value = PerformanceMetrics.smart_round(Decimal("0.000056789"))
        self.assertEqual(value, Decimal("0.00005678"))
        value = PerformanceMetrics.smart_round(Decimal("0"))
        self.assertEqual(value, Decimal("0"))

        value = PerformanceMetrics.smart_round(Decimal("0.123456"), 2)
        self.assertEqual(value, Decimal("0.12"))
Esempio n. 7
0
 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"{PerformanceMetrics.smart_round(Decimal(str(amount)), 8)}",
                 PerformanceMetrics.smart_round(
                     Decimal(str(position.upper_price)), 8),
                 PerformanceMetrics.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)
Esempio n. 8
0
    async def exchange_balances_extra_df(
            self,  # type: HummingbotApplication
            exchange: str,
            ex_balances: Dict[str, Decimal],
            ex_avai_balances: Dict[str, Decimal]):
        conn_setting = AllConnectorSettings.get_connector_settings()[exchange]
        total_col_name = f"Total ({RateOracle.global_token_symbol})"
        allocated_total = Decimal("0")
        rows = []
        for token, bal in ex_balances.items():
            avai = Decimal(ex_avai_balances.get(
                token.upper(),
                0)) if ex_avai_balances is not None else Decimal(0)
            # show zero balances if it is a gateway connector (the user manually
            # chose to show those values with 'gateway connector-tokens')
            if conn_setting.uses_gateway_generic_connector():
                if bal == Decimal(0):
                    allocated = "0%"
                else:
                    allocated = f"{(bal - avai) / bal:.0%}"
            else:
                # the exchange is CEX. Only show balance if non-zero.
                if bal == Decimal(0):
                    continue
                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:
                PerformanceMetrics.smart_round(global_value),
                "sum_not_for_show":
                global_value,
                "Allocated":
                allocated,
            })
        df = pd.DataFrame(data=rows,
                          columns=[
                              "Asset", "Total", total_col_name,
                              "sum_not_for_show", "Allocated"
                          ])
        df.sort_values(by=["Asset"], inplace=True)
        return df, allocated_total
Esempio n. 9
0
    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,
            PerformanceMetrics.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:
            pos_info_df = self.active_positions_df()
            lines.extend(["", "  Positions:"] + [
                "    " + line
                for line in pos_info_df.to_string(index=False).split("\n")
            ])

            pos_profitability_df = self.profitability_df()
            lines.extend(["", "  Positions Performance:"] + [
                "    " + line for line in pos_profitability_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)
Esempio n. 10
0
    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}",
                PerformanceMetrics.smart_round(perf.b_vol_base, precision),
                PerformanceMetrics.smart_round(perf.s_vol_base, precision),
                PerformanceMetrics.smart_round(perf.tot_vol_base, precision)
            ],
            [
                f"{f'Total trade volume ({quote})':<27}",
                PerformanceMetrics.smart_round(perf.b_vol_quote, precision),
                PerformanceMetrics.smart_round(perf.s_vol_quote, precision),
                PerformanceMetrics.smart_round(perf.tot_vol_quote, precision)
            ],
            [
                f"{'Avg price':<27}",
                PerformanceMetrics.smart_round(perf.avg_b_price, precision),
                PerformanceMetrics.smart_round(perf.avg_s_price, precision),
                PerformanceMetrics.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}",
                PerformanceMetrics.smart_round(perf.start_base_bal, precision),
                PerformanceMetrics.smart_round(perf.cur_base_bal, precision),
                PerformanceMetrics.smart_round(perf.tot_vol_base, precision)
            ],
            [
                f"{quote:<17}",
                PerformanceMetrics.smart_round(perf.start_quote_bal,
                                               precision),
                PerformanceMetrics.smart_round(perf.cur_quote_bal, precision),
                PerformanceMetrics.smart_round(perf.tot_vol_quote, precision)
            ],
            [
                f"{trading_pair + ' price':<17}",
                PerformanceMetrics.smart_round(perf.start_price),
                PerformanceMetrics.smart_round(perf.cur_price),
                PerformanceMetrics.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"{PerformanceMetrics.smart_round(perf.hold_value, precision)} {quote}"
            ],
            [
                "Current portfolio value ",
                f"{PerformanceMetrics.smart_round(perf.cur_value, precision)} {quote}"
            ],
            [
                "Trade P&L               ",
                f"{PerformanceMetrics.smart_round(perf.trade_pnl, precision)} {quote}"
            ]
        ]
        perf_data.extend([
            "Fees paid               ",
            f"{PerformanceMetrics.smart_round(fee_amount, precision)} {fee_token}"
        ] for fee_token, fee_amount in perf.fees.items())
        perf_data.extend([[
            "Total P&L               ",
            f"{PerformanceMetrics.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))
Esempio n. 11
0
    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._all_arb_proposals is None:
            return "  The strategy is not ready, please try again later."
        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 = PerformanceMetrics.smart_round(Decimal(str(buy_price)), 8) if buy_price is not None else '-'
            sell_price = PerformanceMetrics.smart_round(Decimal(str(sell_price)), 8) if sell_price is not None else '-'
            mid_price = PerformanceMetrics.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")])

        columns = ["Exchange", "Gas Fees"]
        data = []
        for market_info in [self._market_info_1, self._market_info_2]:
            if hasattr(market_info.market, "network_transaction_fee"):
                transaction_fee: TokenAmount = getattr(market_info.market, "network_transaction_fee")
                data.append([market_info.market.display_name, f"{transaction_fee.amount} {transaction_fee.token}"])
        network_fees_df = pd.DataFrame(data=data, columns=columns)
        if len(data) > 0:
            lines.extend(
                ["", "  Network Fees:"] +
                ["    " + line for line in network_fees_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._all_arb_proposals))

        quotes_rates_df = self.quotes_rate_df()
        lines.extend(["", f"  Quotes Rates ({str(self._rate_source)})"] +
                     ["    " + line for line in str(quotes_rates_df).split("\n")])

        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)