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_flashing_hard_v3' players_per_group = None decisions = [ # pairs of tau2 and tau1# # [0:4] choose 2 and 1 from the chosen 2 ['In 1 month', 'Today'], ['In 3 months', 'Today'], ['In 3 years', 'Today'], ['In 4 years', 'Today'], # [4:9] choose 2 ['In 2 months', 'In 1 month'], ['In 6 months', 'In 1 month'], ['In 1 year', 'In 1 month'], ['In 2 years', 'In 1 month'], ['In 4 years', 'In 1 month'], # [9:12] sub-additivity 1 ['In 6 months', 'Today'], ['In 1 year', 'In 6 months'], ['In 1 year', 'Today'], # [12:15] sub-additivity 2 ['In 2 years', 'In 1 year'], ['In 3 years', 'In 2 years'], ['In 3 years', 'In 1 year'], # [15:18] sub-additivity 3 ['In 1 year', 'Today'], ['In 2 years', 'In 1 year'], ['In 2 years', 'Today'], ] amounts = [40, 50, 60] 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 30 days', 'Today', 25)] example_steps = 1 class Subsession(BaseSubsession): def creating_session(self): if self.round_number == 1: for p in self.get_players(): # set default; only if failed check, becomes True p.participant.vars['failed_comprehension'] = False # randomly assign ((tau2, tau1),pay_amount)'s # determine which 2 sub-additivity sets p.participant.vars['sub_'] = random.sample([1, 2, 3], 2) # determine which sub-additivity set to be assigned with load p.participant.vars['sub_load'] = random.choice(p.participant.vars['sub_']) datessub1 = Constants.decisions[9:12] dates_sub1 = list() amount_tmp = random.choice(Constants.amounts) for date in datessub1: if p.participant.vars['sub_load'] == 1: date = (date, amount_tmp, 1, 1) else: date = (date, amount_tmp, 1, -1) dates_sub1.append(date) datessub2 = Constants.decisions[12:15] dates_sub2 = list() amount_tmp = random.choice(Constants.amounts) for date in datessub2: if p.participant.vars['sub_load'] == 2: date = (date, amount_tmp, 2, 1) else: date = (date, amount_tmp, 2, -1) dates_sub2.append(date) datessub3 = Constants.decisions[15:18] dates_sub3 = list() amount_tmp = random.choice(Constants.amounts) for date in datessub3: if p.participant.vars['sub_load'] == 3: date = (date, amount_tmp, 3, 1) else: date = (date, amount_tmp, 3, -1) dates_sub3.append(date) if 1 not in p.participant.vars['sub_']: dates_sub = dates_sub2 + dates_sub3 p.participant.vars['set_identifier'] = '(2,3)' elif 2 not in p.participant.vars['sub_']: dates_sub = dates_sub1 + dates_sub3 p.participant.vars['set_identifier'] = '(1,3)' elif 3 not in p.participant.vars['sub_']: dates_sub = dates_sub1 + dates_sub2 p.participant.vars['set_identifier'] = '(1,2)' dates_sub_extra = random.choice(dates_sub) dates_sub.append(dates_sub_extra) # randomly choose 2 from 4 dates_1 = list() dates1 = random.sample(Constants.decisions[0:4], 2) # assign load dates1_load = random.choice(dates1) for date in dates1: if date == dates1_load: amount_tmp = random.choice(Constants.amounts) date = (date, amount_tmp, 0, 1) dates_1.append(date) else: amount_tmp = random.choice(Constants.amounts) date = (date, amount_tmp, 0, -1) dates_1.append(date) # randomly choose 1 from the chosen 2 dates_1_extra = random.choice(dates_1) dates_1.append(dates_1_extra) # randomly choose 2 from 4 dates_2 = list() dates2 = random.sample(Constants.decisions[4:9], 2) # 3 SA lists with load + 1 nonSA list with load, then assign load to 2 more lists if dates_sub_extra[3] == -1 and dates_1_extra[3] == -1: for date in dates2: amount_tmp = random.choice(Constants.amounts) date = (date, amount_tmp, 0, 1) dates_2.append(date) # 3 SA lists with load + 2 nonSA list with load, then assign load to 1 more list # 4 SA lists with load + 1 nonSA list with load, then assign load to 1 more list elif dates_sub_extra[3] * dates_1_extra[3] == -1: dates2_load = random.choice(dates2) for date in dates2: if date == dates2_load: amount_tmp = random.choice(Constants.amounts) date = (date, amount_tmp, 0, 1) dates_2.append(date) else: amount_tmp = random.choice(Constants.amounts) date = (date, amount_tmp, 0, -1) dates_2.append(date) # 4 SA lists with load + 2 nonSA list with load, then do not assign more load elif dates_sub_extra[3] == 1 and dates_1_extra[3] == 1: for date in dates2: amount_tmp = random.choice(Constants.amounts) date = (date, amount_tmp, 0, -1) dates_2.append(date) dates_1 = random.sample(dates_1, 3) dates_2 = random.sample(dates_2, 2) dates_sub = random.sample(dates_sub, 7) p.participant.vars['dates'] = random.sample(dates_1 + dates_2 + dates_sub, 12) for p in self.get_players(): p.set_current_task_number() p.set_identifier = p.participant.vars['set_identifier'] class Group(BaseGroup): pass class Player(BasePlayer): prolific_id = models.StringField() # whether see the flashing numbers load_guess = models.IntegerField(min=0, max=1000, blank=False, label="Enter the sum of red numbers that were flashed on the choice list screen") load_sum = models.IntegerField(initial=0) load_correct = models.IntegerField(initial=0) load_num_correct = models.IntegerField(initial=0) load_payoff = models.FloatField(initial=0) load_identifier = models.IntegerField() # which 2 of the 3 sub-additivity sets set_identifier = models.StringField() # current set sub_identifier = models.IntegerField() # 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_confidence_got_wrong = models.BooleanField(initial=False) qn_hypo_got_wrong = models.BooleanField(initial=False) # 4 comprehension questions 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.'], [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 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_lottery = models.IntegerField( choices=[ [0, '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_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]) setattr(self, 'sub_identifier', self.participant.vars['dates'][self.round_number - 1][2]) setattr(self, 'load_identifier', self.participant.vars['dates'][self.round_number - 1][3]) def current_choice(self): iet_choice = [(self.time_date_lhs, self.time_date_rhs, self.pay_amount)] return iet_choice # to generate the list of payments for option B in ListLoad.html def frange(self, start, stop, step): i = start 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 == 0: # 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 def set_load_payoff(self): if not self.failed_comprehension: self.load_payoff = self.participant.vars['load_num_correct'] * self.session.config['load_incentive'] else: self.load_payoff = 0 self.participant.vars['load_payoff'] = self.load_payoff