Exemplo n.º 1
0
    def get_full_ohlcvs(self):
        """Getting all histrical price data through binance api.

        Returns:
            A DataFrame of OHLCV data for all.

        """
        symbol_lookbacks = self.get_all_symbol_lookback()
        ohlcvs = {}

        for (symbol, freq), lookback in symbol_lookbacks.items():
            ohlcvs[(symbol, freq)] = get_all_binance(symbol, freq)
        return ohlcvs
Exemplo n.º 2
0
    def portfolio_backtest(self, ohlcvs, min_freq, quote_assets=['BTC', 'USDT', 'BUSD', 'USDC'], fee=0.002, delay=0):
        """Display portfolio backtest result.

        Calculate overall account asset changes.
        Unit is USD

        Args:
          ohlcvs: A dataframe of symbel.
          min_freq: A str of calculation frequency ex('4h').
          quote_assets: A list of assets name ex(['BTC', 'USDT', 'BUSD', 'ETH']).
          fee: A float of trading fee.
          delay: A int of delayed entry and exit setting.
        Returns:
            widget GUI
        """
        # backtest_results
        results = []
        for method in self._trading_methods:
            for symbol in method.symbols:
                ohlcv = ohlcvs[(symbol, method.freq)]
                result = method.strategy.backtest(ohlcv,
                                                  method.variables, filters=method.filters, freq=method.freq)
                # find weight_btc if it is in the nested dictionary
                weight_btc = method.weight
                if isinstance(weight_btc, dict):
                    weight_btc = (weight_btc[symbol]
                        if symbol in weight else weight_btc['default'])

                weight_btc *= self.ticker_info.get_asset_price_in_btc(method.weight_unit)

                results.append({
                    'name': method.name,
                    'symbol': symbol,
                    'freq': method.freq,
                    'weight': weight_btc,
                    'portfolio': result,
                    'trading_method': method,
                    'signal': result.cash().iloc[-1] == 0,
                })

        results = pd.DataFrame(results)

        import matplotlib.pyplot as plt
        position = {}
        quote_substract = {}
        for index, value in results.transpose().items():
            position[value.loc['name'] + '|' + value.symbol + '|' + value.freq] = (value.portfolio.cash() == 0).shift(
                delay).ffill() * value.weight
        position = pd.DataFrame(position).resample(min_freq).last().ffill()
        position.columns = position.columns.str.split('|').str[1]
        position = position.ffill().fillna(0)
        position = position.groupby(position.columns, axis=1).sum()

        # find quote assets
        quote_asset_col = []
        for symbol in position.columns:
            for q in quote_assets:
                if symbol[-len(q):] == q:
                    quote_asset_col.append(q)
                    break

        quote_position = position.copy()
        quote_position.columns = quote_asset_col
        quote_position = -quote_position.groupby(quote_position.columns, axis=1).sum()

        # calculate return in usdt
        assets = position.columns.str.split('|').str[0].to_list()

        for i, a in enumerate(assets):
            for q in quote_assets:
                if len(a) > 5 and a[-len(q):] == q:
                    assets[i] = a[:-len(q)]

        position.columns = assets
        position = position.groupby(position.columns, axis=1).sum()
        quote_position = quote_position.groupby(quote_position.columns, axis=1).sum()

        all_symbols = list(set(quote_position.columns) | set(position.columns) | set(self._margins.keys()))
        if 'USDT' not in all_symbols:
            all_symbols.append('USDT')

        position = position.reindex(all_symbols, axis=1).fillna(0) + quote_position.reindex(all_symbols, axis=1).fillna(
            0)

        ohlcv_usdt = {a: get_all_binance(a + 'USDT', min_freq) for a in position.columns if a != 'USDT'}

        initial_margin_sum_btc = 0
        for a, w in self._margins.items():
            position[a] += self.ticker_info.get_asset_price_in_btc(a) * w
            initial_margin_sum_btc += self.ticker_info.get_asset_price_in_btc(a) * w

        # remove negative position
        negative_position = ((position < 0) * position).drop('USDT', axis=1, errors='ignore').sum(axis=1)
        pusdt = position['USDT'].copy()
        position = position.clip(0, None)
        position.USDT = pusdt + negative_position

        addition_usdt = -min(position.USDT.min(), 0) / self.ticker_info.get_asset_price_in_btc('USDT')

        if addition_usdt > 0:
            print('WARRN**: additional usdt is required: ', addition_usdt, ' USD')

        p = position.loc[position.index[(position != position.shift()).abs().sum(axis=1) != 0] | position.index[-1:]]
        p.index = p.index.tz_localize(None)

        ohlcv_usdt_close = pd.DataFrame({name: s.close for name, s in ohlcv_usdt.items()})
        ohlcv_usdt_close.index = ohlcv_usdt_close.index.tz_localize(None)

        rebalance_time = (p.index & ohlcv_usdt_close.index)

        ohlcv_usdt_close = ohlcv_usdt_close.loc[rebalance_time]
        p = p.loc[rebalance_time].fillna(0)

        asset_return = ((ohlcv_usdt_close.pct_change().shift(-1).fillna(0)) * p) - fee * (p - p.shift()).abs()
        asset_return.fillna(0, inplace=True)

        (asset_return.cumsum() / self.ticker_info.get_asset_price_in_btc('USDT')).plot()
        plt.show()

        s = (asset_return.sum(axis=1).cumsum() + initial_margin_sum_btc) / self.ticker_info.get_asset_price_in_btc(
            'USDT')
        s.plot()

        plt.show()

        (s / s.cummax()).plot()
        plt.show()

        return results