Beispiel #1
0
    def test_line_charts(self):
        # TODO: This test throws errors related to missing data in games 1 and 4. For now we're not worried about this,
        # since game #3 is our realistic test case, but could be worth going back and debugging later.
        game_id = 3
        user_ids = [1, 3, 4]
        compile_and_pack_player_leaderboard(game_id)
        with patch("backend.logic.base.time") as mock_base_time:
            mock_base_time.time.return_value = simulation_end_time
            make_the_field_charts(game_id)

        # this is basically the internals of async_update_all_games for one game
        for user_id in user_ids:
            serialize_and_pack_pending_orders(game_id, user_id)
            serialize_and_pack_portfolio_details(game_id, user_id)

        # Verify that the JSON objects for chart visuals were computed and cached as expected
        field_chart = s3_cache.unpack_s3_json("3/field_chart")
        self.assertIsNotNone(field_chart)
        self.assertIsNotNone(s3_cache.unpack_s3_json("3/1/current_balances"))
        self.assertIsNotNone(s3_cache.unpack_s3_json("3/3/current_balances"))
        self.assertIsNotNone(s3_cache.unpack_s3_json("3/4/current_balances"))

        # verify chart information
        test_user_data = [
            x for x in field_chart["datasets"] if x["label"] == "cheetos"
        ][0]
        self.assertLessEqual(len(test_user_data["data"]), N_PLOT_POINTS)
Beispiel #2
0
def add_fulfilled_order_entry(game_id: int, user_id: int, order_id: int):
    """Add a fulfilled order to the fulfilled orders table without rebuilding the entire asset"""
    order_status_entry = query_to_dict("""
        SELECT * FROM order_status WHERE order_id = %s ORDER BY id DESC LIMIT 0, 1""", order_id)[0]
    if order_status_entry["status"] == "fulfilled":
        order_entry = query_to_dict("SELECT * FROM orders WHERE id = %s;", order_id)[0]
        symbol = order_entry['symbol']
        timestamp = order_status_entry["timestamp"]
        clear_price = order_status_entry["clear_price"]
        quantity = order_entry["quantity"]
        order_label = f"{symbol}/{int(quantity)} @ {USD_FORMAT.format(clear_price)}/{format_posix_time(timestamp)}"
        buy_or_sell = order_entry["buy_or_sell"]
        new_entry = {
            "order_label": order_label,
            "event_type": buy_or_sell,
            "Symbol": symbol,
            "Cleared on": timestamp,
            "Quantity": quantity,
            "Clear price": clear_price,
            "Basis": quantity * clear_price if buy_or_sell == "buy" else NA_TEXT_SYMBOL,
            "Balance (FIFO)": quantity if buy_or_sell == "buy" else NA_NUMERIC_VAL,
            "Realized P&L": 0 if buy_or_sell == "buy" else NA_NUMERIC_VAL,
            "Realized P&L (%)": 0 if buy_or_sell == "buy" else NA_NUMERIC_VAL,
            "Unrealized P&L": 0 if buy_or_sell == "buy" else NA_NUMERIC_VAL,
            "Unrealized P&L (%)": 0 if buy_or_sell == "buy" else NA_NUMERIC_VAL,
            "Market price": clear_price,
            "as of": timestamp,
            "color": NULL_RGBA
        }
        assert set(FULFILLED_ORDER_MAPPINGS.values()) - set(new_entry.keys()) == set()
        fulfilled_order_table = s3_cache.unpack_s3_json(f"{game_id}/{user_id}/{FULFILLED_ORDER_PREFIX}")
        fulfilled_order_table["data"] = [new_entry] + fulfilled_order_table["data"]
        s3_cache.set(f"{game_id}/{user_id}/{FULFILLED_ORDER_PREFIX}", json.dumps(fulfilled_order_table))
 def test_splits(self):
     df = make_order_performance_table(self.game_id, self.user_id)
     pd.testing.assert_frame_equal(df, pd.DataFrame(self.RECORDS))
     serialize_and_pack_order_performance_assets(self.game_id, self.user_id)
     perf_table = s3_cache.unpack_s3_json(f"{self.game_id}/{self.user_id}/{FULFILLED_ORDER_PREFIX}")
     perf_chart = s3_cache.unpack_s3_json(f"{self.game_id}/{self.user_id}/{ORDER_PERF_CHART_PREFIX}")
     perf_table_df = pd.DataFrame(perf_table["data"])
     self.assertEqual(perf_table_df.shape, (22, 15))
     buy_perf_entries = [x for x in perf_table["data"] if x["event_type"] == "buy"]
     order_labels_table = set([x["order_label"] for x in buy_perf_entries])
     order_labels_chart = set([x["label"] for x in perf_chart["datasets"]])
     self.assertEqual(order_labels_chart, order_labels_table)
     for label in order_labels_table:
         table_entry = [x for x in buy_perf_entries if x["order_label"] == label][0]
         chart_entry = [x for x in perf_chart["datasets"] if x["label"] == label][0]
         self.assertEqual(table_entry["color"], chart_entry["backgroundColor"])
