from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, ExtraModel, ) doc = """ Live auction with extra model. """ class Constants(BaseConstants): name_in_url = 'auction_extra' players_per_group = None num_rounds = 1 instructions_template = 'auction_extra/instructions.html' min_allowable_bid = c(0) max_allowable_bid = c(100) # Error margin for the value estimates shown to the players estimate_error_margin = c(10) class Subsession(BaseSubsession): def creating_session(self): for g in self.get_groups(): import random item_value = random.uniform( Constants.min_allowable_bid, Constants.max_allowable_bid ) g.item_value = round(item_value, 1) class Group(BaseGroup): item_value = models.CurrencyField( doc="""Common value of the item to be auctioned, random for treatment""" ) highest_bidder = models.IntegerField() highest_bid = models.CurrencyField(initial=0) def live_auction(self, id_in_group, bid): bidder = self.get_player_by_id(id_in_group) bidder.indv_bid_counter += 1 Bid.objects.create(player=bidder, amount=bid) if bid > bidder.indv_highest_bid: bidder.indv_highest_bid = bid if bid > self.highest_bid: self.highest_bid = bid self.highest_bidder = id_in_group group_response = dict(id_in_group=id_in_group, bid=bid) return {0: group_response} def set_winner(self): import random players = self.get_players() #self.highest_bid = max([p.indv_highest_bid for p in players]) players_with_highest_bid = [ p for p in players if p.indv_highest_bid == self.highest_bid ] winner = random.choice( players_with_highest_bid ) # if tie, winner is chosen at random winner.is_winner = True for p in players: p.set_payoff() def generate_value_estimate(self): import random minimum = self.item_value - Constants.estimate_error_margin maximum = self.item_value + Constants.estimate_error_margin estimate = random.uniform(minimum, maximum) estimate = round(estimate, 1) if estimate < Constants.min_allowable_bid: estimate = Constants.min_allowable_bid if estimate > Constants.max_allowable_bid: estimate = Constants.max_allowable_bid return estimate class Player(BasePlayer): item_value_estimate = models.CurrencyField( doc="""Estimate of the common value, may be different for each player""" ) indv_highest_bid = models.CurrencyField( initial=Constants.min_allowable_bid, min=Constants.min_allowable_bid, max=Constants.max_allowable_bid, doc="""Amount bidded by the player""", ) indv_bid_counter = models.IntegerField(initial=0) is_winner = models.BooleanField( initial=False, doc="""Indicates whether the player is the winner""" ) def bids(self): bidlist = [] for bid in Bid.objects.filter(player=self): bidlist.append(bid.amount) return bidlist def set_payoff(self): if self.is_winner: self.payoff = self.group.item_value - self.indv_highest_bid if self.payoff < 0: self.payoff = 0 else: self.payoff = 0 class Bid(ExtraModel): player = models.Link(Player) count = models.IntegerField() amount = models.CurrencyField() def custom_export(players): # header row yield ['participant_code', 'bid_count', 'bid_amount'] for bid in Bid.objects.order_by('id'): player = bid.player participant = player.participant yield [participant.code, bid.count, bid.amount]