oTree: Strategic interaction

An Introduction to oTree

Matteo Ploner

The game

A public Goods Game

  • Participants can decide how much contribute to a “public” project out of their endowment
  • Participants are in a group of N subjects (usually 4)
    • What is contributed is multiplied by an efficiency factor $1/N<<1 $
    • What is not contributed is kept in a private account
  • Private incentives are to contribute nothing to the public account
    • But, contributions are efficient
      • \(\Rightarrow\) social dilemma

Treatments: framing

  • We are going to frame the game eiter as a Voluntary Contribution game (VC) or as a Common Pool game (CP)
  • Voluntary Contribution game
    • Participants explicitly decide how much of their endowment contribute to the public project
      • What is not contributed is kept in a private account

Parameters

  • The interaction is repeated 10x in a partner fashion
    • Total earnings are given by the sum of earnings in each stage
  • Groups of 4
    • Matched together for the entire expeirment (partner)
  • The efficiency factor \(\alpha=.5\)
  • The initial endowment is E=100
    • The individual payoff function is
      • VC
    • \(\Pi_i=E-c_i+\alpha \sum_j^N c_j\)
      • where, \(j\) are the members of \(i\)’s group (\(i\) include)
      • \(\sum_j^N c_j\) is the size of the public project
      • CP
        • \(\Pi_i=c_i+ \alpha (N*E-\sum_j^N c_j)\)
  • Choices are in integer steps
    • \(c_i \in \{0, 100\}\)

Screens

Instructions

  • VC

Choices

  • VC

Results

  • CP

oTree code

models.py

  • Set here a few important constants
    • Players per group
    • Number of rounds
    • Individual endowment
    • Multiplier for the public project
      • \(\alpha=\frac{2=multiplier}{4=group~members}\)

models (iii)

  • In class Group we define the payoffs
    • Typical of strategic interaction, while in individual decision making they are defined in Player

class Group(BaseGroup):
    total_choices = models.CurrencyField() # for VC is contributions , for CP is withdrawals
    individual_share = models.CurrencyField() #the share from public project
    total_earnings = models.CurrencyField() # share from public project + private account
#***************************************************************
# Define the method to compute payoff
#***************************************************************
    def set_payoffs(self):
    # conventional name for the payoff function
        players = self.get_players()
        # retrieve players in the subsession
        choices = [p.choice for p in players]
        # store their choices in a list. For CP they are withdrawals, For VC they are contributions
        self.total_choices = sum(choices)
        # sum the total choices (gives the size of the public project)
        if self.session.config['treatment'] == "VC":
        # if treatment is VC
            self.total_earnings = self.total_choices * Constants.multiplier
            # size of the public project
            self.individual_share = (
                self.total_earnings / Constants.players_per_group
            )
            # the individual share from the public project
            for p in players:
            # for all players in the group
                p.payoff = Constants.endowment - p.choice + self.individual_share
                # write the earnings in the payoff field (each player has automatically one)
                # then, we can use participant.payoff to get the sum across rounds
        else: # treatment CP
        # if treatment is CP
            self.total_earnings = ((Constants.endowment*Constants.players_per_group)-self.total_choices) * Constants.multiplier
            # size of the public project
            self.individual_share = (
                self.total_earnings / Constants.players_per_group
            )
            # the individual share from the public project
            for p in players:
            # for all players in the group
                p.payoff =  p.choice + self.individual_share
                # write the earnings in the payoff field (each player has automatically one)
                # then, we can use participant.payoff to get the sum across rounds

pages.py

  • We have 5 pages
  • page_sequence = [Instructions, Contribute, ResultsWaitPage, Results, FinalResults]
    • Instructions(Page)
      • Displayed only in round 1
    • Contribute(Page)
    • ResultsWaitPage(WaitPage)
      • WaitPage → oTree waits until all players in the group have arrived at that point in the sequence, and then all players are allowed to proceed
    • Results(Page)
    • FinalResults(Page)
      • Displayed only in last round

templates: Instructions

{% extends "global/Page.html" %}
{% load staticfiles otree %}
<!--------------------------->

<!-- Title -->

{% block title %}
  <h1>  Instructions </h1>
{% endblock %}

<!--------------------------->

<!-- Main body -->

{% block content %}

<div class="container p-3 my-3 border" style="font-size:18pt">

<h2> The interaction</h2>

{% if treatment == "VC" %} <!-- VC -->
<p>In this study, you will be in a randomly formed group of {{ Constants.players_per_group }} participants. </p>
<p>Each participant in the group is given {{ Constants.endowment }}. </p>
<p>Each participant in the group decides how much she or he is going to contribute to a common project.</p>
<p>Contributions could be any integer between 0 to {{ Constants.endowment }}.</p>

<h2> Your payoff </h2>
<p> The earnings from the project are calculated as follows:
<ul>
  <li>
  The contributions of all {{ Constants.players_per_group }} participants are added up.</li>
  <li>
    The sum of contributions is multiplied by a factor of {{ Constants.multiplier }}: these are the <i>total returns from the project</i>.
  </li>
  <li>
    <i>Total returns from the project</i> are then evenly split among all {{ Constants.players_per_group }}  participants: : these are <i>your earnings from the project</i>.
  </li>