Beispiel #4
0
def get_current_balances_table():
    game_id = request.json.get("game_id")
    username = request.json.get("username")
    if username:
        user_id = get_user_ids([username])[0]
    else:
        user_id = decode_token(request)
    return jsonify(s3_cache.unpack_s3_json(f"{game_id}/{user_id}/{CURRENT_BALANCES_PREFIX}"))
Beispiel #5
0
def get_pending_orders_table():
    game_id = request.json.get("game_id")
    username = request.json.get("username")
    if username:
        user_id = get_user_ids([username])[0]
    else:
        user_id = decode_token(request)
    return jsonify(s3_cache.unpack_s3_json(f"{game_id}/{user_id}/{PENDING_ORDERS_PREFIX}"))
Beispiel #6
0
def get_fulfilled_orders_table():
    game_id = request.json.get("game_id")
    username = request.json.get("username")
    if username:
        user_id = get_user_ids([username])[0]
    else:
        user_id = decode_token(request)
    return jsonify(s3_cache.unpack_s3_json(f"{game_id}/{user_id}/{FULFILLED_ORDER_PREFIX}"))
Beispiel #7
0
def api_game_info():
    user_id = decode_token(request)
    game_id = request.json.get("game_id")
    game_info = get_game_info(game_id)
    game_info["is_host"] = game_info["creator_id"] == user_id
    game_info["user_status"] = get_user_invite_status_for_game(game_id, user_id)
    if game_info["game_status"] in ["active", "finished"]:
        game_info["leaderboard"] = s3_cache.unpack_s3_json(f"{game_id}/{LEADERBOARD_PREFIX}")["records"]
    return jsonify(game_info)
Beispiel #8
0
def order_performance_chart():
    """This endpoints works exactly the same as balances_chart. See above for details
    """
    game_id = request.json.get("game_id")
    username = request.json.get("username")
    if username:
        user_id = get_user_ids([username])[0]
    else:
        user_id = decode_token(request)
    return jsonify(s3_cache.unpack_s3_json(f"{game_id}/{user_id}/{ORDER_PERF_CHART_PREFIX}"))
Beispiel #9
0
    def test_single_player_visuals(self, mock_base_time, mock_game_time):
        mock_base_time.time.return_value = mock_game_time.time.return_value = simulation_end_time
        game_id = 8
        user_id = 1
        serialize_and_pack_pending_orders(game_id, user_id)
        serialize_and_pack_order_performance_assets(game_id, user_id)
        pending_orders_table = s3_cache.unpack_s3_json(
            f"{game_id}/{user_id}/{PENDING_ORDERS_PREFIX}")
        fulfilled_orders_table = s3_cache.unpack_s3_json(
            f"{game_id}/{user_id}/{FULFILLED_ORDER_PREFIX}")
        self.assertEqual(len(pending_orders_table["data"]), 0)
        self.assertEqual(len(fulfilled_orders_table["data"]), 2)
        self.assertEqual(
            set([x["Symbol"] for x in fulfilled_orders_table["data"]]),
            {"NVDA", "NKE"})

        serialize_and_pack_order_performance_assets(game_id, user_id)
        self.assertIn(f"{game_id}/{user_id}/{ORDER_PERF_CHART_PREFIX}",
                      s3_cache.keys())
        op_chart = s3_cache.unpack_s3_json(
            f"{game_id}/{user_id}/{ORDER_PERF_CHART_PREFIX}")
        chart_stocks = set(
            [x["label"].split("/")[0] for x in op_chart["datasets"]])
        expected_stocks = {"NKE", "NVDA"}
        self.assertEqual(chart_stocks, expected_stocks)

        # balances chart
        df = make_user_balances_chart_data(game_id, user_id)
        serialize_and_pack_balances_chart(df, game_id, user_id)
        balances_chart = s3_cache.unpack_s3_json(
            f"{game_id}/{user_id}/{BALANCES_CHART_PREFIX}")
        self.assertEqual(set([x["label"] for x in balances_chart["datasets"]]),
                         {"NVDA", "NKE", "Cash"})

        # leaderboard and field charts
        compile_and_pack_player_leaderboard(game_id)
        make_the_field_charts(game_id)
        field_chart = s3_cache.unpack_s3_json(
            f"{game_id}/{FIELD_CHART_PREFIX}")
        _index_names = query_to_dict("SELECT * FROM index_metadata")
        _index_names = [x["name"] for x in _index_names]
        self.assertEqual(set([x["label"] for x in field_chart["datasets"]]),
                         set(["cheetos"] + _index_names))
