Skip to content

Flask application: Same source code working without error on VS Code but problematic with Amazon Lightsail Ubuntu instance

0

I have a Flask application that is running on VS Code. Through Docker.com, a repository of the Flask application created, and that pushed to Ubuntu instance of Amazon Lightsail (http://44.206.118.123:8080/).

While the index page opening, the dropdown with the form fields not loading of the next 2 form fields (Stock Symbol 1, Stock Symbol 2). Also on changing the stock exchange option in the first form field leading to this:

Bad Request The browser (or proxy) sent a request that this server could not understand.

Error 400 (https://www.canva.com/design/DAGIcfEMV1s/aNAnc-Wot8HDW5v0Te6nzA/edit?utm_content=DAGIcfEMV1s&utm_campaign=designshare&utm_medium=link2&utm_source=sharebutton) seems to suggest the problem is on the client side and not the server as further validated by the fact that the same source code on VS Code working without such errors.

Since the original source code from VS Code from where a repository pushed to Docker.com and then from Docker.com pushed to Ubuntu (AWS Lightsail), tried with this command on Amazon CLI: sudo docker logs <container id>

Here is the screenshot: Enter image description here

223.177.58.195 - - [18/Jun/2024 03:42:18] "POST / HTTP/1.1" 400 -

The above mention of POST and 400 perhaps indicate some issue with form submission setting.

UPDATE

By opening port 443, all the 3 fields now uploads dropdown values correctly. But still clicking a button leads to 500 Internal Server Error now.

Enter image description here

Appears need to address this on app.py: *ValueError: Multi-dimensional indexing (e.g. obj[:, None]) is no longer supported. Convert to a numpy array before indexing instead. *

asked 2 years ago712 views

7 Answers
2
Accepted Answer

Starting with >> Troubleshooting Steps for Flask Application Issues on Amazon Lightsail

Check Logs: Inspect server logs on your Amazon Lightsail instance for errors or warnings.

Environment Differences: Ensure that the environments on Amazon Lightsail and your local machine are identical, including Python, Flask, and other dependencies.

CORS Issues: Verify that Cross-Origin Resource Sharing (CORS) is correctly configured if your application interacts with external APIs.

Form Handling: Check the form handling logic in your Flask routes to ensure all required form fields are properly validated and processed.

JavaScript Errors: Use the browser's developer console to check for JavaScript errors that might be affecting the dropdowns or form functionality.

Network Requests: Inspect network requests in the browser's developer console to ensure they are functioning correctly and receiving expected responses.

Recap with steps: Check Logs Compare Environments Verify CORS Configuration Inspect Form Handling Check JavaScript Console Inspect Network Requests Verify Docker Configuration Check Permissions and Firewall Settings Run Flask Application Directly on Lightsail Providing code snippets, Dockerfile, and error logs can help with more targeted troubleshooting.

answered 2 years ago

EXPERT

reviewed 2 years ago

EXPERT

reviewed 2 years ago

  • Thanks! Updated the post with Amazon CLI error log screenshot.

1

Hello.

Troubleshooting is difficult with only error messages on the browser.
How about trying logging to get the application log?
https://flask.palletsprojects.com/en/2.3.x/logging/

EXPERT

answered 2 years ago

  • Thanks! Updated the post with Amazon CLI error log screenshot.

  • Is it possible for you to share not only the error message but also the relevant code?

1

Thank you for sharing the code.
Judging from the error message and code, I think it occurred when trying to perform a direct multidimensional index operation on a Pandas DataFrame or Series.
I think the following stackoverflow answers will be helpful.
https://stackoverflow.com/questions/75939123/valueerror-multi-dimensional-indexing-e-g-obj-none-is-no-longer-suppor

I think the problem is in the following part of your code.

def compare_stocks(symbol1, symbol2):
    df1 = fetch_historical_data(symbol1)
    df2 = fetch_historical_data(symbol2)
    if df1 is None or df2 is None:
        return None, None, None, None, None, None, f"Could not fetch data for one or both symbols."
    common_start_date = max(df1.index.min(), df2.index.min())
    df1 = df1[df1.index >= common_start_date]
    df2 = df2[df2.index >= common_start_date]
    if df1.empty or df2.empty:
        return None, None, None, None, None, None, "No overlapping data available for the selected stocks."
    else:
        growth1, yearly_returns1 = calculate_growth(df1.copy())
        growth2, yearly_returns2 = calculate_growth(df2.copy())
        cumulative_returns1 = [0]
        cumulative_returns2 = [0]
        for val1, val2 in zip(growth1.values[1:], growth2.values[1:]):
            cumulative_returns1.append(((val1 - growth1.values[0]) / 100) * 100)
            cumulative_returns2.append(((val2 - growth2.values[0]) / 100) * 100)
        return growth1, growth2, yearly_returns1, yearly_returns2, cumulative_returns1, cumulative_returns2, None

So, why not try returning a numpy array with "to_numpy()" as shown below?
https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_numpy.html#pandas.DataFrame.to_numpy

def compare_stocks(symbol1, symbol2):
    df1 = fetch_historical_data(symbol1)
    df2 = fetch_historical_data(symbol2)
    if df1 is None or df2 is None:
        return None, None, None, None, None, None, f"Could not fetch data for one or both symbols."
    common_start_date = max(df1.index.min(), df2.index.min())
    df1 = df1[df1.index >= common_start_date]
    df2 = df2[df2.index >= common_start_date]
    if df1.empty or df2.empty:
        return None, None, None, None, None, None, "No overlapping data available for the selected stocks."
    else:
        growth1, yearly_returns1 = calculate_growth(df1.copy())
        growth2, yearly_returns2 = calculate_growth(df2.copy())
        cumulative_returns1 = [0]
        cumulative_returns2 = [0]
        growth1_values = growth1.to_numpy() # <-- add
        growth2_values = growth2.to_numpy() # <-- add
        for val1, val2 in zip(growth1_values[1:], growth2_values[1:]):
            cumulative_returns1.append(((val1 - rowth1_values[0]) / 100) * 100) # <-- edit
            cumulative_returns2.append(((val2 - growth2_values[0]) / 100) * 100) # <-- edit
        return growth1, growth2, yearly_returns1, yearly_returns2, cumulative_returns1, cumulative_returns2, None
EXPERT

answered 2 years ago

0

These are the original codes on VS Code from where I started with launching Ubuntu instance, trying to make live the same project through Amazon Lightsail:

  1. App.py
from flask import Flask, render_template, request
import requests
import pandas as pd
import matplotlib.pyplot as plt
from io import BytesIO, StringIO
import base64
import csv
import datetime

app = Flask(__name__)

# Replace with your actual API key from Alpha Vantage
API_KEY = "FI5B9EM5VOZTW6WJ"

def fetch_stock_symbols(exchange):
    url = f"https://www.alphavantage.co/query?function=LISTING_STATUS&apikey={API_KEY}&exchange={exchange}"
    try:
        response = requests.get(url)
        response.raise_for_status()

        if response.headers['Content-Type'] == 'application/x-download':
            csv_data = StringIO(response.text)
            csv_reader = csv.DictReader(csv_data)
            return [row['symbol'] for row in csv_reader if not row['symbol'].isdigit()]
        else:
            print("Unexpected response content type:", response.headers['Content-Type'])
            return []

    except requests.RequestException as e:
        print(f"Error fetching symbols: {e}")
        return []

def fetch_historical_data(symbol):
    ten_years_ago = datetime.datetime.now() - datetime.timedelta(days=10*365)
    start_date = ten_years_ago.strftime('%Y-%m-%d')

    url = f"https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol={symbol}&outputsize=full&apikey={API_KEY}"
    try:
        response = requests.get(url)
        response.raise_for_status()

        data = response.json()
        if "Time Series (Daily)" in data:
            df = pd.DataFrame.from_dict(data["Time Series (Daily)"], orient="index")
            df = df.rename(columns={"4. close": "close"})
            df["close"] = pd.to_numeric(df["close"])
            df.index = pd.to_datetime(df.index)
            df = df[df.index >= start_date]
            df.sort_index(inplace=True)
            return df

        return None

    except requests.RequestException as e:
        print(f"Error fetching data for {symbol}: {e}")
        return None

def calculate_growth(df, start_value=100):
    df = df.resample("Y").last()
    growth = (df["close"] / df["close"].iloc[0]) * start_value
    yearly_returns = (growth.pct_change() * 100).round(2)
    return growth, yearly_returns

def compare_stocks(symbol1, symbol2):
    df1 = fetch_historical_data(symbol1)
    df2 = fetch_historical_data(symbol2)

    if df1 is None or df2 is None:
        return None, None, None, None, None, None, f"Could not fetch data for one or both symbols."

    common_start_date = max(df1.index.min(), df2.index.min())

    df1 = df1[df1.index >= common_start_date]
    df2 = df2[df2.index >= common_start_date]

    if df1.empty or df2.empty:
        return None, None, None, None, None, None, "No overlapping data available for the selected stocks."
    else:
        growth1, yearly_returns1 = calculate_growth(df1.copy())
        growth2, yearly_returns2 = calculate_growth(df2.copy())

        cumulative_returns1 = [0]
        cumulative_returns2 = [0]
        for val1, val2 in zip(growth1.values[1:], growth2.values[1:]):
            cumulative_returns1.append(((val1 - growth1.values[0]) / 100) * 100)
            cumulative_returns2.append(((val2 - growth2.values[0]) / 100) * 100)

        return growth1, growth2, yearly_returns1, yearly_returns2, cumulative_returns1, cumulative_returns2, None

@app.route("/", methods=["GET", "POST"])
def index():
    symbols = []
    if request.method == "POST":
        exchange = request.form["exchange"]
        symbol1 = request.form["symbol1"]
        symbol2 = request.form["symbol2"]
        symbols = fetch_stock_symbols(exchange)

        growth1, growth2, yearly_returns1, yearly_returns2, cumulative_returns1, cumulative_returns2, error_message = compare_stocks(symbol1, symbol2)

        if error_message:
            return render_template("index.html", symbols=symbols, error_message=error_message)

        plt.figure(figsize=(10, 6))
        plt.plot(growth1.index, growth1.values, label=symbol1)
        plt.plot(growth2.index, growth2.values, label=symbol2)
        plt.xlabel("Year")
        plt.ylabel("Value of $100 Investment")
        plt.title("Stock Comparison")
        plt.legend()

        img = BytesIO()
        plt.savefig(img, format='png')
        img.seek(0)
        img_base64 = base64.b64encode(img.getvalue()).decode('utf-8')

        start_date = growth1.index[0].strftime('%Y-%m-%d')
        end_date = growth1.index[-1].strftime('%Y-%m-%d')
        final_value1 = growth1.values[-1]
        final_value2 = growth2.values[-1]

        comparison_message = (
            f"On {start_date}, $100 invested in {symbol1} would be worth ${final_value1:.2f} on {end_date}.\n"
            f"On {start_date}, $100 invested in {symbol2} would be worth ${final_value2:.2f} on {end_date}."
        )

        table_data = []
        for year, val1, ret1, val2, ret2, cum_ret1, cum_ret2 in zip(
            growth1.index.year,
            growth1.values,
            yearly_returns1.values,
            growth2.values,
            yearly_returns2.values,
            cumulative_returns1,
            cumulative_returns2
        ):
            table_data.append({
                "year": year,
                "val1": val1,
                "ret1": ret1,
                "val2": val2,
                "ret2": ret2,
                "cum_ret1": cum_ret1,
                "cum_ret2": cum_ret2
            })

        return render_template(
            "result.html",
            img_data=img_base64,
            comparison_message=comparison_message,
            table_data=table_data,
            start_date=start_date,
            end_date=end_date,
            symbol1=symbol1,
            symbol2=symbol2,
        )
    else:
        # Default to NASDAQ symbols on initial load
        symbols = fetch_stock_symbols('NASDAQ')
    return render_template("index.html", symbols=symbols)

if __name__ == "__main__":
    app.run(debug=True)
  1. index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Stock Comparison</title>
</head>
<body>
    <h1>Compare Stocks</h1>
    <form method="POST">
        <label for="exchange">Select Stock Exchange:</label>
        <select name="exchange" id="exchange" onchange="this.form.submit()">
            <option value="NASDAQ" {% if request.form.get('exchange') == 'NASDAQ' %}selected{% endif %}>NASDAQ</option>
            <option value="NYSE" {% if request.form.get('exchange') == 'NYSE' %}selected{% endif %}>NYSE</option>
            <option value="AMEX" {% if request.form.get('exchange') == 'AMEX' %}selected{% endif %}>AMEX</option>
        </select>
        <br><br>
        <label for="symbol1">Stock Symbol 1:</label>
        <select name="symbol1" id="symbol1" required>
            {% for symbol in symbols %}
            <option value="{{ symbol }}">{{ symbol }}</option>
            {% endfor %}
        </select>
        <br><br>
        <label for="symbol2">Stock Symbol 2:</label>
        <select name="symbol2" id="symbol2" required>
            {% for symbol in symbols %}
            <option value="{{ symbol }}">{{ symbol }}</option>
            {% endfor %}
        </select>
        <br><br>
        <button type="submit">Compare</button>
    </form>
    {% if error_message %}
    <p style="color: red;">{{ error_message }}</p>
    {% endif %}
</body>
</html>
  1. result.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Stock Comparison Result</title>
</head>
<body>
    <h1>Stock Comparison Result</h1>
    <p>{{ comparison_message }}</p>
    <img src="data:image/png;base64,{{ img_data }}" alt="Stock Comparison Graph">
    <table border="1">
        <thead>
            <tr>
                <th>Year</th>
                <th>{{ symbol1 }} Value</th>
                <th>{{ symbol1 }} Yearly Return (%)</th>
                <th>{{ symbol2 }} Value</th>
                <th>{{ symbol2 }} Yearly Return (%)</th>
                <th>{{ symbol1 }} Cumulative Return (%)</th>
                <th>{{ symbol2 }} Cumulative Return (%)</th>
            </tr>
        </thead>
        <tbody>
            {% for row in table_data %}
            <tr>
                <td>{{ row.year }}</td>
                <td>{{ row.val1 }}</td>
                <td>{{ row.ret1 }}</td>
                <td>{{ row.val2 }}</td>
                <td>{{ row.ret2 }}</td>
                <td>{{ row.cum_ret1 }}</td>
                <td>{{ row.cum_ret2 }}</td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
    <br>
    <a href="/">Back to Comparison</a>
</body>
</html>

answered 2 years ago

0

While troubleshooting in order to make live for Ubuntu, here are the 2 versions of app.py (with errors):

  1. app.py
from flask import Flask, render_template, request
import requests
import pandas as pd
import matplotlib.pyplot as plt
from io import BytesIO, StringIO
import base64
import csv
import datetime

app = Flask(__name__)


# Replace with your actual API key from Alpha Vantage
API_KEY = "FI5B9EM5VOZTW6WJ"

def fetch_stock_symbols(exchange):
    url = f"https://www.alphavantage.co/query?function=LISTING_STATUS&apikey={API_KEY}&exchange={exchange}"
    try:
        response = requests.get(url)
        response.raise_for_status()

        if response.headers['Content-Type'] == 'application/x-download':
            csv_data = StringIO(response.text)
            csv_reader = csv.DictReader(csv_data)
            return [row['symbol'] for row in csv_reader if not row['symbol'].isdigit()]
        else:
            print("Unexpected response content type:", response.headers['Content-Type'])
            return []

    except requests.RequestException as e:
        print(f"Error fetching symbols: {e}")
        return []

def fetch_historical_data(symbol):
    ten_years_ago = datetime.datetime.now() - datetime.timedelta(days=10*365)
    start_date = ten_years_ago.strftime('%Y-%m-%d')

    url = f"https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol={symbol}&outputsize=full&apikey={API_KEY}"
    try:
        response = requests.get(url)
        response.raise_for_status()

        data = response.json()
        if "Time Series (Daily)" in data:
            df = pd.DataFrame.from_dict(data["Time Series (Daily)"], orient="index")
            df = df.rename(columns={"4. close": "close"})
            df["close"] = pd.to_numeric(df["close"])
            df.index = pd.to_datetime(df.index)
            df = df[df.index >= start_date]
            df.sort_index(inplace=True)
            return df

        return None

    except requests.RequestException as e:
        print(f"Error fetching data for {symbol}: {e}")
        return None

def calculate_growth(df, start_value=100):
    df = df.resample("Y").last()
    growth = (df["close"] / df["close"].iloc[0]) * start_value
    yearly_returns = (growth.pct_change() * 100).round(2)
    return growth, yearly_returns

def compare_stocks(symbol1, symbol2):
    df1 = fetch_historical_data(symbol1)
    df2 = fetch_historical_data(symbol2)

    if df1 is None or df2 is None:
        return None, None, None, None, None, None, f"Could not fetch data for one or both symbols."

    common_start_date = max(df1.index.min(), df2.index.min())

    df1 = df1[df1.index >= common_start_date]
    df2 = df2[df2.index >= common_start_date]

    if df1.empty or df2.empty:
        return None, None, None, None, None, None, "No overlapping data available for the selected stocks."
    else:
        growth1, yearly_returns1 = calculate_growth(df1.copy())
        growth2, yearly_returns2 = calculate_growth(df2.copy())

        cumulative_returns1 = [0]
        cumulative_returns2 = [0]
        for val1, val2 in zip(growth1.values[1:], growth2.values[1:]):
            cumulative_returns1.append(((val1 - growth1.values[0]) / 100) * 100)
            cumulative_returns2.append(((val2 - growth2.values[0]) / 100) * 100)

        return growth1, growth2, yearly_returns1, yearly_returns2, cumulative_returns1, cumulative_returns2, None

@app.route("/", methods=["GET", "POST"])
def index():
    symbols = []
    if request.method == "POST":
        exchange = request.form["exchange"]
        symbol1 = request.form["symbol1"]
        symbol2 = request.form["symbol2"]
        symbols = fetch_stock_symbols(exchange)

        growth1, growth2, yearly_returns1, yearly_returns2, cumulative_returns1, cumulative_returns2, error_message = compare_stocks(symbol1, symbol2)

        if error_message:
            return render_template("index.html", symbols=symbols, error_message=error_message)

        plt.figure(figsize=(10, 6))
        plt.plot(growth1.index, growth1.values, label=symbol1)
        plt.plot(growth2.index, growth2.values, label=symbol2)
        plt.xlabel("Year")
        plt.ylabel("Value of $100 Investment")
        plt.title("Stock Comparison")
        plt.legend()

        img = BytesIO()
        plt.savefig(img, format='png')
        img.seek(0)
        img_base64 = base64.b64encode(img.getvalue()).decode('utf-8')

        start_date = growth1.index[0].strftime('%Y-%m-%d')
        end_date = growth1.index[-1].strftime('%Y-%m-%d')
        final_value1 = growth1.values[-1]
        final_value2 = growth2.values[-1]

        comparison_message = (
            f"On {start_date}, $100 invested in {symbol1} would be worth ${final_value1:.2f} on {end_date}.\n"
            f"On {start_date}, $100 invested in {symbol2} would be worth ${final_value2:.2f} on {end_date}."
        )

        table_data = []
        for year, val1, ret1, val2, ret2, cum_ret1, cum_ret2 in zip(
            growth1.index.year,
            growth1.values,
            yearly_returns1.values,
            growth2.values,
            yearly_returns2.values,
            cumulative_returns1,
            cumulative_returns2
        ):
            table_data.append({
                "year": year,
                "val1": val1,
                "ret1": ret1,
                "val2": val2,
                "ret2": ret2,
                "cum_ret1": cum_ret1,
                "cum_ret2": cum_ret2
            })

        return render_template(
            "result.html",
            img_data=img_base64,
            comparison_message=comparison_message,
            table_data=table_data,
            start_date=start_date,
            end_date=end_date,
            symbol1=symbol1,
            symbol2=symbol2,
        )
    else:
        # Default to NASDAQ symbols on initial load
        symbols = fetch_stock_symbols('NASDAQ')
    return render_template("index.html", symbols=symbols)


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)



answered 2 years ago

0
  1. app.py
from flask import Flask, render_template, request
import requests
import pandas as pd
import matplotlib.pyplot as plt
from io import BytesIO, StringIO
import base64
import csv
import datetime
import numpy as np

app = Flask(__name__)

API_KEY = "FI5B9EM5VOZTW6WJ"

def fetch_stock_symbols(exchange):
    url = f"https://www.alphavantage.co/query?function=LISTING_STATUS&apikey={API_KEY}&exchange={exchange}"
    try:
        response = requests.get(url)
        response.raise_for_status()
        if response.headers['Content-Type'] == 'application/x-download':
            csv_data = StringIO(response.text)
            csv_reader = csv.DictReader(csv_data)
            return [row['symbol'] for row in csv_reader if not row['symbol'].isdigit()]
        else:
            print("Unexpected response content type:", response.headers['Content-Type'])
            return []
    except requests.RequestException as e:
        print(f"Error fetching symbols: {e}")
        return []

def fetch_historical_data(symbol):
    ten_years_ago = datetime.datetime.now() - datetime.timedelta(days=10*365)
    start_date = ten_years_ago.strftime('%Y-%m-%d')
    url = f"https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol={symbol}&outputsize=full&apikey={API_KEY}"
    try:
        response = requests.get(url)
        response.raise_for_status()
        data = response.json()
        if "Time Series (Daily)" in data:
            df = pd.DataFrame.from_dict(data["Time Series (Daily)"], orient="index")
            df = df.rename(columns={"4. close": "close"})
            df["close"] = pd.to_numeric(df["close"])
            df.index = pd.to_datetime(df.index)
            df = df[df.index >= start_date]
            df.sort_index(inplace=True)
            return df
        return None
    except requests.RequestException as e:
        print(f"Error fetching data for {symbol}: {e}")
        return None

def calculate_growth(df, start_value=100):
    df = df.resample("Y").last()
    growth = (df["close"] / df["close"].iloc[0]) * start_value
    yearly_returns = (growth.pct_change() * 100).round(2)
    return growth, yearly_returns

def compare_stocks(symbol1, symbol2):
    df1 = fetch_historical_data(symbol1)
    df2 = fetch_historical_data(symbol2)
    if df1 is None or df2 is None:
        return None, None, None, None, None, None, f"Could not fetch data for one or both symbols."
    common_start_date = max(df1.index.min(), df2.index.min())
    df1 = df1[df1.index >= common_start_date]
    df2 = df2[df2.index >= common_start_date]
    if df1.empty or df2.empty:
        return None, None, None, None, None, None, "No overlapping data available for the selected stocks."
    else:
        growth1, yearly_returns1 = calculate_growth(df1.copy())
        growth2, yearly_returns2 = calculate_growth(df2.copy())
        cumulative_returns1 = [0]
        cumulative_returns2 = [0]
        for val1, val2 in zip(growth1.values[1:], growth2.values[1:]):
            cumulative_returns1.append(((val1 - growth1.values[0]) / 100) * 100)
            cumulative_returns2.append(((val2 - growth2.values[0]) / 100) * 100)
        return growth1, growth2, yearly_returns1, yearly_returns2, cumulative_returns1, cumulative_returns2, None

@app.before_request
def validate_request():
    if request.method == "POST":
        print("Form data received:", request.form)
        if not request.form.get("exchange") or not request.form.get("symbol1") or not request.form.get("symbol2"):
            return {"error": "Missing form data"}, 400

@app.route("/", methods=["GET", "POST"])
def index():
    symbols = []
    if request.method == "POST":
        exchange = request.form["exchange"]
        symbol1 = request.form["symbol1"]
        symbol2 = request.form["symbol2"]
        symbols = fetch_stock_symbols(exchange)
        growth1, growth2, yearly_returns1, yearly_returns2, cumulative_returns1, cumulative_returns2, error_message = compare_stocks(symbol1, symbol2)
        if error_message:
            return render_template("index.html", symbols=symbols, error_message=error_message)
        plt.figure(figsize=(10, 6))
        plt.plot(np.array(growth1.index), np.array(growth1.values), label=symbol1)
        plt.plot(np.array(growth2.index), np.array(growth2.values), label=symbol2)
        plt.xlabel("Year")
        plt.ylabel("Value of $100 Investment")
        plt.title("Stock Comparison")
        plt.legend()
        img = BytesIO()
        plt.savefig(img, format='png')
        img.seek(0)
        img_base64 = base64.b64encode(img.getvalue()).decode('utf-8')
        start_date = growth1.index[0].strftime('%Y-%m-%d')
        end_date = growth1.index[-1].strftime('%Y-%m-%d')
        final_value1 = growth1.values[-1]
        final_value2 = growth2.values[-1]
        comparison_message = (
            f"On {start_date}, $100 invested in {symbol1} would be worth ${final_value1:.2f} on {end_date}.\n"
            f"On {start_date}, $100 invested in {symbol2} would be worth ${final_value2:.2f} on {end_date}."
        )
        table_data = []
        for year, val1, ret1, val2, ret2, cum_ret1, cum_ret2 in zip(
            growth1.index.year,
            growth1.values,
            yearly_returns1.values,
            growth2.values,
            yearly_returns2.values,
            cumulative_returns1,
            cumulative_returns2
        ):
            table_data.append({
                "year": year,
                "val1": val1,
                "ret1": ret1,
                "val2": val2,
                "ret2": ret2,
                "cum_ret1": cum_ret1,
                "cum_ret2": cum_ret2
            })
        return render_template(
            "result.html",
            img_data=img_base64,
            comparison_message=comparison_message,
            table_data=table_data,
            start_date=start_date,
            end_date=end_date,
            symbol1=symbol1,
            symbol2=symbol2,
        )
    else:
        symbols = fetch_stock_symbols('NASDAQ')
    return render_template("index.html", symbols=symbols)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)



answered 2 years ago

0

I understand it is not safe to share API but since the same not mission critical, sharing for easing troubleshooting. Will later delete this and generate another API key.

answered 2 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.