</ul>
<p><i>Your payoff</i> is given by your earnings from the project, plus the amount you did not contribute.</p>

{% else %} <!-- CP -->

<p>In this study, you will be in a randomly formed group of {{ Constants.players_per_group }} participants. </p>
<p> Your group is endowed with a common project of {{ common_proj }}. </p>
<p>Each participant in the group decides how much she or he is going to withdraw from the common project.</p>
<p>Withdrawals could be any integer between 0 to {{ Constants.endowment }}.</p>

<h2> Your payoff </h2>
<p> The earnings from the project are calculated as follows:
<ul>
  <li>
  The withdrawals of all {{ Constants.players_per_group }} participants are added up.</li>
  <li>
    The sum of withdrawals is subtracted from the common project and the resulting amount is multiplied by a factor of  {{ Constants.multiplier }}: these are the <i>total returns from the project</i>.
  </li>
  <li>
    <i>Total returns from the project</i> are then evenly split among all {{ Constants.players_per_group }}  participants: these are <i>your earnings from the project</i>.
  </li>
</ul>
<p><i>Your payoff</i> is given by your earnings from the project, plus the amount you withdrew from the project.</p>


{% endif %}

</div>

<!-- Continue Button -->

<div class="container" style="font-size:18pt">
  <div class="row">
    &nbsp;
  </div>
  <div class="row" style="padding-left:135px;">
    <div class="col-md-10">

    </div>
    <div class="col-md-2">
      <button name="btn_submit" value="True" class="btn btn-primary btn-large">
         <span style="font-size:18pt">Continue</span>
     </button>
    </div>
  </div>
</div>


{% endblock %}
<!--------------------------->

templates: Results

{% extends "global/Page.html" %}
{% load staticfiles otree %}
<!--------------------------->

{% block title %}
    Results ( Round {{ round_number }} of {{Constants.num_rounds}})
{% endblock %}
<!--------------------------->

{% block content %}

<div class="container p-3 my-3 border" style="font-size:18pt">
{% if treatment == "VC" %}
    <table class="table-condensed" style="width:500px; margin-top:20px;">
        <tr><td>You contributed:</td><td>{{ player.choice }}</td></tr>
        <tr><td>Other participants contributed:</td><td></td></tr>
        {% for p in player.get_others_in_group %} <!-- get the list of all players-->
            <tr><td></td><td>{{ p.choice }}</td></tr>
        {% endfor %}
        <tr><td>Total contribution:</td><td>{{ group.total_choices }}</td></tr>
        <tr><td colspan="2"><hr/></td></tr>
        <tr><td>Total earnings from the project:</td><td>{{ group.total_earnings }}</td></tr>
        <tr><td>Your earnings from the project:</td><td>{{ group.individual_share }}</td></tr>
        <tr><td colspan="2"><hr/></td></tr>
        <tr><td>Thus in total you earned:</td><td>{{ player.payoff }}</td></tr>
    </table>
{% else %}
    <table class="table-condensed" style="width:500px; margin-top:20px;">
        <tr><td>You withdrew:</td><td>{{ player.choice }}</td></tr>
        <tr><td>Other participants withdrew:</td><td></td></tr>
        {% for p in player.get_others_in_group %} <!-- get the list of all players-->
            <tr><td></td><td>{{ p.choice }}</td></tr>
        {% endfor %}
        <tr><td>Total withdrawals:</td><td>{{ group.total_choices }}</td></tr>
        <tr><td colspan="2"><hr/></td></tr>
        <tr><td>Total earnings from the project:</td><td>{{ group.total_earnings }}</td></tr>
        <tr><td>Your earnings from the project:</td><td>{{ group.individual_share }}</td></tr>
        <tr><td colspan="2"><hr/></td></tr>
        <tr><td>Thus in total you earned:</td><td>{{ player.payoff }}</td></tr>
    </table>
    {% endif %}
</div>
<!--------------------------->
<!-- Continue Button -->

<div class="container" style="font-size:18pt">
  <div class="row">
    &nbsp;
  </div>
  <div class="row" style="padding-left:135px;">
    <div class="col-md-10">

    </div>
    <div class="col-md-2">
      <button name="btn_submit" value="True" class="btn btn-primary btn-large">
         <span style="font-size:18pt">Continue</span>
     </button>
    </div>
  </div>
</div>
{% endblock %}
<!--------------------------->

Thank you

🦄

To contact me just write me an email

matteo.ploner@unitn.it

or write me on the forum of the course

Appendix

Assignment

  1. Easy
  • Change endowment from 100 to 10000
  1. Less easy
  • Final payment is not the sum of all periods, but a randomly chosen period
    • Hint: use the built-in method in_round()

OTree code

  • The oTree app of this lecture:
Download PGG.zip

References