from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, Page, WaitPage, ) import random doc = """ This is the second-price sealed bid auction game. """ class Constants(BaseConstants): name_in_url = 'RGauction2nd' players_per_group = 3 num_rounds = 2 timeout = 60 # in seconds class Subsession(BaseSubsession): pass class Group(BaseGroup): highest_bid = models.CurrencyField() second_hi_bid = models.CurrencyField() # can be integers if needed winner = models.IntegerField() # player id class Player(BasePlayer): value = models.CurrencyField() bid = models.CurrencyField(min=0, max=100) is_winner = models.BooleanField() # FUNCTIONS def bid_max(player): return player.value def creating_session(subsession): if subsession.round_number == 1 or subsession.round_number == 6: # varying groups subsession.group_randomly() else: subsession.group_like_round(1) # establish a total earnings for p in subsession.get_players(): p.value = random.random()*100 p.is_winner = False if subsession.round_number == 1: p.participant.vars['totalEarnings'] = 0 def auction_outcome(g: Group): # get the set of players in the group players = g.get_players() # get the set of players' bids bids = [p.bid for p in players] # order the bids in descending bids.sort(reverse=True) # set the 2 highest bids to the appropriate group variables g.highest_bid = bids[0] g.second_hi_bid = bids[1] # tie break # first get highest bidding player ID set hi_bidders = [p.id_in_group for p in players if p.bid == g.highest_bid] # randomly choose the winner g.winner = random.choice(hi_bidders) # set the model of the winner winning_player = g.get_player_by_id(g.winner) winning_player.is_winner = True # set payoffs ######## for p in players: if p.is_winner: p.payoff = p.value - g.second_hi_bid else: p.payoff = 0 p.participant.vars['totalEarnings'] += p.participant.payoff # PAGES class Bid(Page): form_model = 'player' # model from which the field to be used form_fields = ['bid'] # exact field @staticmethod def get_timeout_seconds(player: Player): return Constants.timeout # in seconds @staticmethod def before_next_page(player: Player, timeout_happened): if timeout_happened: player.bid = random.random()*player.value class ResultsWaitPage(WaitPage): after_all_players_arrive = 'auction_outcome' body_text = "Please wait for other bids to be submitted" class Results(Page): pass page_sequence = [Bid, ResultsWaitPage, Results]