diff --git a/subjects/mobile-dev/stock-market/README.md b/subjects/mobile-dev/stock-market/README.md index bc649552e7..5662867bb7 100644 --- a/subjects/mobile-dev/stock-market/README.md +++ b/subjects/mobile-dev/stock-market/README.md @@ -2,17 +2,17 @@ ### Instructions -Develop an app that will simulate a `real-time` stock market. You may use [Yahoo](https://algotrading101.com/learn/yahoo-finance-api-guide/#:~:text=Why%20should%20I%20use%20the%20Yahoo%20Finance%20API%3F,-Free&text=One%20good%20reason%20is%20because%20it%20can%20be%20completely%20free.) API for data retrieval. +Develop an app that will simulate a `real-time` stock market. For developing purpose, we provided you with a server providing you mock stock data in the [resources](resources/mock-stock-data-server/). You should fetch all the data in real-time and choose 20 stocks to monitor. The objectives of this exercise are to practice fetching data in real-time, visualizing custom widgets in real-time, and implementing authentication and authorization services. -Upon signing up, users must be given `1.000.000` fake dollars to use within the app for buying and holding stocks. The app should have the following features: +Upon signing up, users must be given `1 000 000` fake dollars to use within the app for buying and holding stocks. The app should have the following features: - `Login/Signup`: Implement a login/signup page and the necessary functionality for user authentication and account creation. - `Wallet`: Develop a wallet page that displays all purchased stocks and the current portfolio of the user. The wallet should show the stocks owned by the user and their respective quantities. - `Historical Data`: Create a page that displays historical data for a chosen stock. This feature will allow users to view and analyze the past performance of a particular stock. -- `Stock Trading`: Implement the ability to buy, sell, and hold stocks. Users should be able to use their simulated funds (starting balance: 1.000.000 fake dollars) to buy and sell stocks. The app should keep track of the user's stock holdings and balance. +- `Stock Trading`: Implement the ability to buy, sell, and hold stocks. Users should be able to use their simulated funds (starting balance: 1 000 000 fake dollars) to buy and sell stocks. The app should keep track of the user's stock holdings and balance. - `Historical Charts`: Provide historical charts of stock prices to help users visualize the stock performance over time. Implement a page that displays charts for the selected stock's price history. -- `Real-Time Data`: Ensure that the stock data is updated in real-time. The data should be updated at least 5 times per second, providing users with the latest stock information. +- `Real-Time Data`: Ensure that the stock data is updated in real-time. The data should be updated at least five times per second, providing users with the latest stock information. - Retrieval of data for a particular stock for the last year or since the company went public. - Choose 20 stocks to monitor and display their data within the application. diff --git a/subjects/mobile-dev/stock-market/audit/README.md b/subjects/mobile-dev/stock-market/audit/README.md index 57007e3ff6..e4c9ab1aa5 100644 --- a/subjects/mobile-dev/stock-market/audit/README.md +++ b/subjects/mobile-dev/stock-market/audit/README.md @@ -14,13 +14,13 @@ ###### Does the app contain a page where you can see the historical data of a stock? -###### Do you have 1.000.000 fake dollars in your account? +###### Do you have 1 000 000 fake dollars in your account? -##### Ask the student which where the 20 stocks he chose to monitored and display their data. +##### Ask the student which where the stocks he chose to monitored and display their data. -###### Are the 20 stocks being monitored and do they display their data within the app? +###### Is the amount of stocks defined in the subject being monitored and do they display their data within the app? -##### Buy 100 shares of a stock. Check the current stock price and make sure your fake dollar balance has decreased to the correct amount as per the purchase. See also if the stock has appeared in your portfolio, and +##### Buy 100 shares of a stock. Check the current stock price and make sure your fake dollar balance has decreased to the correct amount as per the purchase. ###### Were you able to buy the stock? @@ -34,7 +34,7 @@ ###### Does the app display historical charts of the stock prices for the selected stock price history? -###### Does the app update data about a stock at least 5 times per second? +###### Does the app update data about a stock with the minimum frequency defined in the subject (_n_ times per second)? ##### Try to sell everything that you bought. @@ -50,7 +50,7 @@ ###### Can you see historical data in days, weeks, and months slice? -##### Ask the student which of the patterns, `BLoC`, `Pattern` or `MVC`, did they used? Ask them to explain the pattern that they used, and confirm if they implemented it correctly. +##### Ask the student which of the patterns, `BLoC`, `Pattern` or `MVC`, did they use? Ask them to explain the pattern that they used, and confirm if they implemented it correctly. [BLoC](https://pub.dev/packages/flutter_bloc) [Pattern](https://pub.dev/packages/provider) diff --git a/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/.dockerignore b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/.dockerignore new file mode 100644 index 0000000000..68bc17f9ff --- /dev/null +++ b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/.dockerignore @@ -0,0 +1,160 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/.gitignore b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/.gitignore new file mode 100644 index 0000000000..2acb56f85d --- /dev/null +++ b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/.gitignore @@ -0,0 +1,162 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +sample-stocks/ diff --git a/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/.gitignore.old b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/.gitignore.old new file mode 100644 index 0000000000..78b924dc49 --- /dev/null +++ b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/.gitignore.old @@ -0,0 +1,161 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ +stocks diff --git a/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/Dockerfile b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/Dockerfile new file mode 100644 index 0000000000..df08f234f7 --- /dev/null +++ b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/Dockerfile @@ -0,0 +1,15 @@ +# Use the ubuntu +FROM python:3.10-slim + +# Set the working directory to /app +WORKDIR /app + +COPY sample-stocks/ ./sample-stocks/ + +COPY requirements.txt requirements.txt + +RUN pip install -r requirements.txt + +COPY ["app.py", "utils.py", "./"] + +CMD ["python3", "app.py"] diff --git a/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/Makefile b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/Makefile new file mode 100644 index 0000000000..a0465bf46f --- /dev/null +++ b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/Makefile @@ -0,0 +1,18 @@ +IMAGE_NAME="stock-server" +SERVER_PORT=5001 +PUBLIC_PORT=5001 + +sample-stocks: + tar xf sample-stocks.zip + +build-image: + docker rmi ${IMAGE_NAME} || echo "Clean" + docker build -t ${IMAGE_NAME} . + +run: sample-stocks build-image + docker run -d -p ${PUBLIC_PORT}:${SERVER_PORT} --name ${IMAGE_NAME} --rm ${IMAGE_NAME} + +stop: + docker stop ${IMAGE_NAME} + +.PHONY: run stop unzip-sample-stock build-image diff --git a/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/README.md b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/README.md new file mode 100644 index 0000000000..96fdddc2f2 --- /dev/null +++ b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/README.md @@ -0,0 +1,50 @@ +# Mock stock data server + +A simple API to provide fake real time exchange data. The used database is a +sample of [this Kaggle +database](https://www.kaggle.com/datasets/jacksoncrow/stock-market-dataset). + +## How to run it locally + +It is recommended to use the following command to run the server locally: + +```shell +$ make run + +``` + +And to stop the server: + +```shell +$ make stop + +``` + +## Endpoints available + +You can fetch the server with HTTP GET requests at the following endpoints: + +- `/stocks_list`: display a list of available stock symbol. +- `/exchange_rate/`: retrieve current data for the specified symbol. + +Below an example on how to use it (remember that the server needs to be running +locally). + +```shell +$ curl -s localhost:5001/stocks_list | jq | head +[ + "BRID", + "WRB", + "GCO", + "ITW", + "USAU", + "AXR", + "UMBF", + "MTRN", + "UNT", +$ curl localhost:5001/exchange_rate/WRB +{"rate":0.12680993974208832,"symbol":"USD","timestamp":1691667858.912409} +$ curl localhost:5001/exchange_rate/BRID +{"rate":0.38091352581977844,"symbol":"USD","timestamp":1691667862.3328483} +$ +``` diff --git a/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/app.py b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/app.py new file mode 100644 index 0000000000..fad9141a90 --- /dev/null +++ b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/app.py @@ -0,0 +1,35 @@ +from flask import Flask, jsonify +from flask_cors import CORS + +import time +from utils import load_historical_data + +app = Flask(__name__) +CORS(app) + +start_time = time.time() + +historical_data = load_historical_data() + +@app.route('/exchange_rate/') +def get_stock_data(symbol): + if symbol not in list(historical_data.keys()): + return jsonify("Invalid symbol") + current_time = time.time() + step = (int(current_time * 10) - int(start_time * 10)) % len(historical_data[symbol]) + try: + return jsonify({ + 'symbol': 'USD', + 'rate': float(historical_data[symbol][step]), + 'timestamp': current_time + }) + except: + return "Server Error" + +@app.route('/stocks_list') +def list_symbols(): + return jsonify(list(historical_data.keys())) + + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5001) diff --git a/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/requirements.txt b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/requirements.txt new file mode 100644 index 0000000000..43a9c5318c --- /dev/null +++ b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/requirements.txt @@ -0,0 +1,8 @@ +blinker==1.6.2 +click==8.1.6 +Flask==2.3.2 +Flask-Cors==4.0.0 +itsdangerous==2.1.2 +Jinja2==3.1.2 +MarkupSafe==2.1.3 +Werkzeug==2.3.6 diff --git a/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/sample-stocks.zip b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/sample-stocks.zip new file mode 100644 index 0000000000..8cc87ea389 Binary files /dev/null and b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/sample-stocks.zip differ diff --git a/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/utils.py b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/utils.py new file mode 100644 index 0000000000..d05efc0ed3 --- /dev/null +++ b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/utils.py @@ -0,0 +1,24 @@ +import os +import csv + + +def load_historical_data(directory_path='./sample-stocks/'): + historical_data = {} + + file_list = [filename for filename in os.listdir(directory_path) if filename.endswith(".csv")] + for filename in file_list: + symbol = filename.replace(".csv", "") + + historical_data[symbol] = {} + file_path = os.path.join(directory_path, filename) + with open(file_path, 'r') as csv_file: + csv_reader = csv.DictReader(csv_file) + historical_data[symbol] = [row['Close'] for row in csv_reader] + + return historical_data + + +if __name__ == "__main__": + result = load_historical_data() + print(f'keys: {result.keys()}') +