from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) import random author = 'Julian Detemple' doc = """ Contract Design Share Based Contract """ class Constants(BaseConstants): name_in_url = 'ContractDesign_Share' players_per_group = 2 num_rounds = 1 effort_max = 10 effort_increment = 1 effort_choices = range(1, effort_max+1, effort_increment) share_choices = range(0, 110, 10) return_per_effort = 70 return_list = [] for i in effort_choices: return_list.append(i * return_per_effort) # Put costs as list, can then find it with index=effort-1 costs = [0, 20, 40, 60, 90, 120, 160, 200, 250, 300] wage_min = c(-700) wage_max = c(700) outside_option = c(100) overview_table = 'global/Contract_Overview_Table.html' instructions_owner_short = 'ContractDesign_Share/Instructions_Owner_Short.html' instructions_expert_short = 'ContractDesign_Share/Instructions_Expert_Short.html' class Subsession(BaseSubsession): def creating_session(self): self.group_randomly() class Group(BaseGroup): offer_fixed_wage = models.CurrencyField() offer_effort = models.IntegerField() offer_bonus = models.IntegerField() final_decision = models.BooleanField(initial=False) final_effort = models.IntegerField() final_fixed_wage = models.CurrencyField() final_bonus = models.IntegerField() welfare = models.CurrencyField() def set_roles(self): p1, p2 = self.get_players() if random.randint(0, 1) == 1: p1.owner = True else: p2.owner = True def set_payoffs(self): for p in self.get_players(): other = (p.get_others_in_group())[0] p.offered_wage = other.offer_fixed_wage p.offered_bonus = other.offer_bonus p.offered_effort = other.offer_effort if p.decision: p.welfare = Constants.return_per_effort * p.chosen_effort - Constants.costs[p.chosen_effort-1] if self.get_player_by_id(1).owner: owner = self.get_player_by_id(1) expert = self.get_player_by_id(2) else: owner = self.get_player_by_id(2) expert = self.get_player_by_id(1) if expert.decision: self.final_effort = expert.chosen_effort self.final_decision = expert.decision self.final_fixed_wage = owner.offer_fixed_wage self.final_bonus = owner.offer_bonus owner.payoff = (100 - self.final_bonus)/100 * (Constants.return_per_effort * self.final_effort) - self.final_fixed_wage expert.payoff = (self.final_bonus)/100 * (Constants.return_per_effort * self.final_effort) + self.final_fixed_wage - Constants.costs[self.final_effort-1] self.welfare = owner.payoff + expert.payoff else: owner.payoff = 0 expert.payoff = Constants.outside_option self.final_effort = -1 for p in self.get_players(): p.payout = float(p.participant.payoff_plus_participation_fee()) self.offer_fixed_wage = owner.offer_fixed_wage self.offer_effort = owner.offer_effort self.offer_bonus = owner.offer_bonus class Player(BasePlayer): owner = models.BooleanField(initial=False) offer_fixed_wage = models.CurrencyField( min=Constants.wage_min, max=Constants.wage_max, label="Please input the fixed wage payment for the expert (only integers).", ) offer_bonus = models.IntegerField( choices=Constants.share_choices, widget=widgets.RadioSelectHorizontal, label="Please input expert's return share in %.", ) offer_effort = models.IntegerField( choices=Constants.effort_choices, widget=widgets.RadioSelectHorizontal, label="Please choose the effort level which you desire the expert to implement.", ) offered_wage = models.CurrencyField() offered_bonus = models.IntegerField() offered_effort = models.IntegerField() decision = models.BooleanField( choices=[ [True, "Accept"], [False, "Reject"] ], widget=widgets.RadioSelectHorizontal, label="Do you want to accept or reject the contract?", ) chosen_effort = models.IntegerField( choices=Constants.effort_choices, widget=widgets.RadioSelectHorizontal, label="Please decide on your effort level.", ) welfare = models.CurrencyField() payout = models.FloatField()