import random from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, Page, WaitPage ) cu = c doc = 'Sessions as described in Casella\'s \n"LD - experimental design" email' class Constants(BaseConstants): name_in_url = 'Session2a_PR' num_participants = 15 players_per_group = 5 num_rounds = 2 reward = c(100) num_treatments = 1 p = 70 # expert q_lb = 50 # lower bound q_ub = 70 # upper bound two_paid_rounds = False # Two paid rounds if true, four else def shuffle(subsession): session = subsession.session subsession.group_randomly() rng = random.Random() # This we will manually change for different sessions subsession.mva = True subsession.big_group = False # Setting treatment round number subsession.treatment_round_number = 1 + int((subsession.round_number - 1) % (int(Constants.num_rounds/Constants.num_treatments))) # Determining paid rounds # This is irrelevant for practice rounds # if subsession.round_number == 1: # if Constants.two_paid_rounds: # # I've confirmed this should be plus 1 below # paid_rounds = rng.sample(range(1, Constants.num_rounds + 1), 2) # subsession.paid_round1 = paid_rounds[0] # subsession.paid_round2 = paid_rounds[1] # else: # # I've confirmed this should be plus one below # paid_rounds = rng.sample(range(1, int(Constants.num_rounds/2) + 1), 2) # subsession.paid_round1 = paid_rounds[0] # subsession.paid_round2 = paid_rounds[1] # paid_rounds = rng.sample(range(int(Constants.num_rounds/2) + 1, int(Constants.num_rounds) + 1), 2) # subsession.paid_round3 = paid_rounds[0] # subsession.paid_round4 = paid_rounds[1] # else: # if Constants.two_paid_rounds: # subsession.paid_round1 = subsession.in_round(subsession.round_number - 1).paid_round1 # subsession.paid_round2 = subsession.in_round(subsession.round_number - 1).paid_round2 # else: # subsession.paid_round1 = subsession.in_round(subsession.round_number - 1).paid_round1 # subsession.paid_round2 = subsession.in_round(subsession.round_number - 1).paid_round2 # subsession.paid_round3 = subsession.in_round(subsession.round_number - 1).paid_round3 # subsession.paid_round4 = subsession.in_round(subsession.round_number - 1).paid_round4 count = 1 for player in subsession.get_players(): player.token = count player.q = rng.randint(Constants.q_lb, Constants.q_ub) count += 1 if not subsession.big_group: for group in subsession.get_groups(): group.actual = rng.randint(0, 1) group.tiebreaker = rng.randint(0, 1) # Calculate the signal for each player for player in group.get_players(): player.draw = rng.uniform(1, 100) if player.id_in_group == 1: player.expert = True player.q = Constants.p if player.draw <= Constants.p: player.signal = group.actual else: player.signal = 1 - group.actual else: if player.draw <= player.q: player.signal = group.actual else: player.signal = 1 - group.actual else: subsession.actual = rng.randint(0, 1) subsession.tiebreaker = rng.randint(0, 1) expert_ids = rng.sample(range(1, Constants.num_participants + 1), 3) subsession.expert_1 = expert_ids[0] subsession.expert_2 = expert_ids[1] subsession.expert_3 = expert_ids[2] # This works b/c players are always presented in the same order (I think) # After some testing I'm pretty sure this is true # Assign every player an expert (the variable isn't used for experts) # Identify experts at the player level count = 1 for player in subsession.get_players(): player.which_expert = rng.randint(1, 3) if count in expert_ids: player.expert = True player.q = Constants.p count += 1 # Calculate the signal for each player for player in subsession.get_players(): player.draw = rng.uniform(1, 100) if player.expert: if player.draw <= Constants.p: player.signal = subsession.actual else: player.signal = 1 - subsession.actual else: if player.draw <= player.q: player.signal = subsession.actual else: player.signal = 1 - subsession.actual def get_winner_subsession(subsession): session = subsession.session if not subsession.big_group: for group in subsession.get_groups(): get_winner(group) else: count = 1 # Determines if signals are correct and sets experts for player in subsession.get_players(): if player.signal == subsession.actual: # print("x") player.signal_correct = True if player.expert: player.action = player.vote if count == subsession.expert_1: subsession.expert_1_vote = player.vote elif count == subsession.expert_2: subsession.expert_2_vote = player.vote elif count == subsession.expert_3: subsession.expert_3_vote = player.vote else: print("Error 1") if player.vote == 0: subsession.green_votes_experts += 1 elif player.vote == 1: subsession.purple_votes_experts += 1 else: print("Error 3") count += 1 for player in subsession.get_players(): if not player.expert: # Counting direct votes from nonexperts if player.action <= 1: player.vote = player.action if player.action == 0: subsession.green_votes_nonexperts += 1 if player.action == 1: subsession.purple_votes_nonexperts += 1 # Assigning votes from the corresponding expert if nonexpert delegated, counting delegations elif player.action == 2: subsession.delegations += 1 if player.which_expert == 1: player.vote = subsession.expert_1_vote subsession.delegations_1 += 1 elif player.which_expert == 2: player.vote = subsession.expert_2_vote subsession.delegations_2 += 1 elif player.which_expert == 3: player.vote = subsession.expert_3_vote subsession.delegations_3 += 1 else: print("Error 3") # Counting abstentions elif player.action == 3: subsession.abstentions += 1 else: print("Error 2") # Counting votes and calculating payoffs for player in subsession.get_players(): if player.vote == 0: subsession.green_votes += 1 elif player.vote == 1: subsession.purple_votes += 1 if subsession.green_votes > subsession.purple_votes: subsession.chosen_decision = 0 elif subsession.green_votes < subsession.purple_votes: subsession.chosen_decision = 1 else: subsession.chosen_decision = subsession.tiebreaker # Practice rounds should never be paid, thus the dumb boolean if subsession.chosen_decision == subsession.actual: subsession.chosen_correct = True if subsession.round_number == subsession.paid_round1: subsession.paid = True if subsession.round_number == subsession.paid_round2: subsession.paid = True if subsession.round_number == subsession.paid_round3: subsession.paid = True if subsession.round_number == subsession.paid_round4: subsession.paid = True if subsession.paid: for player in subsession.get_players(): # pick one player.payoff += Constants.reward # MV Counterfactual for player in subsession.get_players(): if player.signal == 0: subsession.green_signals += 1 elif player.signal == 1: subsession.purple_signals += 1 if subsession.green_signals > subsession.purple_signals: subsession.mv_decision = 0 elif subsession.green_signals < subsession.purple_signals: subsession.mv_decision = 1 if subsession.mv_decision == subsession.actual: subsession.mv_correct = True # Tabulating winnings for player in subsession.get_players(): player.winnings = player.participant.payoff_plus_participation_fee() class Subsession(BaseSubsession): mva = models.BooleanField() big_group = models.BooleanField() tiebreaker = models.IntegerField(initial=-1) actual = models.IntegerField(initial=-1) expert_1 = models.IntegerField(initial=-1) expert_1_vote = models.IntegerField(initial=-1) expert_2 = models.IntegerField(initial=-1) expert_2_vote = models.IntegerField(initial=-1) expert_3 = models.IntegerField(initial=-1) expert_3_vote = models.IntegerField(initial=-1) delegations = models.IntegerField(initial=0) delegations_1 = models.IntegerField(initial=0) delegations_2 = models.IntegerField(initial=0) delegations_3 = models.IntegerField(initial=0) abstentions = models.IntegerField(initial=0) green_votes = models.IntegerField(initial=0) purple_votes = models.IntegerField(initial=0) green_votes_nonexperts = models.IntegerField(initial=0) purple_votes_nonexperts = models.IntegerField(initial=0) green_votes_experts = models.IntegerField(initial=0) purple_votes_experts = models.IntegerField(initial=0) chosen_decision = models.IntegerField(initial=-1) chosen_correct = models.BooleanField(initial=False) green_signals = models.IntegerField(initial=0) purple_signals = models.IntegerField(initial=0) mv_decision = models.IntegerField(initial=-1) mv_correct = models.BooleanField(initial=False) shuffle = shuffle get_winner_subsession = get_winner_subsession paid_round1 = models.IntegerField(initial=-1) paid_round2 = models.IntegerField(initial=-1) paid_round3 = models.IntegerField(initial=-1) paid_round4 = models.IntegerField(initial=-1) paid = models.BooleanField(initial=False) treatment_round_number = models.IntegerField() def get_winner(group): # Sets the experts action equal to their vote, this is needed b/c the button they use sets vote, not action for player in group.get_players(): if player.expert: player.action = player.vote group.expert_vote = player.vote # determing if signal is correct, setting votes from actions, counting delegations and abstentions for player in group.get_players(): if player.signal == group.actual: player.signal_correct = True if player.action <= 1: player.vote = player.action elif player.action == 2: player.vote = group.expert_vote group.delegations += 1 elif player.action == 3: group.abstentions += 1 # Counting nonexpert votes for player in group.get_players(): if not player.expert: if player.action == 0: group.green_votes_nonexperts += 1 if player.action == 1: group.purple_votes_nonexperts += 1 # Calculate winner and thus payoffs for player in group.get_players(): if player.vote == 0: group.green_votes += 1 elif player.vote == 1: group.purple_votes += 1 if group.green_votes > group.purple_votes: group.chosen_decision = 0 elif group.green_votes < group.purple_votes: group.chosen_decision = 1 else: group.chosen_decision = group.tiebreaker if group.chosen_decision == group.actual: group.chosen_correct = True subsession = group.subsession if subsession.round_number == subsession.paid_round1: group.paid = True if subsession.round_number == subsession.paid_round2: group.paid = True if subsession.round_number == subsession.paid_round3: group.paid = True if subsession.round_number == subsession.paid_round4: group.paid = True if group.paid: for player in group.get_players(): # pick one player.payoff += Constants.reward # MV Counterfactual for player in group.get_players(): if player.signal == 0: group.green_signals += 1 elif player.signal == 1: group.purple_signals += 1 if group.green_signals > group.purple_signals: group.mv_decision = 0 elif group.green_signals < group.purple_signals: group.mv_decision = 1 if group.mv_decision == group.actual: group.mv_correct = True class Group(BaseGroup): tiebreaker = models.IntegerField(initial=-1) actual = models.IntegerField(initial=-1) expert_vote = models.IntegerField(initial=-1) delegations = models.IntegerField(initial=0) abstentions = models.IntegerField(initial=0) green_votes = models.IntegerField(initial=0) purple_votes = models.IntegerField(initial=0) green_votes_nonexperts = models.IntegerField(initial=0) purple_votes_nonexperts = models.IntegerField(initial=0) chosen_decision = models.IntegerField(initial=-1) chosen_correct = models.BooleanField(initial=False) green_signals = models.IntegerField(initial=0) purple_signals = models.IntegerField(initial=0) mv_decision = models.IntegerField(initial=-1) mv_correct = models.BooleanField(initial=False) paid = models.BooleanField(initial=False) get_winner = get_winner class Player(BasePlayer): token = models.IntegerField() expert = models.BooleanField(initial=False) which_expert = models.IntegerField() draw = models.FloatField(initial=0) signal_correct = models.BooleanField(initial=False) signal = models.IntegerField(initial=-1) action = models.IntegerField(choices=[[0, 'Vote Green'], [1, 'Vote Purple'], [2, 'Defer'], [3, 'Abstain']], initial=-1) vote = models.IntegerField(choices=[[0, 'Vote Green'], [1, 'Vote Purple']], initial=-1) winnings = models.CurrencyField() q = models.IntegerField(intial=-1)