def record_position(self, position=1):
     app = db.get_app()
     pos = Position()
     pos.position = position
     pos.week = current_round()
     pos.season = app.config['SEASON']
     self.positions.append(pos)
示例#2
0
    async def __run_buy(self):
        user = User.get_by_discord_id(self.message.author.id)
        order_dict = {
            'operation': "buy",
            'season': app.config['SEASON'],
            'week': current_round()
        }

        if user is None:
            await self.reply([
                (f"User {self.message.author.mention} does not exist."
                 "Use !newuser to create user first.")
            ])
            return

        if len(self.args) not in [2, 3]:
            await self.reply([
                "Incorrect number of arguments!!!",
                self.__class__.buy_help()
            ])
            return
        try:
            stock = Stock.find_by_code(self.args[1])
        except MultipleResultsFound as exc:
            await self.reply([
                f"Stock code **{self.args[1]}** is not unique!!!",
            ])
            return

        if not stock:
            await self.reply([f"Stock code **{self.args[1]}** not found!"])
            return

        if len(self.args) == 3:
            if not represents_int(self.args[2]) or (represents_int(
                    self.args[2]) and not int(self.args[2]) > 0):
                await self.reply(
                    [f"**{self.args[2]}** must be whole positive number!"])
                return
            else:
                if int(self.args[2]) <= app.config['MAX_SHARE_UNITS']:
                    order_dict['buy_shares'] = self.args[2]
                else:
                    order_dict['buy_funds'] = self.args[2]

        round_n = app.config['ROUNDS_COLLECT'][-1]
        match = MatchService.get_game(stock.name, round_n=round_n)
        if match and (match.homeTeamName.strip() in app.config['ADMIN_TEAMS'] or \
                    match.awayTeamName.strip() in app.config['ADMIN_TEAMS']):
            await self.reply(
                [f"You cannot buy stocks of a team going into BYE week!!!"])
            return

        order = OrderService.create(user, stock, **order_dict)
        await self.reply([
            f"Order **{order.id}** placed succesfully.", " ",
            f"**{order.desc()}**"
        ])
        return
