import itertools import json import json as json import math import random import random as random import numpy as np import pandas as pd from otree.api import * author = 'Your name here' doc = """ WTP Sequence """ class Constants(BaseConstants): name_in_url = '9H32Dcs53s2g' players_per_group = None num_rounds = 2 num_participants = 10 timeout = 40 play_rounds = 5 # ordering = ['BA','AB'] ### WTP max_amount = 64 no_decisions = 7 # Payoff Constants payoff_incorrect = cu(0) pwd_rate_high = 12 pwd_piecerate_high = cu(pwd_rate_high) math_rate_high = 12 math_piecerate_high = cu(math_rate_high) pwd_rate_low = 10 pwd_piecerate_low = cu(pwd_rate_low) math_rate_low = 10 math_piecerate_low = cu(math_rate_low) WTP_sequence = ['HighLow', 'LowHigh'] task = 'WTP_Sequence' num_pwd_tasks = 10 num_math_tasks = 10 class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): task = models.StringField() WTP_sequence = models.StringField() ### WTP max_amount = models.FloatField() no_decisions = models.IntegerField() WTP_Dec1 = models.BooleanField() WTP_Dec2 = models.BooleanField() WTP_Dec3 = models.BooleanField() WTP_Dec4 = models.BooleanField() WTP_Dec5 = models.BooleanField() WTP_Dec6 = models.BooleanField() WTP_Dec7 = models.BooleanField() WTP_high_lowest = models.FloatField() WTP_high_highest = models.FloatField() WTP_high_midpoint = models.FloatField() WTP_low_lowest = models.FloatField() WTP_low_highest = models.FloatField() WTP_low_midpoint = models.FloatField() ## Control questions control_q1 = models.PositiveIntegerField( choices=[[1, 'Yes'], [0, 'No']], widget=widgets.RadioSelectHorizontal, initial=None ) control_q2 = models.PositiveIntegerField( choices=[[0, 'Only once.'], [1, 'Each round.']], initial=None, widget=widgets.RadioSelectHorizontal, ) control_q3 = models.PositiveIntegerField( choices=[i for i in range(Constants.no_decisions - 11, Constants.no_decisions + 9)], initial=None, ) WTP_Dec1_time_spent = models.FloatField(blank=True) WTP_Dec2_time_spent = models.FloatField(blank=True) WTP_Dec3_time_spent = models.FloatField(blank=True) WTP_Dec4_time_spent = models.FloatField(blank=True) WTP_Dec5_time_spent = models.FloatField(blank=True) WTP_Dec6_time_spent = models.FloatField(blank=True) WTP_Dec7_time_spent = models.FloatField(blank=True) Instructions_1_time_spent = models.FloatField(blank=True) WTP_Instructions_time_spent = models.FloatField(blank=True) WTP_Middle_time_spent = models.FloatField(blank=True) WTP_Start_time_spent = models.FloatField(blank=True) WTP_Dec1_warnings = models.IntegerField() WTP_Dec2_warnings = models.IntegerField() WTP_Dec3_warnings = models.IntegerField() WTP_Dec4_warnings = models.IntegerField() WTP_Dec5_warnings = models.IntegerField() WTP_Dec6_warnings = models.IntegerField() WTP_Dec7_warnings = models.IntegerField() Instructions_1_warnings = models.IntegerField() WTP_Instructions_warnings = models.IntegerField() WTP_Middle_warnings = models.IntegerField() WTP_Start_warnings = models.IntegerField() # def control_q3_error_message(self,value): # """Customized error message for control question 3.""" # cond = (value != Constants.no_decisions) # if cond: # return 'Your input is incorrect. Please try again!' # FUNCTIONS def creating_session(subsession: Subsession): WTP_sequence = Constants.WTP_sequence.copy() # shuffle the list random.shuffle(WTP_sequence) # make a cycle out of the shuffled list WTP_seq = itertools.cycle(WTP_sequence) for p in subsession.get_players(): # Establishes task ordering & Incentives for Math Task if subsession.round_number == 1: p.participant.vars['WTP_sequence'] = next(WTP_seq) p.participant.vars['WTP_max_amount'] = Constants.max_amount p.participant.vars['WTP_no_decisions'] = Constants.no_decisions p.task = Constants.task p.WTP_sequence = p.participant.vars['WTP_sequence'] # WTP basics p.max_amount = p.participant.vars['WTP_max_amount'] p.no_decisions = p.participant.vars['WTP_no_decisions'] def control_q1_error_message(player: Player, value): """Customized error message for control question 1.""" cond = value != 0 if cond: return '' def control_q2_error_message(player: Player, value): """Customized error message for control question 2.""" cond = value != 1 if cond: return '' # PAGES def bisection(prev_upper_bound, prev_lower_bound, dec): midpoint = (prev_upper_bound + prev_lower_bound) / 2 if dec == True: upper_bound = prev_upper_bound lower_bound = midpoint else: upper_bound = midpoint lower_bound = prev_lower_bound return upper_bound, lower_bound, (upper_bound + lower_bound) / 2 class Instructions_1(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 form_model = 'player' form_fields = ['Instructions_1_warnings', 'Instructions_1_time_spent'] @staticmethod def js_vars(player: Player): return dict(page_name='Instructions_1') class WTP_Instructions(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 form_model = 'player' form_fields = [ 'control_q1', 'control_q2', #'control_q3', 'WTP_Instructions_warnings', 'WTP_Instructions_time_spent', ] @staticmethod def js_vars(player: Player): return dict(page_name='WTP_Instructions') @staticmethod def error_message(player: Player, values): """Customized error message for control question 2. The error message is not actually displayed. This function simply validates the form for us. For the actual error message code look at the html code of the page. """ cond_1 = values['control_q1'] != 0 cond_2 = values['control_q2'] != 1 # cond_3 = (values['control_q3'] != Constants.no_decisions) if cond_1: return 'Your input is incorrect! Please read the instructions again.' elif cond_2: return 'Your input is incorrect! Please read the instructions again.' # elif cond_3: # return 'Your input is incorrect! Please read the instructions again.' class WTP_Dec1(Page): form_model = 'player' form_fields = ['WTP_Dec1', 'WTP_Dec1_warnings', 'WTP_Dec1_time_spent'] @staticmethod def js_vars(player: Player): return dict(page_name='WTP_Dec1') @staticmethod def before_next_page(player: Player, timeout_happened): p_vars = player.participant.vars p_vars[f'WTP_Sequence_{player.round_number}'] = [] p_vars[f'WTP_Sequence_{player.round_number}'].append(player.WTP_Dec1) p_vars['WTP_upper_bound'] = Constants.max_amount p_vars['WTP_lower_bound'] = -Constants.max_amount @staticmethod def vars_for_template(player: Player): midpoint = (Constants.max_amount + (-Constants.max_amount)) / 2 if player.WTP_sequence == 'HighLow': if player.round_number == 1: incentives = Constants.pwd_rate_high elif player.round_number == 2: incentives = Constants.pwd_rate_low elif player.WTP_sequence == 'LowHigh': if player.round_number == 1: incentives = Constants.pwd_rate_low elif player.round_number == 2: incentives = Constants.pwd_rate_high return dict(midpoint=cu(midpoint), incentives=incentives) class WTP_Dec2(Page): form_model = 'player' form_fields = ['WTP_Dec2', 'WTP_Dec2_warnings', 'WTP_Dec2_time_spent'] @staticmethod def js_vars(player: Player): return dict(page_name='WTP_Dec2') @staticmethod def vars_for_template(player: Player): p_vars = player.participant.vars prev_upper_bound, prev_lower_bound = p_vars['WTP_upper_bound'], p_vars['WTP_lower_bound'] upper_bound, lower_bound, midpoint = bisection( p_vars['WTP_upper_bound'], p_vars['WTP_lower_bound'], player.WTP_Dec1 ) p_vars['new_WTP_upper_bound'] = upper_bound p_vars['new_WTP_lower_bound'] = lower_bound if player.WTP_Dec1 == True: rec_points = cu(midpoint) no_rec = cu(0) else: rec_points = cu(0) no_rec = cu(-midpoint) if player.WTP_sequence == 'HighLow': if player.round_number == 1: incentives = Constants.pwd_rate_high elif player.round_number == 2: incentives = Constants.pwd_rate_low elif player.WTP_sequence == 'LowHigh': if player.round_number == 1: incentives = Constants.pwd_rate_low elif player.round_number == 2: incentives = Constants.pwd_rate_high return dict(rec_points=rec_points, no_rec=no_rec, incentives=incentives) @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.vars[f'WTP_Sequence_{player.round_number}'].append(player.WTP_Dec2) player.participant.vars['WTP_upper_bound'] = player.participant.vars['new_WTP_upper_bound'] player.participant.vars['WTP_lower_bound'] = player.participant.vars['new_WTP_lower_bound'] class WTP_Dec3(Page): form_model = 'player' form_fields = ['WTP_Dec3', 'WTP_Dec3_warnings', 'WTP_Dec3_time_spent'] @staticmethod def js_vars(player: Player): return dict(page_name='WTP_Dec3') @staticmethod def vars_for_template(player: Player): p_vars = player.participant.vars prev_upper_bound, prev_lower_bound = p_vars['WTP_upper_bound'], p_vars['WTP_lower_bound'] upper_bound, lower_bound, midpoint = bisection( p_vars['WTP_upper_bound'], p_vars['WTP_lower_bound'], player.WTP_Dec2 ) p_vars['WTP_upper_bound'] = upper_bound p_vars['WTP_lower_bound'] = lower_bound if player.WTP_Dec1 == True: rec_points = cu(midpoint) no_rec = cu(0) else: rec_points = cu(0) no_rec = cu(-midpoint) if player.WTP_sequence == 'HighLow': if player.round_number == 1: incentives = Constants.pwd_rate_high elif player.round_number == 2: incentives = Constants.pwd_rate_low elif player.WTP_sequence == 'LowHigh': if player.round_number == 1: incentives = Constants.pwd_rate_low elif player.round_number == 2: incentives = Constants.pwd_rate_high return dict(rec_points=rec_points, no_rec=no_rec, incentives=incentives) @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.vars[f'WTP_Sequence_{player.round_number}'].append(player.WTP_Dec3) class WTP_Dec4(Page): form_model = 'player' form_fields = ['WTP_Dec4', 'WTP_Dec4_warnings', 'WTP_Dec4_time_spent'] @staticmethod def js_vars(player: Player): return dict(page_name='WTP_Dec4') @staticmethod def vars_for_template(player: Player): p_vars = player.participant.vars upper_bound, lower_bound, midpoint = bisection( p_vars['WTP_upper_bound'], p_vars['WTP_lower_bound'], player.WTP_Dec3 ) p_vars['WTP_upper_bound'] = upper_bound p_vars['WTP_lower_bound'] = lower_bound if player.WTP_Dec1 == True: rec_points = cu(midpoint) no_rec = cu(0) else: rec_points = cu(0) no_rec = cu(-midpoint) if player.WTP_sequence == 'HighLow': if player.round_number == 1: incentives = Constants.pwd_rate_high elif player.round_number == 2: incentives = Constants.pwd_rate_low elif player.WTP_sequence == 'LowHigh': if player.round_number == 1: incentives = Constants.pwd_rate_low elif player.round_number == 2: incentives = Constants.pwd_rate_high return dict(rec_points=rec_points, no_rec=no_rec, incentives=incentives) @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.vars[f'WTP_Sequence_{player.round_number}'].append(player.WTP_Dec4) class WTP_Dec5(Page): form_model = 'player' form_fields = ['WTP_Dec5', 'WTP_Dec5_warnings', 'WTP_Dec5_time_spent'] @staticmethod def js_vars(player: Player): return dict(page_name='WTP_Dec5') @staticmethod def vars_for_template(player: Player): p_vars = player.participant.vars upper_bound, lower_bound, midpoint = bisection( p_vars['WTP_upper_bound'], p_vars['WTP_lower_bound'], player.WTP_Dec4 ) p_vars['WTP_upper_bound'] = upper_bound p_vars['WTP_lower_bound'] = lower_bound if player.WTP_Dec1 == True: rec_points = cu(midpoint) no_rec = cu(0) else: rec_points = cu(0) no_rec = cu(-midpoint) if player.WTP_sequence == 'HighLow': if player.round_number == 1: incentives = Constants.pwd_rate_high elif player.round_number == 2: incentives = Constants.pwd_rate_low elif player.WTP_sequence == 'LowHigh': if player.round_number == 1: incentives = Constants.pwd_rate_low elif player.round_number == 2: incentives = Constants.pwd_rate_high return dict(rec_points=rec_points, no_rec=no_rec, incentives=incentives) @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.vars[f'WTP_Sequence_{player.round_number}'].append(player.WTP_Dec5) class WTP_Dec6(Page): form_model = 'player' form_fields = ['WTP_Dec6', 'WTP_Dec6_warnings', 'WTP_Dec6_time_spent'] @staticmethod def js_vars(player: Player): return dict(page_name='WTP_Dec6') @staticmethod def vars_for_template(player: Player): p_vars = player.participant.vars upper_bound, lower_bound, midpoint = bisection( p_vars['WTP_upper_bound'], p_vars['WTP_lower_bound'], player.WTP_Dec5 ) p_vars['WTP_upper_bound'] = upper_bound p_vars['WTP_lower_bound'] = lower_bound if player.WTP_Dec1 == True: rec_points = cu(midpoint) no_rec = cu(0) else: rec_points = cu(0) no_rec = cu(-midpoint) if player.WTP_sequence == 'HighLow': if player.round_number == 1: incentives = Constants.pwd_rate_high elif player.round_number == 2: incentives = Constants.pwd_rate_low elif player.WTP_sequence == 'LowHigh': if player.round_number == 1: incentives = Constants.pwd_rate_low elif player.round_number == 2: incentives = Constants.pwd_rate_high return dict(rec_points=rec_points, no_rec=no_rec, incentives=incentives) @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.vars[f'WTP_Sequence_{player.round_number}'].append(player.WTP_Dec6) class WTP_Dec7(Page): form_model = 'player' form_fields = ['WTP_Dec7', 'WTP_Dec7_warnings', 'WTP_Dec7_time_spent'] @staticmethod def js_vars(player: Player): return dict(page_name='WTP_Dec7') @staticmethod def vars_for_template(player: Player): p_vars = player.participant.vars upper_bound, lower_bound, midpoint = bisection( p_vars['WTP_upper_bound'], p_vars['WTP_lower_bound'], player.WTP_Dec6 ) p_vars['WTP_upper_bound'] = upper_bound p_vars['WTP_lower_bound'] = lower_bound if player.WTP_Dec1 == True: rec_points = cu(midpoint) no_rec = cu(0) else: rec_points = cu(0) no_rec = cu(-midpoint) if player.WTP_sequence == 'HighLow': if player.round_number == 1: incentives = Constants.pwd_rate_high elif player.round_number == 2: incentives = Constants.pwd_rate_low elif player.WTP_sequence == 'LowHigh': if player.round_number == 1: incentives = Constants.pwd_rate_low elif player.round_number == 2: incentives = Constants.pwd_rate_high return dict(rec_points=rec_points, no_rec=no_rec, incentives=incentives) @staticmethod def before_next_page(player: Player, timeout_happened): p_vars = player.participant.vars p_vars[f'WTP_Sequence_{player.round_number}'].append(player.WTP_Dec7) wtp_upper, wtp_lower, wtp = bisection( p_vars['WTP_upper_bound'], p_vars['WTP_lower_bound'], player.WTP_Dec7 ) if player.WTP_sequence == 'HighLow': if player.round_number == 1: player.WTP_high_highest, player.WTP_high_lowest, player.WTP_high_midpoint = ( wtp_upper, wtp_lower, wtp, ) ( p_vars['WTP_high_highest'], p_vars['WTP_high_lowest'], p_vars['WTP_high_midpoint'], ) = (wtp_upper, wtp_lower, wtp) elif player.round_number == 2: player.WTP_low_highest, player.WTP_low_lowest, player.WTP_low_midpoint = ( wtp_upper, wtp_lower, wtp, ) p_vars['WTP_low_highest'], p_vars['WTP_low_lowest'], p_vars['WTP_low_midpoint'] = ( wtp_upper, wtp_lower, wtp, ) elif player.WTP_sequence == 'LowHigh': if player.round_number == 1: player.WTP_low_highest, player.WTP_low_lowest, player.WTP_low_midpoint = ( wtp_upper, wtp_lower, wtp, ) p_vars['WTP_low_highest'], p_vars['WTP_low_lowest'], p_vars['WTP_low_midpoint'] = ( wtp_upper, wtp_lower, wtp, ) elif player.round_number == 2: player.WTP_high_highest, player.WTP_high_lowest, player.WTP_high_midpoint = ( wtp_upper, wtp_lower, wtp, ) ( p_vars['WTP_high_highest'], p_vars['WTP_high_lowest'], p_vars['WTP_high_midpoint'], ) = (wtp_upper, wtp_lower, wtp) class WTP_Start(Page): form_model = 'player' form_fields = ['WTP_Start_warnings', 'WTP_Start_time_spent'] @staticmethod def js_vars(player: Player): return dict(page_name='WTP_Start') @staticmethod def is_displayed(player: Player): return player.round_number == 1 @staticmethod def vars_for_template(player: Player): if player.WTP_sequence == 'HighLow': if player.round_number == 1: incentives = Constants.pwd_rate_high elif player.round_number == 2: incentives = Constants.pwd_rate_low elif player.WTP_sequence == 'LowHigh': if player.round_number == 1: incentives = Constants.pwd_rate_low elif player.round_number == 2: incentives = Constants.pwd_rate_high max_payoff = (incentives * Constants.num_pwd_tasks) + ( incentives * Constants.num_math_tasks ) ex_pwd = 5 ex_math = 5 example_payoff = (incentives * 5) + (incentives * 5) return dict( incentives=incentives, max_payoff=max_payoff, ex_pwd=ex_pwd, ex_math=ex_math, example_payoff=example_payoff, ) class WTP_Middle(Page): form_model = 'player' form_fields = ['WTP_Middle_warnings', 'WTP_Middle_time_spent'] @staticmethod def js_vars(player: Player): return dict(page_name='WTP_Middle') @staticmethod def is_displayed(player: Player): return player.round_number == 1 @staticmethod def vars_for_template(player: Player): if player.WTP_sequence == 'HighLow': next_incentives = Constants.pwd_rate_low elif player.WTP_sequence == 'LowHigh': next_incentives = Constants.pwd_rate_high max_payoff = (next_incentives * Constants.num_pwd_tasks) + ( next_incentives * Constants.num_math_tasks ) ex_pwd = 5 ex_math = 5 example_payoff = (next_incentives * 5) + (next_incentives * 5) return dict( next_incentives=next_incentives, max_payoff=max_payoff, ex_pwd=ex_pwd, ex_math=ex_math, example_payoff=example_payoff, ) page_sequence = [ Instructions_1, WTP_Instructions, WTP_Start, WTP_Dec1, WTP_Dec2, WTP_Dec3, WTP_Dec4, WTP_Dec5, WTP_Dec6, WTP_Dec7, WTP_Middle, ]