async def private_(self, type_: str, url: str, params: dict = {}) -> dict: timestamp = int(time() * 1000) params.update({'api_key': self.key, 'timestamp': timestamp}) for k in params: if type(params[k]) == bool: params[k] = 'true' if params[k] else 'false' elif type(params[k]) == float: params[k] = str(params[k]) params['sign'] = hmac.new(self.secret.encode('utf-8'), urlencode(sort_dict_keys(params)).encode('utf-8'), hashlib.sha256).hexdigest() async with getattr(self.session, type_)(self.base_endpoint + url, params=params) as response: result = await response.text() return json.loads(result)
def jackrabbit(trades_list: [dict], backtesting_settings: dict, ranges: dict, base_filepath: str): if backtesting_settings['random_starting_candidate']: best = { key: calc_new_val((abs(ranges[key][1]) - abs(ranges[key][0])) / 2, ranges[key], 1.0) for key in sorted(ranges) } print('random starting candidate:', best) else: best = sort_dict_keys({k_: backtesting_settings[k_] for k_ in ranges}) n_days = backtesting_settings['n_days'] results = {} best_gain = -9e9 candidate = best ks = backtesting_settings['n_jackrabbit_iterations'] k = backtesting_settings['starting_k'] ms = np.array([1 / (i / 2 + 16) for i in range(ks)]) ms = ((ms - ms.min()) / (ms.max() - ms.min())) trades_filepath = make_get_filepath( os.path.join(base_filepath, 'trades', '')) json.dump(backtesting_settings, open(base_filepath + 'backtesting_settings.json', 'w'), indent=4, sort_keys=True) print(backtesting_settings, '\n\n') while k < ks - 1: if candidate['min_markup'] >= candidate['max_markup']: candidate['min_markup'] = candidate['max_markup'] settings_ = {**backtesting_settings, **candidate} key = format_dict(candidate) if key in results: print('\nskipping', key) candidate = get_new_candidate(ranges, best) continue print(f'\nk={k}, m={ms[k]:.4f} candidate:\n', candidate) start_time = time() trades = backtest(trades_list, settings_) print('\ntime elapsed', round(time() - start_time, 1), 'seconds') if not trades: print('\nno trades') candidate = get_new_candidate(ranges, best) continue k += 1 tdf = pd.DataFrame(trades).set_index('trade_id') tdf.to_csv(trades_filepath + key + '.csv') closest_liq = ((tdf.price - tdf.liq_price).abs() / tdf.price).min() biggest_pos_size = tdf.pos_size.abs().max() n_closes = len(tdf[tdf.type == 'close']) pnl_sum = tdf.pnl.sum() loss_sum = tdf[tdf.type == 'stop_loss'].pnl.sum() abs_pos_sizes = tdf.pos_size.abs() gain = (pnl_sum + settings_['balance']) / settings_['balance'] average_daily_gain = gain**(1 / n_days) n_trades = len(tdf) result = { 'n_closes': n_closes, 'pnl_sum': pnl_sum, 'loss_sum': loss_sum, 'average_daily_gain': average_daily_gain, 'gain': gain, 'n_trades': n_trades, 'closest_liq': closest_liq, 'biggest_pos_size': biggest_pos_size, 'n_days': n_days } print('\n\n', result) results[key] = {**result, **candidate} if gain > best_gain: best = candidate best_gain = gain print('\n\n\n###############\nnew best', best, '\naverage daily gain:', round(average_daily_gain, 5), '\n\n') print(settings_, '\n') print(results[key], '\n\n') default_live_settings = load_settings(settings_['exchange'], print_=False) live_settings = { k: settings_[k] if k in settings_ else default_live_settings[k] for k in default_live_settings } live_settings['indicator_settings'] = { 'ema': { 'span': best['ema_span'] } } json.dump(live_settings, open(base_filepath + 'best_result_live_settings.json', 'w'), indent=4, sort_keys=True) json.dump(results[key], open(base_filepath + 'best_result.json', 'w'), indent=4, sort_keys=True) candidate = get_new_candidate(ranges, best, m=ms[k]) pd.DataFrame(results).T.to_csv(base_filepath + 'results.csv')
def jackrabbit(agg_trades: pd.DataFrame): ''' # settings for binance settings = { "default_qty": 0.001, "grid_step": 344, "leverage": 125, "maker_fee": 0.00018, "margin_limit": 60, "markups": (0.0038,), "min_qty": 0.001, "n_close_orders": 1, "n_entry_orders": 7, "price_step": 0.01, "qty_step": 0.001, "symbol": "BTCUSDT", "inverse": False, "break_on_loss": True, } ranges = { 'default_qty': (settings['min_qty'], settings['min_qty'] * 1, settings['qty_step']), 'grid_step': (10, 400, 1), 'markups': (0.0005, 0.005, 0.0001), 'n_close_orders': (1, 1, 1), } ''' # settings for bybit settings = { "default_qty": 1.0, "grid_step": 344, "leverage": 100, "maker_fee": -0.00025, "margin_limit": 0.001, "markups": (0.0038, ), "min_qty": 1.0, "n_close_orders": 1, "n_entry_orders": 7, "price_step": 0.5, "qty_step": 1.0, "symbol": "BTCUSD", "inverse": True, "break_on_loss": True, } ranges = { 'default_qty': (1, 30, 1), 'grid_step': (1, 400, 1), 'margin_limit': (0.001, 0.001, 0.0001), 'markups': (0.0001, 0.01, 0.0001), 'n_close_orders': (1, 10, 1), } tweakable = { 'default_qty': 0.0, 'grid_step': 0.0, 'markups': (0.0, 0.0), 'n_close_orders': 0.0 } best = {} for key in tweakable: if type(tweakable[key]) == tuple: best[key] = tuple( sorted([ calc_new_val((ranges[key][1] - ranges[key][0]) / 2, ranges[key], 1.0) for _ in tweakable[key] ])) else: best[key] = calc_new_val((ranges[key][1] - ranges[key][0]) / 2, ranges[key], 1.0) # optional: uncomment to use settings as start candidate. #best = {k_: settings[k_] for k_ in sorted(ranges)} settings = sort_dict_keys(settings) best = sort_dict_keys(best) results = {} best_gain = -99999999 candidate = best ks = 200 k = 0 ms = np.array([1 / (i / 2 + 16) for i in range(ks)]) ms = ((ms - ms.min()) / (ms.max() - ms.min())) results_filename = make_get_filepath( f'jackrabbit_results_grid/{ts_to_date(time())[:19]}') if settings['inverse']: results_filename += '_inverse' n_days = (agg_trades.timestamp.iloc[-1] - agg_trades.timestamp.iloc[0]) / 1000 / 60 / 60 / 24 settings['n_days'] = n_days print('n_days', n_days) # conditions for result approval conditions = [ lambda r: True, ] df = prep_df(agg_trades) while k < ks - 1: try: k += 1 key = tuple([candidate[k_] for k_ in sorted(candidate)]) if key in results: print('skipping', key) candidate = get_new_candidate(ranges, best) continue line = f'\n{k} m={ms[k]:.4f} best {tuple(best.values())}, ' line += f'candidate {tuple(candidate.values())}' print(line) settings_ = { k_: candidate[k_] if k_ in candidate else settings[k_] for k_ in sorted(settings) } trades = backtest(df, settings_) if not trades: print('\nno trades') candidate = get_new_candidate(ranges, best) continue tdf = pd.DataFrame(trades).set_index('trade_id') n_closes = len(tdf[tdf.type == 'close']) pnl_sum = tdf.pnl.sum() loss_sum = tdf[tdf.pnl < 0.0].pnl.sum() abs_pos_sizes = tdf.pos_size.abs() if settings['inverse']: max_margin_cost = (abs_pos_sizes / tdf.pos_price / settings_['leverage']).max() else: max_margin_cost = (abs_pos_sizes * tdf.pos_price / settings_['leverage']).max() gain = (pnl_sum + settings_['margin_limit']) / settings_['margin_limit'] n_trades = len(tdf) result = { 'n_closes': n_closes, 'pnl_sum': pnl_sum, 'loss_sum': loss_sum, 'max_margin_cost': max_margin_cost, 'gain': gain, 'n_trades': n_trades } print('\n', result) results[key] = result if gain > best_gain and all([c(results[key]) for c in conditions]): best = candidate best_gain = gain print('\n\nnew best', best, '\n', gain, '\n') print(settings_) print(results[key], '\n\n') candidate = get_new_candidate(ranges, best, m=ms[k]) pd.DataFrame(results).T.to_csv(results_filename + '.csv') except KeyboardInterrupt: return results return results