示例#3
0
    async def __run_stock(self):
        if (self.args[0]) == "!stock":
            detail = False
            if len(self.args) < 2:
                await self.reply([
                    "Incorrect number of arguments!!!",
                    self.__class__.stock_help()
                ])
            else:
                limit = 24
                if self.args[1] in [
                        "top", "bottom", "hot", "net", "gain", "loss", "gain%",
                        "loss%"
                ] and len(self.args) == 3 and represents_int(
                        self.args[2]) and int(self.args[2]) > 0 and int(
                            self.args[2]) <= limit:
                    if self.args[1] == "top":
                        stocks = Stock.find_top(self.args[2])
                    elif self.args[1] == "bottom":
                        stocks = Stock.find_bottom(self.args[2])
                    elif self.args[1] == "net":
                        stocks = Stock.find_net(self.args[2])
                    elif self.args[1] == "gain":
                        stocks = Stock.find_gain(self.args[2])
                    elif self.args[1] == "gain%":
                        stocks = Stock.find_gain_pct(self.args[2])
                    elif self.args[1] == "loss":
                        stocks = Stock.find_loss(self.args[2])
                    elif self.args[1] == "loss%":
                        stocks = Stock.find_loss_pct(self.args[2])
                    else:
                        stocks = Stock.find_hot(self.args[2])
                elif self.args[1] == "detail" and len(self.args) == 3:
                    detail = True
                    try:
                        stock = Stock.find_by_code(self.args[2])
                        if not stock:
                            await self.reply(
                                [f"{self.args[2]} is not unique stock code"])
                            return
                        stocks = [stock]
                    except MultipleResultsFound as exc:
                        await self.reply(
                            [f"{self.args[2]} is not unique stock code"])
                        return
                else:
                    stocks = Stock.find_all_by_name(" ".join(self.args[1:]))
                msg = []
                change_desc = "Change" if self.args[1] not in [
                    "gain%", "loss%"
                ] else "Change%"
                msg.append(
                    '{:5s} - {:25} {:<8s} {:>7s}{:>9s}{:>8s}{:>11s}'.format(
                        "Code", "Team Name", "Division", "Price", change_desc,
                        "Shares", "Net Worth"))
                msg.append(78 * "-")
                round_n = current_round()
                for stock in stocks[0:limit]:
                    match = MatchService.get_game(stock.name, round_n=round_n)
                    played = "Y" if match and match.match_uuid else "N"
                    changed_value = stock.unit_price_change if self.args[
                        1] not in ["gain%", "loss%"] else 0 if int(
                            stock.unit_price
                        ) == 0 else 100 * stock.unit_price_change / (
                            stock.unit_price - stock.unit_price_change)
                    msg.append(
                        '{:5s} - {:25} {:<8s} {:>7.2f}{:>8.2f}{:1s}{:>8d}{:>11.2f}'
                        .format(stock.code, stock.name, stock.division,
                                stock.unit_price, changed_value, played,
                                stock.share_count, stock.net_worth))
                if detail:
                    round_n = app.config['ROUNDS_COLLECT'][-1]
                    match = MatchService.get_game(stocks[0].name,
                                                  round_n=round_n)
                    if match:
                        homeStock = Stock.find_all_by_name(
                            match.homeTeamName.strip())
                        awayStock = Stock.find_all_by_name(
                            match.awayTeamName.strip())

                        homePrice = 0 if not homeStock else homeStock[
                            0].unit_price
                        awayPrice = 0 if not awayStock else awayStock[
                            0].unit_price

                        homeChange = 0 if not homeStock else homeStock[
                            0].unit_price_change
                        awayChange = 0 if not awayStock else awayStock[
                            0].unit_price_change

                        homeRace = "N/A" if not homeStock else homeStock[0].race
                        awayRace = "N/A" if not awayStock else awayStock[0].race
                        msg.append(" ")
                        msg.append(f"[Round {round_n} Match]")
                        msg.append('{:>37s}  |  {:<36s}'.format(
                            "Home", "Away"))
                        msg.append(78 * "-")
                        msg.append('{:>37s}  |  {:<36s}'.format(
                            match.homeCoachName, match.awayCoachName))
                        msg.append('{:>37s}  |  {:<36s}'.format(
                            match.homeTeamName, match.awayTeamName))
                        msg.append('{:>37s}  |  {:<36s}'.format(
                            homeRace, awayRace))
                        msg.append('{:>37.2f}  |  {:<36.2f}'.format(
                            homePrice, awayPrice))
                        msg.append('{:>37.2f}  |  {:<36.2f}'.format(
                            homeChange, awayChange))

                    # only 1 stock
                    msg.append(" ")
                    msg.append("[Owners]")
                    msg.append(" ")
                    msg.append('{:32s}: {:>8s}{:>11s}'.format(
                        "Name", "Shares", "Net Worth"))
                    msg.append(78 * "-")
                    for share in stocks[0].shares:
                        msg.append('{:32s}: {:8d}{:11.2f}'.format(
                            share.user.short_name(), share.units,
                            round(share.units * share.stock.unit_price, 2)))

                    msg.append(" ")
                    msg.append("[History]")
                    msg.append(" ")
                    msg.append('{:20s}: {:<12s}{:<8s}{:<8s}{:<11s}'.format(
                        "Date", "Unit Price", "Change", "Shares", "Net Worth"))
                    msg.append(78 * "-")
                    for sh in stocks[0].histories:
                        msg.append(
                            '{:20s}: {:10.2f}{:8.2f}{:8d}{:11.2f}'.format(
                                str(sh.date_created), sh.unit_price,
                                sh.unit_price_change, sh.units,
                                round(sh.units * sh.unit_price, 2)))

                if len(stocks) > 20:
                    msg.append("...")
                    msg.append("More stock follows, narrow your search!")
                await self.reply(msg, block=True)
