from otree.api import Currency as c, currency_range from ._builtin import Page, WaitPage from .models import Constants #------------------------------------- # Welcome screens and instructions before the start of the experiment: #------------------------------------- class Instructions_WelcomeScreen(Page): template_name = 'PDE1/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 class Demographics_BeforeExperiment(Page): # template_name = 'PDE1/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 = 'PDE1/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 = random.randint(-3,3)/10 r_asset2 = random.randint(-3,3)/10 total_r = (1+r_asset1)*inv_asset1 + (1+r_asset2)*inv_asset2 bonus_pay = c(total_r/10000) total_pay = bonus_pay + c(2.5) # 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)) return {'inv_asset1': thousand_format(inv_asset1), 'inv_asset2': thousand_format(inv_asset2), 'total_r': thousand_format(total_r), 'r_asset1': percent_format(r_asset1), 'r_asset2': percent_format(r_asset2), 'r_plus11': 1+r_asset1, 'r_plus12': 1+r_asset2, 'bonus_pay': bonus_pay, 'total_pay': total_pay} def is_displayed(self): return self.round_number == 1 # class Instructions_InvestmentDecision(Page): # template_name = 'PDE1/Instructions_InvestmentDecision.html' # # def is_displayed(self): # return self.round_number == 1 #------------------------------------- # Experiment: #------------------------------------- class Instructions_Round1(Page): template_name = 'PDE1/Instructions_Round1.html' def vars_for_template(self): return {'depends': 'Next, you will see a return simulation of 100 possible returns for assets 1 and 2. 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.'} # STILL NEEDS TO BE IMPLEMENTD vary instructions depending on the presentation format # if self.player.in_round(1).format == 0: # Sampling treatment # return {'depends': 'Next, you will see a return simulation of 100 possible returns for assets 1 and 2. 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.'} # elif self.player.in_round(1).format == 1: # Description treatment with return pairs in table # return {'depends': 'Next, you will see the possible returns for assets 1 and 2 in a table, along with the probability for joint returns. The table will give you an impression of the joint asset returns. Take as much time as you need to view this return table.'} # else: # Description treatment "two-dimensional" # return {'depends': 'Next, you will see the possible returns for assets 1 and 2 in a table, along with the probability for joint returns. The table will give you an impression of the joint asset returns. Take as much time as you need to view this return table.'} def is_displayed(self): return self.round_number == 1 class Treatment(Page): template_name = 'PDE1/Treatment.html' def vars_for_template(self): return {'title': 'Table_information', 'array': self.player.participant.vars['treatment_dists'][self.round_number-1], 'image_path':'PDE1/Empty.png' } class Treatment_show_all(Page): template_name = 'PDE1/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(round(numb*100))+'%' # 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':format_percent(pair[0]), 'color2': set_color(pair[1]), 'r2': format_percent(pair[1]), 'sample_number': i}) i += 1 return {'inputs' : table_inputs} class Task_InvestmentDecision(Page): # template_name = 'PDE1/Task_InvestmentDecision.html' form_model = 'player' form_fields = ['InvestmentAsset1', 'InvestmentAsset2'] # not used: 'InvestmentEitherOr' def error_message(self, values): if values["InvestmentAsset1"] + values["InvestmentAsset2"] != 10000: return 'The two investments have to add up to exactly £10\xa0000.' class Task_BeliefsDependence(Page): # template_name = 'PDE1/Task_BeliefsDependence.html' form_model = 'player' form_fields = ['BeliefsDependence_Overall', 'BeliefsDependence_Direction1', 'BeliefsDependence_Direction2'. 'BeliefsDependence_FreqComove1', 'BeliefsDependence_FreqComove2'] # NOT USED # class Task_BeliefsAssets(Page): # # template_name = 'PRE1/Task_BeliefsAssets.html' # form_model = 'player' # form_fields = ['BeliefsDependence_Mu1', 'BeliefsDependence_Mu2', 'BeliefsDependence_PLoss1', 'BeliefsDependence_PLoss2','BeliefsAssets_SubjRisk1','BeliefsAssets_SubjRisk2'] class Task_BeliefsPortfolio(Page): # template_name = 'PDE1/Task_BeliefsPortfolio.html' form_model = 'player' form_fields = ['BeliefsPortfolio_Mu', 'BeliefsPortfolio_PLoss', 'BeliefsPortfolio_SubjRisk'] class Instructions_Round2(Page): template_name = 'PDE1/Instructions_Round2.html' def is_displayed(self): return self.round_number == 1 # return self.round_number == Constants.num_page def vars_for_template(self): return {'depends': '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.'} # STILL NEEDS TO BE IMPLEMENTD vary instructions depending on the presentation format # if self.player.in_round(1).format == 0: # Sampling treatment # return {'depends': 'Next, you will see a return simulation of 100 possible returns for assets 1 and 2. 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.'} # elif self.player.in_round(1).format == 1: # Description treatment with return pairs in table # return {'depends': 'Next, you will see the possible returns for assets 1 and 2 in a table, along with the probability for joint returns. The table will give you an impression of the joint asset returns. Take as much time as you need to view this return table.'} # else: # Description treatment "two-dimensional" # return {'depends': 'Next, you will see the possible returns for assets 1 and 2 in a table, along with the probability for joint returns. The table will give you an impression of the joint asset returns. Take as much time as you need to view this return table.'} # NOT USED # class Task_RoundComparison(Page): # # template_name = 'PDE1/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: #------------------------------------- # NOT USED ''' class Task_ReasonsForDecision(Page): template_name = 'PDE1/Task_RFD.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 = 'PDE1/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_Rho_Consider==2 or player.GenReasons_PD_Consider==2 return (right_round and right_ans) ''' class Demographics_1(Page): # template_name = 'PDE1/Demographics_1.html' form_model = 'player' form_fields = ['Demographics_FinInterest', 'Demographics_Investor', 'Demographics_FinanceProf', 'Demographics_RiskAffinity', 'Demographics_Statistics'] def is_displayed(self): return self.round_number == Constants.num_rounds # NOT USED ''' class Demographics_2(Page): # template_name = 'PDE1/Demographics_2.html' form_model = 'player' form_fields = ['DJ30PF_Return', 'DJ30PF_Risk'] # calls set_payoffs() on player before next page [MU: is this the right place???. ANS: yes, just before the final payoff page] def before_next_page(self): self.player.set_payoffs() def is_displayed(self): return self.round_number == Constants.num_rounds ''' #------------------------------------- # Payment and link to Prolific: #------------------------------------- class FinalPaymentInformation(Page): template_name = 'PDE1/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 = ' + ' + 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.50) + payoff_val return {'runde': self.player.pay_round_num, 'percent_1': rendite1, 'percent_2': rendite2, 'payoff': payoff_val, 'payoff_100': portfolio_val, 'paid_input1': input1, 'paid_input2': input2, 'total_pay': total_pay } class LinkToProlific(Page): template_name = 'PDE1/LinkToProlific.html' def is_displayed(self): return self.round_number == Constants.num_rounds #------------------------------------- # Page sequence #------------------------------------- page_sequence = ( Instructions_WelcomeScreen, Demographics_BeforeExperiment, Instructions_Payment, #Instructions_InvestmentDecision, Instructions_Round1, Treatment, #Treatment_show_all, Task_InvestmentDecision, Task_BeliefsDependence, #Task_BeliefsAssets, Task_BeliefsPortfolio, Instructions_Round2, #Task_RoundComparison, #Task_ReasonsForDecision, #Task_ReasonsContinue, Demographics_1, Demographics_2, FinalPaymentInformation, LinkToProlific )