from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) doc = """ Edited for EC312 Kent by Yidan Chai. The principal offers a contract to the agent, who can decide if to reject or accept. The agent then chooses an effort level. The implementation is based on Gaechter and Koenigstein (2006) . """ class Constants(BaseConstants): name_in_url = 'week5_principal_agent' players_per_group = 2 num_rounds = 6 instructions_template = 'week5_principal_agent/Instructions.html' # """wage = w""" min_fixed_payment = c(100) max_fixed_payment = c(1000) # """Amount principal gets if contract is rejected""" reject_principal_pay = c(0) reject_agent_pay = c(0) # agent_return_share_choices = [ # [percent / 100.0, '{}%'.format(percent)] # for percent in range(10, 100 + 1, 10)] # EFFORT_TO_RETURN = { # 1: 14, # 2: 28, # 3: 42, # 4: 54, # 5: 70, # 6: 84, # 7: 98, # 8: 112, # 9: 126, # 10: 140} EFFORT_TO_COST = { 1: 1, 2: 10, 3: 20, 4: 40, 5: 60, 6: 80, 7: 100, 8: 130, 9: 160, 10: 200} def cost_from_effort(effort): return c(Constants.EFFORT_TO_COST[effort]) # def return_from_effort(effort): # return c(Constants.EFFORT_TO_RETURN[effort]) class Subsession(BaseSubsession): pass class Group(BaseGroup): total_return = models.CurrencyField( doc="""Total return from agent's effort = [Return for single unit of agent's work effort] * [Agent's work effort]""" ) agent_fixed_pay = models.CurrencyField( doc="""Amount offered as fixed pay to agent""", min=Constants.min_fixed_payment, max=Constants.max_fixed_payment, ) agent_return_share = models.IntegerField( choices=range(1, 10 + 1), doc="""Agent's share of total return""", widget=widgets.RadioSelectHorizontal ) agent_work_effort = models.IntegerField( choices=range(1, 10 + 1), doc="""Agent's work effort, [1, 10]""", widget=widgets.RadioSelectHorizontal, blank=True # if they reject, they don't have to submit work effort ) agent_work_cost = models.CurrencyField( doc="""Agent's cost of work effort""" ) contract_accepted = models.BooleanField( doc="""Whether agent accepts proposal""", widget=widgets.RadioSelect, choices=[ [True, 'Accept'], [False, 'Reject'], ] ) def set_payoffs(self): principal = self.get_player_by_role('principal') agent = self.get_player_by_role('agent') if self.contract_accepted: self.agent_work_cost = cost_from_effort(self.agent_work_effort) # self.total_return = return_from_effort(self.agent_work_effort) # money_to_agent = self.agent_return_share * self.total_return + self.agent_fixed_pay agent.payoff = self.agent_fixed_pay - self.agent_work_cost principal.payoff = 200 * self.agent_work_effort - self.agent_fixed_pay else: principal.payoff = Constants.reject_principal_pay agent.payoff = Constants.reject_agent_pay # def return_share_as_percentage(self): # return int(self.agent_return_share * 100) class Player(BasePlayer): def role(self): if self.id_in_group == 1: return 'principal' if self.id_in_group == 2: return 'agent'