示例#4
0
    def list_messages(self, user):
        msg1 = [
            f"**User:** {user.short_name()}\n",
            "```",
            "{:19s}: {:9.2f}".format("Bank",
                                     user.account().amount),
            "{:19s}: {:9.2f}".format("Shares Value", user.shares_value()),
            30 * "-",
            "{:19s}: {:9.2f}".format("Balance", user.balance()),
            "{:19s}: {:9.2f}".format("This Week Gain", user.current_gain()),
            "{:19s}: {:9.2f}".format("Last Week Gain",
                                     user.week_gain(current_round() - 1)),
            "{:19s}: {:>9}".format(
                "Last Week Position",
                user.position(app.config['SEASON'],
                              current_round() - 1)),
            "{:19s}: {:9d}".format("Points", user.points()),
            30 * "-",
        ]
        for record in user.point_card().records:
            msg1.append("{:2d} points - {}".format(record.amount,
                                                   record.reason))
        msg1.extend([
            "```",
            " ",
            f"**Shares:**",
        ])

        msg2 = []
        if user.shares:
            round_n = current_round()
            for share in user.shares:
                gain = round(share.stock.unit_price_change, 2)
                match = MatchService.get_game(share.stock.name,
                                              round_n=round_n)
                played = "Y" if match and match.match_uuid else "N"
                if gain > 0:
                    gain = "+" + str(gain)
                elif gain == 0:
                    gain = "0.00"
                else:
                    gain = str(gain)
                msg2.append(
                    '{:5s} - {:25s}: {:3d} x {:7.2f}, Change: {:>7s}, Played: {:1s}'
                    .format(share.stock.code, share.stock.name, share.units,
                            share.stock.unit_price, gain, played))

        msg3 = []
        msg3.append(" ")
        if user.orders:
            msg3.append(f"**Outstanding Orders:**")

        for order in user.orders:
            if not order.processed and order.operation == "sell":
                msg3.append(f"{order.id}. {order.desc()}")
        msg3.append(" ")

        for order in user.orders:
            if not order.processed and order.operation == "buy":
                msg3.append(f"{order.id}. {order.desc()}")
        msg3.append(" ")

        msg3.append(" ")
        msg3.append(f"**Balance history:**")

        msg4 = []
        msg4.append('{:20s}: {:>8s}{:>13s}'.format("Date", "Shares",
                                                   "Balance"))
        for history in sorted(user.balance_histories,
                              key=lambda x: x.date_created,
                              reverse=True)[:10]:
            msg4.append('{:20s}: {:>8d}{:>13.2f}'.format(
                str(history.date_created), history.shares, history.balance))
        return msg1, msg2, msg3, msg4
