def test_naive_taxes( self, closes, stop_loss, take_profit, target_usd_percentage, balancing_period, distribution, balance, tax_exemption, ): distributions = np.stack([distribution, distribution], axis=1) stop_loss_index = opt.get_stop_loss_index(closes, stop_loss) take_profit_index = opt.get_take_profit_index(closes, take_profit) ( usd_values_without_taxes, asset_values_without_taxes, _, ) = opt.get_balanced_trade_naive( closes, stop_loss_index, take_profit_index, stop_loss, take_profit, target_usd_percentage, balancing_period, orderbook_distributions=distributions, balance=balance, taxes=False, ) trade_without_taxes = usd_values_without_taxes + asset_values_without_taxes usd_values, asset_values, buy_sizes = opt.get_balanced_trade_naive( closes, stop_loss_index, take_profit_index, stop_loss, take_profit, target_usd_percentage, balancing_period, orderbook_distributions=distributions, balance=balance, taxes=True, tax_exemption=tax_exemption, ) assert np.all(usd_values >= 0.0) assert np.all(asset_values >= 0.0) trade = usd_values + asset_values assert np.all(buy_sizes >= 0.0) assert np.all(buy_sizes <= 1e-7) if not tax_exemption: assert np.all(trade <= trade_without_taxes)
def test_naive_spread( self, closes, stop_loss, take_profit, target_usd_percentage, balancing_period, distribution, balance, ): assume(np.sum(distribution) > 0) distributions = np.stack([distribution, distribution], axis=1) stop_loss_index = opt.get_stop_loss_index(closes, stop_loss) take_profit_index = opt.get_take_profit_index(closes, take_profit) ( usd_values_without_spread, asset_values_without_spread, _, ) = opt.get_balanced_trade_naive( closes, stop_loss_index, take_profit_index, stop_loss, take_profit, target_usd_percentage, balancing_period, orderbook_distributions=distributions, balance=0.0, taxes=False, ) trade_without_spread = usd_values_without_spread + asset_values_without_spread usd_values, asset_values, _ = opt.get_balanced_trade_naive( closes, stop_loss_index, take_profit_index, stop_loss, take_profit, target_usd_percentage, balancing_period, orderbook_distributions=distributions, balance=balance, taxes=False, ) assert np.all(usd_values >= 0.0) assert np.all(asset_values >= 0.0) trade = usd_values + asset_values assert np.all(trade <= trade_without_spread)
def test_against_naive( self, closes, stop_loss, take_profit, target_usd_percentage, balancing_period, distribution, balance, tax_exemption, ): distributions = np.stack([distribution, distribution], axis=1) stop_loss_index = opt.get_stop_loss_index(closes, stop_loss) take_profit_index = opt.get_take_profit_index(closes, take_profit) usd_values1, asset_values1, buy_sizes1 = opt.get_balanced_trade_naive( closes, stop_loss_index, take_profit_index, stop_loss, take_profit, target_usd_percentage, balancing_period, orderbook_distributions=distributions, balance=balance, taxes=True, tax_exemption=tax_exemption, ) usd_values2, asset_values2, buy_sizes2 = opt.get_balanced_trade( closes, stop_loss_index, take_profit_index, stop_loss, take_profit, target_usd_percentage, balancing_period, orderbook_distributions=distributions, balance=balance, taxes=True, tax_exemption=tax_exemption, ) np.testing.assert_allclose(usd_values1, usd_values2) np.testing.assert_allclose(asset_values1, asset_values2) np.testing.assert_almost_equal(buy_sizes1, buy_sizes2)
def test_naive_stop_loss_and_take_profit( self, closes, stop_loss, take_profit, target_usd_percentage, ): stop_loss_index = opt.get_stop_loss_index(closes, stop_loss) take_profit_index = opt.get_take_profit_index(closes, take_profit) usd_values, asset_values, _ = opt.get_balanced_trade_naive( closes, stop_loss_index, take_profit_index, stop_loss, take_profit, target_usd_percentage, balancing_period=len(closes) + 2, orderbook_distributions=np.array([[0.0, 0.0]]), balance=0.0, taxes=False, ) assert np.all(usd_values >= 0.0) assert np.all(asset_values >= 0.0) trigger_i = min(stop_loss_index, take_profit_index) triggered = trigger_i < len(closes) trade = usd_values + asset_values if triggered: stop_loss_is_before_take_profit = stop_loss_index <= take_profit_index trigger_value = ( stop_loss if stop_loss_is_before_take_profit else take_profit ) np.testing.assert_allclose( trade[trigger_i:], trigger_value * (1.0 - target_usd_percentage) + target_usd_percentage, )
def simulate( params, moving_volumes, first_timestamps, get_buys_and_sells_fn, balance, k=20, assume_buy=True, return_separate=False, ): data_dir = os.path.abspath( os.path.join(constants.DATA_STORAGE_LOCATION, constants.LOCAL_DATA_DIR)) args = params["params"] aggregate_N, w = args[:2] strategy_N = aggregate_N * w secondary_args = params["secondary_params"] balancing_period = secondary_args["balancing_period"] displacement = secondary_args["displacement"] stop_loss = secondary_args["stop_loss"] take_profit = secondary_args["take_profit"] target_usd_percentage = secondary_args["target_usd_percentage"] k = min(k, len(moving_volumes.columns)) idx_k = np.arange(k) pnl = np.zeros((len(moving_volumes.index), k + 1)) pnl[0, :k] = 1.0 / k active_symbols = np.array([""] * k) timestamp_i = 0 # TODO: randomize first timestamp? timestamp = moving_volumes.index[timestamp_i] next_timestamps = np.array([timestamp] * k) idle_count = 0 with tqdm(total=int(moving_volumes.index[-1] - moving_volumes.index[0]) // 3600) as progress_bar: while timestamp < moving_volumes.index[-1]: li = next_timestamps == timestamp active_symbols[li] = "" volumes = moving_volumes.loc[timestamp].sort_values( ascending=False) i = 0 for active_symbol_i in idx_k[li]: total_pnl = np.sum(pnl[timestamp_i, :]) if pnl[timestamp_i, active_symbol_i] > total_pnl / k: pnl[timestamp_i, k] += (pnl[timestamp_i, active_symbol_i] - total_pnl / k) pnl[timestamp_i, active_symbol_i] = total_pnl / k else: pnl_diff = min( total_pnl / k - pnl[timestamp_i, active_symbol_i], pnl[timestamp_i, k], ) pnl[timestamp_i, k] -= pnl_diff pnl[timestamp_i, active_symbol_i] += pnl_diff while i < len(volumes.index ) and active_symbols[active_symbol_i] == "": symbol = volumes.index[i] i += 1 if symbol in active_symbols: continue first_timestamp = first_timestamps[symbol] if first_timestamp > timestamp: continue ( aggregated_closes, aggregated_lows, aggregated_highs, aggregated_times, spread_data, ) = data.load_data_for_symbol(data_dir, symbol, split_data=False, displacement=displacement) price_data_timestamp_i = utils.binary_search( aggregated_times, timestamp) aggregated_closes_up_to_timestamp = aggregated_closes[: price_data_timestamp_i] buy = assume_buy if len(aggregated_closes_up_to_timestamp) > strategy_N: # ignore possible gaps buy, _, N = get_buys_and_sells_fn( aggregated_closes_up_to_timestamp[-(strategy_N + 1):], *args, as_boolean=True, from_minute=False) assert N == 1 if not buy: continue aggregated_closes = aggregated_closes[ price_data_timestamp_i - strategy_N:] aggregated_lows = aggregated_lows[price_data_timestamp_i - strategy_N:] aggregated_highs = aggregated_highs[ price_data_timestamp_i - strategy_N:] aggregated_times = aggregated_times[ price_data_timestamp_i - strategy_N:] if len(aggregated_closes) <= strategy_N: continue # ignore possible gaps buys, sells, N = get_buys_and_sells_fn(aggregated_closes, *args, from_minute=False) aggregated_closes = aggregated_closes[-(N + 1):] aggregated_lows = aggregated_lows[-(N + 1):] aggregated_highs = aggregated_highs[-(N + 1):] aggregated_times = aggregated_times[-(N + 1):] tax_exemption = utils.get_leverage_from_symbol(symbol) == 1 _, trade_ends = opt.get_trades(buys, sells, aggregate_N, False) trade_end = trade_ends[0] if len(trade_ends) > 0 else 1 trade_closes = (aggregated_closes[1:trade_end + 1] / aggregated_closes[0]) trade_lows = (aggregated_lows[1:trade_end + 1] / aggregated_closes[0]) trade_highs = (aggregated_highs[1:trade_end + 1] / aggregated_closes[0]) trade_times = aggregated_times[1:trade_end + 1] stop_loss_index = opt.get_stop_loss_index( trade_lows, stop_loss) take_profit_index = opt.get_take_profit_index( trade_highs, take_profit) trigger_i = min(stop_loss_index, take_profit_index) usd_values, asset_values, _ = opt.get_balanced_trade( trade_closes, stop_loss_index, take_profit_index, stop_loss, take_profit, target_usd_percentage, balancing_period, spread_data, balance * pnl[timestamp_i, active_symbol_i], taxes=True, tax_exemption=tax_exemption, from_minute=False, ) trade_values = usd_values + asset_values if trigger_i == len(trade_closes): trigger_i -= 1 next_timestamp = timestamp + float( utils.get_smallest_divisible_larger_than( int(trade_times[trigger_i] - timestamp), aggregate_N * 3600, )) next_timestamps[active_symbol_i] = next_timestamp # no need to substract 1 since these are used just with slice trigger_timestamp_i = utils.binary_search( moving_volumes.index.values, trade_times[trigger_i]) next_timestamp_i = utils.binary_search( moving_volumes.index.values, next_timestamp) pnl[timestamp_i + 1:trigger_timestamp_i, active_symbol_i] = (np.interp( moving_volumes.index.values[timestamp_i + 1:trigger_timestamp_i], trade_times[:trigger_i + 1], trade_values[:trigger_i + 1], ) * pnl[timestamp_i, active_symbol_i]) pnl[trigger_timestamp_i:next_timestamp_i, active_symbol_i] = pnl[trigger_timestamp_i - 1, active_symbol_i] active_symbols[active_symbol_i] = symbol if active_symbols[active_symbol_i] == "": idle_count += aggregate_N # move next_timestamps[active_symbol_i] to next time # based on aggregate_N # - the values of pnl (column active_symbol_i) from this # timestamp to the next should remain constant next_timestamp = timestamp + aggregate_N * 3600.0 next_timestamps[active_symbol_i] = next_timestamp # no need to substract 1 since this is used just with slice next_timestamp_i = utils.binary_search( moving_volumes.index.values, next_timestamp) pnl[timestamp_i + 1:next_timestamp_i, active_symbol_i] = pnl[timestamp_i, active_symbol_i] next_timestamp = np.min(next_timestamps) progress_bar.update(int(next_timestamp - timestamp) // 3600) timestamp = next_timestamp timestamp_i = ( utils.binary_search(moving_volumes.index.values, timestamp) - 1) assert (timestamp >= moving_volumes.index[-1] or timestamp == moving_volumes.index[timestamp_i]) if not return_separate: pnl = np.sum(pnl, axis=1) return pnl, idle_count
def test_get_take_profit_index_against_naive(highs, take_profit): assert opt.get_take_profit_index_naive( highs, take_profit ) == opt.get_take_profit_index(highs, take_profit)