So far, I have finished buy, quote, and the register functions, currently working on the index. I finished writing my index and tried to run the program to check, but I get a 500 internal server error.
I am following Devin Finley's guide, and although I am not done with it so far, my program should still be running. I don't know why I am getting these errors, so ANY help would be appreciated!
Helpers function (left untouched from when I downloaded the folder):
import csv
import datetime
import pytz
import requests
import subprocess
import urllib
import uuid
from flask import redirect, render_template, session
from functools import wraps
def apology(message, code=400):
"""Render message as an apology to user."""
def escape(s):
"""
Escape special characters.
https://github.com/jacebrowning/memegen#special-characters
"""
for old, new in [("-", "--"), (" ", "-"), ("_", "__"), ("?", "~q"),
("%", "~p"), ("#", "~h"), ("/", "~s"), ("\"", "''")]:
s = s.replace(old, new)
return s
return render_template("apology.html", top=code, bottom=escape(message)), code
def login_required(f):
"""
Decorate routes to require login.
http://flask.pocoo.org/docs/0.12/patterns/viewdecorators/
"""
@wraps(f)
def decorated_function(*args, **kwargs):
if session.get("user_id") is None:
return redirect("/login")
return f(*args, **kwargs)
return decorated_function
def lookup(symbol):
"""Look up quote for symbol."""
# Prepare API request
symbol = symbol.upper()
end = datetime.datetime.now(pytz.timezone("US/Eastern"))
start = end - datetime.timedelta(days=7)
# Yahoo Finance API
url = (f"https://query1.finance.yahoo.com/v7/finance/download/{urllib.parse.quote_plus(symbol)}"
f"?period1={int(start.timestamp())}"
f"&period2={int(end.timestamp())}"
f"&interval=1d&events=history&includeAdjustedClose=true"
)
# Query API
try:
response = requests.get(url, cookies={"session": str(uuid.uuid4())}, headers={"User-Agent": "python-requests", "Accept": "*/*"})
response.raise_for_status()
# CSV header: Date,Open,High,Low,Close,Adj Close,Volume
quotes = list(csv.DictReader(response.content.decode("utf-8").splitlines()))
quotes.reverse()
price = round(float(quotes[0]["Adj Close"]), 2)
return {
"name": symbol,
"price": price,
"symbol": symbol
}
except (requests.RequestException, ValueError, KeyError, IndexError):
return None
def usd(value):
"""Format value as USD."""
return f"${value:,.2f}"
This is my index function in app.py:
@app.route("/")
@login_required
def index():
"""Show portfolio of stocks"""
#Get user's stocks and shares
stocks = db.execute("SELECT symbol, SUM (shares) as total_shares FROM transactions WHERE user_id = :user_id GROUP BY symbol HAVING total_shares > 0",
user_id=session["user_id"])
#Get user's cash balance
cash = db.execute("SELECT cash FROM users WHERE id = :user_id", user_id=session["user_id"])[0]["cash"]
#Initialize variables for total values
total_value = cash
grand_total = cash
#Iterate over stocks and add price and total value
for stock in stocks:
quote = lookup(stock["symbol"])
stock["name"] = quote["name"]
stock["price"] = quote["price"]
stock["value"] = stock["price"] * stock["total_shares"]
total_value += stock["value"]
grand_total += stock["value"]
return render_template("index.html", stocks=stocks, cash=cash, total_value=total_value, grand_total=grand_total)
This is my index.html:
{% extends "layout.html" %}
{% block title %}
Portfolio
{% endblock %}
{% block main %}
<h2>Portfolio</h2>
<table class="table table-bordered table-striped">
<thead class="thead-light">
<tr>
<th>Symbol</th>
<th>Name</th>
<th>Shares</th>
<th>Price</th>
<th>Total Value</th>
</tr>
</thead>
<tbody>
{% for stock in stocks %}
<tr>
<td>{{ stock.symbol }}</td>
<td>{{ stock.name }}</td>
<td>{{ stock.total_shares }}</td>
<td>{{ stock.price }}</td>
<td>{{ stock * stock.total_shares }}</td>
</tr>
{% endfor %}
<tr>
<td colspan="4" align="right">Cash</td>
<td>{{ cash }}</td>
</tr>
<tr>
<td colspan="4" align="right">Total Value</td>
<td>{{ total_value }}</td>
</tr>
</tbody>
</table>
{% endblock %}
This is my layout.html:
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, width=device-width">
<!-- http://getbootstrap.com/docs/5.1/ -->
<link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" rel="stylesheet">
<script crossorigin="anonymous" src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"></script>
<!-- https://favicon.io/emoji-favicons/money-bag/ -->
<link href="/static/favicon.ico" rel="icon">
<link href="/static/styles.css" rel="stylesheet">
<title>C$50 Finance: {% block title %}{% endblock %}</title>
</head>
<body>
<nav class="bg-light border navbar navbar-expand-md navbar-light">
<div class="container-fluid">
<a class="navbar-brand" href="/"><span class="blue">C</span><span class="red">$</span><span class="yellow">5</span><span class="green">0</span> <span class="red">Finance</span></a>
<button aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation" class="navbar-toggler" data-bs-target="#navbar" data-bs-toggle="collapse" type="button">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbar">
{% if session["user_id"] %}
<ul class="navbar-nav me-auto mt-2">
<li class="nav-item"><a class="nav-link" href="/quote">Quote</a></li>
<li class="nav-item"><a class="nav-link" href="/buy">Buy</a></li>
<li class="nav-item"><a class="nav-link" href="/sell">Sell</a></li>
<li class="nav-item"><a class="nav-link" href="/history">History</a></li>
</ul>
<ul class="navbar-nav ms-auto mt-2">
<li class="nav-item"><a class="nav-link" href="/logout">Log Out</a></li>
</ul>
{% else %}
<ul class="navbar-nav ms-auto mt-2">
<li class="nav-item"><a class="nav-link" href="/register">Register</a></li>
<li class="nav-item"><a class="nav-link" href="/login">Log In</a></li>
</ul>
{% endif %}
</div>
</div>
</nav>
{% if get_flashed_messages() %}
<header>
<div class="alert alert-primary mb-0 text-center" role="alert">
{{ get_flashed_messages() | join(" ") }}
</div>
</header>
{% endif %}
<main class="container-fluid py-5 text-center">
{% block main %}
{% endblock %}
</main>
<footer class="mb-5 small text-center text-muted">
Data provided by <a href="https://iexcloud.io/">IEX</a>
</footer>
</body>
Typo in index.html here
<td>{{ stock * stock.total_shares }}</td>1
stock
is a dict in the liststocks
.