def sim_synthetic_bubble(seed): """ Simulate model once with a shock and return accompanying info on - bubble_type - bubble-episode price - wealth_start - wealth_end + wealth_gini_over_time + palma_over_time + twentytwenty_over_time """ BURN_IN = 200 SHOCK = 12000.0 SHOCK_PERIOD = 400 params = { "spread_max": 0.004087, "fundamental_value": 166, "fundamentalist_horizon_multiplier": 0.73132061, "n_traders": 500, "w_fundamentalists": 37.20189844, "base_risk_aversion": 11.65898537, "mutation_probability": 0.30623129, "init_stocks": 50, "trader_sample_size": 19, "ticks": 700, "std_fundamental": 0.0530163128919286, "std_noise": 0.29985649, "trades_per_tick": 5, "average_learning_ability": 0.57451773, "w_momentum": 0.01, "horizon": 200, "w_random": 1.0 } # simulate model once obs = [] obs_no_shock = [] # run model with parameters print('Simulate once') traders, orderbook = init_objects_distr(params, seed) traders, orderbook = pb_distr_model_shock(traders, orderbook, params, SHOCK, SHOCK_PERIOD, seed) obs.append(orderbook) traders_no_shock, orderbook_no_shock = init_objects_distr(params, seed) traders_no_shock, orderbook_no_shock = pb_distr_model_shock( traders_no_shock, orderbook_no_shock, params, 0.0, SHOCK_PERIOD, seed) obs_no_shock.append(orderbook) # store simulated stylized facts mc_prices, mc_returns, mc_autocorr_returns, mc_autocorr_abs_returns, mc_volatility, mc_volume, mc_fundamentals = organise_data( obs, burn_in_period=BURN_IN) mc_prices_ns, mc_returns_ns, mc_autocorr_returns_ns, mc_autocorr_abs_returns_ns, mc_volatility_ns, mc_volume_ns, mc_fundamentals_ns = organise_data( obs_no_shock, burn_in_period=BURN_IN) y = pd.Series(mc_prices[0][:-1] / mc_fundamentals[0]) y_ns = pd.Series(mc_prices_ns[0][:-1] / mc_fundamentals_ns[0]) obs = len(y) r0 = 0.01 + 1.8 / np.sqrt(obs) swindow0 = int(math.floor(r0 * obs)) dim = obs - swindow0 + 1 IC = 2 adflag = 6 yr = 2 Tb = 12 * yr + swindow0 - 1 nboot = 99 # calc bubbles bsadfs = PSY(y, swindow0, IC, adflag) quantilesBsadf = cvPSYwmboot(y, swindow0, IC, adflag, Tb, nboot=99) monitorDates = y.iloc[swindow0 - 1:obs].index quantile95 = np.dot(np.array([quantilesBsadf]).T, np.ones([1, dim])) ind95 = (bsadfs.T[0] > quantile95[1, ]) periods = monitorDates[ind95] bubble_types = [] bubble_prices = [] wealth_starts = [] wealth_ends = [] ginis_ot = [] palmas_ot = [] twtws_ot = [] bubble_prices_ns = [] wealth_ends_ns = [] ginis_ot_ns = [] palmas_ot_ns = [] twtws_ot_ns = [] if True in ind95: bubbly_dates = find_sequences_ints(periods, monitorDates) proper_bubbles = bubbly_dates.iloc[p_bubbles(bubbly_dates)] # classify the bubbles start_dates = [] end_dates = [] # then add the first bubble episodes start_dates.append(proper_bubbles.iloc[0]['start_date']) end_dates.append(proper_bubbles.iloc[0]['end_date']) if abs(y[end_dates[0]] - y[start_dates[0]]) > y[:end_dates[0]].std(): # classify as boom or bust if y[start_dates[0]] > y[end_dates[0]]: bubble_type = 'bust' else: bubble_type = 'boom' else: if y[start_dates[0]:end_dates[0]].mean() > y[start_dates[0]]: # classify as boom-bust or bust-boom bubble_type = 'boom-bust' else: bubble_type = 'bust-boom' bubble_types.append(bubble_type) # determine the start and end wealth of the bubble money_start = np.array( [x.var.money[BURN_IN + start_dates[0]] for x in traders]) stocks_start = np.array( [x.var.stocks[BURN_IN + start_dates[0]] for x in traders]) wealth_start = money_start + (stocks_start * mc_prices[0].iloc[start_dates[0]]) money_end = np.array( [x.var.money[BURN_IN + end_dates[0]] for x in traders]) stocks_end = np.array( [x.var.stocks[BURN_IN + end_dates[0]] for x in traders]) wealth_end = money_end + (stocks_end * mc_prices[0].iloc[end_dates[0]]) # track money + wealth no shocks TODO check if this works money_end_ns = np.array( [x.var.money[BURN_IN + end_dates[0]] for x in traders_no_shock]) stocks_end_ns = np.array( [x.var.stocks[BURN_IN + end_dates[0]] for x in traders_no_shock]) wealth_end_ns = money_end_ns + (stocks_end_ns * mc_prices_ns[0].iloc[end_dates[0]]) wealth_gini_over_time = [] palma_over_time = [] twentytwenty_over_time = [] # also record the gini etc. over time without the shock wealth_gini_over_time_ns = [] palma_over_time_ns = [] twentytwenty_over_time_ns = [] for t in range(BURN_IN + start_dates[0], BURN_IN + end_dates[0]): money = np.array([x.var.money[t] for x in traders]) stocks = np.array([x.var.stocks[t] for x in traders]) wealth = money + (stocks * orderbook.tick_close_price[t]) share_top_10 = sum( np.sort(wealth)[int(len(wealth) * 0.9):]) / sum(wealth) share_bottom_40 = sum( np.sort(wealth)[:int(len(wealth) * 0.4)]) / sum(wealth) palma_over_time.append(share_top_10 / share_bottom_40) share_top_20 = sum( np.sort(wealth)[int(len(wealth) * 0.8):]) / sum(wealth) share_bottom_20 = sum( np.sort(wealth)[:int(len(wealth) * 0.2)]) / sum(wealth) twentytwenty_over_time.append(share_top_20 / share_bottom_20) wealth_gini_over_time.append(gini(wealth)) # No shocks money_ns = np.array([x.var.money[t] for x in traders_no_shock]) stocks_ns = np.array([x.var.stocks[t] for x in traders_no_shock]) wealth_ns = money_ns + (stocks_ns * orderbook_no_shock.tick_close_price[t]) share_top_10_ns = sum( np.sort(wealth_ns)[int(len(wealth_ns) * 0.9):]) / sum(wealth_ns) share_bottom_40_ns = sum( np.sort(wealth_ns)[:int(len(wealth_ns) * 0.4)]) / sum(wealth_ns) palma_over_time_ns.append(share_top_10_ns / share_bottom_40_ns) share_top_20_ns = np.mean( np.sort(wealth_ns)[int(len(wealth_ns) * 0.8):]) share_bottom_20_ns = np.mean( np.sort(wealth_ns)[:int(len(wealth_ns) * 0.2)]) twentytwenty_over_time_ns.append(share_top_20_ns / share_bottom_20_ns) wealth_gini_over_time_ns.append(gini(wealth_ns)) bubble_prices.append( list(mc_prices[0].iloc[start_dates[0]:end_dates[0]])) wealth_starts.append(list(wealth_start)) wealth_ends.append(list(wealth_end)) ginis_ot.append(wealth_gini_over_time) palmas_ot.append(palma_over_time) twtws_ot.append(twentytwenty_over_time) bubble_prices_ns.append( list(mc_prices_ns[0].iloc[start_dates[0]:end_dates[0]])) wealth_ends_ns.append(list(wealth_end_ns)) ginis_ot_ns.append(wealth_gini_over_time_ns) palmas_ot_ns.append(palma_over_time_ns) twtws_ot_ns.append(twentytwenty_over_time_ns) return bubble_types, bubble_prices, wealth_starts, wealth_ends, ginis_ot, palmas_ot, twtws_ot, bubble_prices_ns, wealth_ends_ns, ginis_ot_ns, palmas_ot_ns, twtws_ot_ns
def simulate_params_efast(NRUNS, parameter_set, fixed_parameters): """ Simulate the model for different parameter sets. Record the difference in Gini inequality. :param NRUNS: integer amount of Monte Carlo simulations :param parameter_set: list of parameters which have been sampled for Sobol sensitivity analysis :param fixed_parameters: list of parameters which will remain fixed :return: numpy array of average stylized facts outcome values for all parameter combinations """ gini_avs = [] real_gini_avs = [] palma_avs = [] real_palma_avs = [] av_profits = [] av_volatilities = [] for parameters in parameter_set: # combine individual parameters with fixed parameters params = fixed_parameters.copy() params.update(parameters) # simulate the model trdrs = [] orbs = [] for seed in range(NRUNS): traders, orderbook = init_objects.init_objects(params, seed) traders, orderbook = exuberance_inequality_model(traders, orderbook, params, seed=seed) trdrs.append(traders) orbs.append(orderbook) mc_prices, mc_returns, mc_autocorr_returns, \ mc_autocorr_abs_returns, mc_volatility, mc_volume, mc_fundamentals = organise_data(orbs, burn_in_period=0) av_volatility = mc_volatility.mean().mean() ginis_ot = [] palmas_ot = [] real_ginis_ot = [] real_palmas_ot = [] profits = [] # determine the start and end wealth for seed, traders in enumerate(trdrs): money_start = np.array([x.var.money[0] for x in traders]) stocks_start = np.array([x.var.stocks[0] for x in traders]) wealth_start = money_start + (stocks_start * orbs[seed].tick_close_price[0]) money_end = np.array([x.var.money[-1] for x in traders]) stocks_end = np.array([x.var.stocks[-1] for x in traders]) wealth_end = money_end + (stocks_end * orbs[seed].tick_close_price[-1]) profits.append((np.array(wealth_end) - np.array(wealth_start)) / np.array(wealth_start)) wealth_gini_over_time = [] palma_over_time = [] real_wealth_gini_over_time = [] real_palma_over_time = [] for t in range(params['ticks'] - 1): money = np.array([x.var.money[t] for x in traders]) stocks = np.array([x.var.stocks[t] for x in traders]) wealth = money + (stocks * orbs[seed].tick_close_price[t]) real_wealth = np.array([x.var.real_wealth[t] for x in traders]) share_top_10 = sum( np.sort(wealth)[int(len(wealth) * 0.9):]) / sum(wealth) share_bottom_40 = sum( np.sort(wealth)[:int(len(wealth) * 0.4)]) / sum(wealth) palma_over_time.append(share_top_10 / share_bottom_40) real_share_top_10 = sum( np.sort(real_wealth)[int(len(real_wealth) * 0.9):]) / sum(real_wealth) real_share_bottom_40 = sum( np.sort(real_wealth)[:int(len(real_wealth) * 0.4)]) / sum(real_wealth) real_palma_over_time.append(real_share_top_10 / real_share_bottom_40) wealth_gini_over_time.append(gini(wealth)) real_wealth_gini_over_time.append(gini(real_wealth)) ginis_ot.append(wealth_gini_over_time) palmas_ot.append(palma_over_time) real_ginis_ot.append(real_wealth_gini_over_time) real_palmas_ot.append(real_palma_over_time) gini_avs.append(np.mean(ginis_ot)) real_gini_avs.append(np.mean(real_ginis_ot)) palma_avs.append(np.mean(palmas_ot)) real_palma_avs.append(np.mean(real_palmas_ot)) av_profits.append(np.mean(profits)) av_volatilities.append(av_volatility) return gini_avs, real_gini_avs, palma_avs, real_palma_avs, av_profits, av_volatilities
def sim_bubble_info(seed): """ Simulate model once and return accompanying info on Inequality: - bubble_type - bubble-episode price - wealth_start - wealth_end + wealth_gini_over_time + palma_over_time + twentytwenty_over_time Information on agent characteristics - risk aversion - horizon - learning ability - chartist expectation - fundamentalist expectation """ BURN_IN = 400 with open('parameters.json', 'r') as f: params = json.loads(f.read()) # simulate model once #traders = [] obs = [] # run model with parameters print('Simulate once') traders, orderbook = init_objects_distr(params, seed) traders, orderbook = pb_distr_model(traders, orderbook, params, seed) #traders.append(traders) obs.append(orderbook) # store simulated stylized facts mc_prices, mc_returns, mc_autocorr_returns, mc_autocorr_abs_returns, mc_volatility, mc_volume, mc_fundamentals = organise_data( obs, burn_in_period=BURN_IN) y = pd.Series(mc_prices[0][:-1] / mc_fundamentals[0]) obs = len(y) r0 = 0.01 + 1.8 / np.sqrt(obs) swindow0 = int(math.floor(r0 * obs)) dim = obs - swindow0 + 1 IC = 2 adflag = 6 yr = 2 Tb = 12 * yr + swindow0 - 1 nboot = 99 # calc bubbles bsadfs = PSY(y, swindow0, IC, adflag) quantilesBsadf = cvPSYwmboot(y, swindow0, IC, adflag, Tb, nboot=99) monitorDates = y.iloc[swindow0 - 1:obs].index quantile95 = np.dot(np.array([quantilesBsadf]).T, np.ones([1, dim])) ind95 = (bsadfs.T[0] > quantile95[1, ]) periods = monitorDates[ind95] bubble_types = [] bubble_prices = [] wealth_starts = [] wealth_ends = [] ginis_ot = [] palmas_ot = [] twtws_ot = [] risk_aversions = [] horizons = [] learning_abilities = [] chartist_expectations = [] fundamentalist_expectations = [] if True in ind95: bubbly_dates = find_sequences_ints(periods, monitorDates) proper_bubbles = bubbly_dates.iloc[p_bubbles(bubbly_dates)] # classify the bubbles start_dates = [] end_dates = [] # add bubble episodes for l in range(len(proper_bubbles)): start_dates.append(proper_bubbles.iloc[l]['start_date']) end_dates.append(proper_bubbles.iloc[l]['end_date']) if abs(y[end_dates[l]] - y[start_dates[l]]) > y[:end_dates[l]].std(): # classify as boom or bust if y[start_dates[l]] > y[end_dates[l]]: bubble_type = 'bust' else: bubble_type = 'boom' else: if y[start_dates[l]:end_dates[l]].mean() > y[start_dates[l]]: # classify as boom-bust or bust-boom bubble_type = 'boom-bust' else: bubble_type = 'bust-boom' bubble_types.append(bubble_type) # determine the start and end wealth of the bubble money_start = np.array( [x.var.money[BURN_IN + start_dates[l]] for x in traders]) stocks_start = np.array( [x.var.stocks[BURN_IN + start_dates[l]] for x in traders]) wealth_start = money_start + (stocks_start * mc_prices[0].iloc[start_dates[l]]) money_end = np.array( [x.var.money[BURN_IN + end_dates[l]] for x in traders]) stocks_end = np.array( [x.var.stocks[BURN_IN + end_dates[l]] for x in traders]) wealth_end = money_end + (stocks_end * mc_prices[0].iloc[end_dates[l]]) # determine characteristics of the agents risk_aversions.append([x.par.risk_aversion for x in traders]) horizons.append([x.par.horizon for x in traders]) learning_abilities.append( [x.par.learning_ability for x in traders]) chartist_expectations.append([ list( np.array(x.var.weight_chartist)[BURN_IN + start_dates[l]:BURN_IN + end_dates[l]] * x.var.forecast_adjust) for x in traders ]) fundamentalist_expectations.append([ list( np.array(x.var.weight_fundamentalist) [BURN_IN + start_dates[l]:BURN_IN + end_dates[l]] * x.var.forecast_adjust) for x in traders ]) wealth_gini_over_time = [] palma_over_time = [] twentytwenty_over_time = [] for t in range(BURN_IN + start_dates[l], BURN_IN + end_dates[l]): money = np.array([x.var.money[t] for x in traders]) stocks = np.array([x.var.stocks[t] for x in traders]) wealth = money + (stocks * orderbook.tick_close_price[t]) share_top_10 = sum( np.sort(wealth)[int(len(wealth) * 0.9):]) / sum(wealth) share_bottom_40 = sum( np.sort(wealth)[:int(len(wealth) * 0.4)]) / sum(wealth) palma_over_time.append(share_top_10 / share_bottom_40) share_top_20 = np.mean( np.sort(wealth)[int(len(wealth) * 0.8):]) share_bottom_20 = np.mean( np.sort(wealth)[:int(len(wealth) * 0.2)]) twentytwenty_over_time.append(share_top_20 / share_bottom_20) wealth_gini_over_time.append(gini(wealth)) bubble_prices.append( list(mc_prices[0].iloc[start_dates[l]:end_dates[l]])) wealth_starts.append(list(wealth_start)) wealth_ends.append(list(wealth_end)) ginis_ot.append(wealth_gini_over_time) palmas_ot.append(palma_over_time) twtws_ot.append(twentytwenty_over_time) return bubble_types, bubble_prices, wealth_starts, wealth_ends, ginis_ot, palmas_ot, twtws_ot, risk_aversions, horizons, learning_abilities, chartist_expectations, fundamentalist_expectations