from otree.api import * import time import random doc = "Asset Market Teams" class C(BaseConstants): NAME_IN_URL = 'asset_market_teams_individs' PLAYERS_PER_GROUP = 10 NUM_ROUNDS = 15 ECU = 10000 class Subsession(BaseSubsession): pass def creating_session(subsession: Subsession): players = subsession.get_players() total_assets = 0 if players[0].round_number == 1: while total_assets != 20: # if [p.num_items for p in players].pop() is not None: # total_assets = sum([p.num_items for p in players]) for p in players: if p.round_number == 1: p.cash = C.ECU p.num_items = random.randint(0, 4) p.dividends = (random.randint(1, 4)) * 10 p.is_buyer = True p.is_seller = True p.current_offer = 0 p.buy = 0 p.sell = 0 total_assets = sum([p.num_items for p in players]) class Group(BaseGroup): start_timestamp = models.IntegerField() class Player(BasePlayer): cash = models.IntegerField() dividends = models.IntegerField() num_items = models.IntegerField() is_buyer = models.BooleanField() is_seller = models.BooleanField() current_offer = models.CurrencyField() buy = models.IntegerField() sell = models.IntegerField() class Transaction(ExtraModel): group = models.Link(Group) buyer = models.Link(Player) seller = models.Link(Player) price = models.CurrencyField() seconds = models.IntegerField(doc="Timestamp (seconds since beginning of trading)") def find_match(buyers, sellers): for buyer in buyers: for seller in sellers: if seller.num_items > 0 and seller.current_offer <= buyer.current_offer and seller.current_offer > 0 and buyer.current_offer > 0: if buyer.id_in_group != seller.id_in_group: # return as soon as we find a match (the rest of the loop will be skipped) return [buyer, seller] def live_method(player: Player, data): group = player.group players = group.get_players() buyers = [p for p in players if p.is_buyer] sellers = [p for p in players if p.is_seller] news = None if data: offer = int(data['offer']) player.current_offer = offer buy = int(data['buy']) sell = int(data['sell']) player.buy = buy player.sell = sell if player.buy == 1: # look for a seller match = find_match(buyers=[player], sellers=[p for p in players if p.sell == 1]) if player.sell == 1: # look for a buyer match = find_match(buyers=[p for p in players if p.buy == 1], sellers=[player]) if match: [buyer, seller] = match price = buyer.current_offer Transaction.create( group=group, buyer=buyer, seller=seller, price=price, seconds=int(time.time() - group.start_timestamp), ) buyer.num_items += 1 seller.num_items -= 1 buyer.cash -= price seller.cash += price buyer.current_offer = 0 # take seller current offer from screen ID seller.current_offer = 0 news = dict(buyer=buyer.id_in_group, seller=seller.id_in_group, price=price) bids = sorted([p.current_offer for p in buyers if (p.buy == 1 and p.current_offer > 0)], reverse=True) asks = sorted([p.current_offer for p in sellers if (p.sell == 1 and p.current_offer > 0)]) highcharts_series = [[tx.seconds, tx.price] for tx in Transaction.filter(group=group)] return { p.id_in_group: dict( num_items=p.num_items, current_offer=p.current_offer, cash=p.cash, dividends=p.dividends, bids=bids, asks=asks, highcharts_series=highcharts_series, news=news, buy=p.buy, sell=p.sell, ) for p in players } # PAGES class WaitToStart(WaitPage): @staticmethod def after_all_players_arrive(group: Group): group.start_timestamp = int(time.time()) @staticmethod def vars_for_template(player: Player): group = player.group players = group.get_players() for p in players: if p.round_number > 1: p.cash = (p.in_round(p.round_number - 1)).cash + ((p.in_round(p.round_number - 1)).num_items * (p.in_round(p.round_number - 1)).dividends) p.num_items = (p.in_round(p.round_number - 1)).num_items p.dividends = (p.in_round(p.round_number - 1)).dividends p.is_buyer = True p.is_seller = True p.current_offer = 0 p.buy = 0 p.sell = 0 class PreTradingChat(Page): pass class Trading(Page): live_method = live_method @staticmethod def js_vars(player: Player): return dict(id_in_group=player.id_in_group) @staticmethod def get_timeout_seconds(player: Player): import time group = player.group return (group.start_timestamp + 3 * 60) - time.time() class ResultsWaitPage(WaitPage): pass class Results(Page): @staticmethod def js_vars(player: Player): return dict(cash=player.cash, dividends=player.dividends, num_items=player.num_items) # def before_next_page(player: Player): # participant = player.participant # player.participant.vars['cash'] = player.cash # player.participant.vars['num_items'] = player.num_item class Payment(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 15 @staticmethod def js_vars(player: Player): return dict(cash=player.cash, dividends=player.dividends, num_items=player.num_items) page_sequence = [WaitToStart, Trading, ResultsWaitPage, Results, Payment]