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 index 96fdddc2f..5673057c7 100644 --- 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 @@ -26,6 +26,7 @@ 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. +- `/hist/?start_date="YYYY-MM-DD"&end_date"YYYY-MM-DD"`: retrieve data for the specified symbol between the two selected dates. Below an example on how to use it (remember that the server needs to be running locally). @@ -42,9 +43,20 @@ $ curl -s localhost:5001/stocks_list | jq | head "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} +$ curl 'localhost:5001/exchange_rate/AAME' +{"currency":"USD","datetime":"Thu, 02 May 2024 14:38:58 GMT","rate":2.4804475372724473} +$ curl -s 'localhost:5001/hist/AAME?start_date=2024-04-01&end_date=2024-05-03' | jq | head +{ + "currency": "USD", + "values": [ + { + "close": 2.609999895095825, + "date": "Tue, 02 Apr 2024 00:00:00 GMT" + }, + { + "close": 2.569999933242798, + "date": "Wed, 03 Apr 2024 00:00:00 GMT" $ ``` + +> Remember that this are mock data! The date of the historical data will vary depending on the starting date of the server. 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 index 99276e827..7bc24162d 100644 --- 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 @@ -1,9 +1,11 @@ +import time +from datetime import datetime +from random import uniform + from flask import Flask, jsonify, request from flask_cors import CORS -from random import uniform -import time -from utils import load_data +from utils import get_historical_data, load_data app = Flask(__name__) CORS(app) @@ -16,18 +18,55 @@ historical_data = load_data() @app.route('/exchange_rate/') def get_stock_data(symbol): if symbol not in list(historical_data.keys()): - return jsonify("Invalid symbol") + response = jsonify({"error": "Invalid symbol"}) + response.status_code = 404 + return response current_time = time.time() - last_value = historical_data[symbol].Close[-1] + last_value = historical_data[symbol].iloc[-1].Close step = (int(current_time * 10) - int(start_time * 10) ) % len(historical_data[symbol]) return jsonify({ - 'symbol': 'USD', + 'currency': 'USD', 'rate': last_value * (1 + uniform(0.05, -0.05) + step * 0.0005), - 'timestamp': current_time + 'datetime': datetime.fromtimestamp(current_time) }) +@app.route('/hist/') +def get_hist_data(symbol): + if symbol not in list(historical_data.keys()): + response = jsonify({"error": "Invalid symbol"}) + response.status_code = 404 + return response + + df = historical_data[symbol] + args = request.args + start_date = args.get("start_date") + end_date = args.get("end_date") + if not start_date or not end_date: + response = jsonify({"error": "start_date and end_date required"}) + response.status_code = 400 + return response + + try: + filtered = get_historical_data(df, start_date, end_date, start_time) + data = filtered[['datetime', 'Close']].to_dict(orient="list") + + values = [ + {"date": dt.date(), "close": close} + for dt, close in zip(data["datetime"], data["Close"])] + response = jsonify({ + "currency": 'USD', + "values": values, + }) + return response + + except Exception as e: + response = jsonify({'error': str(e)}) + response.status_code = 400 + return response + + @app.route('/stocks_list') def list_symbols(): return jsonify(list(historical_data.keys())) 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 index 65cbdcf81..4e3284381 100644 --- 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 @@ -1,25 +1,9 @@ import os -import csv +from datetime import datetime + import pandas as pd -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 - - def load_data(directory_path='./sample-stocks/'): historical_data = {} @@ -28,13 +12,36 @@ def load_data(directory_path='./sample-stocks/'): for filename in file_list: symbol = filename.replace(".csv", "") file_path = os.path.join(directory_path, filename) - historical_data[symbol] = pd.read_csv( - file_path, index_col=0, parse_dates=True) - + historical_data[symbol] = pd.read_csv(file_path, parse_dates=[0]) return historical_data +def get_historical_data(df, start, end, start_time): + today = datetime.fromtimestamp(start_time).date() + last_entry = df.sort_values(by="Date").iloc[-1] + delta_today_last_entry = today - last_entry.Date.date() + + try: + query_start_dt = datetime.fromisoformat(start) + query_end_dt = datetime.fromisoformat(end) + if query_end_dt < query_start_dt: + raise Exception("end_date must come after start_date") + if query_end_dt.date() > today: + query_end_dt = datetime.fromtimestamp(start_time) + + df['datetime'] = df.Date + delta_today_last_entry + return (df.loc[ + (df.datetime >= query_start_dt) & + (df.datetime <= query_end_dt)]) + except Exception as e: + raise Exception(str(e)) + + if __name__ == "__main__": + result = load_data() print(f'keys: {result.keys()}') - print(result["AE"].Close[-1]) + now = datetime.now() + + df = result["AE"] + print(df.info())