from otree.api import * import random import json import numpy as np doc = """ Your app description """ class C(BaseConstants): NAME_IN_URL = 'Intermediate_inflation' PLAYERS_PER_GROUP = None NUM_ROUNDS = 96 # make it 96 days and the month_num =6 --> must add 5 more rounds in order to ask the second phase questions and make sure to fix ranges. month_num = 6 Payment_per_choice = cu(1) # vars days and months # lets say we have 2 month and 16 days in one month # therefore, we have 6 days in total goods = ['Good A'] * 7 + ['Good B'] * 6 + ['Good C'] * 2 + ['Good D'] * 1 # create a good list that contains all months' goods # we can not shuffle goods every round goods_lst = [] for i in range(month_num): goods_copy = goods.copy() random.shuffle(goods_copy) goods_lst.append(goods_copy) print(goods_lst) class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): purchase = models.FloatField(widget= widgets.RadioSelect) choices = models.StringField() good = models.StringField() total_inflation_p = models.FloatField(min=None, #max=100.0, label="What was the TOTAL percentage change of the price of a basket from month 1 to month 6?" ) inflation_p_A = models.FloatField(min=None, #max=100.0, label="What was the total percentage change of the price of good A from month 1 to month 6?" ) inflation_p_B = models.FloatField(min=None, #max=100.0, label="What was the total percentage change of the price of good B from month 1 to month 6?" ) inflation_p_C = models.FloatField(min=None, #max=100.0, label="What was the total percentage change of the price of good C from month 1 to month 6?" ) inflation_p_D = models.FloatField(min=None, #max=100.0, label="What was the total percentage change of the price of good D from month 1 to month 6?" ) payoff_phase_1 = models.IntegerField() payoff_phase_2 = models.FloatField() Actual_total_Inflation = models.FloatField() Actual_Inflation_Good_A = models.FloatField() Actual_Inflation_Good_B = models.FloatField() Actual_Inflation_Good_C = models.FloatField() Actual_Inflation_Good_D = models.FloatField() prolific_id = models.StringField(initial="empty") # Function def purchase_choices(player): for round_num in range(1, C.NUM_ROUNDS+1): if player.round_number == round_num: choices_lst = json.loads(player.choices) choices = choices_lst[round_num - 1] return choices def creating_session(subsession): print("This is creating session for round " + str(subsession.round_number)) if subsession.round_number == 1: total_inflation = 0.25 inflation = (1 + total_inflation)**(1/5) mean_price_month1 = [1, 7, 122, 470] mean_price_month2 = [price * inflation for price in mean_price_month1] mean_price_month3 = [price * inflation for price in mean_price_month2] mean_price_month4 = [price * inflation for price in mean_price_month3] mean_price_month5 = [price * inflation for price in mean_price_month4] mean_price_month6 = [price * inflation for price in mean_price_month5] all_choices = [] for i in range(int((C.NUM_ROUNDS)/ C.month_num)): # subtracted -1 so that I get 32/2 all_choices.append(random.sample(np.round(np.random.uniform(0.9 * mean_price_month1[0], 1.1 * mean_price_month1[0], 1000), 2).tolist(), 3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month1[1], 1.1 * mean_price_month1[1], 1000),2).tolist(), 3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month1[2], 1.1 * mean_price_month1[2], 1000),2).tolist(), 3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month1[3], 1.1 * mean_price_month1[3], 1000),2).tolist(), 3)) for i in range(int((C.NUM_ROUNDS)/ C.month_num)): all_choices.append(random.sample(np.round(np.random.uniform(0.9 * mean_price_month2[0], 1.1 * mean_price_month2[0], 1000), 2).tolist(), 3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month2[1], 1.1 * mean_price_month2[1], 1000),2).tolist(), 3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month2[2], 1.1 * mean_price_month2[2], 1000),2).tolist(), 3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month2[3], 1.1 * mean_price_month2[3], 1000),2).tolist(), 3)) for i in range(int((C.NUM_ROUNDS)/C.month_num)): all_choices.append(random.sample(np.round(np.random.uniform(0.9 * mean_price_month3[0], 1.1 * mean_price_month3[0], 1000),2).tolist(),3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month3[1], 1.1 * mean_price_month3[1], 1000),2).tolist(),3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month3[2], 1.1 * mean_price_month3[2], 1000),2).tolist(),3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month3[3], 1.1 * mean_price_month3[3], 1000),2).tolist(),3)) for i in range(int((C.NUM_ROUNDS)/C.month_num)): all_choices.append(random.sample(np.round(np.random.uniform(0.9 * mean_price_month4[0], 1.1 * mean_price_month4[0], 1000),2).tolist(),3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month4[1], 1.1 * mean_price_month4[1], 1000),2).tolist(),3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month4[2], 1.1 * mean_price_month4[2], 1000),2).tolist(),3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month4[3], 1.1 * mean_price_month4[3], 1000),2).tolist(),3)) for i in range(int((C.NUM_ROUNDS)/C.month_num)): all_choices.append(random.sample(np.round(np.random.uniform(0.9 * mean_price_month5[0], 1.1 * mean_price_month5[0], 1000),2).tolist(),3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month5[1], 1.1 * mean_price_month5[1], 1000),2).tolist(),3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month5[2], 1.1 * mean_price_month5[2], 1000),2).tolist(),3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month5[3], 1.1 * mean_price_month5[3], 1000),2).tolist(),3)) for i in range(int((C.NUM_ROUNDS) /C.month_num)): all_choices.append(random.sample(np.round(np.random.uniform(0.9 * mean_price_month6[0], 1.1 * mean_price_month6[0], 1000),2).tolist(),3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month6[1], 1.1 * mean_price_month6[1], 1000),2).tolist(),3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month6[2], 1.1 * mean_price_month6[2], 1000),2).tolist(),3) + random.sample(np.round(np.random.uniform(0.9 * mean_price_month6[3], 1.1 * mean_price_month6[3], 1000),2).tolist(),3)) players = subsession.get_players() for p in players: p.choices = json.dumps(all_choices) print(p.choices) else: # pass the choices and good from round 1 to later rounds for p in subsession.get_players(): p_round_one = p.in_round(1) p.choices = p_round_one.choices print("This following sets the p.good for round " + str(subsession.round_number)) # The following flattens a list of list, i.e., # changing [[1, 2][3, 4][5, 6]] to [1, 2, 3, 4, 5, 6] flat_good_lst = [i for l in C.goods_lst for i in l] for p in subsession.get_players(): p.good = flat_good_lst[p.round_number - 1] print(p.good) # PAGES #class Welcome(Page): # @staticmethod # def is_displayed(player): # return player.round_number == 1 class Introduction1(Page): @staticmethod def before_next_page(player, timeout_happened): participant = player.participant # store the prolific_id, even when they opt not to attend the experiment player.prolific_id = player.participant.label @staticmethod def is_displayed(player): return player.round_number == 1 class Choice(Page): form_model = 'player' form_fields = ['purchase'] @staticmethod def get_timeout_seconds(player: Player): # Set a 30-second timer if it's not the first round if player.round_number > 1: return 30 # Don't set a timer for the first round else: return None @staticmethod def vars_for_template(player): if player.round_number < 17: month_number = 1 shopping_day = range(1, 17)[player.round_number - 1] elif player.round_number >= 17 and player.round_number < 33: month_number = 2 shopping_day = range(1, 17)[player.round_number - 1 - 16] elif player.round_number >= 33 and player.round_number < 49: month_number = 3 shopping_day = range(1, 17)[player.round_number - 1 - 32] elif player.round_number >= 49 and player.round_number < 65: month_number = 4 shopping_day = range(1, 17)[player.round_number - 1 - 48] elif player.round_number >= 65 and player.round_number < 81: month_number = 5 shopping_day = range(1, 17)[player.round_number - 1 - 64] elif player.round_number >= 81 and player.round_number < 97: month_number = 6 shopping_day = range(1, 17)[player.round_number - 1 - 80] else: return None good = player.good if Choice.get_timeout_seconds(player) is not None: timer_text = 'Time remaining for this day: ' else: timer_text = '(There is no time limit for your first shopping day.)' # MAYBE PUT VERY LARGE NUMBER FOR SECONDS IN FIRST ROUND THEN WE WOULD HAVE THE TIMER TEXT # IF IT IS NECESSARY TO MENTION NO TIME limit in that round return { 'good_to_buy': good, 'shopping_day': shopping_day, 'month_number': month_number, 'timer_text': timer_text, 'payoff_points_rounds': int(player.participant.payoff) } @staticmethod def before_next_page(player, timeout_happened): choice_prices = json.loads(player.choices) print(player.good) # print(sorted(choice_prices[0:3])) if player.good == 'Good A': if player.purchase == sorted(choice_prices[player.round_number - 1][0:3])[0]: player.payoff = 5 elif player.purchase == sorted(choice_prices[player.round_number - 1][0:3])[1]: player.payoff = 3 elif player.purchase == sorted(choice_prices[player.round_number - 1][0:3])[2]: player.payoff = 1 else: player.payoff = 0 elif player.good == 'Good B': if player.purchase == sorted(choice_prices[player.round_number - 1][3:6])[0]: player.payoff = 5 elif player.purchase == sorted(choice_prices[player.round_number - 1][3:6])[1]: player.payoff = 3 elif player.purchase == sorted(choice_prices[player.round_number - 1][3:6])[2]: player.payoff = 1 else: player.payoff = 0 elif player.good == 'Good C': if player.purchase == sorted(choice_prices[player.round_number - 1][6:9])[0]: player.payoff = 5 elif player.purchase == sorted(choice_prices[player.round_number - 1][6:9])[1]: player.payoff = 3 elif player.purchase == sorted(choice_prices[player.round_number - 1][6:9])[2]: player.payoff = 1 else: player.payoff = 0 elif player.good == 'Good D': if player.purchase == sorted(choice_prices[player.round_number - 1][9:12])[0]: player.payoff = 5 elif player.purchase == sorted(choice_prices[player.round_number - 1][9:12])[1]: player.payoff = 3 elif player.purchase == sorted(choice_prices[player.round_number - 1][9:12])[2]: player.payoff = 1 else: player.payoff = 0 #print(player.payoff) print(f"payoff for {player.round_number} is {player.payoff}") player.payoff_phase_1 = int(player.participant.payoff) print(f" The payoff of phase I is {player.payoff_phase_1}") class Introduction2(Page): @staticmethod def is_displayed(player): return player.round_number == C.NUM_ROUNDS class InflationQuestions(Page): form_model = 'player' form_fields = ['total_inflation_p', 'inflation_p_A', 'inflation_p_B', 'inflation_p_C', 'inflation_p_D'] @staticmethod def is_displayed(player): return player.round_number == C.NUM_ROUNDS @staticmethod def before_next_page(player: Player, timeout_happened): choice_prices = json.loads(player.choices) Price_goods = {} for i in range(len(C.goods_lst)): for j in range(len(C.goods_lst[i])): key = C.goods_lst[i][j] value = choice_prices[(i * len(C.goods_lst[i])) + j] if key in Price_goods: Price_goods[key].append(value) else: Price_goods[key] = [value] print(Price_goods) Prices_A_1 = [i[:3] for i in Price_goods['Good A'][:7]] print(Prices_A_1) minimum_prices_A1 = [] for i in Prices_A_1: minimum_price = min(i) minimum_prices_A1.append(minimum_price) P_A1 = sum(minimum_prices_A1) print(P_A1) Prices_A_6 = [i[:3] for i in Price_goods['Good A'][35:]] # print(Prices_A_2) minimum_prices_A6 = [] for i in Prices_A_6: minimum_price = min(i) minimum_prices_A6.append(minimum_price) P_A6 = sum(minimum_prices_A6) print(P_A6) Prices_B_1 = [i[3:6] for i in Price_goods['Good B'][:6]] print(Prices_B_1) minimum_prices_B1 = [] for i in Prices_B_1: minimum_price = min(i) minimum_prices_B1.append(minimum_price) P_B1 = sum(minimum_prices_B1) print(P_B1) Prices_B_6 = [i[3:6] for i in Price_goods['Good B'][30:]] print(Prices_B_6) minimum_prices_B6 = [] for i in Prices_B_6: minimum_price = min(i) minimum_prices_B6.append(minimum_price) P_B6 = sum(minimum_prices_B6) print(P_B6) Prices_C_1 = [i[6:9] for i in Price_goods['Good C'][:2]] print(Prices_C_1) minimum_prices_C1 = [] for i in Prices_C_1: minimum_price = min(i) minimum_prices_C1.append(minimum_price) P_C1 = sum(minimum_prices_C1) print(P_C1) Prices_C_6 = [i[6:9] for i in Price_goods['Good C'][10:]] print(Prices_C_6) minimum_prices_C6 = [] for i in Prices_C_6: minimum_price = min(i) minimum_prices_C6.append(minimum_price) P_C6 = sum(minimum_prices_C6) print(P_C6) Prices_D_1 = [i[9:12] for i in Price_goods['Good D'][:1]] print(Prices_D_1) minimum_prices_D1 = [] for i in Prices_D_1: minimum_price = min(i) minimum_prices_D1.append(minimum_price) P_D1 = sum(minimum_prices_D1) print(P_D1) Prices_D_6 = [i[9:12] for i in Price_goods['Good D'][5:]] print(Prices_D_6) minimum_prices_D6 = [] for i in Prices_D_6: minimum_price = min(i) minimum_prices_D6.append(minimum_price) P_D6 = sum(minimum_prices_D6) print(P_D6) def sum_prices(*args): return sum(args) Prices_month_1 = sum_prices(P_A1, P_B1, P_C1, P_D1) print(Prices_month_1) print(f"sum of prices in month 1 {Prices_month_1}") Prices_month_6 = sum_prices(P_A6, P_B6, P_C6, P_D6) print(Prices_month_6) print(f"sum of prices in month 6 {Prices_month_6}") actual_total_inflation = ((Prices_month_6 - Prices_month_1) / Prices_month_1) * 100 actual_inflation_A = ((P_A6 - P_A1) / P_A1) * 100 actual_inflation_B = ((P_B6 - P_B1) / P_B1) * 100 actual_inflation_C = ((P_C6 - P_C1) / P_C1) * 100 actual_inflation_D = ((P_D6 - P_D1) / P_D1) * 100 print(f"actual infaltion are respectively {actual_total_inflation}, {actual_inflation_A},{actual_inflation_B}.{actual_inflation_C},{actual_inflation_D}") # Store the calculated values in the participant's session player.participant.vars['actual_total_inflation'] = actual_total_inflation player.participant.vars['actual_inflation_A'] = actual_inflation_A player.participant.vars['actual_inflation_B'] = actual_inflation_B player.participant.vars['actual_inflation_C'] = actual_inflation_C player.participant.vars['actual_inflation_D'] = actual_inflation_D player.payoff = (max(0,(425 - 500 * (abs(player.total_inflation_p - round(actual_total_inflation, 2)) / 100))) + max(0,(125 - 500 * (abs(player.inflation_p_A - round(actual_inflation_A, 2)) / 100))) + max(0,(125 - 500 * (abs(player.inflation_p_B - round(actual_inflation_B, 2)) / 100))) + max(0,(125 - 500 * (abs(player.inflation_p_C - round(actual_inflation_C, 2)) / 100))) + max(0,(125 - 500 * (abs(player.inflation_p_D - round(actual_inflation_D, 2)) / 100)))) player.payoff_phase_2 = float(player.payoff) # store this so we can use in the # next page print(f"payoff for Phase 2 is {player.payoff_phase_2}") class Result(Page): @staticmethod def is_displayed(player): return player.round_number == C.NUM_ROUNDS def vars_for_template(player: Player): print(f"whole payoff is {player.participant.payoff}") #print(f"The whole payoff is {player.payoff_phase_1 + player.payoff_phase_2}") # recall the following: # “participant.payoff” automatically stores the sum of “player.payoff" # from all subsessions. # you used it in the Choice.html, and you can also use it here. session = player.session phase1_points = player.payoff_phase_1 phase2_points = player.payoff_phase_2 #phase1_money= (cu(phase1_points).to_real_world_currency(session)) * session.config.get('exchange_rate') #phase2_money = (cu(phase2_points).to_real_world_currency(session)) * session.config.get('exchange_rate') phase1_money = round(phase1_points * session.config.get('exchange_rate'),2) phase2_money = round(phase2_points * session.config.get('exchange_rate'),2) total_money = round(phase1_money + phase2_money,2) player.participant.payoff = total_money #total_money = (cu(phase1_points + phase2_points).to_real_world_currency(session))* session.config.get('exchange_rate') # Access the stored values from the participant's session actual_total_inflation = round(player.participant.vars['actual_total_inflation'], 1) actual_inflation_A = round(player.participant.vars['actual_inflation_A'], 1) actual_inflation_B = round(player.participant.vars['actual_inflation_B'], 1) actual_inflation_C = round(player.participant.vars['actual_inflation_C'], 1) actual_inflation_D = round(player.participant.vars['actual_inflation_D'], 1) # Update model fields with rounded values in order to put into my data player.Actual_total_Inflation = actual_total_inflation player.Actual_Inflation_Good_A = actual_inflation_A player.Actual_Inflation_Good_B = actual_inflation_B player.Actual_Inflation_Good_C = actual_inflation_C player.Actual_Inflation_Good_D = actual_inflation_D return { 'phase1_points': phase1_points, 'phase1_money': phase1_money, 'phase2_points': phase2_points, 'phase2_money': phase2_money, 'total_money': total_money, 'actual_total_inflation': actual_total_inflation, 'actual_inflation_A': actual_inflation_A, 'actual_inflation_B': actual_inflation_B, 'actual_inflation_C': actual_inflation_C, 'actual_inflation_D': actual_inflation_D, } page_sequence = [Introduction1, Choice, Introduction2,InflationQuestions, Result]