Example #1
0
def submit_order():
    # Even before rendering the page, try to connect to RabbitMQ. If RabbitMQ
    # is not running, then redirect to an error page
    mq = ch = None
    try:
        mq: pika.BlockingConnection = get_mq()
        ch = mq.channel()
        ch.queue_declare(queue='incoming_order')
    except AMQPConnectionError as e:
        error_msg = "Webserver failed to connect to order queue"
        return redirect(url_for("exchange.error", error_msg=error_msg))

    form = OrderSubmitForm(request.form)
    if request.method == "POST" and form.validate_on_submit():
        new_order: Order = Order(
            security_symbol=form.security_symbol.data,
            side=form.side.data,
            size=form.size.data,
            price=form.price.data,
            all_or_none=form.all_or_none.data,
            immediate_or_cancel=form.immediate_or_cancel.data,
            owner_id=current_user.user_id)
        if new_order.side == "ask":
            user_existing_asset = get_db().query(Asset).get(
                (current_user.user_id, new_order.security_symbol))
            if user_existing_asset is None or user_existing_asset.asset_amount < new_order.size:
                return redirect(
                    url_for("exchange.error", error_msg="Insufficient assets"))
            else:
                logger.info(
                    f"Subtracting {new_order.size} shares of {new_order.security_symbol} from {current_user}"
                )
                user_existing_asset.asset_amount -= new_order.size
        if new_order.price is None:
            logger.info(f"Marking market order {new_order}")
            new_order.immediate_or_cancel = True
        db = get_db()
        db.add(new_order)
        db.commit()
        logger.info(f"{new_order} committed to database")

        ch.basic_publish(exchange='',
                         routing_key='incoming_order',
                         body=new_order.json)
        logger.info(f"{new_order} submitted to order queue")

        return redirect(url_for("exchange.dashboard"))
    return render_template("exchange/submit_order.html",
                           form=form,
                           title="Submit order")
Example #2
0
def start_company():
    form = StartCompanyForm(request.form)
    db = get_db()
    if request.method == "POST" and form.validate_on_submit():
        new_company: Company = Company(symbol=form.company_symbol.data,
                                       name=form.company_name.data,
                                       initial_value=form.input_cash.data,
                                       initial_size=form.size.data,
                                       founder_id=current_user.user_id,
                                       market_price=form.input_cash.data /
                                       form.size.data)
        db.add(new_company)

        founder_cash = db.query(Asset).get((current_user.user_id, "_CASH"))
        founder_cash.asset_amount -= float(form.input_cash.data)

        # Since this is a new company, the founder will definitely not have
        # prior assets
        founder_stocks = Asset(owner_id=current_user.user_id,
                               asset_symbol=form.company_symbol.data,
                               asset_amount=form.size.data)
        db.add(founder_stocks)
        db.commit()
        logger.info(f"{new_company} committed to database")
        logger.info(f"{founder_stocks} committed to database")

        return redirect(url_for("exchange.dashboard"))
    return render_template("exchange/start_company.html",
                           form=form,
                           title="Start company")
Example #3
0
def dashboard():
    db = get_db()
    # Any amount of cash will be displayed
    cash = [a for a in current_user.assets if (a.asset_symbol == "_CASH")][0]
    cash.asset_amount_display = format_number(cash.asset_amount,
                                              locale="en_US")
    # Empty assets for stocks will not be displayed
    stocks = [
        a for a in current_user.assets
        if (a.asset_symbol != "_CASH") and (a.asset_amount > 0)
    ]

    # Compute stocks' market value by company's market price * asset_amount
    # Then compute net worth by summing up cash and stocks market value
    net_worth = cash.asset_amount
    for stock in stocks:
        market_price = db.query(Company).get(stock.asset_symbol).market_price
        stock.market_value = market_price * stock.asset_amount
        stock.market_value_display = format_number(stock.market_value,
                                                   locale="en_US")
        stock.asset_amount_display = format_number(int(stock.asset_amount),
                                                   locale="en_US")
        net_worth += stock.market_value
    net_worth_display = format_number(net_worth, locale="en_US")
    return render_template("exchange/dashboard.html",
                           cash=cash,
                           stocks=stocks,
                           net_worth=net_worth_display,
                           title="Dashboard")
Example #4
0
def register():
    form = RegistrationForm(request.form)
    if request.method == "POST" and form.validate_on_submit():
        db_session = get_db()
        if db_session.query(User).filter(
                User.username == form.username.data).first() is not None:
            form.username.errors.append("Username already taken!")
        else:
            new_user: User = User(username=form.username.data,
                                  password_hash=generate_password_hash(
                                      form.password.data))
            db_session.add(new_user)
            db_session.commit()
            # Each user receives $10,000.00 of cash upon registration
            initial_cash_amount = 10000
            initial_cash = Asset(owner_id=new_user.user_id,
                                 asset_symbol="_CASH",
                                 asset_amount=initial_cash_amount)
            db_session.add(initial_cash)
            db_session.commit()
            logger.info(f"{new_user} received ${initial_cash_amount:.2f}")

            return redirect(url_for("auth.login"))

    return render_template("auth/register.html", form=form)
Example #5
0
def load_user(user_id):
    db_session = get_db()
    if user_id is not None:
        loaded_user = db_session.query(User).get(user_id)
        logger.info(f"Loading {loaded_user}")
        return loaded_user
    return None
