from otree.api import * import time import math import copy as cp import time import numpy as np import random from . import functions as f doc = """ main task of baseline treatment for the experiment two currencies """ class C(BaseConstants): NAME_IN_URL = 'experiment_baseline' table_style_template = 'experiment_baseline/table_style.html' common_style_template = 'experiment_baseline/common_style.html' instructions_baseline_template = "instructions_baseline/instructions_content.html" fixTop_template = 'experiment_baseline/fixTop.html' block_dierolls_template = 'experiment_baseline/block_dierolls.html' history_template = 'experiment_baseline/history.html' PLAYERS_PER_GROUP = None NUM_ROUNDS = 0 DICE_MAX = 10 DELTA = 0.90 # BLOCK_SIZE = 10 MAX_PRODUCE = 20 # Excel path # change exel file xlsx to xls since the xlrd package does not support the former format now excel_path = "configs/config1.xls" show_up_fee = f.get_show_up_fee(excel_path) # Total participants # players_per_group = get_participant(excel_path) # Experiment max round # num_rounds = 5 # If period meet this value, check previous random number. # block_length = f.get_block_length(excel_path) block_length = 3 print("Block length: ", block_length) blp1 = block_length + 1 # Experiment period end time, unit: second experiment_max_time_second = f.get_experiment_timeout(excel_path) print("Experiment max time second: ", experiment_max_time_second) # TODO: uncomment for actual experiment # Get each sequence ending period # sequence_period_list = f.read_sequence_random_number(excel_path) # Testing sequence_period_list = [1, 6] print("Sequence period list: ", sequence_period_list) sequence_duration_list = [] for i in sequence_period_list: if i >= block_length: sequence_duration_list.append(i) else: sequence_duration_list.append(block_length) print("Sequence duration list:", sequence_duration_list) # Get each sequence ending round number out of total number of periods across all sequences from itertools import accumulate sequence_end_periods = list(accumulate(sequence_duration_list)) print("Sequence end list: ", sequence_end_periods) # Get each sequence starting round number out of total number of periods across all sequences sequence_start_periods = [1] + [r + 1 for r in sequence_end_periods[0:-1]] print('sequence start list:', sequence_start_periods) # Max sequence max_sequence = len(sequence_period_list) # Critical period value for period in sequence_period_list: if period < block_length: NUM_ROUNDS += block_length else: NUM_ROUNDS += period print("NUM_ROUNDS: ", NUM_ROUNDS) critical_period_value = f.get_critical_period_value(excel_path) # Critical lower period timeout critical_period_timeout_lower = f.get_critical_period_timeout_lower(excel_path) # Critical upper period timeout critical_period_timeout_upper = f.get_critical_period_timeout_upper(excel_path) # Block check timeout block_check_timeout = f.get_block_check_timeout(excel_path) # Introduction page timeout introduction_timeout = f.get_introduction_timeout(excel_path) # Decision page timeout decision_timeout = f.get_decision_timeout(excel_path) # Starting red tokens starting_tokens_red = f.get_starting_red_tokens(excel_path) # Starting green tokens starting_tokens_green = f.get_starting_green_tokens(excel_path) # Conversion rate conversion_rate = f.get_conversion_rate(excel_path) class Subsession(BaseSubsession): pass class Group(BaseGroup): # Random number [1, 10] random_number = models.IntegerField() # Market total planning produce Good A in red tokens totalProduce1Red = models.FloatField(initial=0) # Market total planning produce Good A in green tokens totalProduce1Green = models.FloatField(initial=0) # Market total planning produce Good B in red tokens totalProduce2Red = models.FloatField(initial=0) # Market total planning produce Good B in green tokens totalProduce2Green = models.FloatField(initial=0) # Market total planning bid for good A in red tokens totalSpend1Red = models.FloatField(initial=0) # Market total planning bid for good A in green tokens totalSpend1Green = models.FloatField(initial=0) # Market total planning bid for good B in red tokens totalSpend2Red = models.FloatField(initial=0) # Market total planning bid for good B in green tokens totalSpend2Green = models.FloatField(initial=0) # Current market 0 means A, 1 means B current_market = models.IntegerField(initial=0) # Track whether period counts towards final payout sequenceOver = models.BooleanField(initial=False) class Player(BasePlayer): # Sequence of current experiment_constant sequence = models.IntegerField(initial=1) # Period of current sequence period = models.IntegerField(initial=1) # role: '1.consumer.2.producer' or '1.producer.2.consumer' type = models.StringField(initial="-1") # Prices of good A in red token and green token Price1Red = models.FloatField(initial=-1) Price1Green = models.FloatField(initial=-1) # Prices of good B in red token and green token Price2Red = models.FloatField(initial=-1) Price2Green = models.FloatField(initial=-1) BalanceRed = models.FloatField(initial=-1) BalanceGreen = models.FloatField(initial=-1) BalanceRedStart1 = models.FloatField(initial=-1) BalanceGreenStart1 = models.FloatField(initial=-1) BalanceRedStart2 = models.FloatField(initial=-1) BalanceGreenStart2 = models.FloatField(initial=-1) # 1.Consumer.2.Producer # Total units of good A consumed Consume1 = models.FloatField(initial=-1) Consume1Red = models.FloatField(initial=-1) Consume1Green = models.FloatField(initial=-1) # Market A payoff Payoff1 = models.FloatField(initial=-1) # How many red tokens to bid to buy good A Spend1Red = models.FloatField(min=0, label="Amount of red tokens you would like to spend on good A (choose between 0 and " "red token holding).") # How many green tokens to bid to buy good A Spend1Green = models.FloatField(min=0, label="Amount of green tokens you would like to spend on good A (choose between 0 " "and green token holding).") Produce2Red = models.FloatField(min=0, max=20.00, label="The amount of good B you plan to produce for red tokens.") Produce2Green = models.FloatField(min=0, max=20.00, label="The amount of good B you plan to produce for green tokens.") Spend1RedFinal = models.FloatField(initial=0) Spend1GreenFinal = models.FloatField(initial=0) Produce2RedFinal = models.FloatField(initial=0) Produce2GreenFinal = models.FloatField(initial=0) # Total units of good A to produce Produce2 = models.FloatField(initial=-1, min=0, max=20.00) # Red and Green tokens earned by selling good B received2Red = models.FloatField(initial=-1) received2Green = models.FloatField(initial=-1) # 1.Producer.2.Consumer Produce1Red = models.FloatField(min=0, max=20.00, label="The amount of good A you plan to produce for red tokens.") Produce1Green = models.FloatField(min=0, max=20.00, label="The amount of good A you plan to produce for green tokens.") Produce1RedFinal = models.FloatField(initial=0) Produce1GreenFinal = models.FloatField(initial=0) Spend2RedFinal = models.FloatField(initial=0) Spend2GreenFinal = models.FloatField(initial=0) # Total units of good A to produce Produce1 = models.FloatField(initial=-1, min=0, max=20.00) # Red and Green tokens earned by selling good A received1Red = models.FloatField(initial=-1) received1Green = models.FloatField(initial=-1) Consume2 = models.FloatField(initial=-1) Consume2Red = models.FloatField(initial=-1) Consume2Green = models.FloatField(initial=-1) # Market B payoff Payoff2 = models.FloatField(initial=-1) Spend2Red = models.FloatField(min=0, label="Amount of red tokens you would like to spend on good B (choose between 0 and " "red token holding).") Spend2Green = models.FloatField(min=0, label="Amount of green tokens you would like to spend on good B (choose between 0 " "and green token holding).") # Add up all the periods of sequence sequence_earnings = models.FloatField(min=0) """" Output some variables """ # # Starting money # startMoney = models.FloatField(initial=0) # # Actual sequence earn # actualSequenceEarn = models.FloatField(initial=0) # # The accumulation of the sequence earn of the experiment_constant # sessionEarn = models.FloatField(initial=0) # # # The actual accumulation of the sequence earn of the experiment_constant # actualSessionEarn = models.FloatField(initial=0) # keep track of which sequence corresponds to which earnings (for sequence transition page only) sequence_tracker = models.FloatField(initial=math.inf) def Spend1Red_max(player): return f.display2(player.BalanceRed) def Spend1Green_max(player): return f.display2(player.BalanceGreen) def Spend2Red_max(player): return f.display2(player.BalanceRed) def Spend2Green_max(player): return f.display2(player.BalanceGreen) # FUNCTIONS def creating_session(subsession: Subsession): players = subsession.get_players() n_players = len(players) crit_rounds = C.sequence_start_periods.copy() # Every critical round determine type (consumer or producer) if subsession.round_number in crit_rounds: types = ['1.consumer.2.producer', '1.producer.2.consumer'] * int(n_players / 2) random.shuffle(types) for i in range(int(n_players)): players[i].type = types[i] random.shuffle(types) for i in range(int(n_players), n_players): players[i].type = types[i - int(n_players)] else: for i, p in enumerate(players): p.type = p.in_round(subsession.round_number - 1).type def calc_last_time_stamp(group: Group): last_time_stamp = 0 the_first_period = group.in_round(1) for p in the_first_period.get_players(): player_time_stamp = p.session.vars["{:d}_time_stamp".format(p.id_in_group)] if player_time_stamp > last_time_stamp: last_time_stamp = player_time_stamp return last_time_stamp def is_end_within_the_block(group: Group): current_play_round = group.get_players()[0].period round_index = 0 for p in range(group.round_number - current_play_round + 1, group.round_number + 1): print("Round ", group.round_number, " Period ", p, " random number is ", group.in_round(p).random_number) if group.in_round(p).random_number == 10: round_index = p print("The random number is in round:", p) break if round_index == 0 or round_index == group.round_number: group.sequenceOver = 0 else: group.sequenceOver = 1 return round_index def Produce1Red_error_message(player, value): split_string = str(value).split('.') if len(split_string) > 1 and len(split_string[1]) > 2: return "Up to 2 decimal points are allowed" def Produce1Green_error_message(player, value): split_string = str(value).split('.') if len(split_string) > 1 and len(split_string[1]) > 2: return "Up to 2 decimal points are allowed" def Produce2Red_error_message(player, value): split_string = str(value).split('.') if len(split_string) > 1 and len(split_string[1]) > 2: return "Up to 2 decimal points are allowed" def Produce2Green_error_message(player, value): split_string = str(value).split('.') if len(split_string) > 1 and len(split_string[1]) > 2: return "Up to 2 decimal points are allowed" def Spend1Red_error_message(player, value): split_string = str(value).split('.') if len(split_string) > 1 and len(split_string[1]) > 2: return "Up to 2 decimal points are allowed" def Spend1Green_error_message(player, value): split_string = str(value).split('.') if len(split_string) > 1 and len(split_string[1]) > 2: return "Up to 2 decimal points are allowed" def Spend2Red_error_message(player, value): split_string = str(value).split('.') if len(split_string) > 1 and len(split_string[1]) > 2: return "Up to 2 decimal points are allowed" def Spend2Green_error_message(player, value): split_string = str(value).split('.') if len(split_string) > 1 and len(split_string[1]) > 2: return "Up to 2 decimal points are allowed" def update_group_status(subsession: Subsession): players = subsession.get_players() for p in players: previous_player = p.in_round(p.round_number - 1) previous_session_vars = p.in_round(p.round_number - 1).session.vars # Hold the previous sequence as current sequence p.sequence = previous_player.sequence # Current period = previous period + 1 p.period = previous_player.period + 1 p.BalanceRed = previous_player.BalanceRed p.BalanceRedStart1 = p.BalanceRed p.BalanceGreen = previous_player.BalanceGreen p.BalanceGreenStart1 = p.BalanceGreen p.Payoff1 = 0 p.sequence_earnings = previous_player.sequence_earnings """"Output variables""" # player.startMoney = previous_player.startMoney # p.actualSequenceEarn = previous_player.actualSequenceEarn # p.sessionEarn = previous_player.sessionEarn # p.actualSessionEarn = previous_player.actualSessionEarn def summary_in_specific_round(player: Player, in_round): # History player in specific round history_player = player.in_round(in_round) # Table for type - consumer in Market A and producer in Market B if player.type == '1.consumer.2.producer': # Column 2: Good A consumed Consume1 = history_player.Consume1 # Column 3: Good B produced Produce2 = history_player.Produce2 # Column 4: Market earning market_earning = f.ua(Consume1) + f.cost(Produce2) # Column 5: Period starting red tokens BalanceRedStart1 = history_player.BalanceRedStart1 # Column 6: Period starting green tokens BalanceGreenStart1 = history_player.BalanceGreenStart1 # Column 7: Period final red tokens BalanceRedFinal2 = BalanceRedStart1 - history_player.Spend1RedFinal + history_player.received2Red # Column 8: Period final green tokens BalanceGreenFinal2 = BalanceGreenStart1 - history_player.Spend1GreenFinal + history_player.received2Green # Column9: Sequence earning sequence_earnings = history_player.sequence_earnings return [in_round, f.display2(Consume1), f.display2(Produce2), f.display2(market_earning), f.display2(BalanceRedStart1), f.display2(BalanceGreenStart1), f.display2(BalanceRedFinal2), f.display2(BalanceGreenFinal2), f.display2(sequence_earnings) ] # Table for type - producer in Market A and consumer in Market B else: # Column 2: Good A produced Produce1 = history_player.Produce1 # Column 3: Good B consumed Consume2 = history_player.Consume2 # Column 4: Market earning market_earning = f.ub(Consume2) + f.cost(Produce1) # Column 5: Period starting red tokens BalanceRedStart1 = history_player.BalanceRedStart1 # Column 6: Period starting green tokens BalanceGreenStart1 = history_player.BalanceGreenStart1 # Column 7: Period final red tokens BalanceRedFinal2 = BalanceRedStart1 + history_player.received1Red - history_player.Spend2RedFinal # Column 8: Period final green tokens BalanceGreenFinal2 = BalanceGreenStart1 + history_player.received1Green - history_player.Spend2GreenFinal # Column9: Sequence earning sequence_earnings = history_player.sequence_earnings return [in_round, f.display2(Produce1), f.display2(Consume2), f.display2(market_earning), f.display2(BalanceRedStart1), f.display2(BalanceGreenStart1), f.display2(BalanceRedFinal2), f.display2(BalanceGreenFinal2), f.display2(sequence_earnings) ] def get_history_table(player: Player, period_ongoing: bool): current_period = player.period # Show random number id period equal or greater to block size if current_period > C.block_length: if period_ongoing: history = [[0, 0, 0, 0, 0, 0, 0, 0, 0]] history.clear() period_index = 1 for p in range(player.round_number - player.period + 1, player.round_number): row = summary_in_specific_round(player, p) row[0] = period_index row.append(player.group.in_round(p).random_number) history.append(row) period_index += 1 else: history = [[0, 0, 0, 0, 0, 0, 0, 0, 0]] history.clear() period_index = 1 for p in range(player.round_number - player.period + 1, player.round_number + 1): row = summary_in_specific_round(player, p) row[0] = period_index row.append(player.group.in_round(p).random_number) history.append(row) period_index += 1 # Don't show random number if period < block size else: # Show history up until previous period for pages before market B summary if period_ongoing: history = [[0, 0, 0, 0, 0, 0, 0, 0, 0]] history.clear() period_index = 1 for p in range(player.round_number - player.period + 1, player.round_number): row = summary_in_specific_round(player, p) row[0] = period_index history.append(row) period_index += 1 # show history till current period at market B summary page else: history = [[0, 0, 0, 0, 0, 0, 0, 0, 0]] history.clear() period_index = 1 for p in range(player.round_number - player.period + 1, player.round_number + 1): row = summary_in_specific_round(player, p) row[0] = period_index history.append(row) period_index += 1 # Add a condition for block check # Show history up until current period return history # From competing currencies def get_stage1_outcomes(subsession: Subsession): # print("get_stage1_outcomes()...") players = subsession.get_players() consumers = [p for p in players if p.type == '1.consumer.2.producer'] producers = [p for p in players if p.type == '1.producer.2.consumer'] group = subsession.get_groups() totalSpendRed = sum([p.Spend1Red for p in consumers]) totalSpendGreen = sum([p.Spend1Green for p in consumers]) totalProduceRed = sum([p.Produce1Red for p in producers]) totalProduceGreen = sum([p.Produce1Green for p in producers]) for g in group: g.totalSpend1Red = f.display2(totalSpendRed) g.totalSpend1Green = f.display2(totalSpendGreen) g.totalProduce1Red = f.display2(totalProduceRed) g.totalProduce1Green = f.display2(totalProduceGreen) if totalProduceRed > 0 and totalSpendRed > 0: price1Red = totalSpendRed / totalProduceRed else: price1Red = 0 if totalProduceGreen > 0 and totalSpendGreen > 0: price1Green = totalSpendGreen / totalProduceGreen else: price1Green = 0 ### CALCULATE PAYOFFS TO PLAYERS AND UPDATE BALANCES for p in consumers: if totalProduceRed > 0 and totalSpendRed > 0: Spend1Red = p.Spend1Red qRed = Spend1Red / price1Red else: Spend1Red = 0 qRed = 0 p.BalanceRed -= Spend1Red if totalProduceGreen > 0 and totalSpendGreen > 0: Spend1Green = p.Spend1Green qGreen = Spend1Green / price1Green else: Spend1Green = 0 qGreen = 0 p.BalanceGreen -= Spend1Green p.Spend1RedFinal = Spend1Red p.Spend1GreenFinal = Spend1Green p.Consume1Red = f.display2(qRed) p.Consume1Green = f.display2(qGreen) p.Consume1 = qRed + qGreen p.Payoff1 = f.ua(p.Consume1) p.sequence_earnings += p.Payoff1 p.payoff = p.Payoff1 p.BalanceRedStart2 = p.BalanceRed p.BalanceGreenStart2 = p.BalanceGreen for p in producers: if totalProduceRed > 0 and totalSpendRed > 0: qRed = p.Produce1Red else: qRed = 0 p.received1Red = qRed * price1Red p.BalanceRed += p.received1Red if totalProduceGreen > 0 and totalSpendGreen > 0: qGreen = p.Produce1Green else: qGreen = 0 p.received1Green = qGreen * price1Green p.BalanceGreen += p.received1Green p.Produce1RedFinal = f.display2(qRed) p.Produce1GreenFinal = f.display2(qGreen) p.Produce1 = qRed + qGreen p.Payoff1 = f.cost(p.Produce1) p.sequence_earnings += p.Payoff1 p.payoff = p.Payoff1 p.BalanceRedStart2 = p.BalanceRed p.BalanceGreenStart2 = p.BalanceGreen for p in players: p.Price1Red = f.display2(price1Red) p.Price1Green = f.display2(price1Green) # update_history(p) # From lucas tree program any_player = players[0] any_group = group[0] last_time_stamp = calc_last_time_stamp(any_group) time_stamp_delta = time.time() - last_time_stamp print("Experiment time run: second", round(time_stamp_delta, 2)) def get_stage2_outcomes(subsession: Subsession): # print("get_stage2_outcomes()...") players = subsession.get_players() consumers = [p for p in players if p.type == '1.producer.2.consumer'] producers = [p for p in players if p.type == '1.consumer.2.producer'] group = subsession.get_groups() totalSpendRed = sum([p.Spend2Red for p in consumers]) totalSpendGreen = sum([p.Spend2Green for p in consumers]) totalProduceRed = sum([p.Produce2Red for p in producers]) totalProduceGreen = sum([p.Produce2Green for p in producers]) period_number = C.sequence_period_list[players[0].sequence - 1] for g in group: g.totalSpend2Red = f.display2(totalSpendRed) g.totalSpend2Green = f.display2(totalSpendGreen) g.totalProduce2Red = f.display2(totalProduceRed) g.totalProduce2Green = f.display2(totalProduceGreen) if players[0].period == period_number: g.random_number = f.block_end_dice(C.DICE_MAX, C.DELTA)[0] else: g.random_number = f.integer_random(9) + 1 if totalProduceRed > 0 and totalSpendRed > 0: price2Red = totalSpendRed / totalProduceRed else: price2Red = 0 if totalProduceGreen > 0 and totalSpendGreen > 0: price2Green = totalSpendGreen / totalProduceGreen else: price2Green = 0 ### CALCULATE PAYOFFS TO PLAYERS AND UPDATE BALANCES for p in consumers: if totalProduceRed > 0 and totalSpendRed > 0: Spend2Red = p.Spend2Red qRed = Spend2Red / price2Red else: Spend2Red = 0 qRed = 0 p.BalanceRed -= Spend2Red if totalProduceGreen > 0 and totalSpendGreen > 0: Spend2Green = p.Spend2Green qGreen = Spend2Green / price2Green else: Spend2Green = 0 qGreen = 0 p.BalanceGreen -= Spend2Green p.Spend2RedFinal = Spend2Red p.Spend2GreenFinal = Spend2Green p.Consume2Red = f.display2(qRed) p.Consume2Green = f.display2(qGreen) p.Consume2 = qRed + qGreen p.Payoff2 = f.ub(p.Consume2) p.sequence_earnings += p.Payoff2 p.payoff = p.Payoff2 for p in producers: if totalProduceRed > 0 and totalSpendRed > 0: qRed = p.Produce2Red else: qRed = 0 p.received2Red = qRed * price2Red p.BalanceRed += p.received2Red if totalProduceGreen > 0 and totalSpendGreen > 0: qGreen = p.Produce2Green else: qGreen = 0 p.received2Green = qGreen * price2Green p.BalanceGreen += p.received2Green p.Produce2RedFinal = f.display2(qRed) p.Produce2GreenFinal = f.display2(qGreen) p.Produce2 = qRed + qGreen p.Payoff2 = f.cost(p.Produce2) p.sequence_earnings += p.Payoff2 p.payoff = p.Payoff2 for p in players: p.Price2Red = f.display2(price2Red) p.Price2Green = f.display2(price2Green) # update_history(p) # From lucas tree program any_player = players[0] any_group = group[0] last_time_stamp = calc_last_time_stamp(any_group) time_stamp_delta = time.time() - last_time_stamp print("Experiment time run: second", round(time_stamp_delta, 2)) # Check if experiment_constant timeout if time_stamp_delta > C.experiment_max_time_second or any_player.sequence >= C.max_sequence: # Check the random number in block if any_player.period == C.block_length: for r in range(any_group.round_number - C.block_length + 1, any_group.round_number + 1): if any_group.in_round(r).random_number == 10: any_group.session.vars["finish_experiment"] = True # Check the random number period by period if random number 10 not in block elif any_player.period >= C.block_length and any_group.random_number == 10: any_group.session.vars["finish_experiment"] = True def get_block_random_numbers(player: Player): # This function will only be called at block check page sequence = player.sequence first_period = C.sequence_start_periods[sequence - 1] # first_period = player.round_number - C.block_length +1 last_period = player.round_number block = player.in_rounds(first_period, last_period) block_history = [] block_end = False for b in block: if b.group.random_number > C.DICE_MAX * C.DELTA: block_end = True block_period = dict(period=b.period, random_number=b.group.random_number, block_end=block_end) block_history.append(block_period) return block_history def get_price_history(player: Player): sequence = player.sequence first_period = C.sequence_start_periods[sequence - 1] # first_period = player.round_number - C.block_length +1 last_period = player.round_number price1Red_history = [] price1Green_history = [] price2Red_history = [] price2Green_history = [] previous_player = player.in_rounds(first_period, last_period) for p in previous_player: Price1Red = f.display2(p.Price1Red) if (p.Price1Red != "None" and p.Price1Red != -1) else None Price1Green = f.display2(p.Price1Green) if (p.Price1Green != "None" and p.Price1Green != -1) else None Price2Red = f.display2(p.Price2Red) if (p.Price2Red != "None" and p.Price2Red != -1) else None Price2Green = f.display2(p.Price2Green) if (p.Price2Green != "None" and p.Price2Green != -1) else None price1Red_history.append(Price1Red) price1Green_history.append(Price1Green) price2Red_history.append(Price2Red) price2Green_history.append(Price2Green) return dict(Price1Red=price1Red_history, Price1Green=price1Green_history, Price2Red=price2Red_history, Price2Green=price2Green_history) def market_a_chart(X): produce_cost = [] consume_benefit = [] for x in range(X): produce_cost.append(-f.cost(x)) consume_benefit.append(f.display2(f.ua(x))) return dict(cost=produce_cost, benefit=consume_benefit) def market_b_chart(X): produce_cost = [] consume_benefit = [] for x in range(X): produce_cost.append(-f.cost(x)) consume_benefit.append(f.display2(f.ub(x))) return dict(cost=produce_cost, benefit=consume_benefit) # PAGES class p01_Introduction(Page): """Description of the game: How to play and returns expected""" timeout_seconds = C.introduction_timeout @staticmethod def is_displayed(player: Player): # display introduction page to first period of each sequence return player.round_number in C.sequence_start_periods @staticmethod def vars_for_template(player: Player): # Tokens at the first Period if player.type == '1.consumer.2.producer': player.BalanceRed = C.starting_tokens_red player.BalanceRedStart1 = player.BalanceRed player.BalanceGreen = C.starting_tokens_green player.BalanceGreenStart1 = player.BalanceGreen # player.startMoney = C.starting_tokens_red else: player.BalanceRed = 0 player.BalanceRedStart1 = 0 player.BalanceGreen = 0 player.BalanceGreenStart1 = 0 player.period = 1 if player.round_number == 1: player.sequence = 1 else: prev_player = player.in_round(player.round_number - 1) player.sequence = prev_player.sequence + 1 player.Payoff1 = 0 player.sequence_earnings = 0 player.session.vars["{:d}_time_stamp".format(player.id_in_group)] = time.time() return dict( block_length=C.block_length, block_length_plus_one=C.block_length + 1 ) class p02_PreMarketA_WaitForAll(WaitPage): # template_name = "experiment_baseline/p05_MarketA_WaitPage.html" wait_for_all_groups = True @staticmethod def after_all_players_arrive(subsession: Subsession): update_group_status(subsession) @staticmethod def is_displayed(player: Player): # display this wait page to periods other than the first period of the first sequence return player.round_number not in C.sequence_start_periods @staticmethod def vars_for_template(player: Player): return dict( block_length=C.block_length, block_length_plus_one=C.block_length + 1, sequence=player.sequence, period=player.period ) # @staticmethod # def vars_for_template(player: Player): # show_table = True if player.period > 1 else False # show_history_random_number = False if player.period < C.block_length else True # period_ongoing = True # history_table = [] # if player.period > 1: # history_table = get_history_table(player, period_ongoing) # # return dict( # table_list=history_table, # id=player.id_in_group, # sequence=player.sequence, # period=player.period, # show_history_random_number=show_history_random_number, # show_table=show_table # ) # # @staticmethod # def js_vars(player: Player): # price_history = get_price_history(player) # Price1Red = price_history['Price1Red'] # Price1Green = price_history['Price1Green'] # Price2Red = price_history['Price2Red'] # Price2Green = price_history['Price2Green'] # 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': "Red Price", 'data': Price1Red, 'color': 'red'}, # {'name': "Green Price", 'data': Price1Green, 'color': 'green'}], # highcharts_series_2=[{'name': "Red Price", 'data': Price2Red, 'color': 'red'}, # {'name': "Green Price", 'data': Price2Green, 'color': 'green'}], # highcharts_series_3=[{'name': "Cost of Production", 'data': cost1}, # {'name': "Benefit of Consumption", 'data': benefit1}], # highcharts_series_4=[{'name': "Cost of Production", 'data': cost2}, # {'name': "Benefit of Consumption", 'data': benefit2}], # timeout=C.decision_timeout * 1000 # ) class p03_MarketA_Consumer(Page): """Consumer's round in market A""" form_model = 'player' form_fields = ['Spend1Red', 'Spend1Green'] @staticmethod def is_displayed(player: Player): return player.type == '1.consumer.2.producer' @staticmethod def vars_for_template(player: Player): n = len(player.session.get_participants()) return dict( id=player.id_in_group, sequence=player.sequence, period=player.period, red_balance=math.floor(player.BalanceRedStart1 * 100) / 100, green_balance=math.floor(player.BalanceGreenStart1 * 100) / 100, total_token_p1_red=C.starting_tokens_red * n / 2, total_token_market_red=C.starting_tokens_red * player.session.num_participants / 2, price_history=get_price_history(player) ) @staticmethod def js_vars(player: Player): price_history = get_price_history(player) Price1Red = price_history['Price1Red'] Price1Green = price_history['Price1Green'] Price2Red = price_history['Price2Red'] Price2Green = price_history['Price2Green'] 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': "Red Price", 'data': Price1Red, 'color': 'red'}, {'name': "Green Price", 'data': Price1Green, 'color': 'green'}], highcharts_series_2=[{'name': "Red Price", 'data': Price2Red, 'color': 'red'}, {'name': "Green Price", 'data': Price2Green, 'color': 'green'}], highcharts_series_3=[{'name': "Cost of Production", 'data': cost1}, {'name': "Benefit of Consumption", 'data': benefit1}], highcharts_series_4=[{'name': "Cost of Production", 'data': cost2}, {'name': "Benefit of Consumption", 'data': benefit2}], timeout=C.decision_timeout * 1000 ) class p04_MarketA_Producer(Page): """Producer base class""" form_model = 'player' form_fields = ['Produce1Red', 'Produce1Green'] @staticmethod def is_displayed(player: Player): return player.type == '1.producer.2.consumer' @staticmethod def vars_for_template(player: Player): n = len(player.session.get_participants()) return dict( id=player.id_in_group, sequence=player.sequence, period=player.period, red_balance=math.floor(player.BalanceRedStart1 * 100) / 100, green_balance=math.floor(player.BalanceGreenStart1 * 100) / 100, total_token_p1_red=C.starting_tokens_red * n / 2, total_token_market_red=C.starting_tokens_red * player.session.num_participants / 2, ) @staticmethod def js_vars(player: Player): price_history = get_price_history(player) Price1Red = price_history['Price1Red'] Price1Green = price_history['Price1Green'] Price2Red = price_history['Price2Red'] Price2Green = price_history['Price2Green'] 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': "Red Price", 'data': Price1Red, 'color': 'red'}, {'name': "Green Price", 'data': Price1Green, 'color': 'green'}], highcharts_series_2=[{'name': "Red Price", 'data': Price2Red, 'color': 'red'}, {'name': "Green Price", 'data': Price2Green, 'color': 'green'}], highcharts_series_3=[{'name': "Cost of Production", 'data': cost1}, {'name': "Benefit of Consumption", 'data': benefit1}], highcharts_series_4=[{'name': "Cost of Production", 'data': cost2}, {'name': "Benefit of Consumption", 'data': benefit2}], timeout=C.decision_timeout * 1000 ) class p05_MarketA_WaitPage(WaitPage): template_name = "experiment_baseline/p05_MarketA_WaitPage.html" form_model = 'player' wait_for_all_groups = True @staticmethod def after_all_players_arrive(subsession: Subsession): get_stage1_outcomes(subsession) @staticmethod def vars_for_template(player: Player): show_table = True if player.period > 1 else False period_ongoing = True show_history_random_number = True if player.period > C.block_length else False history_table = [] if player.period > 1: history_table = get_history_table(player, period_ongoing) return dict( table_list=history_table, id=player.id_in_group, sequence=player.sequence, period=player.period, show_history_random_number=show_history_random_number, show_table=show_table ) @staticmethod def js_vars(player: Player): price_history = get_price_history(player) Price1Red = price_history['Price1Red'] Price1Green = price_history['Price1Green'] Price2Red = price_history['Price2Red'] Price2Green = price_history['Price2Green'] 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': "Red Price", 'data': Price1Red, 'color': 'red'}, {'name': "Green Price", 'data': Price1Green, 'color': 'green'}], highcharts_series_2=[{'name': "Red Price", 'data': Price2Red, 'color': 'red'}, {'name': "Green Price", 'data': Price2Green, 'color': 'green'}], highcharts_series_3=[{'name': "Cost of Production", 'data': cost1}, {'name': "Benefit of Consumption", 'data': benefit1}], highcharts_series_4=[{'name': "Cost of Production", 'data': cost2}, {'name': "Benefit of Consumption", 'data': benefit2}], timeout=C.decision_timeout * 1000 ) class p06_MarketA_SummaryPage(Page): def get_timeout_seconds(player: Player): if player.round_number <= 3: return 1500 else: return 900 @staticmethod def vars_for_template(player: Player): # Common entry for all participants period_ongoing = True show_table = True if player.period > 1 else False show_history_random_number = True if player.period > C.block_length else False Price1Red = player.Price1Red Price1Green = player.Price1Green player.BalanceRedStart2 = player.BalanceRed player.BalanceGreenStart2 = player.BalanceGreen dictionary = dict( table_list=get_history_table(player, period_ongoing), show_history_random_number=show_history_random_number, show_table=show_table, total_red_tokens_bid=player.group.totalSpend1Red, total_green_tokens_bid=player.group.totalSpend1Green, total_produced_red=player.group.totalProduce1Red, total_produced_green=player.group.totalProduce1Green, price_red=Price1Red, price_green=Price1Green, point_earned_in_market=player.Payoff1, beginning_red_balance=player.BalanceRedStart1, beginning_green_balance=player.BalanceGreenStart1, ending_red_balance=player.BalanceRed, ending_green_balance=player.BalanceGreen, ) # entries for consumers if player.type == "1.consumer.2.producer": dictionary.update(dict( red_spent=player.Spend1RedFinal, green_spent=player.Spend1GreenFinal, quantity_bought_red=player.Consume1Red, quantity_bought_green=player.Consume1Green, points_earned_from_consuming=f.ua(player.Consume1), )) # entries for producers else: dictionary.update(dict( red_produced=player.Produce1RedFinal, green_produced=player.Produce1GreenFinal, red_earned=player.received1Red, green_earned=player.received1Green )) return dictionary class p07_MarketB_Consumer(Page): form_model = 'player' form_fields = ['Spend2Red', 'Spend2Green'] @staticmethod def is_displayed(player: Player): return player.type == '1.producer.2.consumer' @staticmethod def vars_for_template(player: Player): player.group.current_market = 1 n = len(player.session.get_participants()) return dict( id=player.id_in_group, sequence=player.sequence, period=player.period, red_balance=math.floor(player.BalanceRedStart2 * 100) / 100, green_balance=math.floor(player.BalanceGreenStart2 * 100) / 100, total_token_p1_red=C.starting_tokens_red * n / 2, total_token_market_red=C.starting_tokens_red * player.session.num_participants / 2, ) @staticmethod def js_vars(player: Player): price_history = get_price_history(player) Price1Red = price_history['Price1Red'] Price1Green = price_history['Price1Green'] Price2Red = price_history['Price2Red'] Price2Green = price_history['Price2Green'] 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': "Red Price", 'data': Price1Red, 'color': 'red'}, {'name': "Green Price", 'data': Price1Green, 'color': 'green'}], highcharts_series_2=[{'name': "Red Price", 'data': Price2Red, 'color': 'red'}, {'name': "Green Price", 'data': Price2Green, 'color': 'green'}], highcharts_series_3=[{'name': "Cost of Production", 'data': cost1}, {'name': "Benefit of Consumption", 'data': benefit1}], highcharts_series_4=[{'name': "Cost of Production", 'data': cost2}, {'name': "Benefit of Consumption", 'data': benefit2}], timeout=C.decision_timeout * 1000 ) class p08_MarketB_Producer(Page): form_model = 'player' form_fields = ['Produce2Red', 'Produce2Green'] @staticmethod def is_displayed(player: Player): return player.type == '1.consumer.2.producer' @staticmethod def vars_for_template(player: Player): player.group.current_market = 1 n = len(player.session.get_participants()) return dict( id=player.id_in_group, sequence=player.sequence, period=player.period, red_balance=math.floor(player.BalanceRedStart2 * 100) / 100, green_balance=math.floor(player.BalanceGreenStart2 * 100) / 100, total_token_p1_red=C.starting_tokens_red * n / 2, total_token_market_red=C.starting_tokens_red * player.session.num_participants / 2, ) @staticmethod def js_vars(player: Player): price_history = get_price_history(player) Price1Red = price_history['Price1Red'] Price1Green = price_history['Price1Green'] Price2Red = price_history['Price2Red'] Price2Green = price_history['Price2Green'] 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': "Red Price", 'data': Price1Red, 'color': 'red'}, {'name': "Green Price", 'data': Price1Green, 'color': 'green'}], highcharts_series_2=[{'name': "Red Price", 'data': Price2Red, 'color': 'red'}, {'name': "Green Price", 'data': Price2Green, 'color': 'green'}], highcharts_series_3=[{'name': "Cost of Production", 'data': cost1}, {'name': "Benefit of Consumption", 'data': benefit1}], highcharts_series_4=[{'name': "Cost of Production", 'data': cost2}, {'name': "Benefit of Consumption", 'data': benefit2}], timeout=C.decision_timeout * 1000 ) class p09_MarketB_WaitPage(WaitPage): template_name = "experiment_baseline/p09_MarketB_WaitPage.html" form_model = 'player' wait_for_all_groups = True @staticmethod def after_all_players_arrive(subsession: Subsession): get_stage2_outcomes(subsession) @staticmethod def vars_for_template(player: Player): period_ongoing = True player.group.current_market = 1 show_table = True if player.period > 1 else False show_history_random_number = True if player.period > C.block_length else False return dict( table_list=get_history_table(player, period_ongoing), id=player.id_in_group, sequence=player.sequence, period=player.period, show_history_random_number=show_history_random_number, show_table=show_table ) @staticmethod def js_vars(player: Player): price_history = get_price_history(player) Price1Red = price_history['Price1Red'] Price1Green = price_history['Price1Green'] Price2Red = price_history['Price2Red'] Price2Green = price_history['Price2Green'] 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': "Red Price", 'data': Price1Red, 'color': 'red'}, {'name': "Green Price", 'data': Price1Green, 'color': 'green'}], highcharts_series_2=[{'name': "Red Price", 'data': Price2Red, 'color': 'red'}, {'name': "Green Price", 'data': Price2Green, 'color': 'green'}], highcharts_series_3=[{'name': "Cost of Production", 'data': cost1}, {'name': "Benefit of Consumption", 'data': benefit1}], highcharts_series_4=[{'name': "Cost of Production", 'data': cost2}, {'name': "Benefit of Consumption", 'data': benefit2}], timeout=C.decision_timeout * 1000 ) class p10_MarketB_SummaryPage(Page): def get_timeout_seconds(player: Player): if player.round_number <= 3: # return 150 return 1500 else: # return 90 return 1500 @staticmethod def vars_for_template(player: Player): period_ongoing = False player.group.current_market = 1 show_table = True if player.period > 1 else False show_history_random_number = True if player.period > C.block_length else False page_status = 0 if player.period > C.block_length: end_in_round = is_end_within_the_block(player.group) if end_in_round > 0: page_status = 2 else: page_status = 1 Price2Red = round(player.Price2Red, 2) Price2Green = round(player.Price2Green, 2) # Common entry for all participants dictionary = dict( show_table=show_table, show_history_random_number=show_history_random_number, table_list=get_history_table(player, period_ongoing), total_red_tokens_bid=player.group.totalSpend2Red, total_green_tokens_bid=player.group.totalSpend2Green, total_produced_red=player.group.totalProduce2Red, total_produced_green=player.group.totalProduce2Green, price_red=Price2Red, price_green=Price2Green, point_earned_in_market=player.Payoff2, beginning_red_balance=player.BalanceRedStart2, beginning_green_balance=player.BalanceGreenStart2, ending_red_balance=player.BalanceRed, ending_green_balance=player.BalanceGreen, page_status=page_status, random_number=player.group.random_number ) # entries for consumers if player.type == "1.producer.2.consumer": dictionary.update(dict( red_spent=player.Spend2RedFinal, green_spent=player.Spend2GreenFinal, quantity_bought_red=player.Consume2Red, quantity_bought_green=player.Consume2Green, points_earned_from_consuming=f.ub(player.Consume2), )) # entries for producers else: dictionary.update(dict( red_produced=player.Produce2RedFinal, green_produced=player.Produce2GreenFinal, red_earned=player.received2Red, green_earned=player.received2Green, )) return dictionary class p11_BlockCheck(Page): # testing timeout_seconds = C.block_check_timeout * 1000 # TODO: needs to comment out testing time_out # timeout_seconds = C.block_check_timeout def is_displayed(player: Player): # Period continue before 10 (debug: current is 3) return player.period == C.block_length # def before_next_page(player: Player): # if player.round_number == 1: # return @staticmethod def vars_for_template(player: Player): period_ongoing = False page_status = 2 end_in_round = is_end_within_the_block(player.group) sequence_earnings = 0 if end_in_round > 0: page_status = 1 sequence_earnings = player.group.in_round(end_in_round) \ .get_player_by_id(player.id_in_group) \ .sequence_earnings dictionary = dict( block_random_numbers=get_block_random_numbers(player), continuation_chance=C.DICE_MAX * C.DELTA, # table_list=get_history_table(player, period_ongoing), sequence_earnings=sequence_earnings, page_status=page_status, block_end_period=C.sequence_period_list[player.sequence - 1], show_history_random_number=1 ) return dictionary class p12_SequenceTransition(Page): def is_displayed(player: Player): if player.period >= C.block_length: end_in_round = is_end_within_the_block(player.group) if end_in_round > 0: player.sequence_tracker = player.sequence_earnings return True return False @staticmethod def vars_for_template(player: Player): earnings = [] points = 0 for p in range(1, player.round_number + 1): if player.in_round(p).sequence_tracker != math.inf: earnings.append(player.in_round(p).sequence_tracker) points += player.in_round(p).sequence_tracker index = [] i = 1 for j in earnings: index.append(i) i += 1 sequences = zip(index, earnings) dollars = round(points * C.conversion_rate, 2) total_money = round(dollars + C.show_up_fee, 2) # Get a dictionary that stores actual earning of sequences played so far num_seq_played = player.sequence seq_num = 1 sequence_earning_list = [] tot_earnings = 0 for s in range(num_seq_played): seq_last_period = C.sequence_end_periods[s] last_me = player.in_round(seq_last_period) seq_tot = f.display2(last_me.sequence_earnings) tot_earnings += seq_tot seq_earning_summary = dict(sequence_number=seq_num, seq_earning=seq_tot) sequence_earning_list.append(seq_earning_summary) seq_num += 1 return dict( sequences=sequences, points=round(points, 2), dollars=dollars, total_money=total_money, sequence_earning_list=sequence_earning_list, total_points=round(tot_earnings, 2) ) page_sequence = [ p01_Introduction, p02_PreMarketA_WaitForAll, p03_MarketA_Consumer, p04_MarketA_Producer, p05_MarketA_WaitPage, p06_MarketA_SummaryPage, p07_MarketB_Consumer, p08_MarketB_Producer, p09_MarketB_WaitPage, p10_MarketB_SummaryPage, p11_BlockCheck, p12_SequenceTransition, ]