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
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