from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) import random import itertools author = 'Thomas Graeber' doc = """ Subjective uncertainty in risk """ class Constants(BaseConstants): name_in_url = 'within_subjec_risk' players_per_group = None decisions = { 'probabilities': [[5], [10], [25], [50], [75], [90], [95]], 'amounts': [15, 20, 25], } rocl_probability = 1/3 combinations = len(decisions['probabilities']) * len(decisions['amounts']) num_rounds = 6 num_rounds_gains = 3 class Subsession(BaseSubsession): def before_session_starts(self): if self.round_number == 1: for p in self.get_players(): p.participant.vars['failed_comprehension'] = False p.participant.vars['lists_paying_round'] = random.randint(1, Constants.num_rounds) p.participant.vars['losses_first'] = random.choice([True, False]) p.participant.vars['list_sequence'] = random.sample(range(0, Constants.combinations), Constants.num_rounds_gains) p.participant.vars['list_sequence'].extend(random.sample(range(0, Constants.combinations), Constants.num_rounds_gains)) for p in self.get_players(): p.losses_first = p.participant.vars['losses_first'] p.set_current_task_number() if p.round_number == p.participant.vars['lists_paying_round']: p.on_paying_round = True class Group(BaseGroup): pass class Player(BasePlayer): task_number = models.IntegerField() task_identifier = models.StringField() switching_point_1 = models.FloatField() # switching_point_2 = models.FloatField() on_paying_round = models.BooleanField(initial=False) lottery_amount = models.IntegerField() lottery_probability = models.IntegerField() is_rocl = models.BooleanField() type = models.StringField() endowment = models.FloatField() rocl_probability = models.IntegerField() # Field which is 0 if always Option B, 1 if switching point, 2 if never option B indicator_never_always_switcher = models.IntegerField() switching_point = models.FloatField() lottery_identifier = models.StringField() confidence = models.FloatField() confidence_upper_bound = models.FloatField() confidence_lower_bound = models.FloatField() losses_first = models.BooleanField() random_payoff = models.CurrencyField() random_right_side_amount = models.CurrencyField() failed_comprehension = models.BooleanField(initial=False) qn_lottery_got_wrong = models.BooleanField(initial=False) qn_list_got_wrong = models.BooleanField(initial=False) qn_confidence_got_wrong = models.BooleanField(initial=False) qn_lottery = models.IntegerField( choices=[ [0, 'It is possible that I get paid both $15 and $5, i.e., I may receive a total amount of $20 from this lottery.'], [1, 'I receive EITHER $15 OR $5 from this lottery.'], [0, 'It is possible that I receive no money from this lottery.'], ], widget=widgets.RadioSelect, blank=False, label="" ) qn_list = models.IntegerField( choices=[ [0, 'This person indicated that the lottery is worth more to them than $9.'], [0, 'This person indicated that the lottery is worth between $3 and $7 to them. '], [1, 'This person indicated that the lottery is worth between $8 and $9 to them.'], ], widget=widgets.RadioSelect, blank=False, label="" ) qn_confidence = models.FloatField( blank=False, label="" ) def set_current_task_number(self): setattr(self, 'task_number', self.participant.vars['list_sequence'][self.round_number-1]) task_list = [] l = itertools.product( Constants.decisions['probabilities'], Constants.decisions['amounts'], ) task_list.extend(l) tup = task_list[self.task_number] setattr(self, 'lottery_probability', random.choice(tup[0])) if self.losses_first and self.round_number <= Constants.num_rounds_gains or not self.losses_first and self.round_number > Constants.num_rounds_gains: setattr(self, 'lottery_amount', -tup[1]) else: setattr(self, 'lottery_amount', tup[1]) if self.lottery_probability in [0, 100] or random.random() >= Constants.rocl_probability: setattr(self, 'is_rocl', False) else: setattr(self, 'is_rocl', True) if self.is_rocl: setattr(self, 'type', 'rocl') else: setattr(self, 'type', 'list') setattr(self, 'task_identifier', 'lottery_prob{}_am{}_rocl{}'.format( self.lottery_probability, self.lottery_amount, self.is_rocl, )) # setattr(self, 'lottery_amount', random.choice(Constants.decisions[self.task_number]['y_list'])) # setattr(self, 'task_identifier', Constants.decisions[self.task_number]['name']) if self.lottery_amount > 0: setattr(self, 'endowment', 0) else: setattr(self, 'endowment', abs(self.lottery_amount)) def frange(self, start, stop, step): i = start while i < stop: if isinstance(i, int): yield i else: yield round(i, 2) i += step def right_side_amounts1(self): if self.lottery_amount > 0: lst = self.frange(0, self.lottery_amount + 1, 1) else: lst = self.frange(self.lottery_amount, 1, 1) return list(enumerate(lst, 1)) def current_lottery(self): # lott = Constants.decisions[self.task_number]['lottery'] # lott_new = [] # for x, y in lott: # if y == 'y': # lott_new.append((x, self.lottery_amount)) # else: # lott_new.append((x, y)) if self.is_rocl: lott = [('X', self.lottery_amount), ('100% - X', 0)] else: lott = [(self.lottery_probability, self.lottery_amount), (100 - self.lottery_probability, 0)] return lott def rocl_range(self): if self.lottery_probability in [95, 5]: rr = [self.lottery_probability - 5, self.lottery_probability + 5] else: rr = [self.lottery_probability - 10, self.lottery_probability + 10] return rr def range_bounds(self): if self.lottery_amount > 0: bounds = [0, self.lottery_amount] elif self.lottery_amount < 0: bounds = [self.lottery_amount, 0] return bounds def table_length1(self): return abs(self.lottery_amount) + 1 def set_switching_point_and_indicator(self): if self.lottery_amount > 0: if self.switching_point == 9999: self.switching_point = self.lottery_amount + 1 self.indicator_never_always_switcher = 2 elif self.switching_point == 0: self.indicator_never_always_switcher = 0 else: self.indicator_never_always_switcher = 1 elif self.lottery_amount < 0: if self.switching_point == 9999: self.switching_point = 1 self.indicator_never_always_switcher = 2 elif self.switching_point == self.lottery_amount: self.indicator_never_always_switcher = 0 else: self.indicator_never_always_switcher = 1 def set_payoffs(self): random_right_side_amount = random.choice(self.right_side_amounts1())[1] possible_payoff = 0 if random_right_side_amount >= self.switching_point: possible_payoff = c(random_right_side_amount + self.endowment) else: if not self.is_rocl: prob = self.lottery_probability else: setattr(self, 'rocl_probability', random.randint(self.rocl_range()[0], self.rocl_range()[1])) prob = self.rocl_probability outcome = random.random() < prob / 100 possible_payoff = c(outcome * self.lottery_amount) + self.endowment setattr(self, 'random_payoff', possible_payoff) if self.on_paying_round: if 'possible_payoffs' in self.participant.vars: self.participant.vars['possible_payoffs'].append(round(possible_payoff, 2)) else: self.participant.vars['possible_payoffs'] = [round(possible_payoff, 2)]