# -*- coding: utf8 -*- # from otree.db import models import otree.models import otree.constants from otree.api import (models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer,Currency as c, currency_range ) import math from django.core.exceptions import ValidationError import random #from scipy.optimize import fsolve from copy import deepcopy doc = """ Forecast game in which participants forecast future (net) output at different horizons """ # parameters that do not change: to refer to them constants.something, no need for self. as not part of the hierarchy class Constants(otree.constants.BaseConstants): players_per_group = None # as we have only one group of players num_rounds = 60 show_up_fee = 0 rho = 0.95 beta=1 a1 = 2 a2 = -1 a3 =0 theta_init=0 sigma_eta=20 sigma_epsilon=20 sigma_u=20 base=0 name_in_url = 'Forecast' class Subsession(otree.models.BaseSubsession): debt = models.BooleanField() horizon = models.IntegerField() consensus = models.BooleanField() # definition of the treatment # def creating_session(self): # # randomize to treatments # for player in self.get_groups(): # player.color = random.choice(['blue', 'red']) # ISA: create a whole sequence of shocks, check that use of keys and dictionary is ok! def creating_session(self): # random.seed(10) 1 no need for randomness in the shocks # if self.session.config['treatment']=='debt4': # self.horizon=2 # self.debt=True # self.consensus=False # elif self.session.config['treatment'] == 'debt8': # self.horizon = 6 # self.debt = True # self.consensus = False # if self.session.config['treatment']=='nodebt4': # self.horizon=2 # self.debt=False # self.consensus = False # elif self.session.config['treatment'] == 'nodebt8': # self.horizon = 6 # self.debt = False # self.consensus = False # elif self.session.config['treatment'] == 'consen_med': # self.horizon = 6 # self.debt = False # self.consensus = True # elif self.session.config['treatment'] == 'consen_best': # self.horizon = 6 # self.debt = False # self.consensus = True # elif self.session.config['treatment'] == 'revision': # self.horizon = 6 # self.debt = False # self.consensus = False random.seed(10) self.session.vars['epsilon_init'] = [random.normalvariate(0, Constants.sigma_epsilon) for i in range(Constants.num_rounds)] # From normal Distribution self.session.vars['eta_init'] = [random.normalvariate(0, Constants.sigma_eta) for i in range(Constants.num_rounds)] self.session.vars['u_init'] = [random.normalvariate(0, Constants.sigma_u) for i in range(Constants.num_rounds)] self.session.vars['epsilon'] = [random.normalvariate(0, Constants.sigma_epsilon) for i in range(Constants.num_rounds)] # From normal Distribution self.session.vars['eta'] = [random.normalvariate(0, Constants.sigma_eta) for i in range(Constants.num_rounds)] self.session.vars['u'] = [random.normalvariate(0, Constants.sigma_u) for i in range(Constants.num_rounds)] self.session.vars['theta_init'] = [0]*(Constants.num_rounds) self.session.vars['x1_init'] = [0]*(Constants.num_rounds) self.session.vars['x2_init'] = [0]*(Constants.num_rounds) self.session.vars['y_init'] = [0]*(Constants.num_rounds) for i in range(1,(Constants.num_rounds)): self.session.vars['theta_init'][i] = Constants.rho * self.session.vars['theta_init'][i-1] + self.session.vars['eta_init'][i] self.session.vars['x1_init'][i] = Constants.base+Constants.a1 * self.session.vars['theta_init'][i] + self.session.vars['u_init'][i] self.session.vars['x2_init'][i] = Constants.base+Constants.a2 * self.session.vars['theta_init'][i] self.session.vars['y_init'][i] = Constants.beta*(-Constants.base+self.session.vars['x1_init'][i] + self.session.vars['x2_init'][i]+ self.session.vars['epsilon_init'][i]) # the main thing of the experiment is in group: class Group(otree.models.BaseGroup): theta = models.FloatField() x1 = models.FloatField() x2 = models.FloatField() y = models.FloatField() eta = models.FloatField() epsilon = models.FloatField() u = models.FloatField() # it is a function set_payoffs, self is the argument (group in this case), function called from the views file def model(self): if self.subsession.round_number == 1: self.theta = Constants.rho * self.session.vars['theta_init'][Constants.num_rounds-1] + self.session.vars['eta'][ self.subsession.round_number - 1] else: self.theta = Constants.rho * self.in_previous_rounds()[-1].theta + self.session.vars['eta'][ self.subsession.round_number - 1] self.x1 =Constants.base+Constants.a1 * self.theta + self.session.vars['u'][self.subsession.round_number - 1] self.x2 =Constants.base+ Constants.a2 * self.theta self.y = Constants.beta*(-Constants.base+self.x1 + self.x2 + self.session.vars['epsilon'][self.subsession.round_number - 1]) self.epsilon = self.session.vars['epsilon'][self.subsession.round_number - 1] self.u = self.session.vars['u'][self.subsession.round_number - 1] self.eta = self.session.vars['eta'][self.subsession.round_number - 1] class Player(otree.models.BasePlayer): # # group = models.ForeignKey(Group, null=True) # subsession = models.ForeignKey(Subsession) # # save the players' forecasts nowcast = models.FloatField( initial=1000, doc=""" Each player's forecast: """ # {} # """.format(Constants.guess_max) ) forecast = models.FloatField( initial=1000, doc=""" Each player's forecast: """ # {} # """.format(Constants.guess_max) ) # for the time out no_decision_timeout = models.BooleanField(initial=False) forecast_lag = models.FloatField(min=0, initial=None) paid_forc = models.FloatField(min=0, initial=None) abs_FE = models.FloatField(min=0, initial=None) # forecast error in a period score_FE = models.FloatField(min=0, initial=None) # payoff in a period abs_NE = models.FloatField(min=0, initial=None) # forecast error in a period score_NE = models.FloatField(min=0, initial=None) # payoff in a period cum_score_y = models.FloatField(min=0, initial = 0) # cumulative payoff tot_score = models.FloatField(min=0, initial = 0) discounted_cum_score = models.FloatField(min=0, initial = 0) real_cum_score_y = models.CurrencyField(min=0, initial = 0) # cumulative payoff in terms of euros FE_selected = models.IntegerField() def set_payoffs(self): if self.subsession.round_number == 1: # Initialize, remember round_number starts from 1 and not 0!! self.abs_NE = abs(self.group.y - self.nowcast) self.score_NE = round(100 * max(0, (1 - self.abs_NE / 20))) self.score_FE = 0 self.tot_score = self.score_NE self.FE_selected = 0 self.cum_score_y = self.score_NE self.discounted_cum_score = 0 else: self.forecast_lag = self.in_previous_rounds()[-1].forecast self.abs_NE = abs(self.group.y - self.nowcast) self.score_NE = round(100 * max(0, (1 - self.abs_NE / 20))) self.abs_FE = abs(self.group.y - self.in_previous_rounds()[-1].forecast) self.score_FE = round(100 * max(0, (1 - self.abs_FE / 20))) if random.random() < 0.5: self.tot_score = self.score_NE self.FE_selected = 0 else: self.tot_score = self.score_FE self.FE_selected = 1 self.cum_score_y = self.tot_score + self.in_previous_rounds()[-1].cum_score_y def set_fin_payoff(self): cum_score_ne = self.score_NE cum_score_fe = self.score_FE for r in self.in_previous_rounds(): cum_score_ne += r.score_NE cum_score_fe += r.score_FE if cum_score_ne > 450 and cum_score_fe > 450/60*59: self.payoff = self.cum_score_y else: self.payoff = 0 # below are for the end-of-experiment questionnaire q_age = models.PositiveIntegerField(verbose_name='What is your age?', choices=range(18, 100), initial=None) q_gender = models.StringField(initial=None, choices=['Male', 'Female'], verbose_name='What is your gender?', widget=widgets.RadioSelect()) q_study = models.StringField( verbose_name='What is the highest level of educational degree that you hold?', choices=['Graduate school (e.g. Masters, Ph.D., Post-doctoral degrees)','College','High school','Below high school','Other'], widget=widgets.RadioSelect()) q_experience = models.StringField(initial=None, choices=['Yes', 'No'], verbose_name='Have you taken statistics classes?', widget=widgets.RadioSelect()) question1 = models.StringField( choices=['Red process', 'Light blue process', 'Purple process', 'Light blue and purple processes', 'Light blue and red processes', 'Purple and red processes', 'All three processes'], widget=widgets.RadioSelect(), verbose_name='When I made my decision, I meanly considered recent observations of the') comment = models.StringField(blank=True, verbose_name='If you want to leave us a comment, please do so here.')