Beispiel #10
0
def balances_chart():
    """Be default, the frontend will load with username = null for the chart selector dropdown, and we'll show them
    their own chart. When the user proactively picks a username to checkout, this will be sent in the POST request to
    this endpoint and used to pull up the appropriate chart
    """
    game_id = request.json.get("game_id")
    username = request.json.get("username")
    if username:
        user_id = get_user_ids([username])[0]
    else:
        user_id = decode_token(request)
    return jsonify(s3_cache.unpack_s3_json(f"{game_id}/{user_id}/{BALANCES_CHART_PREFIX}"))
Beispiel #11
0
    def test_visuals_after_hours(self):
        game_id = 5
        start_time = 1591923966
        self._start_game_runner(start_time, game_id)

        # These are the internals of the celery tasks that called to update their state
        serialize_and_pack_pending_orders(game_id, self.user_id)
        pending_orders_table = s3_cache.unpack_s3_json(
            f"{game_id}/{self.user_id}/{PENDING_ORDERS_PREFIX}")
        self.assertEqual(pending_orders_table["data"][0]["Symbol"],
                         self.stock_pick)
        self.assertEqual(len(pending_orders_table["data"]), 1)
        fulfilled_orders_table = s3_cache.unpack_s3_json(
            f"{game_id}/{self.user_id}/{FULFILLED_ORDER_PREFIX}")
        self.assertEqual(fulfilled_orders_table["data"], [])

        serialize_and_pack_portfolio_details(game_id, self.user_id)
        current_balances = s3_cache.unpack_s3_json(
            f"{game_id}/{self.user_id}/{CURRENT_BALANCES_PREFIX}")
        self.assertEqual(len(current_balances["data"]), 0)

        with patch("backend.logic.base.time") as base_time_mock:
            base_time_mock.time.side_effect = [start_time] * 2 * 2
            df = make_user_balances_chart_data(game_id, self.user_id)
            serialize_and_pack_balances_chart(df, game_id, self.user_id)
            balances_chart = s3_cache.unpack_s3_json(
                f"{game_id}/{self.user_id}/{BALANCES_CHART_PREFIX}")
            self.assertEqual(len(balances_chart["datasets"]), 1)
            self.assertEqual(balances_chart["datasets"][0]["label"], "Cash")
            self.assertEqual(balances_chart["datasets"][0]["backgroundColor"],
                             NULL_RGBA)

            compile_and_pack_player_leaderboard(game_id)
            leaderboard = s3_cache.unpack_s3_json(
                f"{game_id}/{LEADERBOARD_PREFIX}")
            self.assertTrue(
                all([
                    x["cash_balance"] == STARTING_VIRTUAL_CASH
                    for x in leaderboard["records"]
                ]))
Beispiel #12
0
    def test_visuals_with_data(self, mock_base_time, mock_game_time):
        mock_base_time.time.return_value = mock_game_time.time.return_value = simulation_end_time
        game_id = 3
        user_id = 1
        serialize_and_pack_pending_orders(game_id, user_id)
        pending_order_table = s3_cache.unpack_s3_json(
            f"{game_id}/{user_id}/{PENDING_ORDERS_PREFIX}")
        self.assertNotIn("order_id", pending_order_table["headers"])
        self.assertEqual(len(pending_order_table["headers"]), 9)

        user_ids = get_active_game_user_ids(game_id)
        for player_id in user_ids:
            serialize_and_pack_order_performance_assets(game_id, player_id)

        op_chart_3_1 = s3_cache.unpack_s3_json(
            f"{game_id}/{user_id}/{ORDER_PERF_CHART_PREFIX}")
        chart_stocks = set(
            [x["label"].split("/")[0] for x in op_chart_3_1["datasets"]])
        expected_stocks = {"AMZN", "TSLA", "LYFT", "SPXU", "NVDA"}
        self.assertEqual(chart_stocks, expected_stocks)
        for user_id in user_ids:
            self.assertIn(f"{game_id}/{user_id}/{ORDER_PERF_CHART_PREFIX}",
                          s3_cache.keys())
