from otree.api import * import random author = 'Lingguo XU' doc = """ Part 2: belief elicitations """ class Constants(BaseConstants): name_in_url = 'Part2' players_per_group = None num_rounds = 1 ECUpercorrect = 40 ECUpercorrectPart2 = 100 ECU_BSR = 200 fixed_payment = 200 REAL_AVG = 17 class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): # Absolute belief and confidence on belief bef_attempts = models.IntegerField(min=0, max=30, label="Please fill in a number between 0 and 30.") bef_abs = models.IntegerField(min=0, max=30, label="Please fill in a number between 0 and 30.") bef_abs_confi = models.IntegerField(label="") bef_avg = models.IntegerField(min=0, max=30, label="Please fill in a number between 0 and 30.") bef_avg_confi = models.IntegerField(label="") # Over/under estimation bef_abs_over = models.IntegerField(label="", choices=[[1, 'Over-estimated'], [2, 'Under-estimated']], widget=widgets.RadioSelect ) # Number of correct guess num_correct_part2 = models.IntegerField() # Noisy feedback noise = models.IntegerField() noisy_feedback = models.IntegerField() # Relative belief def make_field_bef_rel(): return models.IntegerField(initial=0, min=0, max=100, label="Please select a number between 0 and 100.") #bef_rel, five number for five intervals, bef_rel_5 is top 10 rank bef_rel_1 = make_field_bef_rel() bef_rel_2 = make_field_bef_rel() bef_rel_3 = make_field_bef_rel() bef_rel_4 = make_field_bef_rel() bef_rel_5 = make_field_bef_rel() # Mean and mode of bef_rel, see Rel_bef page for coding bef_rel_mean = models.FloatField() bef_rel_mode = models.IntegerField() bef_rel_median_b = models.IntegerField() # for computing median beliefs, see Chen and Schildberg (2019) bef_rel_median = models.FloatField() # for computing median beliefs, see Chen and Schildberg (2019) # Real relative performance real_rel = models.IntegerField() # The interval subjects actually ranked, using subjects from Pilot 1 and 2 # real_rel_Pilot2 = models.IntegerField() # The interval subjects actually ranked, using subjects from Pilot 2 random_broke = models.BooleanField() # Indicator variable for those whose correct answers are on the break point (12, 16, 19, 22 for 100 subjects in Pilot 1 & 2) bef_rel_real = models.IntegerField() # The percentage subjects assigned to his real relative performance interval # bef_rel_real_Pilot2 = models.IntegerField() # The percentage subjects assigned to his real relative performance interval, ranking based on data from Pilot 2 bsr_random_interval = models.IntegerField() # pick a random interval which will be used to determine whether subjects receive reward or not bsr_t = models.IntegerField() # = 100 if bsr_random_interval = real_rel bsr_p = models.IntegerField() # The percentage subjects assigned to the interval randomly drew by the computer bsr_penalty = models.IntegerField() # Chances of receiving reward according to BSR bsr_n = models.IntegerField() # pick a random number which will be used to determine whether subjects receive reward or not bsr_payment = models.IntegerField() # payment from bef_rel question based on BSR bsr_clicked = models.BooleanField(initial = 0) #Payoff for Part 2 payoff_part2 = models.IntegerField() # FUNCTIONS # generate random numbers from 1 to 100 that will be used in BSR def creating_session(subsession): for player in subsession.get_players(): player.bsr_n = random.choice(range(1, 10001)) player.bsr_random_interval = random.choice([1, 2, 3, 4, 5]) player.noise = random.choice([-3, -2, -1, 0, 1, 2, 3]) print('set player.bsr_n to', player.bsr_n) print('set player.bsr_random_interval to', player.bsr_random_interval) print('set player.noise to', player.noise) # PAGES class Introduction_ASU(Page): def is_displayed(player): return player.participant.is_dropout == False @staticmethod def get_timeout_seconds(player): participant = player.participant if participant.is_dropout: return 1 # instant timeout, 1 second else: return player.session.config['my_page_timeout_seconds'] @staticmethod def before_next_page(player, timeout_happened): participant = player.participant if timeout_happened: participant.is_dropout = False score_noise = player.participant.correctanswer_R1 + player.noise if score_noise <= 0: player.noisy_feedback = 0 elif score_noise > 30: player.noisy_feedback = 30 else: player.noisy_feedback = score_noise player.participant.score = player.noisy_feedback class Abs_bef_1(Page): form_model = 'player' form_fields = ['bef_attempts', 'bef_abs'] def is_displayed(player): return player.participant.is_dropout == False @staticmethod def get_timeout_seconds(player): participant = player.participant if participant.is_dropout: return 1 # instant timeout, 1 second else: return player.session.config['my_page_timeout_seconds'] @staticmethod def before_next_page(player, timeout_happened): participant = player.participant if timeout_happened: participant.is_dropout = True class Abs_bef_2(Page): form_model = 'player' form_fields = ['bef_abs_confi', 'bef_abs_over'] def is_displayed(player): return player.participant.is_dropout == False @staticmethod def get_timeout_seconds(player): participant = player.participant if participant.is_dropout: return 1 # instant timeout, 1 second else: return player.session.config['my_page_timeout_seconds'] @staticmethod def before_next_page(player, timeout_happened): participant = player.participant if timeout_happened: participant.is_dropout = True class Avg_bef(Page): form_model = 'player' form_fields = ['bef_avg', 'bef_avg_confi'] def is_displayed(player): return player.participant.is_dropout == False @staticmethod def get_timeout_seconds(player): participant = player.participant if participant.is_dropout: return 1 # instant timeout, 1 second else: return player.session.config['my_page_timeout_seconds'] @staticmethod def before_next_page(player, timeout_happened): participant = player.participant if timeout_happened: participant.is_dropout = True class Noisy_feedback(Page): def is_displayed(player): return player.participant.is_dropout == False @staticmethod def get_timeout_seconds(player): participant = player.participant if participant.is_dropout: return 1 # instant timeout, 1 second else: return player.session.config['my_page_timeout_seconds'] @staticmethod def before_next_page(player, timeout_happened): participant = player.participant if timeout_happened: participant.is_dropout = True class Rel_bef(Page): form_model = 'player' form_fields = ['bef_rel_1','bef_rel_2','bef_rel_3','bef_rel_4','bef_rel_5', 'bsr_clicked'] def is_displayed(player): return player.participant.is_dropout == False @staticmethod def get_timeout_seconds(player): participant = player.participant if participant.is_dropout: return 1 # instant timeout, 1 second else: return player.session.config['my_page_timeout_seconds'] @staticmethod def before_next_page(player, timeout_happened): participant = player.participant if timeout_happened: participant.is_dropout = True # Compute mean relative belief, bef_rel_mean player.bef_rel_mean = round(5 * player.bef_rel_5/100 + 4 * player.bef_rel_4/100 + 3 * player.bef_rel_3/100 + 2 * player.bef_rel_2/100 + 1 * player.bef_rel_1/100, 4) # Compute mode relative belief, bef_rel_mode, if multiple maxes, randomly choose one bef_rel_list = [player.bef_rel_5, player.bef_rel_4, player.bef_rel_3, player.bef_rel_2, player.bef_rel_1] bef_rel_list_values = [5, 4, 3, 2, 1] # Important: need to be in the same order as in bef_rel_list max_value_indice = [i for i, x in enumerate(bef_rel_list) if x == max(bef_rel_list)] player.bef_rel_mode = bef_rel_list_values[random.choice(max_value_indice)] # Computer median beliefs, Chen and Schildberg (2019) sum1 = player.bef_rel_1 sum2 = sum1 + player.bef_rel_2 sum3 = sum2 + player.bef_rel_3 sum4 = sum3 + player.bef_rel_4 sum5 = sum4 + player.bef_rel_5 if sum1 >= 50: player.bef_rel_median_b = 1 player.bef_rel_median = round(1 - (sum1-50)/player.bef_rel_1, 4) elif sum2 >= 50: player.bef_rel_median_b = 2 player.bef_rel_median = round(2 - (sum2-50)/player.bef_rel_2, 4) elif sum3 >= 50: player.bef_rel_median_b = 3 player.bef_rel_median = round(3 - (sum3-50)/player.bef_rel_3, 4) elif sum4 >= 50: player.bef_rel_median_b = 4 player.bef_rel_median = round(4 - (sum4-50)/player.bef_rel_4, 4) else: player.bef_rel_median_b = 5 player.bef_rel_median = round(5 - (sum5-50)/player.bef_rel_5, 4) ## BSR mechanism # Compute subject's rank from 5 (top) to 1 (bottom) and get her belief on this rank if player.participant.correctanswer_R1 > 22: player.real_rel = 5 elif player.participant.correctanswer_R1 == 22: if player.bsr_n > 5000: player.real_rel = 5 else: player.real_rel = 4 elif player.participant.correctanswer_R1 > 19: player.real_rel = 4 elif player.participant.correctanswer_R1 == 19: if player.bsr_n > 5000: player.real_rel = 4 else: player.real_rel = 3 elif player.participant.correctanswer_R1 > 16: player.real_rel = 3 elif player.participant.correctanswer_R1 == 16: if player.bsr_n > 5000: player.real_rel = 3 else: player.real_rel = 2 elif player.participant.correctanswer_R1 > 12: player.real_rel = 2 elif player.participant.correctanswer_R1 == 12: if player.bsr_n > 5000: player.real_rel = 2 else: player.real_rel = 1 else: player.real_rel = 1 # Tage those participants who were randomly broken into the adjacent intervals player.random_broke = ((player.participant.correctanswer_R1 == 12) or (player.participant.correctanswer_R1 == 16) or (player.participant.correctanswer_R1 == 19) or (player.participant.correctanswer_R1 == 22)) # BSR mechanism, first choose bsr_p, then decide the number for bsr_t, then implment BSR player.bef_rel_real = bef_rel_list[bef_rel_list_values.index(player.real_rel)] player.bsr_p = bef_rel_list[bef_rel_list_values.index(player.bsr_random_interval)] if player.real_rel == player.bsr_random_interval: player.bsr_t = 100 # Compute probability score and final bsr outcome player.bsr_penalty = (player.bsr_p-player.bsr_t) ** 2 if player.bsr_penalty <= player.bsr_n: player.bsr_payment = Constants.ECU_BSR else: player.bsr_payment = 0 else: player.bsr_t = 0 player.bsr_penalty = (player.bsr_p-player.bsr_t) ** 2 if player.bsr_penalty <= player.bsr_n: player.bsr_payment = Constants.ECU_BSR else: player.bsr_payment = 0 # Compute player payoff in Part 2: check if the guess for attempts, absolute, and average are correct player.num_correct_part2 = (player.bef_attempts == player.participant.questionsattempted_R1) + ( player.bef_abs == player.participant.correctanswer_R1) + (player.bef_avg == Constants.REAL_AVG) # player.payoff_part2 = player.num_correct_part2 * Constants.ECUpercorrectPart2 + player.bsr_payment player.payoff_part2 = Constants.fixed_payment + player.num_correct_part2 * Constants.ECUpercorrectPart2 + player.bsr_payment # Save payoff in Part 1 and Part 2, and belief in attempts and success as participants variables player.participant.part2payoff = player.payoff_part2 player.participant.bef_attempts = player.bef_attempts player.participant.bef_abs = player.bef_abs class EndPage_ASU(Page): def is_displayed(player): return player.participant.is_dropout == False @staticmethod def get_timeout_seconds(player): participant = player.participant if participant.is_dropout: return 1 # instant timeout, 1 second else: return player.session.config['my_page_timeout_seconds'] @staticmethod def before_next_page(player, timeout_happened): participant = player.participant if timeout_happened: participant.is_dropout = False page_sequence = [Introduction_ASU, Abs_bef_1, Abs_bef_2, Avg_bef, Noisy_feedback, Rel_bef, EndPage_ASU] # page_sequence = [Rel_bef]