Example #6
0
    def validate(self):
        supervalidate = Form.validate(self)
        db = get_db()
        if db.query(Company).get(self.company_symbol.data) is not None:
            self.company_symbol.errors.append("Company symbol already taken")
            return False

        return supervalidate
Example #7
0
def view_company(company_symbol):
    db = get_db()
    company = db.query(Company).get(company_symbol)
    if company is None:
        return redirect(
            url_for("exchange.error",
                    error_msg=f"Company {company_symbol} does not exist"))
    else:
        company.create_date_display = company.create_dttm.strftime("%Y-%m-%d")
        company.founder_name = company.founder.username
        return render_template("exchange/view_company.html",
                               company=company,
                               title=f"Company: {company_symbol}")
Example #8
0
def login():
    form = LoginForm(request.form)
    if request.method == "POST" and form.validate_on_submit():
        db_session = get_db()
        user = db_session.query(User).filter(
            User.username == form.username.data).first()
        if (user is not None) and check_password_hash(user.password_hash,
                                                      form.password.data):
            login_user(user)
            return redirect(url_for('exchange.dashboard'))
        else:
            form.password.errors.append(
                "Login failed; check your username and password")

    return render_template("auth/login.html", form=form)
Example #9
0
def recent_orders():
    """Render the most recent (up to) 50 orders
    """
    db = get_db()
    ownership = (Order.owner_id == current_user.user_id)
    create_dttm_desc = Order.create_dttm.desc()
    recent_orders = db.query(Order).filter(ownership).order_by(
        create_dttm_desc).limit(50).all()
    for order in recent_orders:
        order.side_display = "Buy" if order.side == "bid" else "Sell"
        order.price_display = f"${order.price:.2f}" if order.price is not None else "any price available"
        order.create_dttm_display = order.create_dttm.strftime(
            "%Y-%m-%d %H:%M:%S")

    return render_template("exchange/recent_orders.html",
                           orders=recent_orders,
                           title="Recent orders")
Example #10
0
def recent_transactions():
    """Render the most recent (up to) 50 transactions
    """
    db = get_db()
    order_ids = [o.order_id for o in current_user.orders]
    involves_current_user = Transaction.ask_id.in_(order_ids) \
        | Transaction.bid_id.in_(order_ids)
    dttm_desc = Transaction.transact_dttm.desc()
    transactions = db.query(Transaction).filter(
        involves_current_user).order_by(dttm_desc).limit(50).all()

    for t in transactions:
        t.side_display = "Bought" if (t.bid_id in order_ids) else "Sold"
        t.dttm_display = t.transact_dttm.strftime("%Y-%m-%d %H:%M:%S")

    return render_template("exchange/recent_transactions.html",
                           transactions=transactions,
                           title="Recent transactions")
Example #11
0
def stock_chart_data():
    symbol = request.args['symbol']
    zoom = request.args['zoom'] if "zoom" in request.args else "year"
    debug = int(request.args['debug']) if "debug" in request.args else 0
    db = get_db()

    # Query all transactions with transaction dttm sorted from earlier to later
    tfilter = (Transaction.security_symbol == symbol)
    # Add the dttm filter, which depends on the zoom level
    cutoff = dt.datetime.utcnow() - ZOOM_CONFIGS[zoom].cutoff_offset
    scale_unit = ZOOM_CONFIGS[zoom].scale_unit
    tfilter = tfilter & (Transaction.transact_dttm >= cutoff)

    sort_key = Transaction.transact_dttm.asc()
    query = db.query(Transaction).filter(tfilter).order_by(sort_key)

    # Convert the set of transactions into a 2 column dataframe: price vs dttm
    df = pd.read_sql(query.statement, db.bind)[['transact_dttm', 'price']]
    if debug:
        # If debug is set to True, then return dummy data without reading
        # from database
        random.seed(10)
        df = pd.DataFrame({
            "transact_dttm": [
                dt.datetime.fromtimestamp(
                    random.uniform(cutoff.timestamp(),
                                   dt.datetime.utcnow().timestamp()))
                for i in range(500)
            ],
            "price": [random.uniform(10, 100) for i in range(500)]
        }).sort_values('transact_dttm')
    agg_data_points = aggregate_stock_chart(df, zoom)
    agg_data_points_dict = [{
        "t": dp.t * 1000,
        "o": dp.o,
        "h": dp.h,
        "l": dp.l,
        "c": dp.c,
        "y": dp.c
    } for dp in agg_data_points]
    max_price = 0 if pd.isna(df['price'].max()) else df['price'].max()
    min_price = 0 if pd.isna(df['price'].min()) else df['price'].min()
    price_std = 0 if pd.isna(df['price'].std()) else df['price'].std()

    data = {
        "labels": [],
        "datasets": [{
            "label": "market price",
            "data": agg_data_points_dict
        }]
    }
    options = {
        "scales": {
            "x": {
                "type": 'time',
                "distribution": 'linear',
                "time": {
                    "unit": scale_unit
                }
            },
            "y": {
                "suggestedMax": max_price + 0.7 * price_std,
                "suggestedMin": max(0, min_price - 0.7 * price_std)
            }
        }
    }
    return jsonify({"data": data, "options": options})
Example #12
0
def autocomplete_companies():
    db = get_db()
    companies = db.query(Company).all()
    data = {c.symbol: None for c in companies}
    return jsonify(data)