示例#5
0
    async def __run_sell(self):
        user = User.get_by_discord_id(self.message.author.id)
        order_dict = {
            'operation': "sell",
            'season': app.config['SEASON'],
            'week': current_round()
        }

        if user is None:
            await self.reply([
                (f"User {self.message.author.mention} does not exist."
                 "Use !newuser to create user first.")
            ])
            return

        if len(self.args) not in [2, 3]:
            await self.reply([
                "Incorrect number of arguments!!!",
                self.__class__.sell_help()
            ])
            return
        if self.args[1] == "all":
            if len(user.shares):
                for share in user.shares:
                    order = OrderService.create(user, share.stock,
                                                **order_dict)
                    await self.reply([
                        f"Order placed succesfully.", " ",
                        f"**{order.desc()}**"
                    ])
            else:
                await self.reply([f"You do not own any shares"])
        else:
            try:
                stock = Stock.find_by_code(self.args[1])
            except MultipleResultsFound as exc:
                await self.reply([
                    f"Stock code **{self.args[1]}** is not unique!!!",
                ])
                return

            if not stock:
                await self.reply([f"Stock code **{self.args[1]}** not found!"])
                return

            if len(self.args) == 3:
                if not represents_int(self.args[2]) or (represents_int(
                        self.args[2]) and not int(self.args[2]) > 0):
                    await self.reply(
                        [f"**{self.args[2]}** must be whole positive number!"])
                    return
                else:
                    order_dict['sell_shares'] = int(self.args[2])

            share = Share.query.join(Share.user, Share.stock).filter(
                User.id == user.id, Stock.id == stock.id).one_or_none()

            if not share:
                await self.reply([
                    f"You do not own any shares of **{self.args[1]}** stock!"
                ])
                return

            order = OrderService.create(user, stock, **order_dict)
            await self.reply([
                f"Order **{order.id}** placed succesfully.", " ",
                f"**{order.desc()}**"
            ])
        return
 def current_gain(self):
     app = db.get_app()
     return self.balance() - self.account().snapshot_for_week(current_round()-1).amount
 def __init__(self):
     app = db.get_app()
     self.season = app.config['SEASON']
     self.amount = Decimal(self.INIT_CASH)
     self.make_snapshot(current_round()-1)
def main(argv):
    """main()"""
    try:
        opts, args = getopt.getopt(argv, "h")
    except getopt.GetoptError:
        print('process_orders.py -h')
        sys.exit(2)
    for opt, arg in opts:
        if opt == '-h':
            print("Process all queued orders")
            sys.exit(0)

    try:

        def chunk_orders(orders):
            group_count = 10
            order_chunks = [
                orders[i:i + group_count]
                for i in range(0, len(orders), group_count)
            ]
            for chunk in order_chunks:
                msg = []
                for order in chunk:
                    order = OrderService.process(order)
                    msg.append(f"{order.user.mention()}: {order.result}")

                OrderNotificationService.notify("\n".join(msg))

        AdminNotificationService.notify("Updating DB ...")
        StockService.update()
        AdminNotificationService.notify("Done")
        AdminNotificationService.notify("Closing market ...")
        OrderService.close()
        AdminNotificationService.notify("Done")

        AdminNotificationService.notify("Processing SELL orders...")
        orders = Order.query.order_by(asc(Order.date_created)).filter(
            Order.processed == False, Order.operation == "sell").all()
        chunk_orders(orders)
        AdminNotificationService.notify("Done")

        AdminNotificationService.notify("Processing BUY orders...")
        orders = Order.query.order_by(asc(Order.date_created)).filter(
            Order.processed == False, Order.operation == "buy").all()
        chunk_orders(orders)
        AdminNotificationService.notify("Done")

        AdminNotificationService.notify("Opening market...")
        OrderService.open()
        AdminNotificationService.notify("Done")

        # points and gains only after allowed
        if app.config['ALLOW_TRACKING']:
            AdminNotificationService.notify("Recording gains...")
            for user in User.query.all():
                user.account().make_snapshot(current_round())
            db.session.commit()
            AdminNotificationService.notify("Done")

            AdminNotificationService.notify("Recording positions...")
            sorted_users = UserService.week_gain(current_round(),
                                                 User.query.count())
            for i, (position, value, user) in enumerate(sorted_users):
                user.record_position(position)
            db.session.commit()
            AdminNotificationService.notify("Done")

            AdminNotificationService.notify("Awarding points...")
            for i, (position, value, user) in enumerate(sorted_users):
                if position > 25:
                    break
                user.award_points(
                    POINTS[position],
                    f"Top {position} gain in week {current_round()}")
                OrderNotificationService.notify(
                    f"{user.mention()}: Awarded {POINTS[position]} points for top {position} gain ({round(value,2)}) in week {current_round()}"
                )
            db.session.commit()
            AdminNotificationService.notify("Done")
        else:
            AdminNotificationService.notify("Point awards skipped")

    except Exception as exc:
        AdminNotificationService.notify(str(exc))
        raise exc