diff --git a/subjects/mobile-dev/stock-market/README.md b/subjects/mobile-dev/stock-market/README.md index f4a9a82be..5662867bb 100644 --- a/subjects/mobile-dev/stock-market/README.md +++ b/subjects/mobile-dev/stock-market/README.md @@ -2,8 +2,8 @@ ### 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. -You should fetch all the data in real-time and choose 10 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. +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: @@ -12,9 +12,9 @@ Upon signing up, users must be given `1 000 000` fake dollars to use within the - `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. - `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 one time 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 10 stocks to monitor and display their data within the application. +- Choose 20 stocks to monitor and display their data within the application. Make sure to manage states using one of the following patterns: 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 000000000..68bc17f9f --- /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 000000000..68bc17f9f --- /dev/null +++ b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/.gitignore @@ -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.old b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/.gitignore.old new file mode 100644 index 000000000..78b924dc4 --- /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 000000000..df08f234f --- /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 000000000..d2a47a943 --- /dev/null +++ b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/Makefile @@ -0,0 +1,18 @@ +IMAGE_NAME="stock-server" +SERVER_PORT=5000 +PUBLIC_PORT=5000 + +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 000000000..40e770e8b --- /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:5000/stocks_list | jq | head +[ + "BRID", + "WRB", + "GCO", + "ITW", + "USAU", + "AXR", + "UMBF", + "MTRN", + "UNT", +$ curl localhost:5000/exchange_rate/WRB +{"rate":0.12680993974208832,"symbol":"USD","timestamp":1691667858.912409} +$ curl localhost:5000/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 000000000..905dad8db --- /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() # Dictionary to store 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=5000) 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 000000000..43a9c5318 --- /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 000000000..36c2c0c05 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 000000000..4a898d3e2 --- /dev/null +++ b/subjects/mobile-dev/stock-market/resources/mock-stock-data-server/utils.py @@ -0,0 +1,25 @@ +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: + if filename.endswith(".csv"): + 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()}') +