from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, ) import random import itertools import numpy as np from django import forms from django.forms import widgets as django_widgets import math author = 'Zheng Li' doc = """ Intertemporal Choice """ class Constants(BaseConstants): name_in_url = 'inter_default_v5' players_per_group = None num_subjects = 1000000 cap = 0.95 decisions_low = [ #[0:4] ['In 12 months', 'Today'], ['In 10 months', 'Today'], ['In 8 months', 'Today'], ['In 6 months', 'Today'], #[4:12] ['In 5 months', 'Today'], ['In 4 months', 'Today'], ['In 3 months', 'Today'], ['In 2 months', 'Today'], ['In 1 month', 'Today'], ['In 2 weeks', 'Today'], ['In 1 week', 'Today'], ['In 3 days', 'Today'], ] decisions_high = [ # [0:8] ['In 4 years', 'Today'], ['In 3.5 years', 'Today'], ['In 3 years', 'Today'], ['In 2.5 years', 'Today'], ['In 2 years', 'Today'], ['In 21 months', 'Today'], ['In 18 months', 'Today'], ['In 15 months', 'Today'], #[8:12] ['In 12 months', 'Today'], ['In 10 months', 'Today'], ['In 8 months', 'Today'], ['In 6 months', 'Today'], ] low_early = list() high_early = list() for pair in decisions_low[6:12]: low_early.append(pair[0]) for pair in decisions_high[6:12]: high_early.append(pair[0]) amounts = range(30,52,2) steps = 2 num_rounds = 12 # to generate the certainty-uncertainty spectrum bar list1 = np.arange(1 * 20, - 1, -1) list2 = [] list2.append(0) for x in range(20): list2.append((x+1)*5) example_set = [('In 6 months', 'Today', 40)] example_set_low = [('In 3 months', 'Today', 40)] example_set_high = [('In 18 months', 'Today', 40)] example_steps = 2 class Subsession(BaseSubsession): def creating_session(self): # counters: age self.session.vars['age_1'] = 0 self.session.vars['age_2'] = 0 self.session.vars['age_3'] = 0 self.session.vars['age_4'] = 0 self.session.vars['age_5'] = 0 self.session.vars['age_6'] = 0 # counters: gender self.session.vars['gender_1'] = 0 self.session.vars['gender_2'] = 0 # counters: education self.session.vars['education_1'] = 0 self.session.vars['education_2'] = 0 self.session.vars['education_3'] = 0 self.session.vars['education_4'] = 0 # counters: income self.session.vars['income_1'] = 0 self.session.vars['income_2'] = 0 self.session.vars['income_3'] = 0 self.session.vars['income_4'] = 0 self.session.vars['income_5'] = 0 self.session.vars['income_6'] = 0 self.session.vars['income_7'] = 0 self.session.vars['income_8'] = 0 self.session.vars['income_9'] = 0 # counters: race self.session.vars['race_1'] = 0 self.session.vars['race_2'] = 0 self.session.vars['race_3'] = 0 self.session.vars['race_4'] = 0 self.session.vars['race_5'] = 0 if self.round_number == 1: for p in self.get_players(): # p.participant.vars['tests_passed'] = True # p.participant.vars['failed_attention'] = False p.participant.vars['failed_demographics'] = False p.participant.vars['failed_comprehension'] = False # p.participant.vars['counter_age'] = p.counter_age p.participant.vars['counter_gender'] = p.counter_gender p.participant.vars['counter_education'] = p.counter_education p.participant.vars['counter_income'] = p.counter_income p.participant.vars['counter_race'] = p.counter_race # set treatment group: low default or high default p.participant.vars['default_identifier'] = random.choice([0, 1]) if p.participant.vars['default_identifier'] == 0: decisions = Constants.decisions_low[0:4]+ Constants.decisions_low[4:12] elif p.participant.vars['default_identifier'] == 1: decisions = Constants.decisions_high[8:12] + Constants.decisions_high[0:8] p.participant.vars['date_list'] = list() for date in decisions: p.participant.vars['date_list'].append(date[0]) dates_target = list() for date in decisions[0:4]: amount_tmp = random.choice(Constants.amounts) date = (date, amount_tmp) dates_target.append(date) dates_target = random.sample(dates_target, 4) dates_default = list() for date in decisions[4:12]: amount_tmp = random.choice(Constants.amounts) date = (date, amount_tmp) dates_default.append(date) dates_default = random.sample(dates_default, 8) p.participant.vars['dates'] = dates_target + dates_default for p in self.get_players(): p.default_identifier = p.participant.vars['default_identifier'] p.set_current_task_number() class Group(BaseGroup): pass class Player(BasePlayer): prolific_id = models.StringField(label="Please enter your Prolific ID") tests_passed = models.BooleanField(initial=True) completed = models.IntegerField(initial=0) # attention check attention_check2 = models.StringField(label="") attention_check2_num = models.IntegerField(initial=0) failed_attention = models.BooleanField(initial=False) # sociodemographics age = models.IntegerField( max=100, min=18, label="Your age:", blank=False, ) gender = models.IntegerField(label="Your sex:") def gender_choices(self): choices = [ [1, 'Male'], [2, 'Female'] ] random.shuffle(choices) return choices education = models.IntegerField( choices=[ [1, 'No high school graduation'], [2, 'Currently in High school or high school graduate'], [3, 'Some college, but no degree'], [4, "Bachelor's degree"], [5, "Graduate or professional degree"], ], label="Your highest educational attainment:", blank=False ) income = models.IntegerField( choices=[ [1, 'Below $15,000'], [2, '$15,000 - $24,999'], [3, '$25,000 - $34,999'], [4, '$35,000 - $49,999'], [5, '$50,000 - $74,999'], [6, '$75,000 - $99,999'], [7, '$100,000 - $149,999'], [8, '$150,000 - $199,999'], [9, '$200,000 or more'], ], label="Your approximate annual household income:", blank=False ) race = models.IntegerField(label="Your race:") def race_choices(self): choices = [ [1, 'White'], [2, 'Black'], [3, 'Hispanic'], [4, 'Asian'], [5, 'Other'] ] random.shuffle(choices) return choices counter_age = models.IntegerField(initial=0) counter_gender = models.IntegerField(initial=0) counter_education = models.IntegerField(initial=0) counter_income = models.IntegerField(initial=0) counter_race = models.IntegerField(initial=0) failed_demographics = models.BooleanField(initial=False) # indicator for low/high default group default_identifier = models.IntegerField( choices=[ [0, 'low default'], [1, 'high default'], ], widget=widgets.RadioSelect, blank=False, label="" ) # parameters in the optimization problem pay_amount = models.IntegerField() # benchmark payment at tau2 time_date_lhs = models.StringField() #tau2 time_date_rhs = models.StringField() #tau1 # indicator_never_always_switcher = models.IntegerField() # indifferent payment task: switching_point = models.FloatField() confidence = models.FloatField() # higher -> more confident; from 0 to 20 respectively corresponding to from 0% to 100%; step = $5% # overall indicator of whether passed the comprehension check failed_comprehension = models.BooleanField(initial=False) # indicators of whether correctly answered each question qn_lottery_got_wrong = models.BooleanField(initial=False) qn_hypo_got_wrong = models.BooleanField(initial=False) qn_datelist_got_wrong = models.BooleanField(initial=False) qn_confidence_got_wrong = models.BooleanField(initial=False) # 4 comprehension questions qn_lottery = models.IntegerField( choices=[ [35, 'It would be possible that I get paid both $15 and $20, i.e., I may receive a total amount of $35 from this decision.'], [1, 'I would receive EITHER $15 today OR $20 in 10 days.'], [0, 'It would be possible that I receive no money from this decision.'], ], widget=widgets.RadioSelect, blank=False, label="" ) qn_hypo = models.IntegerField( choices=[ [1, 'In making my decisions, I am asked to assume that I will actually receive all payments indicated, regardless of whether they take place now or in the future.'], [2, 'In making my decisions, I am asked to assume that it is less likely that I will actually receive payments that are meant to take place in the future.'], [0, 'In making my decisions, I am asked to assume that it is less likely that I will actually receive payments that are meant to take place now.'], ], widget=widgets.RadioSelect, blank=False, label="" ) qn_datelist = models.IntegerField( choices=[ [2, 'In 3 months. This is marked as the relevant payment date.'], [1, 'In 18 months. This is marked as the relevant payment date.'], [50, 'Which date is marked as “Relevant date” for Option A doesn’t matter. The relevant delayed payment date differs across rows in the choice list.'] ], widget=widgets.RadioSelect, blank=False, label="" ) qn_confidence = models.FloatField( blank=False, label="" ) # to determine parameters in the current task def set_current_task_number(self): setattr(self, 'time_date_lhs', self.participant.vars['dates'][self.round_number - 1][0][0]) setattr(self, 'time_date_rhs', self.participant.vars['dates'][self.round_number - 1][0][1]) setattr(self, 'pay_amount', self.participant.vars['dates'][self.round_number - 1][1]) def current_choice(self): iet_choice = [(self.time_date_lhs, self.time_date_rhs, self.pay_amount)] return iet_choice def example_choice(self): if self.default_identifier == 0: iet_choice = Constants.example_set_low elif self.default_identifier == 1: iet_choice = Constants.example_set_high return iet_choice # to generate the list of payments for option B in ListLoad.html def frange(self, start, stop, step): i = start + step while i < stop: if isinstance(i, int): yield i else: yield round(i, 2) i += step # to display the list of payments for option B in List.html def right_side_amounts1(self): if self.pay_amount > 0: lst = self.frange(0, self.pay_amount + 1, Constants.steps) return list(enumerate(lst, 1)) # creating a list of tuples from looping "lst" with the starting index = 1 def right_side_amounts2(self): lst = self.frange(0, Constants.example_set[0][2] + 1, Constants.example_steps) return list(enumerate(lst, 1)) # to display the confidence interval in Valuation.html def range_bounds(self): if self.pay_amount > 0: bounds = [0, self.pay_amount] return bounds # def table_length1(self): return abs(self.pay_amount)/Constants.steps + 1 # def set_switching_point_and_indicator(self): if self.pay_amount > 0: if self.switching_point == 9999: # the template sets it to be 9999 when the player always chooses option A self.switching_point = self.pay_amount + Constants.steps self.indicator_never_always_switcher = 2 elif self.switching_point == Constants.steps: # the template sets it to be 0 when the player always chooses option B self.indicator_never_always_switcher = 0 else: self.indicator_never_always_switcher = 1 # when a middle point is chosen (what is desired) elif self.pay_amount < 0: ###how if self.switching_point == 9999: self.switching_point = 1 self.indicator_never_always_switcher = 2 elif self.switching_point == self.pay_amount: self.indicator_never_always_switcher = 0 else: self.indicator_never_always_switcher = 1