Beispiel #13
0
def serialize_and_pack_portfolio_comps_chart(df: pd.DataFrame, game_id: int):
    usernames = get_game_users(game_id)
    user_colors = assign_colors(usernames)
    datasets = []
    if df["username"].nunique() == df.shape[0]:
        # if our portfolio dataframe only has as many rows as there are users in the game, this means that we've just
        # started the game, and can post a null chart to the field
        for username, color in user_colors.items():
            null_chart = make_null_chart(username)
            datasets.append(null_chart["datasets"][0])
        labels = null_chart["labels"]
        chart_json = dict(labels=list(labels), datasets=datasets)
    else:
        colors = []
        for username in df["username"].unique():
            colors.append(user_colors[username])
        chart_json = make_chart_json(df, "username", "value", colors=colors)

    leaderboard = s3_cache.unpack_s3_json(f"{game_id}/{LEADERBOARD_PREFIX}")
    chart_json["leaderboard"] = leaderboard["records"]
    s3_cache.set(f"{game_id}/{FIELD_CHART_PREFIX}", json.dumps(chart_json))
Beispiel #14
0
    def test_winner_payouts(self):
        """Use canonical game #3 to simulate a series of winner calculations on the test data. Note that since we only
        have a week of test data, we'll effectively recycle the same information via mocks
        """
        game_id = 3
        user_ids = get_active_game_user_ids(game_id)
        self.assertEqual(user_ids, [1, 3, 4])
        game_info = get_game_info(game_id)

        n_players = len(user_ids)
        pot_size = n_players * game_info["buy_in"]
        self.assertEqual(pot_size, 300)

        last_payout_date = get_last_sidebet_payout(game_id)
        self.assertIsNone(last_payout_date)

        offset = make_date_offset(game_info["side_bets_period"])
        self.assertEqual(offset, DateOffset(days=7))

        start_time = game_info["start_time"]
        end_time = game_info["end_time"]
        self.assertEqual(start_time, simulation_start_time)

        n_sidebets = n_sidebets_in_game(start_time, end_time, offset)
        self.assertEqual(n_sidebets, 2)

        # we'll mock in daily portfolio values to speed up the time this test takes
        user_1_portfolio = portfolio_value_by_day(game_id, 1, start_time,
                                                  end_time)
        user_3_portfolio = portfolio_value_by_day(game_id, 3, start_time,
                                                  end_time)
        user_4_portfolio = portfolio_value_by_day(game_id, 4, start_time,
                                                  end_time)

        # expected sidebet dates
        start_dt = posix_to_datetime(start_time)
        end_dt = posix_to_datetime(end_time)
        sidebet_dates = get_expected_sidebets_payout_dates(
            start_dt, end_dt, game_info["side_bets_perc"], offset)
        sidebet_dates_posix = [datetime_to_posix(x) for x in sidebet_dates]

        with patch("backend.logic.metrics.portfolio_value_by_day"
                   ) as portfolio_mocks, patch(
                       "backend.logic.base.time") as base_time_mock:
            time = Mock()
            time_1 = datetime_to_posix(posix_to_datetime(start_time) + offset)
            time_2 = end_time

            time.time.side_effect = base_time_mock.time.side_effect = [
                time_1, time_2
            ]
            portfolio_mocks.side_effect = [
                user_1_portfolio, user_3_portfolio, user_4_portfolio
            ] * 4

            winner_id, score = get_winner(game_id, start_time, end_time,
                                          game_info["benchmark"])
            log_winners(game_id, time.time())
            sidebet_entry = query_to_dict(
                "SELECT * FROM winners WHERE id = 1;")[0]
            self.assertEqual(sidebet_entry["winner_id"], winner_id)
            self.assertAlmostEqual(sidebet_entry["score"], score, 4)
            side_pot = pot_size * (game_info["side_bets_perc"] /
                                   100) / n_sidebets
            self.assertEqual(sidebet_entry["payout"],
                             side_pot * PERCENT_TO_USER)
            self.assertEqual(sidebet_entry["type"], "sidebet")
            self.assertEqual(sidebet_entry["start_time"], start_time)
            self.assertEqual(sidebet_entry["end_time"], sidebet_dates_posix[0])
            self.assertEqual(sidebet_entry["timestamp"], time_1)

            log_winners(game_id, time.time())
            sidebet_entry = query_to_dict(
                "SELECT * FROM winners WHERE id = 2;")[0]
            self.assertEqual(sidebet_entry["winner_id"], winner_id)
            self.assertAlmostEqual(sidebet_entry["score"], score, 4)
            self.assertEqual(sidebet_entry["payout"],
                             side_pot * PERCENT_TO_USER)
            self.assertEqual(sidebet_entry["type"], "sidebet")
            self.assertEqual(sidebet_entry["start_time"],
                             sidebet_dates_posix[0])
            self.assertEqual(sidebet_entry["end_time"], sidebet_dates_posix[1])
            self.assertEqual(sidebet_entry["timestamp"], time_2)

            overall_entry = query_to_dict(
                "SELECT * FROM winners WHERE id = 3;")[0]
            final_payout = pot_size * (1 - game_info["side_bets_perc"] / 100)
            self.assertEqual(overall_entry["payout"],
                             final_payout * PERCENT_TO_USER)
            with self.engine.connect() as conn:
                df = pd.read_sql("SELECT * FROM winners", conn)
            self.assertEqual(df.shape, (3, 10))

        serialize_and_pack_winners_table(game_id)
        payouts_table = s3_cache.unpack_s3_json(f"{game_id}/{PAYOUTS_PREFIX}")
        self.assertEqual(len(payouts_table["data"]), 3)
        self.assertTrue(
            sum([x["Type"] == "Sidebet" for x in payouts_table["data"]]), 2)
        self.assertTrue(
            sum([x["Type"] == "Overall" for x in payouts_table["data"]]), 1)
        for entry in payouts_table["data"]:
            if entry["Type"] == "Sidebet":
                self.assertEqual(entry["Payout"], side_pot * PERCENT_TO_USER)
            else:
                self.assertEqual(entry["Payout"],
                                 final_payout * PERCENT_TO_USER)
