Currency and Decimal

Moneda

In many experiments, participants play for currency: either real money, or points.

Configuring currency

Here is how to configure what currency you use (points, dollars, euros, etc.).

If you are using oTree 6+ it’s recommended to define a DecimalUnit class in units.py, (see the section on DecimalUnit for more info):

class USD(DecimalUnit):
    storage_places = 4
    input_places = 0
    input_unit_label = '$'
    output_min_places = 0
    output_max_places = 2

    @staticmethod
    def output(formatted, raw):
        return f"${formatted}"

Then in settings.py put the path to this class:

CURRENCY_UNIT = 'units.USD'

If you are using oTree 5, then you should set the REAL_WORLD_CURRENCY_CODE and USE_POINTS settings.

Using currencies

Puedes escribir cu(42) para representar «42 unidades de moneda». Funciona igual que un número (por ejemplo, cu(0.1) + cu(0.2) == cu(0.3)). La ventaja es que cuando se muestra a los usuarios, se formateará automáticamente como $0.30 o 0,30 , etc., dependiendo de tus ajustes de REAL_WORLD_CURRENCY_CODE y LANGUAGE_CODE.

Usa CurrencyField para almacenar monedas en la base de datos. Por ejemplo:

class Player(BasePlayer):
    random_bonus = models.CurrencyField()

Para hacer una lista de montos de moneda, usa currency_range:

currency_range(0, 0.10, 0.02)
# this gives:
# [$0.00, $0.02, $0.04, $0.06, $0.08, $0.10]

En las plantillas, en lugar de usar la función cu(), debes usar el filtro |cu. Por ejemplo, {{ 20|cu }} se muestra como 20 puntos.

payoffs

Cada jugador tiene un campo payoff. Si tu jugador gana dinero, debes almacenarlo en este campo. participant.payoff almacena automáticamente la suma de los payoffs de todas las subsesiones. Puedes modificar participant.payoff directamente, por ejemplo, para redondear el payoff final a un número entero.

At the end of the experiment, a participant’s total profit can be accessed by participant.payoff_plus_participation_fee().

DecimalField

Nota

To use this, you must install oTree 6.0

DecimalField is based on the Python Decimal datatype, which can represent base-10 numbers exactly and therefore avoids annoying arithmetic errors that occur with float. (You can find lots of info online about this subject.)

When defining a DecimalField, you specify unit= to indicate what entity it represents, e.g.:

xyz = models.DecimalField(unit=units.Celsius)

And create units.py in your project root folder and import that into your app. units.py should have content like this:

from otree.api import DecimalUnit

class Celsius(DecimalUnit):
    storage_places = 4
    output_max_places = 2
    output_min_places = 0
    input_places = 0
    input_unit_label = '°C'

This lets you separately configure the precision used for input (participant filling a form), storage (internal calculations and database), and output (displaying in a template).

  • storage_places is the number of decimal places used internally (for database storage and calculations). If you set storage_places=6, then 1/3 will be stored as 0.333333.

  • The output_ properties apply when displaying the content in a template. If you set output_max_places=2 and output_min_places=0, then 9.876 will display as 9.87. but 9.000 will display as 9 (remove trailing zeros).

  • The input_ properties are relevant if the field is included in a form. If you set input_places=0, then the user must input a whole number. input_unit_label sets the label on the right edge of the number input.

You can also define a function that will generate the display value. It takes 2 arguments: the formatted value (e.g. "1,234.5") and the raw numeric value:

class Celsius(DecimalUnit):
    # ...

    @staticmethod
    def output(formatted, raw):
        if raw < 10:
            color = 'blue'
        elif raw < 20:
            color = 'green'
        elif raw < 30:
            color = 'yellow'
        else:
            color = 'red'
        return f"<span style='color: {color};'>{formatted}°C</span>"

Decimal datatype

Apart from database fields, you can define decimal values throughout your code by calling the unit type directly, e.g. ROOM_TEMP = units.Celsius(25).