from otree.api import Currency as c, currency_range from ._builtin import Page, WaitPage from .models import Constants import statistics import re import random def c_format(currency): c_str = str(currency) # turn currency into String c_space = re.sub(r"\B(?=(?:\d{3})+\.)", "\xa0", c_str) # add spaces between thousands with regex return c_space.rstrip('0').rstrip('.') # remov trailing zeros # ------------------------------------- # Welcome screens and instructions before the start of the experiment: # ------------------------------------- class Instructions_WelcomeScreen(Page): template_name = 'FR1/Instructions_WelcomeScreen.html' form_model = 'player' form_fields = ['browser_first', 'prolific_id'] def error_message(self, value): # print('prolific id is', value) # print(len(value)) if (value['prolific_id'] == None): return ('Please enter your Prolific ID. Currently, the ID field is empty') elif (len(value['prolific_id']) != 24): id_len = len(value['prolific_id']) return ( 'You Prolific ID is not correct! The ID you inserted has {} characters. The Prolific ID is 24 characters long'.format( id_len)) def is_displayed(self): return self.round_number == 1 def vars_for_template(self): dp = 'This experiment has two rounds. In each of the rounds you are asked to choose between two alternatives, as well as ' \ 'assess the outcomes and riskiness of the two alternatives. We will also ask a few additional questions after the rounds.\n\n ' \ 'The experiment will take approximately 10 minutes. For your participation in this experiment, you will ' \ 'receive a base payment of £2.00 and an additional bonus payment of approximately £1.00. The exact amount of the bonus payment ' \ 'depends on your decisions. The bonus payment will be based on the outcomes of the alternative you choose in the ' \ 'first round or the second round of the experiment. One of these rounds will be randomly selected for the payment.' \ ' You will be informed about the selected round and your exact payment at the end of the experiment.' return {'depend': dp} class Demographics_BeforeExperiment(Page): # template_name = 'FR1/Demographics_BeforeExperiment.html' form_model = 'player' form_fields = ['Demographics_Age', 'Demographics_Sex'] def is_displayed(self): return self.round_number == 1 class Instructions_Payment(Page): template_name = 'FR1/Instructions_Payment.html' def vars_for_template(self): # randomize the payoff example import random inv_asset1 = c(random.randint(0, 10) * (10 ** 3)) # turn the interger into currency inv_asset2 = c(10000) - inv_asset1 r_asset1 = min((random.randint(0, 10) *0.2),2) #+ (0.02 * random.randint(0,4))),2) r_asset2 = random.randint(0, 20) / float(10.0) total_r = (1 + r_asset1) * inv_asset1 + (1 + r_asset2) * inv_asset2 port_return = total_r / 10000 - 1 bonus_pay = c(r_asset1) total_pay = bonus_pay + c(2.0) base_pay = c(2.0) alternative = random.choice([1, 2]) # return percentage to right form def percent_format(d): rendite1 = ' + ' + str("%.1f" % (d * 100)).rstrip('0').rstrip('.') + '%' if d < 0: rendite1 = ' - ' + str("%.1f" % (d * 100))[1:].rstrip('0').rstrip('.') + '%' return rendite1 import re def thousand_format(c): c_str = str(c) # currency to string c_space = re.sub(r"\B(?=(?:\d{3})+\.)", "\xa0", c_str) # add spacec with regex return c_space.rstrip('0').rstrip('.') # print(thousand_format(inv_asset1)) dp = 'In the following, you are asked to select between two different alternatives.' \ ' You are also asked to assess the outcomes and riskiness of the alternatives. ' \ 'You will receive more information about the alternatives soon.\n\n Your bonus payment will be randomly drawn ' \ 'from the outcomes of the alternative that you chose. \n\n' return {'inv_asset1': thousand_format(inv_asset1), 'inv_asset2': thousand_format(inv_asset2), 'total_r': thousand_format(total_r), 'r_asset1': c(r_asset1), 'r_asset2': thousand_format(r_asset2), 'r_plus11': 1 + r_asset1, 'r_plus12': 1 + r_asset2, 'bonus_pay': bonus_pay, 'total_pay': total_pay, 'port_return': percent_format(port_return), 'alternative': alternative, 'base_pay': base_pay, 'depend': dp} def is_displayed(self): return self.round_number == 1 # ------------------------------------- # Experiment: # ------------------------------------- class Instructions_Round1(Page): template_name = 'FR1/Instructions_Round1.html' def vars_for_template(self): if self.player.participant.id_in_session %24 in {1, 4 , 7 , 10 , 13 , 16 , 19 , 22}: dp = 'simulation ' dp2 = 'The outcomes are drawn from the joint distribution of the two alternatives.' else: dp = 'description ' dp2 = '' length = len(self.player.participant.vars['treatment_dists'][self.round_number - 1]) return {'depends': dp, 'depends2': dp2, 'length': length} def is_displayed(self): return self.round_number == 1 class Treatment_L(Page): template_name = 'FR1/Treatment_L.html' def vars_for_template(self): for i in self.player.participant.vars['treatment_dists'][self.round_number - 1]: i[0] = round(i[0], 2) i[1] = round(i[1], 2) return {'title': 'Table_information', 'array': self.player.participant.vars['treatment_dists'][self.round_number - 1], 'image_path': 'FR1/Empty.png' } def is_displayed(self): return self.participant.id_in_session%24 in {1, 7 , 13 , 19} class Treatment_D(Page): form_model = 'player' form_fields = ['clicks'] template_name = 'FR1/Treatment_D.html' def vars_for_template(self): for i in self.player.participant.vars['treatment_dists'][self.round_number - 1]: i[0] = round(i[0], 2) i[1] = round(i[1], 2) i[2] = round(i[2], 2) return {'title': 'Table_information', 'array': self.player.participant.vars['treatment_dists'][self.round_number - 1], 'image_path': 'FR1/Empty.png' } def is_displayed(self): return self.participant.id_in_session%24 in { 4 , 10 , 16 , 22} class TreatmentDE_D(Page): template_name = 'FR1/TreatmentDE_D.html' def vars_for_template(self): def set_color(numb): if (numb < 0): return 'negative' else: return 'positive' def format_percent(numb): return '£' +str((numb)) # create a list containing all information of each row in HTML table table_inputs = [] i = 1 for pair in self.player.participant.vars['treatment_dists'][self.round_number - 1]: if ((pair[1] >0)): table_inputs.append({'color1': set_color(pair[0]), 'r1': str(c(pair[0])), 'color2': set_color(pair[1]), 'r2': '+' + str(c(pair[1])), 'color3': set_color(pair[2]), 'r3': str(c(pair[2])), 'sample_number': i}) i += 1 else: table_inputs.append({'color1': set_color(pair[0]), 'r1': str(c(pair[0])), 'color2': set_color(pair[1]), 'r2': str(c(pair[1])), 'color3': set_color(pair[2]), 'r3': str(c(pair[2])), 'sample_number': i}) i += 1 return {'inputs': table_inputs} def is_displayed(self): return self.participant.id_in_session%24 in { 5 , 11 , 17 , 23} class TreatmentDE_L(Page): template_name = 'FR1/TreatmentDE_L.html' def vars_for_template(self): def set_color(numb): if (numb < 0): return 'negative' else: return 'positive' def format_percent(numb): return '£' + str((numb)) # create a list containing all information of each row in HTML table table_inputs = [] i = 1 for pair in self.player.participant.vars['treatment_dists'][self.round_number - 1]: table_inputs.append({'color1': set_color(pair[0]), 'r1': c(pair[0]), 'color2': set_color(pair[1]), 'r2': c(pair[1]), 'sample_number': i}) i += 1 return {'inputs': table_inputs} def is_displayed(self): return self.participant.id_in_session%24 in {2 , 8 , 14 , 20} class TreatmentDS_D_10(Page): template_name = 'FR1/TreatmentDS_D_10.html' def vars_for_template(self): dp_a = ['£0.20 less than Alternative 1 when Alternative 1 pays £0.20, £0.40, £0.60, …, £2.00 (in 10 out of 11 cases) i.e., it pays £0.00, £0.20, £0.40, …, £1.80.', '£2.00 more than Alternative 1 when Alternative 1 pays £0.00 (in 1 out of 11 cases), i.e., it pays £2.00.'] dp_b = ['£0.20 more than Alternative 1 when Alternative 1 pays £0.00, £0.20, £0.40, …, £1.80 (in 10 out of 11 cases) i.e., it pays £0.20, £0.40, £0.60, …, £2.00.', '£2.00 less than Alternative 1 when Alternative 1 pays £2.00 (in 1 out of 11 cases), i.e., it pays £0.00.'] if self.player.participant.id_in_session%24 in {12, 6}: dp1 = 'Alternative 1 pays each of the 11 outcomes £0.00, £0.20, £0.40, …, £2.00 with equal likelihood.' dp2 = dp_a[self.participant.vars['randomized_order'][0]] dp3 = dp_a[self.participant.vars['randomized_order'][1]] else: dp1 = 'Alternative 1 pays each of the 11 outcomes £0.00, £0.20, £0.40, …, £2.00 with equal likelihood.' dp2 = dp_b[self.participant.vars['randomized_order'][0]] dp3 = dp_b[self.participant.vars['randomized_order'][1]] def set_color(numb): if (numb < 0): return 'negative' else: return 'positive' def format_percent(numb): return '£' +str((numb)) # create a list containing all information of each row in HTML table table_inputs = [] i = 1 for pair in self.player.participant.vars['treatment_dists'][self.round_number - 1]: table_inputs.append({'color1': set_color(pair[0]), 'r1': c(pair[0]), 'color2': set_color(pair[1]), 'r2': c(pair[1]), 'sample_number': i}) i += 1 return {'inputs': table_inputs, 'dp1': dp1, 'dp2': dp2, 'dp3': dp3} def is_displayed(self): return self.participant.id_in_session%24 in {6,12, 18, 0} and len(self.player.participant.vars['treatment_dists'][self.round_number - 1]) < 50 class TreatmentDS_D_100(Page): template_name = 'FR1/TreatmentDS_D_100.html' def vars_for_template(self): dp_a = ['£0.02 less than Alternative 1 when Alternative 1 pays £0.02, £0.04, £0.06, …, £2.00 (in 100 out of 101 cases), i.e., it pays £0.00, £0.02, £0.04, …, £1.98.', ' £2.00 more than Alternative 1 when Alternative 1 pays £0.00 (in 1 out of 101 cases), i.e., it pays £2.00. '] dp_b = [' £0.02 more than Alternative 1 when Alternative 1 pays £0.00, £0.02, £0.04, …, £1.98 (in 100 out of 101 cases), i.e., it pays £0.02, £0.04, £0.06, …, £2.00.', ' £2.00 less than Alternative 1 when Alternative 1 pays £2.00 (in 1 out of 101 cases), i.e., it pays £0.00.'] if self.player.participant.id_in_session%24 in {12, 6}: dp1 = ' Alternative 1 pays each of the 101 outcomes £0.00, £0.02, £0.04, …, £2.00 with equal likelihood.' dp2 = dp_a[self.participant.vars['randomized_order'][0]] dp3 = dp_a[self.participant.vars['randomized_order'][1]] else: dp1 = 'Alternative 1 pays each of the 101 outcomes £0.00, £0.02, £0.04, …, £2.00 with equal likelihood.' dp2 = dp_b[self.participant.vars['randomized_order'][0]] dp3 = dp_b[self.participant.vars['randomized_order'][1]] def set_color(numb): if (numb < 0): return 'negative' else: return 'positive' def format_percent(numb): return '£' +str((numb)) # create a list containing all information of each row in HTML table table_inputs = [] i = 1 for pair in self.player.participant.vars['treatment_dists'][self.round_number - 1]: table_inputs.append({'color1': set_color(pair[0]), 'r1': c(pair[0]), 'color2': set_color(pair[1]), 'r2': c(pair[1]), 'sample_number': i}) i += 1 return {'inputs': table_inputs, 'dp1': dp1, 'dp2': dp2, 'dp3': dp3} def is_displayed(self): return self.participant.id_in_session%24 in {6,12, 18, 0} and len(self.player.participant.vars['treatment_dists'][self.round_number - 1]) > 50 class TreatmentDS_L_10(Page): template_name = 'FR1/TreatmentDS_L_10.html' def vars_for_template(self): dp_a = ['£0.00, £0.20, £0.40, …, £1.80 when Alternative 1 pays £0.20, £0.40, £0.60, …, £2.00 (in 10 out of 11 cases).', '£2.00 when Alternative 1 pays £0.00 (in 1 out of 11 cases).'] dp_b = ['£0.20, £0.40, £0.60, …, £2.00 when Alternative 1 pays £0.00, £0.20, £0.40, …, £1.80 (in 10 out of 11 cases).', '£0.00 when Alternative 1 pays £2.00 (in 1 out of 11 cases).'] if self.player.participant.id_in_session%24 in {3, 9}: dp1 = 'Alternative 1 pays each of the 11 outcomes £0.00, £0.20, £0.40, …, £2.00 with equal likelihood.' dp2 = dp_a[self.participant.vars['randomized_order'][0]] dp3 = dp_a[self.participant.vars['randomized_order'][1]] else: dp1 = 'Alternative 1 pays each of the 11 outcomes £0.00, £0.20, £0.40, …, £2.00 with equal likelihood.' dp2 = dp_b[self.participant.vars['randomized_order'][0]] dp3 = dp_b[self.participant.vars['randomized_order'][1]] def set_color(numb): if (numb < 0): return 'negative' else: return 'positive' def format_percent(numb): return '£' +str((numb)) # create a list containing all information of each row in HTML table table_inputs = [] i = 1 for pair in self.player.participant.vars['treatment_dists'][self.round_number - 1]: table_inputs.append({'color1': set_color(pair[0]), 'r1': c(pair[0]), 'color2': set_color(pair[1]), 'r2': c(pair[1]), 'sample_number': i}) i += 1 return {'inputs': table_inputs, 'dp1': dp1, 'dp2': dp2, 'dp3': dp3} def is_displayed(self): return self.participant.id_in_session%24 in {3, 9, 15, 21} and len(self.player.participant.vars['treatment_dists'][self.round_number - 1]) < 50 class TreatmentDS_L_100(Page): template_name = 'FR1/TreatmentDS_L_100.html' def vars_for_template(self): dp_a = ['£0.00, £0.02, £0.04, …, £1.98 when Alternative 1 pays £0.02, £0.04, £0.06, …, £2.00 (in 100 out of 101 cases).', '£2.00 when Alternative 1 pays £0.00 (in 1 out of 101 cases).'] dp_b = ['£0.02, £0.04, £0.06, …, £2.00 when Alternative 1 pays £0.00, £0.02, £0.04, …, £1.98 (in 100 out of 101 cases).', '£0.00 when Alternative 1 pays £2.00 (in 1 out of 101 cases).'] if self.player.participant.id_in_session%24 in {3, 9}: dp1 = 'Alternative 1 pays each of the 101 outcomes £0.00, £0.02, £0.04, …, £2.00 with equal likelihood.' dp2 = dp_a[self.participant.vars['randomized_order'][0]] dp3 = dp_a[self.participant.vars['randomized_order'][1]] else: dp1 = 'Alternative 1 pays each of the 101 outcomes £0.00, £0.02, £0.04, …, £2.00 with equal likelihood.' dp2 = dp_b[self.participant.vars['randomized_order'][0]] dp3 = dp_b[self.participant.vars['randomized_order'][1]] def set_color(numb): if (numb < 0): return 'negative' else: return 'positive' def format_percent(numb): return '£' +str((numb)) # create a list containing all information of each row in HTML table table_inputs = [] i = 1 for pair in self.player.participant.vars['treatment_dists'][self.round_number - 1]: table_inputs.append({'color1': set_color(pair[0]), 'r1': c(pair[0]), 'color2': set_color(pair[1]), 'r2': c(pair[1]), 'sample_number': i}) i += 1 return {'inputs': table_inputs, 'dp1': dp1, 'dp2': dp2, 'dp3': dp3} def is_displayed(self): return self.participant.id_in_session%24 in {3, 9, 15, 21} and len(self.player.participant.vars['treatment_dists'][self.round_number - 1]) > 50 class Treatment_show_all(Page): template_name = 'FR1/Treatment_show_all.html' def vars_for_template(self): def set_color(numb): if (numb < 0): return 'negative' else: return 'positive' def format_percent(numb): return '£' +str((numb)) # create a list containing all information of each row in HTML table table_inputs = [] i = 0 for pair in self.player.participant.vars['treatment_dists'][self.round_number - 1]: table_inputs.append({'color1': set_color(pair[0]), 'r1': format_percent(pair[0]), 'color2': set_color(pair[1]), 'r2': format_percent(pair[1]), 'sample_number': i}) i += 1 return {'inputs': table_inputs} def is_displayed(self): return self.participant.id_in_session%24 in {1, 7 , 13 , 19, 4 , 10 , 16 , 22 } class Task_Decision(Page): template_name = 'FR1/Task_Decision.html' form_model = 'player' form_fields = ['InvestmentEitherOr'] def vars_for_template(self): a = self.player.clicks return {'clicks': a} #class Task_BeliefsDependence(Page): # # template_name = 'FR1/Task_BeliefsDependence.html' # form_model = 'player' # form_fields = ['BeliefsDependence_FreqComove1', 'BeliefsDependence_FreqComove2', 'BeliefsDependence_FreqOutperf'] class Task_BeliefsAssets(Page): # template_name = 'PRE1/Task_BeliefsAssets.html' form_model = 'player' form_fields = ['Average_of_A', 'Average_of_B','How_Risky_A','How_Risky_B'] class Task_BeliefsPortfolio(Page): # template_name = 'FR1/Task_BeliefsPortfolio.html' form_model = 'player' form_fields = ['How_Risky_A', 'How_Risky_B'] class Instructions_Round2(Page): template_name = 'FR1/Instructions_Round2.html' def is_displayed(self): return self.round_number == 1 # return self.round_number == Constants.num_page def vars_for_template(self): if self.player.participant.id_in_session%24 in {1, 4, 7, 10, 13, 16, 19, 22}: dp = 'simulation ' dp2 = 'The outcomes are drawn from the joint distribution of the two alternatives.' else: dp = 'description ' dp2 = '' length = len(self.player.participant.vars['treatment_dists'][self.round_number]) return {'dp1': dp, 'dp2': dp2, 'length': length} # 'Next, you will see a return simulation of 50 possible returns for both assets. This simulation will give you an impression of the joint asset returns. The returns are drawn at random from the joint return distribution of the two assets. Take as much time as you need to view this return simulation.' class Task_RoundComparison(Page): # template_name = 'FR1/Task_RoundComparison.html' form_model = 'player' form_fields = ['ComparisonRounds_Risk', 'ComparisonRounds_Return'] def is_displayed(self): return self.round_number == Constants.num_rounds # ------------------------------------- # Questionnaire after experiment: # ------------------------------------- class Task_ReasonsForDecision(Page): template_name = 'FR1/Task_ReasonsForDecision.html' form_model = 'player' form_fields = ['GenReasons_Mu_Consider', 'GenReasons_SigmaPL_Consider', #'GenReasons_Rho_Consider', 'GenReasons_PD_Consider' ] def is_displayed(self): return self.round_number == Constants.num_rounds class Task_ReasonsContinue(Page): template_name = 'FR1/Task_ReasonsContinue.html' form_model = 'player' # select the questions asked based on the Task_ReasonsForDecision answers def get_form_fields(self): form_fields = [] player = self.player if player.GenReasons_Mu_Consider == 2: form_fields.append('GenReasons_Mu_Direction') if player.GenReasons_SigmaPL_Consider == 2: form_fields.append('GenReasons_SigmaPL_Direction') # if player.GenReasons_Rho_Consider == 2: # form_fields.append('GenReasons_Rho_Direction') if player.GenReasons_PD_Consider == 2: form_fields.append('GenReasons_PD_Direction') return form_fields def is_displayed(self): right_round = self.round_number == Constants.num_rounds player = self.player right_ans = player.GenReasons_Mu_Consider == 2 or player.GenReasons_SigmaPL_Consider == 2 or player.GenReasons_PD_Consider == 2 return (right_round and right_ans) class Demographics_2(Page): form_model = 'player' form_fields = ['DJ30PF_Return', 'DJ30PF_Risk'] def is_displayed(self): return self.round_number == Constants.num_rounds class Demographics_1(Page): # template_name = 'FR1/Demographics_1.html' form_model = 'player' form_fields = ['Demographics_RiskAffinity', 'Demographics_Statistics'] def is_displayed(self): return self.round_number == Constants.num_rounds def before_next_page(self): datArray = self.player.participant.vars['treatment_dists'][self.round_number - 1] # if self.player.in_round(1).invest_first == 0: # asset1Perc = float(self.player.in_round(self.player.in_round(1).paid_subsection).InvestmentAsset1) / 10000 # asset2Perc = float(self.player.in_round(self.player.in_round(1).paid_subsection).InvestmentAsset2) / 10000 portRet = [] num_port_Neg = 0 # for i in range(len(datArray)): # portRet.append(datArray[i][0] * asset1Perc + datArray[i][1] * asset2Perc) # for i in range(len(portRet)): # if portRet[i] < 0: # num_port_Neg = num_port_Neg + 1 # self.player.in_round(self.player.in_round(1).paid_subsection).BeliefsPortfolio_Mu_Res = statistics.median( # portRet) * 100 # self.player.in_round(self.player.in_round(1).paid_subsection).BeliefsPortfolio_PLoss_Res = num_port_Neg * 2 self.player.set_payoffs() # ------------------------------------- # Payment and link to Prolific: # ------------------------------------- class FinalPaymentInformation(Page): template_name = 'FR1/FinalPaymentInformation.html' form_model = 'player' form_fields = ['Satisfaction', 'OpenFeedback'] def is_displayed(self): return self.round_number == Constants.num_rounds def vars_for_template(self): # return percentage to right form rendite1 = "" rendite2 = "" if self.player.in_round(1).invest_first == 1: rendite1 = ' + ' + str("%.1f" % (self.player.paid_rendite1 * 100)).rstrip('0').rstrip('.') if self.player.paid_rendite1 < 0: rendite1 = ' - ' + str("%.1f" % (self.player.paid_rendite1 * 100))[1:].rstrip('0').rstrip('.') rendite2 = ' + ' + str("%.1f" % (self.player.paid_rendite2 * 100)).rstrip('0').rstrip('.') if self.player.paid_rendite2 < 0: rendite2 = ' - ' + str("%.1f" % (self.player.paid_rendite2 * 100))[1:].rstrip('0').rstrip('.') # Change currency to right form import re def right_form(c): c_str = str(c) # currency to string c_space = re.sub(r"\B(?=(?:\d{3})+\.)", " ", c_str) # add spacec with regex return c_space.rstrip('0').rstrip('.') # remove trailing zeros # portfolio_val = right_form(self.player.payoff_100) payoff_val = self.player.payoff input1 = right_form(self.player.paid_input1) input2 = right_form(self.player.paid_input2) total_pay = c(2.00) + payoff_val alternative = self.player.in_round(self.player.in_round(1).paid_subsection).InvestmentEitherOr original_draw = payoff_val / (2/5) payoff_other = c(self.participant.vars['payoff_other']) if alternative == "Alternative 2": alternative_other = "Alternative 1" else: alternative_other = "Alternative 2" # if index_temp == 4 or index_temp == 5 or index_temp == 8: # response = str(round(response, 2)) + ' %' # real_response = str(round(real_response, 2)) + ' %' return {'runde': self.player.pay_round_num, 'original_draw': original_draw, 'percent_1': rendite1, 'percent_2': rendite2, 'payoff': payoff_val, 'paid_input1': input1, 'paid_input2': input2, 'total_pay': total_pay, 'random_question_index': self.player.in_round(1).random_question_index, 'random_question_round': self.player.in_round(1).paid_subsection, 'invest_first': self.player.in_round(1).invest_first, 'short_q': self.player.in_round(1).short_q, 'alternative': alternative, 'payoff_other': payoff_other, 'alternative_other': alternative_other } class LinkToProlific(Page): template_name = 'FR1/LinkToProlific.html' def is_displayed(self): return self.round_number == Constants.num_rounds # ------------------------------------- # Page sequence # ------------------------------------- page_sequence = ( Instructions_WelcomeScreen, Demographics_BeforeExperiment, Instructions_Payment, Instructions_Round1, TreatmentDE_D, TreatmentDE_L, TreatmentDS_D_10, TreatmentDS_D_100, TreatmentDS_L_10, TreatmentDS_L_100, Treatment_D, Treatment_L, #Treatment_show_all, Task_Decision, #Task_BeliefsDependence, Task_BeliefsAssets, #Task_BeliefsPortfolio, Instructions_Round2, #Task_RoundComparison, Task_ReasonsForDecision, Task_ReasonsContinue, Demographics_1, #Demographics_2, FinalPaymentInformation, LinkToProlific )