Beispiel #15
0
def removing_pending_order(game_id: int, user_id: int, order_id: int):
    fn = f"{game_id}/{user_id}/{PENDING_ORDERS_PREFIX}"
    order_json = s3_cache.unpack_s3_json(fn)
    order_json["data"] = [entry for entry in order_json["data"] if entry["order_id"] != order_id]
    s3_cache.set(fn, json.dumps(order_json))
Beispiel #16
0
def api_games_per_users():
    return jsonify(s3_cache.unpack_s3_json(GAMES_PER_USER_PREFIX))
Beispiel #17
0
def api_orders_per_active_user():
    return jsonify(s3_cache.unpack_s3_json(ORDERS_PER_ACTIVE_USER_PREFIX))
Beispiel #18
0
def get_leaderboard():
    game_id = request.json.get("game_id")
    return jsonify(s3_cache.unpack_s3_json(f"{game_id}/{LEADERBOARD_PREFIX}"))
Beispiel #19
0
def get_payouts_table():
    game_id = request.json.get("game_id")
    return jsonify(s3_cache.unpack_s3_json(f"{game_id}/{PAYOUTS_PREFIX}"))
Beispiel #20
0
    def _start_game_runner(self, start_time, game_id):
        s3_cache.flushall()
        user_statuses = get_user_invite_statuses_for_pending_game(game_id)
        pending_user_usernames = [
            x["username"] for x in user_statuses if x["status"] == "invited"
        ]
        pending_user_ids = get_user_ids(pending_user_usernames)

        # get all user IDs for the game. For this test case everyone is going or accept
        with self.engine.connect() as conn:
            result = conn.execute(
                "SELECT DISTINCT user_id FROM game_invites WHERE game_id = %s",
                game_id).fetchall()
        all_ids = [x[0] for x in result]
        self.user_id = all_ids[0]

        # all users accept their game invite
        with patch("backend.logic.games.time") as game_time_mock, patch(
                "backend.logic.base.time") as base_time_mock:
            game_time_mock.time.return_value = start_time
            time = Mock()
            time.time.return_value = base_time_mock.time.return_value = start_time
            for user_id in pending_user_ids:
                respond_to_game_invite(game_id, user_id, "joined", time.time())

        # check that we have the balances that we expect
        sql = "SELECT balance, user_id from game_balances WHERE game_id = %s;"
        with self.engine.connect() as conn:
            df = pd.read_sql(sql, conn, params=[game_id])
        self.assertTrue(df.shape, (0, 2))

        sql = "SELECT balance, user_id from game_balances WHERE game_id = %s;"
        with self.engine.connect() as conn:
            df = pd.read_sql(sql, conn, params=[game_id])
        self.assertTrue(df.shape, (4, 2))

        # a couple things should have just happened here. We expect to have the following assets available to us
        # now in our redis cache: (1) an empty open orders table for each user, (2) an empty current balances table for
        # each user, (3) an empty field chart for each user, (4) an empty field chart, and (5) an initial game stats
        # list
        cache_keys = s3_cache.keys()
        self.assertIn(f"{game_id}/{LEADERBOARD_PREFIX}", cache_keys)
        self.assertIn(f"{game_id}/{FIELD_CHART_PREFIX}", cache_keys)
        for user_id in all_ids:
            self.assertIn(f"{game_id}/{user_id}/{CURRENT_BALANCES_PREFIX}",
                          cache_keys)
            self.assertIn(f"{game_id}/{user_id}/{PENDING_ORDERS_PREFIX}",
                          cache_keys)
            self.assertIn(f"{game_id}/{user_id}/{FULFILLED_ORDER_PREFIX}",
                          cache_keys)
            self.assertIn(f"{game_id}/{user_id}/{BALANCES_CHART_PREFIX}",
                          cache_keys)
            self.assertIn(f"{game_id}/{user_id}/{ORDER_PERF_CHART_PREFIX}",
                          cache_keys)

        # quickly verify the structure of the chart assets. They should be blank, with transparent colors
        field_chart = s3_cache.unpack_s3_json(
            f"{game_id}/{FIELD_CHART_PREFIX}")
        self.assertEqual(len(field_chart["datasets"]), len(all_ids))
        chart_colors = [x["backgroundColor"] for x in field_chart["datasets"]]
        self.assertTrue(all([x == NULL_RGBA for x in chart_colors]))

        leaderboard = s3_cache.unpack_s3_json(
            f"{game_id}/{LEADERBOARD_PREFIX}")
        self.assertEqual(len(leaderboard["records"]), len(all_ids))
        self.assertTrue(
            all([
                x["cash_balance"] == STARTING_VIRTUAL_CASH
                for x in leaderboard["records"]
            ]))

        a_current_balance_table = s3_cache.unpack_s3_json(
            f"{game_id}/{self.user_id}/{CURRENT_BALANCES_PREFIX}")
        self.assertEqual(a_current_balance_table["data"], [])

        an_open_orders_table = s3_cache.unpack_s3_json(
            f"{game_id}/{self.user_id}/{PENDING_ORDERS_PREFIX}")
        self.assertEqual(an_open_orders_table["data"], [])
        a_fulfilled_orders_table = s3_cache.unpack_s3_json(
            f"{game_id}/{self.user_id}/{FULFILLED_ORDER_PREFIX}")
        self.assertEqual(a_fulfilled_orders_table["data"], [])

        a_balances_chart = s3_cache.unpack_s3_json(
            f"{game_id}/{self.user_id}/{BALANCES_CHART_PREFIX}")
        self.assertEqual(len(a_balances_chart["datasets"]), 1)
        self.assertEqual(a_balances_chart["datasets"][0]["label"], "Cash")
        self.assertEqual(a_balances_chart["datasets"][0]["backgroundColor"],
                         NULL_RGBA)

        # now have a user put an order. It should go straight to the queue and be reflected in the open orders table,
        # but they should not have any impact on the user's balances if the order is placed outside of trading day
        self.stock_pick = "TSLA"
        self.market_price = 1_000
        with patch("backend.logic.games.time") as game_time_mock, patch(
                "backend.logic.base.time") as base_time_mock:
            game_time_mock.time.side_effect = [start_time + 1] * 2
            base_time_mock.time.return_value = start_time + 1
            stock_pick = self.stock_pick
            cash_balance = get_current_game_cash_balance(self.user_id, game_id)
            current_holding = get_current_stock_holding(
                self.user_id, game_id, stock_pick)
            order_id = place_order(user_id=self.user_id,
                                   game_id=game_id,
                                   symbol=self.stock_pick,
                                   buy_or_sell="buy",
                                   cash_balance=cash_balance,
                                   current_holding=current_holding,
                                   order_type="market",
                                   quantity_type="Shares",
                                   market_price=self.market_price,
                                   amount=1,
                                   time_in_force="day")
            serialize_and_pack_pending_orders(game_id, self.user_id)
            add_fulfilled_order_entry(game_id, self.user_id, order_id)
            serialize_and_pack_portfolio_details(game_id, self.user_id)
