from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, Page, WaitPage, ) import random import itertools doc = """ This app aims to test people's decision-making on collision coverage for their cars if there is a chance that an accident would happen due to subject's fault. """ class Constants(BaseConstants): name_in_url = 'insurance_game' players_per_group = None num_rounds = 20 timeout_seconds = 120 # two probabilities of accident occurrence probability1 = 0.1 probability2 = 0.2 # probability for different losses conditioning on accident occurrence probability3 = 1 / 3 instructions_template = 'insurance/Instructions.html' # initial vehicle value to each subject endowment = 25000 # if accident happens, three different losses slight_loss = 500 half_loss = 12500 total_loss = 18750 # three different collision coverage plans premium1 = 1210 premium2 = 1170 premium3 = 1130 deductible1 = 500 deductible2 = 1000 deductible3 = 1500 class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): probability = models.FloatField() loss_level = models.IntegerField(initial=-10) accident_happen = models.StringField(initial='hello') scenarios = models.StringField() premium = models.IntegerField(initial=-1) deductible = models.IntegerField(initial=-1) payoffs = models.FloatField() earnings = models.FloatField() prob = models.IntegerField() uncertainty = models.IntegerField() heuristic = models.IntegerField() decision = models.IntegerField(choices= [[1, 'No collision coverage. Premium: ECU0'], [2, 'Collision coverage plan: ECU500 deductible, ECU25,000 per accident. Premium: ECU1,210'], [3, 'Collision coverage plan: ECU1,000 deductible, ECU25,000 per accident. Premium: ECU1,170'], [4, 'Collision coverage plan: ECU1,500 deductible, ECU25,000 per accident. Premium: ECU1,130']], widget=widgets.RadioSelect, label="Please make a decision on your collision coverage:") final_payoff = models.FloatField() # doc="""This player's decision""", # for test part q1 = models.IntegerField(choices= [[1, "ECU25,000, $250"], [2, "ECU25,000, $25"], [3, "ECU23,790, $23.79"]], widget=widgets.RadioSelect, label="Q1. You purchased collision coverage with ECU500 deductible. Premium is ECU1,210. No accident happens. " "What's your final proper value and payoff in this round?") q2 = models.IntegerField(choices= [[1, "ECU22,830, $22.83"], [2, "ECU24,000, $24"], [3, "ECU25,000, $25"]], widget=widgets.RadioSelect, label="Q2. You purchased collision coverage with ECU1,000 deductible. " "Premium is ECU1,170. Accident happens and causes half loss. What's your final proper value and payoff in this round?") q3 = models.IntegerField(choices= [[1, "ECU25,000, $25"], [2, "ECU16,120, $16.12"], [3, "ECU22,370, $23.70"]], widget=widgets.RadioSelect, label="Q3. You purchased collision coverage with ECU1,500 deductible. " "Premium is ECU1,130. Accident happens and causes total loss. What's your final proper value and payoff in this round?") q4 = models.IntegerField(choices= [[1, "ECU25,000, $25"], [2, "ECU0, $0"], [3, "ECU6,250, $6.25"]], widget=widgets.RadioSelect, label="Q4. You have no collision coverage. Accident happens and causes total loss. What's your final proper value and payoff in this round?") payoffs_q1 = models.FloatField() payoffs_q2 = models.FloatField() payoffs_q3 = models.FloatField() payoffs_q4 = models.FloatField() payoffs_test = models.FloatField() # for survey part age = models.IntegerField(choices= [[1, "Under 18"], [2, "18-20"], [3, "21-24"], [4, "25-30"], [5, "31-35"], [6, "36-45"], [7, "46-55"], [8, "56-65"], [9, "above 65"], [10, "Prefer not to answer"]], widget=widgets.RadioSelect, label="1. Please select your age group:") gender = models.IntegerField(choices=[[1, "Male"], [2, "Female"], [3, "Other/Non-binary"], [4, "Prefer not to answer"]], widget=widgets.RadioSelect, label="2. Please select your gender:") race = models.IntegerField(choices= [[1, "White only, non-Hispanic"], [2, "Black only, non-Hispanic"], [3, "Asian only, non-Hispanic"], [4, "Native Hawaiian or other Pacific Islander only, non-Hispanic"], [5, "American Indian or Alaskan Native only"], [6, "Other race only, non-Hispanic"], [7, "Multiracial, non-Hispanic"], [8, "Hispanic"], [9, "Prefer not to say"]], widgets=widgets.RadioSelect, label="3. Please select your race group:") educ = models.IntegerField(choices= [[1, "Some high school"], [2, "High school graduate"], [3, "Some college"], [4, "College graduate"], [5, "Post-graduate degree"], [6, "Prefer not to answer"]], widget=widgets.RadioSelect, label="4. What is the highest level of education you have obtained?") prob_happen = models.FloatField(max=1, min=0, label="5. What do you think of the probability of a car accident in reality (from 0-1, use two decimal) ?") vehicle = models.IntegerField(choices=[[1, "Passenger car"], [2, "Motorcycle"], [3, "SUV"], [4, "truck"], [5, "Other"], [6, "I don't drive"]], widget=widgets.RadioSelect, label="6. Please select the type of vehicle you drive:") years = models.IntegerField(choices=[[1, "Less then 1 year"], [2, "1-3 years"], [3, "3-5 years"], [4, "6-10 years"], [5, "More than 10 years"]], widget=widgets.RadioSelect, label="7. Please select your driving experience:") days = models.IntegerField(choices=[[1, "1 day"], [2, "2 days"], [3, "3 days"], [4, "4 days"], [5, "5 days"], [6, "6 days"], [7, "7 days"]], widget=widgets.RadioSelect, label="8. How many days do you usually drive per week?") skill = models.IntegerField(choices=[[1, "Below average"], [2, "Average"], [3, "Above average"]], widget=widgets.RadioSelect, label="9. How well do you think of your driving skills?") accident = models.IntegerField(choices=[[1, "Yes"], [2, "No"], [3, "Prefer not to answer"]], widget=widgets.RadioSelect, label="10. Have you ever been in a car accident?") coverage = models.IntegerField(choices=[[1, "Yes"], [2, "No"]], widget=widgets.RadioSelect, label="11. Do you have collision coverage in your current vehicle insurance plan?") consent = models.IntegerField(choices=[[1, "Yes"], [2, "No"]], widget=widgets.RadioSelect, label="Do you want to complete a short survey to earn another $5?") survey_payoff = models.IntegerField() total_payoff = models.FloatField() selected_round_number = models.IntegerField() selected_payoffs = models.IntegerField() # Functions # def creating_session(subsession): # randomize to treatments # for player in subsession.get_players(): # player.scenarios = random.choice(['A1','A2','B1','B2','C1','C2']) # print('set player.scenarios', player.scenarios) # def creating_session(subsession): # balanced treatment groups # import itertools # scenarios = itertools.cycle(['A1', 'A2', 'B1', 'B2', 'C1', 'C2']) ## for player in subsession.get_players(): # player.scenarios = next(scenarios) def creating_session(subsession): print('in creating session') import random # prob_values = itertools.cycle([1, 1, 1, 1, 2, 2, 2, 2]) # uncertainty_values = itertools.cycle([1, 1, 2, 2, 1, 1, 2, 2]) # heuristic_values = itertools.cycle([1, 2, 1, 2, 1, 2, 1, 2]) prob_values = itertools.cycle([1, 1, 1, 2, 2, 2]) uncertainty_values = itertools.cycle([1, 2, 2, 1, 2, 2]) heuristic_values = itertools.cycle([1, 1, 2, 1, 1, 2]) for p in subsession.get_players(): if p.round_number == 1: p.participant.vars['paying_round'] = random.randint(1, Constants.num_rounds) p.prob = next(prob_values) p.uncertainty = next(uncertainty_values) p.heuristic = next(heuristic_values) if p.prob == 1: if subsession.round_number <= 10: p.probability = Constants.probability1 else: p.probability = Constants.probability2 else: if subsession.round_number <= 10: p.probability = Constants.probability2 else: p.probability = Constants.probability1 def before_session_starts(player): if player.round_number == 1: paying_round: int = random.randint(1, Constants.num_rounds) player.session.vars['paying_round'] = paying_round def payoffs_test(player): # payoff for each question if player.q1 == 3: player.payoffs_q1 = 1 else: player.payoffs_q1 = 0 if player.q2 == 1: player.payoffs_q2 = 1 else: player.payoffs_q2 = 0 if player.q3 == 2: player.payoffs_q3 = 1 else: player.payoffs_q3 = 0 if player.q4 == 3: player.payoffs_q4 = 1 else: player.payoffs_q4 = 0 player.participant.vars['test_earnings'] = player.payoffs_q1 + player.payoffs_q2 + player.payoffs_q3 + player.payoffs_q4 #def test_payoff(player): #player.payoffs_test = player.payoffs_q1 + player.payoffs_q2 + player.payoffs_q3 + player.payoffs_q4 def results(player): print('probability') random_draw = random.random() if random_draw <= player.probability: player.accident_happen = 'Yes' player.loss_level = random.choice([Constants.slight_loss, Constants.half_loss, Constants.total_loss]) else: player.accident_happen = 'No' player.loss_level = 0 print(random_draw) print(player.loss_level) def choice(player): print('premium, deductible') if player.decision == 2: player.premium = Constants.premium1 player.deductible = Constants.deductible1 elif player.decision == 3: player.premium = Constants.premium2 player.deductible = Constants.deductible2 elif player.decision == 4: player.premium = Constants.premium3 player.deductible = Constants.deductible3 else: player.premium = 0 player.deductible = Constants.endowment def set_payoffs(player): # when accident happens if player.accident_happen == "Yes": if player.decision == 2 or player.decision == 3 or player.decision == 4: # player chooses to have collision coverage and slight loss happens if player.loss_level == 500: player.payoffs = Constants.endowment - player.premium - player.loss_level player.earnings = player.payoffs / 1000 # player chooses to have collision coverage and half loss happens elif player.loss_level == 12500: player.payoffs = Constants.endowment - player.premium - player.deductible player.earnings = player.payoffs / 1000 # player chooses to have collision coverage and total loss happens else: player.payoffs = Constants.endowment * 0.75 - player.premium - player.deductible player.earnings = player.payoffs / 1000 # player doesn't buy collision coverage and accident happens else: player.payoffs = Constants.endowment - player.loss_level player.earnings = player.payoffs / 1000 # when accident doesn't happen else: player.payoffs = Constants.endowment - player.premium player.earnings = player.payoffs / 1000 def other_payoffs(player): # payoff for survey if player.consent == 1: player.participant.vars['survey_payoff'] = 5 else: player.participant.vars['survey_payoff'] = 0 def final_payoffs(player): old_player = player.in_round(player.participant.vars['paying_round']) player.selected_round_number = player.participant.vars['paying_round'] player.participant.vars['selected_payoffs'] = old_player.earnings player.participant.vars['total_earnings'] = player.participant.vars['test_earnings'] + player.participant.vars['selected_payoffs'] + player.participant.vars['survey_payoff'] # PAGES class Welcome(Page): def is_displayed(player): return player.subsession.round_number == 1 class Introduction(Page): def is_displayed(player): return player.subsession.round_number == 1 class Test1(Page): def is_displayed(player): return player.subsession.round_number == 1 form_model = 'player' form_fields = ['q1'] class Test_result1(Page): def is_displayed(player): return player.subsession.round_number == 1 def vars_for_template(p: Player): txt1 = "" if p.q1 == 3: txt1 = "Great! This is the correct answer. You earn $1." else: txt1 = "You gave the wrong answer. This is how to calculate: Property value = ECU25,000 (car value) - ECU1,210 (premium) = ECU23,790, your earnings = 23,790/1000 = $23.79" return dict( response1=txt1, ) class Test2(Page): def is_displayed(player): return player.subsession.round_number == 1 form_model = 'player' form_fields = ['q2'] class Test_result2(Page): def is_displayed(player): return player.subsession.round_number == 1 def vars_for_template(p: Player): txt2 = "" if p.q2 == 1: txt2 = "Great! This is the correct answer. You earn $1." else: txt2 = "You gave the wrong answer. This is how to calculate: Property value = ECU25,000 (car value) - ECU1,170 (premium) - ECU1,000 (deductible) = ECU22,830, your earnings = 22,830/1000 = $22.83" return dict( response2=txt2, ) class Test3(Page): def is_displayed(player): return player.subsession.round_number == 1 form_model = 'player' form_fields = ['q3'] class Test_result3(Page): def is_displayed(player): return player.subsession.round_number == 1 def vars_for_template(p: Player): txt3 = "" if p.q3 == 2: txt3 = "Great! This is the correct answer. You earn $1." else: txt3 = "You gave the wrong answer. This is how to calculate = ECU18,750 (car value) - ECU1,130 (premium) - ECU1,500 (deductible) = ECU16,120, your earnings = 16,120/1000 = $16.12" return dict( response3=txt3, ) class Test4(Page): def is_displayed(player): return player.subsession.round_number == 1 form_model = 'player' form_fields = ['q4'] @staticmethod def before_next_page(player, timeout_happened): payoffs_test(player) class Test_result4(Page): def is_displayed(player): return player.subsession.round_number == 1 def vars_for_template(p: Player): txt4 = "" if p.q4 == 3: txt4 = "Great! This is the correct answer. You earn $1." else: txt4 = "You gave the wrong answer. This is how to calculate: Property value = ECU25,000 (car value) - ECU18,750 (loss) = ECU6,250, your earnings = 6,250/1000 = $6.25" return dict( response4=txt4, ) class Treatment(Page): def is_displayed(player): return player.subsession.round_number == 1 class Decision(Page): form_model = 'player' form_fields = ['decision'] # @staticmethod # def get_timeout_seconds(player): # return Constants.timeout_seconds @staticmethod def before_next_page(player, timeout_happened): results(player) choice(player) set_payoffs(player) # if timeout_happened: # player.decision = ['No collision coverage. Premium: ECU0'] class Results(Page): pass class Change(Page): def is_displayed(player): return player.subsession.round_number == 11 class Final(Page): form_model = 'player' form_fields = ['consent'] def vars_for_template(p: Player): old_player = p.in_round(p.participant.vars['paying_round']) return dict( selected_round_number = p.participant.vars['paying_round'], selected_payoff = old_player.earnings ) def is_displayed(player): return player.subsession.round_number == 20 def before_next_page(player, timeout_happened): before_session_starts(player) other_payoffs(player) final_payoffs(player) class Survey1(Page): def is_displayed(player): return player.subsession.round_number == 20 and player.consent == 1 form_model = 'player' form_fields = ['age', 'gender', 'race', 'educ', 'prob_happen', 'vehicle'] def before_next_page(player, timeout_happened): final_payoffs(player) class Survey2(Page): def is_displayed(player): return player.subsession.round_number == 20 and player.consent == 1 and player.vehicle != 6 form_model = 'player' form_fields = ['years', 'days', 'skill', 'accident', 'coverage'] def before_next_page(player, timeout_happened): final_payoffs(player) class Thanks(Page): def is_displayed(player): return player.subsession.round_number == 20 page_sequence = [Welcome, Introduction, Test1, Test_result1, Test2, Test_result2, Test3, Test_result3, Test4, Test_result4, Treatment, Change, Decision, Results, Final, Survey1, Survey2, Thanks] #page_sequence = [Treatment, Change, Decision, Results, Final, Survey1, Survey2, Thanks]