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_placesis the number of decimal places used internally (for database storage and calculations). If you setstorage_places=6, then1/3will be stored as0.333333.The
output_properties apply when displaying the content in a template. If you setoutput_max_places=2andoutput_min_places=0, then9.876will display as9.87. but9.000will display as9(remove trailing zeros).The
input_properties are relevant if the field is included in a form. If you setinput_places=0, then the user must input a whole number.input_unit_labelsets 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).