from otree.api import * doc = """ instructions of baseline treatment for the experiment two currencies """ try: import xlrd except: import os os.system('pip install xlrd') import xlrd # def get_block_length(file_path): # work_book = xlrd.open_workbook(filename=file_path) # sheet = work_book.sheet_by_index(0) # return int(sheet.col_values(1)[1]) class C(BaseConstants): NAME_IN_URL = 'instructions_baseline' table_a_template = 'instructions_baseline/cost_benefit_marketA.html' instructions_template = 'instructions_baseline/instructions_content.html' common_style_template = 'instructions_baseline/common_style.html' excel_path = "configs/config.xlsx" PLAYERS_PER_GROUP = None NUM_ROUNDS = 1 NUM_RED_TOKENS = 5 NUM_GREEN_TOKENS = 5 DICE_MAX = 10 DELTA = 0.90 # BLOCK_SIZE = get_block_length(excel_path) BLOCK_SIZE = 10 MAX_PRODUCE = 20 class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): q1 = models.IntegerField(label="How many markets are there in each period?") q2 = models.BooleanField(widget=widgets.RadioSelect, choices=[[True, 'Yes'], [False, 'No']], label="Can you choose whether you are a producer or a consumer in any market?") q3 = models.BooleanField(widget=widgets.RadioSelect, choices=[[True, 'True'], [False, 'False']], label="If you are a producer in a market, you can bid tokens to buy and consume in that market.") q4 = models.BooleanField(widget=widgets.RadioSelect, choices=[[True, 'True'], [False, 'False']], label="If you are a producer in market A, you will be a consumer in market B.") q5a = models.BooleanField(widget=widgets.RadioSelect, choices=[[True, 'Yes'], [False, 'No']], label="Does your token balance carry over from period to period?") q5b = models.BooleanField(widget=widgets.RadioSelect, choices=[[True, 'Yes'], [False, 'No']], label="From sequence to sequence?") q6 = models.IntegerField(widget=widgets.RadioSelect, choices=[[1, 'a. Producers may get a consumption benefit in the next market.'], [2, 'b. Producers get a gain of tokens.'], [3, 'c. Both (a) and (b) are correct.'], [4, 'd. None of the above are correct.']], label="Producing goods is costly and subtracts points from your point total. What is the benefit of producing?") q7a = models.FloatField(min=-100, label="What is your payoff in points from market A? (Use the middle column of Table A)") q7b1 = models.FloatField(label="How many red tokens do you earn by selling good A?") q7b2 = models.FloatField(label="How many green tokens do you earn by selling good A?") q7c = models.FloatField(label="How many units of Good B are you able to buy and consume if you bid all the tokens earned in market A?") q7d = models.FloatField(label="What is your payoff in points from market B? (Use the last column of Table B)") q7e = models.FloatField(label="What is your total payoff in points from market A and market B?") q8 = models.BooleanField(widget=widgets.RadioSelect, choices=[[True, 'True'], [False, 'False']], label="The total amount of tokens in the economy is constant.") q9 = models.BooleanField(widget=widgets.RadioSelect, choices=[[True, 'True'], [False, 'False']], label="Your point total from all sequences are converted into dollars and paid to you in " "cash at the end of the experiment.") q10 = models.BooleanField(widget=widgets.RadioSelect, choices=[[True, 'True'], [False, 'False']], label="Tokens are converted to dollar earnings at the end of the experiment.") q11a = models.FloatField(min=0, max=1, label="Suppose it is period 2 of a sequence. What is the probability that the sequence continues with a period 3?") q11b = models.BooleanField(widget=widgets.RadioSelect, choices=[[True, 'Yes'], [False, 'No']], label="Would your answer be any different if we replaced period 2 with period 12 and period 3 with period 13?") q12 = models.BooleanField(widget=widgets.RadioSelect, choices=[[True, 'True'], [False, 'False']], label=f"Each sequence begins with a {C.BLOCK_SIZE} period block.") q13 = models.BooleanField(widget=widgets.RadioSelect, choices=[[True, 'True'], [False, 'False']],) #FUNCTIONS # benefit for consumer in market A def ua(x): beta = 2.6563 eta = 0.37851 return beta * (pow(x, 1 - eta) / (1 - eta)) # benefit for consumer in market B def ub(x): v0 = 8 return v0 + x # cost for producer in both Market A and Market B def cost(x): return x # Table A def market_a_table(X): table = [] for x in range(X): produce_cost = cost(x) consume_benefit = ua(x) row = dict(quantity=x, cost=produce_cost, benefit="{:.2f}".format(consume_benefit)) table.append(row) return table def market_a_chart(X): produce_cost = [] consume_benefit = [] for x in range(X): produce_cost.append(cost(x)) consume_benefit.append(round(ua(x),2)) return dict(cost=produce_cost, benefit=consume_benefit) # Table B def market_b_table(X): table = [] for x in range(X): produce_cost = cost(x) consume_benefit = ub(x) row = dict(quantity=x, cost=produce_cost, benefit="{:.2f}".format(consume_benefit)) table.append(row) return table def market_b_chart(X): produce_cost = [] consume_benefit = [] for x in range(X): produce_cost.append(cost(x)) consume_benefit.append(round(ub(x),2)) return dict(cost=produce_cost, benefit=consume_benefit) #get the list of dice that ends the sequence def get_end_dice(): dice_continue_max = int(C.DICE_MAX * C.DELTA) all_dice = [i + 1 for i in list(range(C.DICE_MAX))] dice_continue = [i + 1 for i in list(range(dice_continue_max))] dice_end_list = [i for i in all_dice if i not in dice_continue] if len(dice_end_list) == 1: dice_end = dice_end_list[0] else: dice_end = ' or '.join([str(i) for i in dice_end_list]) return dice_end def get_quiz_data(player: Player): return [ dict( name='q1', solution=2, explanation="All participants will interact in two markets, called \"market A\" and \"market B\". ", ), dict( name='q2', solution=False, explanation="Your roles in these markets are determined randomly at the beginning of the experiment. " "Half of you will always be consumers in market A and producers in market B; the other half will " "always be producers in market A and consumers in market B.", ), dict( name='q3', solution=False, explanation="You can sell your output to exchange for any type of token," " and then use the tokens to buy goods in the next market where you are a consumer.", ), dict( name='q4', solution=True, explanation="Markets A and B alternate over time, so if you are a consumer in the current market, " "you will be a producer in the following market, and vice versa.", ), dict( name='q5a', solution=True, explanation="Within a sequence, tokens and point totals carry over from the current period to the next.", ), dict( name='q5b', solution=False, explanation="Tokens held at the end of a sequence cannot be carried to a new sequence and have no redemption value.", ), dict( name='q6', solution=3, explanation="When you decide how much to produce, notice the tradeoff between the production cost " "(incurred in the current market) and consumption benefit (to be realized in the next market).", ), dict( name='q7a', solution=-6, explanation="According to Table A, the Produce-and-Sell cost of producing (3+3) = 6 units of the good is 6 points. ", ), dict( name='q7b1', solution=6, explanation="2x3=6", ), dict( name='q7b2', solution=9, explanation="3x3=9", ), dict( name='q7c', solution=6, explanation="6/2+9/3=6", ), dict( name='q7d', solution=14, explanation="According to Table B, the Buy-and-Consume benefit of consuming 6 units of the good is 14 points.", ), dict( name='q7e', solution=8, explanation="14-6=8", ), dict( name='q8', solution=True, explanation="The total amount of tokens in the economy is always constant.", ), dict( name='q9', solution=True, explanation=f"The point total from all sequences will be converted into cash at the rate of 1 point " f"= ${player.session.config['real_world_currency_per_point']}.", ), dict( name='q10', solution=False, explanation="Tokens held at the end of a sequence cannot be carried to a new sequence and have no redemption value", ), dict( name='q11a', solution=0.9, explanation="After each period, there is always a 90% (probability 0.9) chance the sequence " "continues to a new period and a 10% (probability 0.1) chance the sequence ends", ), dict( name='q11b', solution=False, explanation="The probability that the sequence continues to a new period is the same after every period.", ), dict( name='q12', solution=True, explanation="The first 10 periods of a sequence are called a block.", ), dict( name='q13', solution=True, explanation="At the end of a block, you learn the realization of the random draws for all 10 periods in the " "block and therefore whether the sequence has actually ended. If the number \"10\" is drawn anytime " "within the block, the sequence has ended. The final period of the sequence is the first period " "where a \"10\" is drawn. Your decisions after the final period are ignored and do not count " "towards your final earnings.", ), ] # PAGES class Instructions(Page): @staticmethod def vars_for_template(player: Player): Q = 20 return dict( participation_fee=player.session.config['participation_fee'], conversion_rate=player.session.config['real_world_currency_per_point'], num_participants=player.session.num_participants, num_tokens=C.NUM_RED_TOKENS * C.NUM_GREEN_TOKENS, dice_continue_max=int(C.DICE_MAX * C.DELTA), dice_end=get_end_dice(), p_continue=int(100 * C.DELTA), p_end=100 - int(100 * C.DELTA), new_block_period=C.BLOCK_SIZE + 1, table_a=market_a_table(Q + 1), table_b=market_b_table(Q + 1), market_a_example_benefit="{:.2f}".format(ua(7)), market_a_chart=market_a_chart(Q+1) ) @staticmethod def js_vars(player: Player): market1 = market_a_chart(21) cost1 = market1['cost'] benefit1 = market1['benefit'] market2 = market_b_chart(21) cost2 = market2['cost'] benefit2 = market2['benefit'] return dict( highcharts_series_1=[{'name': "Cost of Production", 'data': cost1}, {'name': "Benefit of Consumption", 'data': benefit1}], highcharts_series_2=[{'name': "Cost of Production", 'data': cost2}, {'name': "Benefit of Consumption", 'data': benefit2}], ) class ResultsWaitPage(WaitPage): pass class Quiz(Page): form_model = 'player' form_fields = ['q1', 'q2', 'q3', 'q4', 'q5a', 'q5b', 'q6', 'q7a', 'q7b1','q7b2', 'q7c', 'q7d', 'q7e', 'q8', 'q9', 'q10', 'q11a', 'q11b', 'q12', 'q13'] @staticmethod def vars_for_template(player: Player): Q = 20 return dict( dice_end=get_end_dice(), participation_fee=player.session.config['participation_fee'], conversion_rate=player.session.config['real_world_currency_per_point'], num_participants=player.session.num_participants, num_tokens=C.NUM_RED_TOKENS * C.NUM_GREEN_TOKENS, dice_continue_max=int(C.DICE_MAX * C.DELTA), p_continue=int(100 * C.DELTA), p_end=100 - int(100 * C.DELTA), new_block_period=C.BLOCK_SIZE + 1, table_a=market_a_table(Q + 1), table_b=market_b_table(Q + 1), market_a_example_benefit="{:.2f}".format(ua(7)) ) @staticmethod def js_vars(player: Player): market1 = market_a_chart(21) cost1 = market1['cost'] benefit1 = market1['benefit'] market2 = market_b_chart(21) cost2 = market2['cost'] benefit2 = market2['benefit'] return dict( highcharts_series_1=[{'name': "Cost of Production", 'data': cost1}, {'name': "Benefit of Consumption", 'data': benefit1}], highcharts_series_2=[{'name': "Cost of Production", 'data': cost2}, {'name': "Benefit of Consumption", 'data': benefit2}], ) class QuizResults(Page): form_model = 'player' form_fields = ['q1', 'q2', 'q3', 'q4', 'q5a', 'q5b', 'q6', 'q7a', 'q7b1','q7b2', 'q7c', 'q7d', 'q7e', 'q8', 'q9', 'q10', 'q11a', 'q11b', 'q12', 'q13'] @staticmethod def vars_for_template(player: Player): Q = 20 fields = get_quiz_data(player) # we add an extra key 'is_correct' to each field for d in fields: d['is_correct'] = getattr(player, d['name']) == d['solution'] return dict(q1=fields[0], q2=fields[1], q3=fields[2], q4=fields[3], q5a=fields[4], q5b=fields[5], q6=fields[6], q7a=fields[7], q7b1=fields[8], q7b2=fields[9], q7c=fields[10], q7d=fields[11], q7e=fields[12], q8=fields[13], q9=fields[14], q10=fields[15], q11a=fields[16], q11b=fields[17], q12=fields[18], q13=fields[19], participation_fee=player.session.config['participation_fee'], conversion_rate=player.session.config['real_world_currency_per_point'], num_participants=player.session.num_participants, num_tokens=C.NUM_RED_TOKENS * C.NUM_GREEN_TOKENS, dice_continue_max=int(C.DICE_MAX * C.DELTA), dice_end=get_end_dice(), p_continue=int(100 * C.DELTA), p_end=100 - int(100 * C.DELTA), new_block_period=C.BLOCK_SIZE + 1, table_a=market_a_table(Q + 1), table_b=market_b_table(Q + 1), market_a_example_benefit="{:.2f}".format(ua(7)) ) page_sequence = [Instructions, Quiz, QuizResults]