from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, ) import math import random author = 'Nishtha Sharma' doc = """ Retirement Savings Task - treatment 3 (task2) with different annual and lumpsum benefits depending on the period of claiming ssb """ class Constants(BaseConstants): name_in_url = 'RST3_Task2' players_per_group = None num_rounds = 40 RandomList = random.sample(range(1, 100), 40) cutofflist = [96, 96, 96, 96, 96, 96, 96, 96, 96, 95, 95, 95, 95, 94, 94, 94, 93, 93, 93, 92, 91, 91, 90, 89, 88, 87, 86, 85, 83, 82, 80, 79, 77, 75, 73, 71, 70, 68, 67, 0] difflist = [x1 - x2 for (x1, x2) in zip(cutofflist, RandomList)] min_age = 62 Task = 2 savings_start = c(145350) interest_rate = 1.027 min_consumption = c(14887) annualBenefits_list = [14887, 15376, 15913, 16502, 17153, 17873, 18672, 19564, 20563] lumpsum_list = [0, 7725, 15744, 24112, 32812, 41912, 51449, 61457, 71999] class Subsession(BaseSubsession): paying_round = models.IntegerField() paying_task = models.IntegerField() cutoff = models.IntegerField() draw = models.IntegerField() def payingTask(self): A = self.in_round(1) self.cutoff = Constants.cutofflist[self.round_number - 1] self.draw = Constants.RandomList[self.round_number - 1] if self.round_number == 1: self.paying_round = next(i for i, v in enumerate(Constants.difflist) if v < 0) + 1 print(self.paying_round) else: self.paying_round = A.paying_round class Group(BaseGroup): pass class Player(BasePlayer): ssb_choice = models.BooleanField(label="Do you want to claim benefits this period?", widget=widgets.RadioSelect) is_claimed = models.BooleanField() starting_balance = models.CurrencyField() intermediate_balance = models.CurrencyField() ending_balance = models.CurrencyField() consumption = models.CurrencyField() is_balance_low = models.BooleanField() annual_benefits = models.CurrencyField() lumpsum_benefits = models.CurrencyField() ssb = models.CurrencyField() default_consumption = models.CurrencyField() last_balance = models.CurrencyField() ssb_chosen = models.CurrencyField() ssb_benefits_low_balance = models.CurrencyField() period_payoff = models.FloatField() cumulative_payoff = models.FloatField() task2_payoff = models.FloatField() ssb_benefits_period9 = models.CurrencyField() def set_claim(self): if self.round_number > 1: A = self.in_round(self.round_number - 1) else: A = self.in_round(self.round_number) if self.round_number == 1: self.is_claimed = 0 elif self.round_number == 2: self.is_claimed = A.ssb_choice elif A.is_claimed == 1: self.is_claimed = 1 else: self.is_claimed = A.ssb_choice if self.round_number > 1: A = self.in_round(self.round_number - 1) else: A = self.in_round(self.round_number) # Defining starting_balance if self.round_number == 1: self.starting_balance = Constants.savings_start else: self.starting_balance = A.ending_balance * Constants.interest_rate self.starting_balance = round(self.starting_balance, 2) if self.round_number == 1: self.last_balance = 0 else: self.last_balance = self.in_round(self.round_number - 1).ending_balance # If balance is low if self.starting_balance < 14887: self.is_balance_low = 1 else: self.is_balance_low = 0 def set_ssb(self): if self.round_number > 1: A = self.in_round(self.round_number - 1) else: A = self.in_round(self.round_number) if self.round_number > 1 and A.annual_benefits > 0: self.annual_benefits = A.annual_benefits self.lumpsum_benefits = 0 self.ssb = A.annual_benefits else: if self.is_balance_low: self.annual_benefits = Constants.annualBenefits_list[self.round_number - 1] self.lumpsum_benefits = Constants.lumpsum_list[self.round_number - 1] self.ssb_benefits_low_balance = Constants.annualBenefits_list[self.round_number - 1] + \ Constants.lumpsum_list[self.round_number - 1] self.ssb = Constants.annualBenefits_list[self.round_number - 1] + Constants.lumpsum_list[ self.round_number - 1] elif self.ssb_choice: self.annual_benefits = Constants.annualBenefits_list[self.round_number - 1] self.lumpsum_benefits = Constants.lumpsum_list[self.round_number - 1] self.ssb_chosen = Constants.annualBenefits_list[self.round_number - 1] + \ Constants.lumpsum_list[ self.round_number - 1] self.ssb = Constants.annualBenefits_list[self.round_number - 1] + Constants.lumpsum_list[ self.round_number - 1] elif self.round_number == 9: self.annual_benefits = Constants.annualBenefits_list[self.round_number - 1] self.lumpsum_benefits = Constants.lumpsum_list[self.round_number - 1] self.ssb_benefits_period9 = Constants.annualBenefits_list[self.round_number - 1] + \ Constants.lumpsum_list[ self.round_number - 1] self.ssb = self.ssb_benefits_period9 else: self.annual_benefits = 0 self.lumpsum_benefits = 0 self.ssb = 0 def set_intermediate_balance(self): if self.round_number > 1: A = self.in_round(self.round_number - 1) else: A = self.in_round(self.round_number) # Defining default consumption if self.round_number == 1: self.default_consumption = Constants.min_consumption elif A.consumption < self.starting_balance + self.ssb: self.default_consumption = A.consumption else: self.default_consumption = self.starting_balance + self.ssb self.intermediate_balance = self.starting_balance + self.ssb def set_end_balance(self): self.ending_balance = self.starting_balance + self.ssb - self.consumption self.ending_balance = round(self.ending_balance, 2) def set_payoffs(self): self.period_payoff = (1 - math.exp(-(self.consumption - 14887) / 20000)) * 3 self.period_payoff = round(self.period_payoff, 2) if self.round_number > 1: l = self.in_round(self.round_number - 1) self.cumulative_payoff = l.cumulative_payoff + self.period_payoff else: self.cumulative_payoff = self.period_payoff self.cumulative_payoff = round(self.cumulative_payoff, 2) self.payoff = 0 x = self.in_round(self.subsession.paying_round) self.task2_payoff = x.cumulative_payoff if Constants.Task == self.subsession.paying_task: x.payoff = x.cumulative_payoff else: x.payoff = 0 @property def payoff(self): return self._payoff @payoff.setter def payoff(self, value): if value is None: value = 0 delta = value - self._payoff self._payoff += delta self.participant.payoff += delta # should save it because it may not be obvious that modifying # player.payoff also changes a field on a different model self.participant.save() if delta == 0: return print( f'Setting payoff to: {value}. player:\t{self._payoff}, participant:\t{self.participant.payoff}, participant.code:{self.participant.code} ({Constants.name_in_url}, round {self.round_number})')