from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) import random doc = """ """ class Constants(BaseConstants): name_in_url = 'ravens' players_per_group = None ask = True # set True if Ask treatment, False if NoAsk method = 'Karni' # set 'NonInc', 'Inc' or 'Karni' reverse = False # set True for additional treatment with reversed order (belief and then donation) explicit = False # set True for additional NoAsk treatment where we make explicit that they will not be asked pilot = False # set True for pilot with 10 participants in NonInc who skip NonInc belief elicitation page minutes_given = 5 participation_fee = 2.5 piece_rate = 0.1 payment_in_points = 0 num_rounds = 5 # num_rounds = 1 # for testing answer_keys = [4, 2, 2, 1, 2, 7, 3, 5, 2, 5, 6, 4] instructions_template = 'ravens/Instructions.html' donation_value = 0.4 donation_implemented = 0.8 remaining_payoff = 2.1 altruism_rate = 0.03 # number of previous participants out of 10 choosing donate previous_participant = 3 # set this after calibration pilot optionb_probabilities = [100, 90, 80, 70, 60, 50, 40, 30, 20, 10, 0] optionb_probabilities_add = [100, 80, 60, 40, 30, 20, 10, 0] class Subsession(BaseSubsession): def creating_session(self): # this is run before the start of every round if self.round_number == 1: for p in self.get_players(): p.participant.vars['completion_code'] = random.randint(1000, 9999) p.participant.vars['num_correct'] = 0 p.participant.vars['scenario_pay'] = random.randint(1, 11) p.participant.vars['scenario_pay_add'] = random.randint(1, 8) p.participant.vars['consensus_random_number'] = random.randint(1, 10) class Group(BaseGroup): # Function for assigning the card colour def draw_card(self, green_cards): for p in self.get_players(): p.random_number = random.randint(1, 10) if p.random_number <= green_cards: p.card_colour = 'GREEN' else: p.card_colour = 'RED' def calculate_karni_payoff(self): revealed_choices = [] for p in self.get_players(): p.rand_number_optionB = random.randint(1, 100) # assign optionA_chosen = True for the randomly chosen scenario if getattr(p, 'game_outcome' + str(p.participant.vars['scenario_pay'])) == 1: p.optionA_chosen = True elif getattr(p, 'game_outcome' + str(p.participant.vars['scenario_pay'])) == 0: p.optionA_chosen = False # if subject chose Option B if not p.optionA_chosen and p.rand_number_optionB <= Constants.optionb_probabilities_add[ p.participant.vars['scenario_pay_add'] - 1]: p.karni_payoff = c(0) elif not p.optionA_chosen and p.rand_number_optionB > Constants.optionb_probabilities_add[ p.participant.vars['scenario_pay_add'] - 1]: p.karni_payoff = c(Constants.donation_value) # if subject chose Option A elif p.optionA_chosen and p.random_number <= Constants.previous_participant: p.karni_payoff = c(c(Constants.donation_value)) elif p.optionA_chosen and p.random_number > Constants.previous_participant: p.karni_payoff = c(0) def calculate_karni_payoff_add(self): revealed_choices = [] for p in self.get_players(): p.rand_number_optionB = random.randint(1, 100) # assign optionA_chosen = True for the randomly chosen scenario if getattr(p, 'game_outcome' + str(p.participant.vars['scenario_pay_add'])) == 1: p.optionA_chosen = True elif getattr(p, 'game_outcome' + str(p.participant.vars['scenario_pay_add'])) == 0: p.optionA_chosen = False # if subject chose Option B if not p.optionA_chosen and p.rand_number_optionB <= Constants.optionb_probabilities[ p.participant.vars['scenario_pay'] - 1]: p.karni_payoff = c(0) elif not p.optionA_chosen and p.rand_number_optionB > Constants.optionb_probabilities[ p.participant.vars['scenario_pay'] - 1]: p.karni_payoff = c(Constants.donation_value) # if subject chose Option A elif p.optionA_chosen and p.random_number <= Constants.previous_participant: p.karni_payoff = c(c(Constants.donation_value)) elif p.optionA_chosen and p.random_number > Constants.previous_participant: p.karni_payoff = c(0) # Function for creating multiple fields def make_field(label): return models.BooleanField( choices=[[0, 'B'], [1, 'A']], label=label, widget=widgets.RadioSelect, ) class Player(BasePlayer): accept = models.BooleanField(widget=widgets.RadioSelect) mturkID = models.StringField() attention = models.StringField(label='What is one plus two?') attention_pilot = models.StringField(label='Name a color starting with the letter \'b\'') answer = models.IntegerField(choices=[1, 2, 3, 4, 5, 6, 7, 8]) ans_correct = models.BooleanField() ravens_total = models.IntegerField() completion_code = models.IntegerField() # randomly generated number which participants enter as completion code consensus_random_number = models.IntegerField() # Comprehension questions q1 = models.StringField(label='', choices=['1 in 10', '5 in 10', '9 in 10'], widget=widgets.RadioSelect) q2 = models.StringField(label='', choices=['$0.00', '$0.40', '$0.80'], widget=widgets.RadioSelect) q3 = models.StringField(label='', choices=['$2.00', '$2.10', '$2.50'], widget=widgets.RadioSelect) q4 = models.StringField(label='', choices=['$0.00', '$0.40', '$0.80'], widget=widgets.RadioSelect) q5 = models.StringField(label='', choices=['$2.00', '$2.10', '$2.50'], widget=widgets.RadioSelect) q6 = models.StringField(label='', choices=['$2.00', '$2.10', '$2.50'], widget=widgets.RadioSelect) comprehension_incorrect = models.BooleanField() q7 = models.StringField(label='', choices=['2 GREEN cards, 8 RED cards', '3 GREEN cards, 7 RED cards', '4 GREEN cards, 6 RED cards'], widget=widgets.RadioSelect) q8 = models.StringField(label='', choices=['0 in 10 chance', '1 in 10 chance', '10 in 10 chance'], widget=widgets.RadioSelect) altruism_incorrect = models.BooleanField() charity_other = models.StringField(choices=['Against Malaria Foundation', 'COVID Response Fund for WHO', 'Doctors without Borders', 'Feeding America', 'Johns Hopkins Centre for Health Security', 'No Kid Hungry', 'The Salvation Army', 'World Wildlife Fund'], label='I believe the following charity was most commonly chosen') charity = models.StringField(choices=['Against Malaria Foundation', 'COVID Response Fund for WHO', 'Doctors without Borders', 'Feeding America', 'Johns Hopkins Centre for Health Security', 'No Kid Hungry', 'The Salvation Army', 'World Wildlife Fund'], label='I believe the following charity is most worthy of donations') donation = models.BooleanField(label='I choose to donate $0.40', widget=widgets.RadioSelect) random_number = models.IntegerField() rand_number_optionB = models.IntegerField() card_colour = models.StringField() initial_implemented = models.BooleanField() second_implemented = models.BooleanField() noninc_belief = models.IntegerField(min=0, max=10, label='') inc_belief = models.IntegerField(min=0, max=10, label='') scenario_pay = models.IntegerField() optionA_chosen = models.BooleanField(initial=False) karni_payoff = models.CurrencyField(initial=0) inc_payoff = models.CurrencyField(initial=0) altruism = models.BooleanField(label='Do you wish to draw another card?', widget=widgets.RadioSelect) altruism_amount = models.CurrencyField(label='How much do you wish to spend to increase the chances of your ' 'donation being implemented?', initial=0) def altruism_amount_choices(self): return currency_range(c(0.03), c(0.27), c(0.03)) # Revealed belief fields game_outcome1 = make_field('') game_outcome2 = make_field('') game_outcome3 = make_field('') game_outcome4 = make_field('') game_outcome5 = make_field('') game_outcome6 = make_field('') game_outcome7 = make_field('') game_outcome8 = make_field('') game_outcome9 = make_field('') game_outcome10 = make_field('') game_outcome11 = make_field('') # Demographic questions age = models.IntegerField(max=120, min=18, label='What is your age?') gender = models.IntegerField(choices=[[1, 'Woman'], [2, 'Man'], [3, 'Non-binary/Gender Diverse'], [4, 'My Gender identity is not listed'], [5, 'Prefer not to say']], label='What is your gender?') ethnicity = models.IntegerField(choices=[[1, 'White'], [2, 'Black/African American'], [3, 'Native American'], [4, 'Asian'], [5, 'Hispanic/Latino'], [6, 'Other']], label='What is your ethnicity?') education = models.IntegerField(choices=[[1, 'Elementary/primary school'], [2, 'Secondary/high school'], [3, 'College Undergraduate'], [4, 'College Postgraduate'], [5, 'Not applicable']], label='What is your highest level of education obtained?') political = models.IntegerField(choices=[[1, 'Left'], [2, 'Center-Left'], [3, 'Center-Right'], [4, 'Right'], [5, 'Other']], label='What is your political orientation?', widget=widgets.RadioSelectHorizontal) income = models.IntegerField(choices=[[1, 'Less than $20k'], [2, '$20k-$39k'], [3, '$40k-$59k'], [4, '$60k-$79k'], [5, '$80k-$100k'], [6, 'More than $100k']], label='What is your average household income per year?') subjectiveincome = models.IntegerField(choices=[[1, 'Not satisfied at all'], [2, 'Not satisfied'], [3, 'Neutral'], [4, 'Satisfied'], [5, 'Very satisfied']], label='How satisfied are you with the financial situation ' 'of your household?', widget=widgets.RadioSelectHorizontal) religiosity = models.IntegerField(choices=[[1, 'Strongly Disagree'], [2, 'Disagree'], [3, 'Neutral'], [4, 'Agree'], [5, 'Strongly Agree']], label='My religion is very important to me', widget=widgets.RadioSelectHorizontal) carpenter = models.IntegerField( label='Think about the last time you gave to a charity before today. What was more important to you:', choices=[[1, 'The total amount given by everyone'], [2, 'The amount that you personally gave'], [3, 'Some other aspect of giving']], widget=widgets.RadioSelect) # second carpenter's question total_donation = models.IntegerField(label='The total amount given by everyone', min=0, max=100) own_donation = models.IntegerField(label='The amount that I personally gave', min=0, max=100) other_aspect = models.IntegerField(label='Some other aspect of giving', min=0, max=100) worthiness = models.IntegerField(choices=[[1, 'Strongly Disagree'], [2, 'Disagree'], [3, 'Neutral'], [4, 'Agree'], [5, 'Strongly Agree']], label='', widget=widgets.RadioSelectHorizontal) prosocial = models.IntegerField(choices=[[1, '0'], [2, '1'], [3, '2'], [4, '3'], [5, '4'], [6, '5 or more']], label='In the past month, how many times have you volunteered your time ' 'or made donations of money or other items to a charitable cause?') instructions = models.LongStringField(label='') donation_open = models.LongStringField(label='') belief_open = models.LongStringField(label='') altruism_open = models.LongStringField(label='') optimism = models.IntegerField( label='On the following scale (where 1 = not optimistic at all and 10 = extremely optimistic),' ' how optimistic do you consider yourself to be?', choices=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) people_good = models.StringField(label='All in all, I think people are generally good.', choices=[['SD', 'Strongly disagree'], ['D', 'Disagree'], ['N', 'Neutral'], ['A', 'Agree'], ['SA', 'Strongly agree']], widget=widgets.RadioSelectHorizontal) consensus = models.IntegerField(label='', min=0, max=10) # additional questions for karni treatment karni_optionA = models.LongStringField(label='When you saw Option A on the screen, what did you think about?') karni_optionA_belief = models.BooleanField(widget=widgets.RadioSelect, label='When evaluating Option A, did you think about the chances that a previous participant chose to donate?') karni_switch = models.StringField(choices=[['belief', 'I switched depending on how likely I thought ' 'it was that a previous participant chose to donate'], ['fifty', 'I switched when the probability of earning $0.40 was ' 'around 50% in Option B'], ['midpoint', 'I switched somewhere around the middle ' '(i.e. around Scenario 5 or 6 out of 11 Scenarios)'], ['random', 'I decided randomly'], ['other', 'Other']], widget=widgets.RadioSelect, label='How did you decide when to switch from Option A to Option B?') karni_switch_other = models.LongStringField(label='If you specified “Other” above, please explain your decision.', blank=True)