Beispiel #21
0
def field_chart():
    game_id = request.json.get("game_id")
    return jsonify(s3_cache.unpack_s3_json(f"{game_id}/{FIELD_CHART_PREFIX}"))
Beispiel #22
0
    def test_visuals_during_trading(self):
        # TODO: Add a canonical test with fully populated data
        """When a user first places an order, we don't necessarily expect that security to have generated any data, yet.
        There should be a blank chart until data is available
        """
        game_id = 5
        start_time = simulation_start_time
        self._start_game_runner(start_time, game_id)

        # now have a user put in a couple orders. Valid market orders should clear and reflect in the balances table,
        # valid stop/limit orders should post to pending orders
        serialize_and_pack_pending_orders(game_id, self.user_id)
        pending_orders_table = s3_cache.unpack_s3_json(
            f"{game_id}/{self.user_id}/{PENDING_ORDERS_PREFIX}")
        fulfilled_orders_table = s3_cache.unpack_s3_json(
            f"{game_id}/{self.user_id}/{FULFILLED_ORDER_PREFIX}")

        # since the order has been filled, we expect a clear price to be present
        self.assertNotEqual(fulfilled_orders_table["data"][0]["Clear price"],
                            NA_TEXT_SYMBOL)
        self.assertEqual(fulfilled_orders_table["data"][0]["Symbol"],
                         self.stock_pick)
        self.assertEqual(pending_orders_table["data"], [])
        self.assertEqual(len(fulfilled_orders_table["data"]), 1)

        serialize_and_pack_portfolio_details(game_id, self.user_id)
        current_balances = s3_cache.unpack_s3_json(
            f"{game_id}/{self.user_id}/{CURRENT_BALANCES_PREFIX}")
        self.assertEqual(len(current_balances["data"]), 1)

        with patch("backend.logic.base.time") as base_time_mock:
            base_time_mock.time.side_effect = [start_time + 10] * 2 * 2
            df = make_user_balances_chart_data(game_id, self.user_id)
            serialize_and_pack_balances_chart(df, game_id, self.user_id)
            balances_chart = s3_cache.unpack_s3_json(
                f"{game_id}/{self.user_id}/{BALANCES_CHART_PREFIX}")
            self.assertEqual(len(balances_chart["datasets"]), 2)
            stocks = set([x["label"] for x in balances_chart["datasets"]])
            self.assertEqual(stocks, {"Cash", self.stock_pick})
            self.assertNotIn(
                NULL_RGBA,
                [x["backgroundColor"] for x in balances_chart["datasets"]])

            compile_and_pack_player_leaderboard(game_id)
            leaderboard = s3_cache.unpack_s3_json(
                f"{game_id}/{LEADERBOARD_PREFIX}")
            user_stat_entry = [
                x for x in leaderboard["records"] if x["id"] == self.user_id
            ][0]
            self.assertEqual(user_stat_entry["cash_balance"],
                             STARTING_VIRTUAL_CASH - self.market_price)
            self.assertTrue(
                all([
                    x["cash_balance"] == STARTING_VIRTUAL_CASH
                    for x in leaderboard["records"] if x["id"] != self.user_id
                ]))

        fulfilled_orders_table = s3_cache.unpack_s3_json(
            f'{game_id}/{self.user_id}/{FULFILLED_ORDER_PREFIX}')
        self.assertIn("order_label", fulfilled_orders_table["data"][0].keys())
        self.assertIn("color", fulfilled_orders_table["data"][0].keys())