from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) import config_collat import uuid import random import ast debug = True author = "CSN/IFREE REU 2019 oTree Team" doc = """ Full Collateral Game """ class Constants(BaseConstants): """ Description: Inherits oTree Class BaseConstants. Defines constants for the experiment these will remain unchanged Input: uuid - (ID generating package) config_collat - (Dictionary of treatment parameters) Output: None """ group_id = uuid.uuid4() name_in_url = 'Full_Collateral_Game' # name in webbrowser list_of_treatments = config_collat.parameters.keys() randomized_treatments = config_collat.randomized_treatments random.shuffle(randomized_treatments) randomized_treatment = randomized_treatments[0] timer = 15 quiz_answers = [True, 'The lender offers a repayment rate, the borrower offers collateral, the lender' ' offers a loan, the borrower accepts the loan agreement', '1-5', '3', 'The lender', 'The lender can obtain some value from the collateral up to the value minus the collateral fee'] treatment = 'treatment1' # randomized_treatment dic_of_treatment_parameters = config_collat.parameters[treatment] rate_of_return = float(dic_of_treatment_parameters['rate_of_return']) # boolean has not been integrated yet contract_enforcement = eval(dic_of_treatment_parameters['contract_enforcement']) players_per_group = int(dic_of_treatment_parameters["players_per_group"]) num_rounds = int(dic_of_treatment_parameters["num_rounds"]) initial_points = c(dic_of_treatment_parameters["initial_points "]) recovery_fee = c(dic_of_treatment_parameters["recovery_fee"]) productivity = int(dic_of_treatment_parameters["productivity"]) instructions_payoff = c(10) information_score_sheet = 'Full_Collateral_Game/Information_Score_Sheet.html' practice_information_score_sheet = 'Full_Collateral_Game/Information_Score_Sheet_Practice_Lender.html' practice_information_score_sheet= 'Full_Collateral_Game/Information_Score_Sheet_Practice_Borrower.html' '''Quiz Answers''' q2_choices = random.sample([ [1, 'The lender offers a repayment rate, the borrower offers collateral, the lender offers a loan, the borrower accepts the loan agreement'], [2, 'The lender offers a loan and a repayment rate, the borrower offers collateral, the lender accepts the loan agreement'], [3, 'The borrower offers a repayment rateand collateral, the lender offers a loan, the borrower accepts the loan agreement'], [4, 'The borrower offers collateral, the lender offers the loan, the borrower offers a repayment rate, and the lender accepts the loan agreement'], ], 4) q3_choices = random.sample([ [1, '0-10'], [2, '1-10'], [3, '1-5'], [4, '5-10'], ], 4) q4_choices = random.sample([ [1, '1.5'], [2, '2'], [3, '2.5'], [4, '3'], [5, '4'], ], 4) q5_choices = random.sample([ [1, 'A contractual algorithm'], [2, 'The lender'], [3, 'The borrower'], ], 3) q6_choices = random.sample([ [1, 'The lender obtains the full value of the collateral'], [2, 'The lender can obtain additional points from the borrower’s project return'], [3, 'The lender can obtain some value from the collateral up to the value minus the collateral fee'], [4, 'The lender cannot obtain any additional compensation'] ], 4) question_one_solution = True question_two_solution = 1 question_three_solution = 1 question_four_solution = 4 if treatment == 'treatment1' or treatment == 'treatment2': question_five_solution = 2 else: question_five_solution = 1 question_six_solution = 3 class Subsession(BaseSubsession): """ Description: Inherits oTree Class BaseSubsession. Defines subsession for the experiment. Input: None Output: None """ class Group(BaseGroup): ''' Description: Inherits BaseGroup oTree class. Assigns group characteristics. Input: None Output: None ''' # this is here so we can grab its field name treatment = models.CharField(initial=Constants.treatment) treatment_recovery_fee = models.CurrencyField(initial=Constants.recovery_fee) treatment_contract_enforcement = models.BooleanField(initial=Constants.contract_enforcement) rate_of_return = models.FloatField(initial=Constants.rate_of_return) collateral_after_feee = models.CurrencyField() collateral = models.CurrencyField(min=0, max=Constants.initial_points ) loan = models.CurrencyField(min=0, max=Constants.initial_points ) lender_return = models.CurrencyField(min=0) actual_return = models.FloatField() accept_loan = models.CharField( verbose_name='Do you accept and invest the Loan Package ?', choices=['Yes', 'No'], widget=widgets.RadioSelect) satisfied = models.CharField( verbose_name='Are you satisfied with the Outcome?', choices=['Yes', 'No'], widget=widgets.RadioSelect) recovered_collateralral = models.CurrencyField(min=0) returned_collateral = models.CurrencyField() expected_return = models.CurrencyField() expected_borrower_profit = models.CurrencyField() lender_money = models.CurrencyField(initial=Constants.initial_points ) borrower_money = models.CurrencyField(initial=Constants.initial_points ) project_return = models.CurrencyField() def lender_return_max(self): """ Description: Sets a maximum value for the field lender_return Input: Loan - (Global, Stored in models.py, Group, Currency) Productivity - (Global, models.py, Constants, Integer) Output: Max Return - (Loan * Productivity) """ max_return = int(self.loan) * Constants.productivity return max_return def recovered_collateralral_max(self): """ Description: Sets a maximum value for the field recovered_collateralral Input: Value of Collateral - (Global, Stored in models.py, Group, Currency) Output: Max Seized Collateral - (Value of Collateral) """ return self.collateral_after_feee class Player(BasePlayer): """ Description: Inherits oTree class BasePlayer. Defines player characteristics. Input: None Output: None """ money = models.CurrencyField(initial=Constants.initial_points ) def role(self): """ Description: Inherits oTree class BasePlayer. Defines player characteristics. Input: Player - (Player Location) Output: Player Role """ if self.id_in_group == 1: self.participant.vars['role'] = 'lender' return 'lender' if self.id_in_group == 2: self.participant.vars['role'] = 'borrower' return 'borrower' '''Empty variables for the instruction examples that will be defined in the creating_session method above.''' example_loan_amount = models.IntegerField(initial=None) example_return_amount = models.IntegerField(initial=None) example_collateral_amount = models.IntegerField(initial=None) example_salvage_max = models.IntegerField(initial=None) prac_collateral = models.IntegerField(initial=0) prac_collateral_input = models.IntegerField(initial=None) prac_loan_offer = models.IntegerField(initial=None) prac_loan_offer_input = models.IntegerField(initial=None) prac_borrower_money = models.CurrencyField(initial=Constants.initial_points ) prac_lender_money = models.CurrencyField(initial=Constants.initial_points ) prac_project_return = models.CurrencyField() prac_recovered_collateral= models.CurrencyField() prac_returned_collateral = models.CurrencyField() prac_loan_package_decision = models.CharField( choices=['Yes', 'No'], widget=widgets.RadioSelect ) prac_repayment = models.IntegerField(initial=None) prac_repayment_input = models.IntegerField(initial=None) '''def prac_repayment_max(self): return self.prac_repayment * Constants.productivity''' prac_max_return = models.IntegerField(initial=None) prac_collateral_decision = models.CharField( choices=['Yes', 'No'], widget=widgets.RadioSelect ) prac_collateral_after_cost = models.IntegerField(initial=None) prac_recovered_collateral = models.IntegerField(initial=None) prac_collateral_seizure_input = models.IntegerField(initial=None) '''def prac_recovered_collateral_max(self): return self.prac_collateral - Constants.recovery_fee''' current_practice_page = models.IntegerField(initial=1) '''Quiz''' # Counter of the questions answered correctly on the first try num_correct = models.IntegerField(initial=0) quiz_page_counter = models.IntegerField(initial=0) q1_incorrect_attempts = models.IntegerField(initial=0) q1_incorrect = models.IntegerField(initial=0) q1_timeout = models.IntegerField(initial=0) q2_incorrect_attempts = models.IntegerField(initial=0) q2_timeout = models.IntegerField(initial=0) q2_incorrect = models.IntegerField(initial=0) q3_incorrect_attempts = models.IntegerField(initial=0) q3_timeout = models.IntegerField(initial=0) q3_incorrect = models.IntegerField(initial=0) q4_incorrect_attempts = models.IntegerField(initial=0) q4_timeout = models.IntegerField(initial=0) q4_incorrect = models.IntegerField(initial=0) q5_incorrect_attempts = models.IntegerField(initial=0) q5_timeout = models.IntegerField(initial=0) q5_incorrect = models.IntegerField(initial=0) q6_incorrect_attempts = models.IntegerField(initial=0) q6_timeout = models.IntegerField(initial=0) q6_incorrect = models.IntegerField(initial=0) quiz_earnings = models.CurrencyField(initial=0) question_one_response = models.BooleanField(verbose_name='', widget=widgets.RadioSelect, choices=[ [True, 'True'], [False, 'False'], ] ) question_two_response = models.IntegerField(verbose_name='', widget=widgets.RadioSelect, choices=Constants.q2_choices ) question_three_response = models.IntegerField(verbose_name='', widget=widgets.RadioSelect, choices=Constants.q3_choices ) question_four_response = models.IntegerField(verbose_name='', widget=widgets.RadioSelect, choices=Constants.q4_choices ) question_five_response = models.IntegerField(verbose_name='', widget=widgets.RadioSelect, choices=Constants.q5_choices ) question_six_response = models.IntegerField(verbose_name='', widget=widgets.RadioSelect, choices=Constants.q6_choices ) quiz_earnings = models.CurrencyField(initial=0) ''' Endowment: {{Constants.initial_points }} Role: {{player.role}} Productivity: {{Constants.productivity }} repayment rate{{Constants.rate_of_return}} Collateral: {{group.collateral}} Loan: {{group.loan}} Money: {{player.money}} Return: {{group.lender_return}} Expected Borrower Profit: {{group.expected_borrower_profit}} Expected Lender Return: {{group.expected_return}} Salvage Cost: {{Constants.recovery_fee}} Seized Collateral: {{group.recovered_collateralral}} '''