From 7d54c16ec290c1538f4aa091a2b8f1850236e354 Mon Sep 17 00:00:00 2001 From: Lev Gusiev Date: Sun, 14 Jun 2026 00:13:16 +0200 Subject: [PATCH 01/14] docs(#30): update roadmap and readme --- README.md | 15 ++++++++------- docs/roadmap.md | 6 +++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 2914fa1..44d51a9 100644 --- a/README.md +++ b/README.md @@ -336,14 +336,15 @@ Current documentation: ## Status -ARGUS is under active development. +ARGUS has completed its first foundation phase. -The project is currently transitioning from a small FX converter into a broader market analytics platform. +The project now has a runnable local Python application, a Tkinter GUI prototype, basic analytics, tests, documentation, CI checks and open-source readiness files. Current focus: -- finish Sprint 1 foundation -- prepare first public release -- improve README and project documentation -- keep the application runnable and testable -- prepare the next analytics and data-source expansion +- start Sprint 2 — Market Analytics & Data Source Expansion +- improve historical exchange-rate data support +- add stronger market metrics +- expand pandas-based analytics workflows +- improve dashboard usefulness without adding unnecessary chart noise +- document metric definitions, assumptions and data-source behavior diff --git a/docs/roadmap.md b/docs/roadmap.md index 4df584c..85706af 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -5,7 +5,7 @@ The roadmap is intentionally iterative: each sprint should leave the project in ## Sprint 1 — Product Foundation & First Public Release -**Status:** In progress +**Status:** Completed Build a small but usable Python application with a clear structure, tests, documentation and first release readiness. @@ -25,11 +25,11 @@ Scope: - Collaboration documentation through `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md` and `LICENSE` Outcome: -ARGUS can be run locally, tested, understood by other developers and used as a small desktop analytics prototype. +Sprint 1 established the local ARGUS foundation with package structure, GUI prototype, analytics prototype, tests, documentation, CI, Dependabot and governance files. ### Sprint 2 — Market Analytics & Data Source Expansion -**Status:** Planned +**Status:** In progress Move from simple FX conversion toward broader market analytics. From ddf687abc506d9c78f12e81b35368dfc455cf2e0 Mon Sep 17 00:00:00 2001 From: Lev Gusiev <89646710+BytecodeBrewer@users.noreply.github.com> Date: Mon, 15 Jun 2026 13:52:04 +0200 Subject: [PATCH 02/14] ci(#32): add workflow permissions --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7cb6c89..c60d464 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,9 @@ # This workflow ensures that the code is tested and meets quality standards on every push and pull request name: Tests +permissions: + contents: read + on: push: pull_request: From c844621c2af413a7af94f726a8d37c9e8a9cc55c Mon Sep 17 00:00:00 2001 From: Lev Gusiev Date: Tue, 16 Jun 2026 12:32:34 +0200 Subject: [PATCH 03/14] docs(#32): add docstrings to funtions --- src/argus/analytics/charts/trend_chart.py | 27 +++++++++++ src/argus/analytics/metrics/trend_metrics.py | 51 ++++++++++++++++++++ src/argus/clients/exchangerate_client.py | 38 +++++++++------ src/argus/domain/validation.py | 28 +++++++++++ src/argus/gui/app.py | 33 +++++++++++++ src/argus/main.py | 3 ++ src/argus/services/calculator_service.py | 18 ++++++- src/argus/services/conversion_service.py | 28 ++++++++++- src/argus/services/timeseries_service.py | 15 ++++-- src/legacy/cli/interface.py | 47 ++++++++++++++++++ src/legacy/debug_main.py | 3 ++ 11 files changed, 268 insertions(+), 23 deletions(-) diff --git a/src/argus/analytics/charts/trend_chart.py b/src/argus/analytics/charts/trend_chart.py index 57c5193..d475bc7 100644 --- a/src/argus/analytics/charts/trend_chart.py +++ b/src/argus/analytics/charts/trend_chart.py @@ -4,6 +4,33 @@ def create_trendchart(curr: str, dates: pd.DataFrame): + """ + Create a trend chart for exchange-rate analysis. + + Builds a Matplotlib figure showing the exchange rate, its rolling + average, and the daily percentage change for a selected currency. + The minimum and maximum exchange-rate values are highlighted in the + chart. + + Args: + curr (str): Currency code or currency pair identifier used for + the trend analysis. + dates (pd.DataFrame): DataFrame containing the date information + used to prepare the time-series analysis. + + Returns: + matplotlib.figure.Figure: Matplotlib figure containing the trend + chart. + + Notes: + The chart uses two y-axes: + + - The left y-axis displays the exchange rate and rolling average. + - The right y-axis displays the daily percentage change. + + Minimum and maximum exchange-rate values are marked with scatter + points and annotations. + """ df = pd.DataFrame() df, min_max_rates = prepare_trend_analysis(curr, dates) min_date = min_max_rates["min_date"][0] diff --git a/src/argus/analytics/metrics/trend_metrics.py b/src/argus/analytics/metrics/trend_metrics.py index 9493ff3..5622acb 100644 --- a/src/argus/analytics/metrics/trend_metrics.py +++ b/src/argus/analytics/metrics/trend_metrics.py @@ -2,18 +2,69 @@ def add_daily_percentage_change(df: pd.DataFrame) -> pd.DataFrame: + """ + Add the daily percentage change of the exchange rate. + + Calculates the percentage change between each rate value and the + previous rate value. The result is added as a new column named + ``daily_pct_change``. + + Args: + df (pd.DataFrame): DataFrame containing at least a ``rate`` column. + + Returns: + pd.DataFrame: A copy of the input DataFrame with an added + ``daily_pct_change`` column. + + Notes: + The first row will contain ``NaN`` because there is no previous + rate value to compare against. + """ result = df.copy() result["daily_pct_change"] = result["rate"].pct_change() * 100 return result def add_rolling_average(df: pd.DataFrame) -> pd.DataFrame: + """ + Add a rolling average of the exchange rate. + + Calculates a rolling mean over the ``rate`` column using a fixed + window size of 3 rows. The result is added as a new column named + ``roll_avg``. + + Args: + df (pd.DataFrame): DataFrame containing at least a ``rate`` column. + + Returns: + pd.DataFrame: A copy of the input DataFrame with an added + ``roll_avg`` column. + """ result = df.copy() result["roll_avg"] = result["rate"].rolling(window=3, min_periods=1).mean() return result def get_min_max_rates(df: pd.DataFrame) -> dict: + """ + Get the minimum and maximum exchange-rate values. + + Finds the rows with the lowest and highest values in the ``rate`` + column and returns their dates and rates in a dictionary. + + Args: + df (pd.DataFrame): DataFrame containing at least ``date`` and + ``rate`` columns. + + Returns: + dict: Dictionary containing the minimum and maximum rate data with + the following keys: + + - ``min_date``: Date of the lowest exchange rate. + - ``min_rate``: Lowest exchange-rate value. + - ``max_date``: Date of the highest exchange rate. + - ``max_rate``: Highest exchange-rate value. + """ min_max = {"min_date": [], "min_rate": [], "max_date": [], "max_rate": []} min_id = df["rate"].idxmin() max_id = df["rate"].idxmax() diff --git a/src/argus/clients/exchangerate_client.py b/src/argus/clients/exchangerate_client.py index 71e9207..6a26499 100644 --- a/src/argus/clients/exchangerate_client.py +++ b/src/argus/clients/exchangerate_client.py @@ -6,7 +6,16 @@ ) -def get_rates(curr1, curr2): +def get_rates(curr1: str, curr2: str) : + """ + Get the exchange rate between two currencies using the ExchangeRate-API. + + Args: + curr1 (str): The base currency code (e.g., "USD"). + curr2 (str): The target currency code (e.g., "EUR"). + + Returns: A dictionary containing the result status, error type (if any), and conversion rate (if successful). + """ url = f"{EXCHANGE_RATE_BASE_URL}/{EXCHANGE_RATE_API_KEY}/pair/{curr1}/{curr2}" data = {"result": "", "error_type": "", "conversion_rate": None} @@ -43,23 +52,20 @@ def get_rates(curr1, curr2): return None -def check_error(err_type): +def check_error(err_type: str) -> None: + """ + Check the error type returned by the API and print an appropriate message. + + Args: err_type (str): The error type returned by the API. + + Returns: None + """ match err_type: case "unsupported-code" | "malformed-request": - print("Ungültige Anfrage! Bitter versuchen Sie es später erneut.") + print("Invalid request! Please try again later.") case "invalid-key": - print( - "Ungültiger API-Key! Checken Sie Ihren API-Key und versuchen Sie es erneut." - ) + print("Invalid API key! Please check your API key and try again.") case "inactive-account": - print( - "Inaktives Konto! Bitte auf exchangerate-api.com gehen und Konto aktivieren." - ) + print("Inactive account! Please go to exchangerate-api.com and activate your account.") case "quota-reached": - print( - "Anfrage-Limit erreicht! Bitte später erneut versuchen oder auf exchangerate-api.com upgraden." - ) - - -# Testen, ob die API funktioniert -# data = get_rates("EUR", "USD") + print("Request limit reached! Please try again later or upgrade to exchangerate-api.com.") diff --git a/src/argus/domain/validation.py b/src/argus/domain/validation.py index 8e08d16..16879a7 100644 --- a/src/argus/domain/validation.py +++ b/src/argus/domain/validation.py @@ -167,10 +167,24 @@ def normalize_input_string(input: str) -> str: + """ + Normalizes the input string by stripping leading and trailing whitespace and converting it to uppercase. + + Arg1: input: str - the input string to be normalized + + Return: str - the normalized input string + """ return input.strip().upper() def parse_amount(value: str) -> float | None: + """ + Parses the input string to a float. If the input is not a valid number, it returns None. + + Arg1: value: str - the input string to be parsed as a float + + Return: float or None - the parsed float value if valid, otherwise None + """ try: return float(value) except ValueError: @@ -178,8 +192,22 @@ def parse_amount(value: str) -> float | None: def is_valid_curr_code(code: str) -> bool: + """ + Checks if the given currency code is valid. + + Arg1: code: str - the currency code to be checked + + Return: bool - True if the currency code is valid, otherwise False + """ return code in VALID_CURRENCY_CODES def is_valid_op(op: str) -> bool: + """ + Checks if the given operation is valid. + + Arg1: op: str - the operation to be checked + + Return: bool - True if the operation is valid, otherwise False + """ return op in VALID_OPS diff --git a/src/argus/gui/app.py b/src/argus/gui/app.py index 141fec5..65edb99 100644 --- a/src/argus/gui/app.py +++ b/src/argus/gui/app.py @@ -8,6 +8,10 @@ def on_close() -> None: + """ + Handles the closing of the application window. It ensures that any open trend chart is destroyed and + the application is properly closed. + """ if trend_chart_widget is not None: trend_chart_widget.destroy() @@ -16,11 +20,17 @@ def on_close() -> None: def hide_trend_chart() -> None: + """ + Hides the trend chart from the GUI if it is currently displayed. + """ if trend_chart_widget is not None: trend_chart_widget.pack_forget() def show_menu() -> None: + """ + Displays the main menu in the application. It updates the GUI to show the menu interface. + """ app_frame.pack_forget() calc_frame.pack_forget() conv_frame.pack_forget() @@ -30,6 +40,9 @@ def show_menu() -> None: def show_calc() -> None: + """ + Displays the calculator in the application. It updates the GUI to show the calculator interface. + """ conv_frame.pack_forget() hide_trend_chart() menu_frame.pack_forget() @@ -42,6 +55,9 @@ def show_calc() -> None: def show_conv() -> None: + """ + Displays the currency converter in the application. It updates the GUI to show the converter interface. + """ calc_frame.pack_forget() hide_trend_chart() menu_frame.pack_forget() @@ -54,6 +70,10 @@ def show_conv() -> None: def show_trend() -> None: + """ + Displays the trend chart in the application. It prepares the data for trend analysis, + creates the trend chart, and updates the GUI to show the chart. + """ global trend_canvas global trend_chart_widget @@ -101,6 +121,11 @@ def show_trend() -> None: def act_calculate() -> None: + """ + Handles the calculation action when the "Calculate" button is clicked. + It checks the validity of the input numbers and operator, performs the calculation, + and updates the result label accordingly. + """ resp1 = num1.get() resp1 = parse_amount(resp1) @@ -131,6 +156,11 @@ def act_calculate() -> None: def act_convert() -> None: + """ + Handles the conversion action when the "Convert" button is clicked. + It checks the validity of the input currencies and amount, performs the conversion, + and updates the result label accordingly. + """ resp1 = check_currency(curr1.get()) resp2 = check_currency(curr2.get()) amount = parse_amount(amount_e.get()) @@ -162,6 +192,9 @@ def act_convert() -> None: def app() -> None: + """ + The main function that initializes and starts the GUI application. It sets up the main window, frames, labels, entries, and buttons, and defines the layout of the application. + """ root.mainloop() diff --git a/src/argus/main.py b/src/argus/main.py index a6fd534..2090b84 100644 --- a/src/argus/main.py +++ b/src/argus/main.py @@ -2,6 +2,9 @@ def main() -> None: + """ + The main function that starts the application. + """ app() diff --git a/src/argus/services/calculator_service.py b/src/argus/services/calculator_service.py index 40c1022..8686af1 100644 --- a/src/argus/services/calculator_service.py +++ b/src/argus/services/calculator_service.py @@ -2,7 +2,13 @@ def check_op(op: str) -> bool: - # Tipp: Liste verwenden, wenn mehr als 2 Optionen für etwas besteht + """ + Checks if the input operator is valid. + + Arg1: op: str - the operator to be checked for validity + + Return: bool - True if the operator is valid, otherwise False + """ if is_valid_op(op): return True else: @@ -10,7 +16,15 @@ def check_op(op: str) -> bool: def calc(num1: float, num2: float, op: str) -> float | None: - # Tipp: Auf Ifelse verzichten, wenn davon mehr als 3 Stück entstehen + """ + Performs a calculation based on the provided operator. + + Arg1: num1: float - the first number + Arg2: num2: float - the second number + Arg3: op: str - the operator to be used for the calculation + + Return: float or None - the result of the calculation if valid, otherwise None + """ match op: case "+": return num1 + num2 diff --git a/src/argus/services/conversion_service.py b/src/argus/services/conversion_service.py index 7d16d76..ffbe1ad 100644 --- a/src/argus/services/conversion_service.py +++ b/src/argus/services/conversion_service.py @@ -1,9 +1,14 @@ from argus.clients import exchangerate_client as ex_client from argus.domain.validation import normalize_input_string, is_valid_curr_code - -# This function has to be moved to dmoain def check_currency(question: str) -> str | None: + """ + Checks if the input question contains a valid currency code. + + Arg1: question: str - the question to be checked for a valid currency code + + Return: str or None - the valid currency code if found, otherwise None + """ resp = normalize_input_string(question) if is_valid_curr_code(resp): @@ -13,6 +18,15 @@ def check_currency(question: str) -> str | None: def get_conv_rate(resp1: str, resp2: str) -> float | None: + """ + Gets the conversion rate between two currencies. + + Arg1: resp1: str - the first currency code + Arg2: resp2: str - the second currency code + + Return: float or None - the conversion rate if found, otherwise None + """ + data = ex_client.get_rates(resp1, resp2) if data is None: @@ -22,6 +36,16 @@ def get_conv_rate(resp1: str, resp2: str) -> float | None: def convert(amount: float, resp1: str, resp2: str) -> float | None: + """ + Converts an amount from one currency to another using the conversion rate. + + Arg1: amount: float - the amount to be converted + Arg2: resp1: str - the first currency code + Arg3: resp2: str - the second currency code + + Return: float or None - the converted amount if conversion rate is found, otherwise None + """ + data = get_conv_rate(resp1, resp2) if data is not None: return amount * data diff --git a/src/argus/services/timeseries_service.py b/src/argus/services/timeseries_service.py index 6ef34ae..172919b 100644 --- a/src/argus/services/timeseries_service.py +++ b/src/argus/services/timeseries_service.py @@ -7,9 +7,18 @@ ) -def prepare_trend_analysis( - mock_curr: str, df: pd.DataFrame -) -> tuple[pd.DataFrame, dict]: +def prepare_trend_analysis(mock_curr: str, df: pd.DataFrame) -> tuple[pd.DataFrame, dict]: + """ + Prepares the data for trend analysis by adding conversion rates, daily percentage change, and rolling average. + + Arg1: mock_curr: str - the currency code for which the trend analysis is to + be performed + Arg2: df: pd.DataFrame - the DataFrame containing the dates for which the + conversion rates are to be added + + Return: tuple[pd.DataFrame, dict] - a tuple containing the updated DataFrame with conversion rates, + daily percentage change, and rolling average, and a dictionary with the minimum and maximum rates + """ df["rate"] = 0.0 # For each date one API call to get the rate for i in range(len(df)): diff --git a/src/legacy/cli/interface.py b/src/legacy/cli/interface.py index fa9931a..727adaf 100644 --- a/src/legacy/cli/interface.py +++ b/src/legacy/cli/interface.py @@ -4,6 +4,18 @@ def display_convert() -> None: + """ + Display the currency conversion workflow in the developer interface. + + Prompts the user for an amount, validates both currency inputs, sends + the conversion request, and prints the converted result. + + Args: + None + + Returns: + None + """ while True: amount = parse_amount(input("Amount: ")) if amount is None: @@ -39,6 +51,18 @@ def display_convert() -> None: def display_calc() -> None: + """ + Display the calculator workflow in the developer interface. + + Prompts the user for two numeric values and an arithmetic operation, + validates the input, calculates the result, and prints it to the console. + + Args: + None + + Returns: + None + """ while True: num1 = parse_amount(input("First number: ")) if num1 is None: @@ -66,6 +90,17 @@ def display_calc() -> None: def return_to_menu() -> str: + """ + Ask the user whether they want to return to the menu. + + Repeats the prompt until the user enters either ``y`` or ``n``. + + Args: + None + + Returns: + str: ``y`` if the user wants to return to the menu, otherwise ``n``. + """ while True: repeat = input("Would you like to return to the menu? (y/n) ") match repeat: @@ -78,6 +113,18 @@ def return_to_menu() -> str: def dev_interface() -> None: + """ + Run the developer command-line interface. + + Displays a simple menu that allows the user to choose between the + calculator, currency conversion, or exiting the program. + + Args: + None + + Returns: + None + """ initConv = "Welcome to the Calculator with Currency Conversion!" print(initConv) while True: diff --git a/src/legacy/debug_main.py b/src/legacy/debug_main.py index 8d82035..5ce0c56 100644 --- a/src/legacy/debug_main.py +++ b/src/legacy/debug_main.py @@ -2,6 +2,9 @@ def start_cli() -> None: + """ + Starts the command-line interface for development purposes. + """ dev_interface() From a098a8c39aae62d97639c35ea4737f87199801b4 Mon Sep 17 00:00:00 2001 From: Lev Gusiev Date: Tue, 16 Jun 2026 12:45:08 +0200 Subject: [PATCH 04/14] fix(#32): fix err msg of test_check_error --- tests/test_exchangerate_client.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_exchangerate_client.py b/tests/test_exchangerate_client.py index 51e8174..39a70fa 100644 --- a/tests/test_exchangerate_client.py +++ b/tests/test_exchangerate_client.py @@ -104,25 +104,25 @@ def test_get_resp(url, timeout): def test_check_error(capsys): check_error("unsupported-code") captured = capsys.readouterr() - assert captured.out == "Ungültige Anfrage! Bitter versuchen Sie es später erneut.\n" + assert captured.out == "Invalid request! Please try again later.\n" check_error("invalid-key") captured = capsys.readouterr() assert ( captured.out - == "Ungültiger API-Key! Checken Sie Ihren API-Key und versuchen Sie es erneut.\n" + == "Invalid API key! Please check your API key and try again.\n" ) check_error("inactive-account") captured = capsys.readouterr() assert ( captured.out - == "Inaktives Konto! Bitte auf exchangerate-api.com gehen und Konto aktivieren.\n" + == "Inactive account! Please go to exchangerate-api.com and activate your account.\n" ) check_error("quota-reached") captured = capsys.readouterr() assert ( captured.out - == "Anfrage-Limit erreicht! Bitte später erneut versuchen oder auf exchangerate-api.com upgraden.\n" + == "Request limit reached! Please try again later or upgrade to exchangerate-api.com.\n" ) From 5b9344ff17051e3fabd312246626eec08fe91ed9 Mon Sep 17 00:00:00 2001 From: Lev Gusiev Date: Tue, 16 Jun 2026 12:48:12 +0200 Subject: [PATCH 05/14] style(#32): ruff reformated the code --- src/argus/clients/exchangerate_client.py | 12 ++++++++---- src/argus/gui/app.py | 6 +++--- src/argus/main.py | 2 +- src/argus/services/conversion_service.py | 7 ++++--- src/argus/services/timeseries_service.py | 8 +++++--- tests/test_exchangerate_client.py | 5 +---- 6 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/argus/clients/exchangerate_client.py b/src/argus/clients/exchangerate_client.py index 6a26499..8ea5e89 100644 --- a/src/argus/clients/exchangerate_client.py +++ b/src/argus/clients/exchangerate_client.py @@ -6,11 +6,11 @@ ) -def get_rates(curr1: str, curr2: str) : +def get_rates(curr1: str, curr2: str): """ Get the exchange rate between two currencies using the ExchangeRate-API. - Args: + Args: curr1 (str): The base currency code (e.g., "USD"). curr2 (str): The target currency code (e.g., "EUR"). @@ -66,6 +66,10 @@ def check_error(err_type: str) -> None: case "invalid-key": print("Invalid API key! Please check your API key and try again.") case "inactive-account": - print("Inactive account! Please go to exchangerate-api.com and activate your account.") + print( + "Inactive account! Please go to exchangerate-api.com and activate your account." + ) case "quota-reached": - print("Request limit reached! Please try again later or upgrade to exchangerate-api.com.") + print( + "Request limit reached! Please try again later or upgrade to exchangerate-api.com." + ) diff --git a/src/argus/gui/app.py b/src/argus/gui/app.py index 65edb99..829a905 100644 --- a/src/argus/gui/app.py +++ b/src/argus/gui/app.py @@ -71,7 +71,7 @@ def show_conv() -> None: def show_trend() -> None: """ - Displays the trend chart in the application. It prepares the data for trend analysis, + Displays the trend chart in the application. It prepares the data for trend analysis, creates the trend chart, and updates the GUI to show the chart. """ global trend_canvas @@ -157,8 +157,8 @@ def act_calculate() -> None: def act_convert() -> None: """ - Handles the conversion action when the "Convert" button is clicked. - It checks the validity of the input currencies and amount, performs the conversion, + Handles the conversion action when the "Convert" button is clicked. + It checks the validity of the input currencies and amount, performs the conversion, and updates the result label accordingly. """ resp1 = check_currency(curr1.get()) diff --git a/src/argus/main.py b/src/argus/main.py index 2090b84..7130dbf 100644 --- a/src/argus/main.py +++ b/src/argus/main.py @@ -2,7 +2,7 @@ def main() -> None: - """ + """ The main function that starts the application. """ app() diff --git a/src/argus/services/conversion_service.py b/src/argus/services/conversion_service.py index ffbe1ad..0dc3cf0 100644 --- a/src/argus/services/conversion_service.py +++ b/src/argus/services/conversion_service.py @@ -1,6 +1,7 @@ from argus.clients import exchangerate_client as ex_client from argus.domain.validation import normalize_input_string, is_valid_curr_code + def check_currency(question: str) -> str | None: """ Checks if the input question contains a valid currency code. @@ -23,7 +24,7 @@ def get_conv_rate(resp1: str, resp2: str) -> float | None: Arg1: resp1: str - the first currency code Arg2: resp2: str - the second currency code - + Return: float or None - the conversion rate if found, otherwise None """ @@ -36,13 +37,13 @@ def get_conv_rate(resp1: str, resp2: str) -> float | None: def convert(amount: float, resp1: str, resp2: str) -> float | None: - """ + """ Converts an amount from one currency to another using the conversion rate. Arg1: amount: float - the amount to be converted Arg2: resp1: str - the first currency code Arg3: resp2: str - the second currency code - + Return: float or None - the converted amount if conversion rate is found, otherwise None """ diff --git a/src/argus/services/timeseries_service.py b/src/argus/services/timeseries_service.py index 172919b..3646200 100644 --- a/src/argus/services/timeseries_service.py +++ b/src/argus/services/timeseries_service.py @@ -7,16 +7,18 @@ ) -def prepare_trend_analysis(mock_curr: str, df: pd.DataFrame) -> tuple[pd.DataFrame, dict]: +def prepare_trend_analysis( + mock_curr: str, df: pd.DataFrame +) -> tuple[pd.DataFrame, dict]: """ Prepares the data for trend analysis by adding conversion rates, daily percentage change, and rolling average. - + Arg1: mock_curr: str - the currency code for which the trend analysis is to be performed Arg2: df: pd.DataFrame - the DataFrame containing the dates for which the conversion rates are to be added - Return: tuple[pd.DataFrame, dict] - a tuple containing the updated DataFrame with conversion rates, + Return: tuple[pd.DataFrame, dict] - a tuple containing the updated DataFrame with conversion rates, daily percentage change, and rolling average, and a dictionary with the minimum and maximum rates """ df["rate"] = 0.0 diff --git a/tests/test_exchangerate_client.py b/tests/test_exchangerate_client.py index 39a70fa..faf0864 100644 --- a/tests/test_exchangerate_client.py +++ b/tests/test_exchangerate_client.py @@ -108,10 +108,7 @@ def test_check_error(capsys): check_error("invalid-key") captured = capsys.readouterr() - assert ( - captured.out - == "Invalid API key! Please check your API key and try again.\n" - ) + assert captured.out == "Invalid API key! Please check your API key and try again.\n" check_error("inactive-account") captured = capsys.readouterr() From 37b84423d17b84dd556ff27a7a6fdfa46a711b06 Mon Sep 17 00:00:00 2001 From: Lev Gusiev Date: Tue, 16 Jun 2026 12:49:15 +0200 Subject: [PATCH 06/14] style(#32): ruff reformated the code again --- src/argus/clients/exchangerate_client.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/argus/clients/exchangerate_client.py b/src/argus/clients/exchangerate_client.py index 8ea5e89..2a87fbb 100644 --- a/src/argus/clients/exchangerate_client.py +++ b/src/argus/clients/exchangerate_client.py @@ -6,11 +6,11 @@ ) -def get_rates(curr1: str, curr2: str): +def get_rates(curr1: str, curr2: str) : """ Get the exchange rate between two currencies using the ExchangeRate-API. - Args: + Args: curr1 (str): The base currency code (e.g., "USD"). curr2 (str): The target currency code (e.g., "EUR"). @@ -62,14 +62,10 @@ def check_error(err_type: str) -> None: """ match err_type: case "unsupported-code" | "malformed-request": - print("Invalid request! Please try again later.") + print("Invalid request! Please try again later.\n") case "invalid-key": - print("Invalid API key! Please check your API key and try again.") + print("Invalid API key! Please check your API key and try again.\n") case "inactive-account": - print( - "Inactive account! Please go to exchangerate-api.com and activate your account." - ) + print("Inactive account! Please go to exchangerate-api.com and activate your account.\n") case "quota-reached": - print( - "Request limit reached! Please try again later or upgrade to exchangerate-api.com." - ) + print("Request limit reached! Please try again later or upgrade to exchangerate-api.com.\n") From cdcf143a2ddd4d2f52dfba09daef3f10cef10da6 Mon Sep 17 00:00:00 2001 From: Lev Gusiev Date: Tue, 16 Jun 2026 12:54:24 +0200 Subject: [PATCH 07/14] fix(#32): remove \n check_error --- src/argus/clients/exchangerate_client.py | 8 ++++---- tests/test_exchangerate_client.py | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/argus/clients/exchangerate_client.py b/src/argus/clients/exchangerate_client.py index 2a87fbb..6a26499 100644 --- a/src/argus/clients/exchangerate_client.py +++ b/src/argus/clients/exchangerate_client.py @@ -62,10 +62,10 @@ def check_error(err_type: str) -> None: """ match err_type: case "unsupported-code" | "malformed-request": - print("Invalid request! Please try again later.\n") + print("Invalid request! Please try again later.") case "invalid-key": - print("Invalid API key! Please check your API key and try again.\n") + print("Invalid API key! Please check your API key and try again.") case "inactive-account": - print("Inactive account! Please go to exchangerate-api.com and activate your account.\n") + print("Inactive account! Please go to exchangerate-api.com and activate your account.") case "quota-reached": - print("Request limit reached! Please try again later or upgrade to exchangerate-api.com.\n") + print("Request limit reached! Please try again later or upgrade to exchangerate-api.com.") diff --git a/tests/test_exchangerate_client.py b/tests/test_exchangerate_client.py index faf0864..39a70fa 100644 --- a/tests/test_exchangerate_client.py +++ b/tests/test_exchangerate_client.py @@ -108,7 +108,10 @@ def test_check_error(capsys): check_error("invalid-key") captured = capsys.readouterr() - assert captured.out == "Invalid API key! Please check your API key and try again.\n" + assert ( + captured.out + == "Invalid API key! Please check your API key and try again.\n" + ) check_error("inactive-account") captured = capsys.readouterr() From 74be18dbb6ddcaec02d4bf6d225a07b54de5d287 Mon Sep 17 00:00:00 2001 From: Lev Gusiev Date: Tue, 16 Jun 2026 12:56:10 +0200 Subject: [PATCH 08/14] style(#32): ruff reformated the code again --- src/argus/clients/exchangerate_client.py | 12 ++++++++---- tests/test_exchangerate_client.py | 5 +---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/argus/clients/exchangerate_client.py b/src/argus/clients/exchangerate_client.py index 6a26499..8ea5e89 100644 --- a/src/argus/clients/exchangerate_client.py +++ b/src/argus/clients/exchangerate_client.py @@ -6,11 +6,11 @@ ) -def get_rates(curr1: str, curr2: str) : +def get_rates(curr1: str, curr2: str): """ Get the exchange rate between two currencies using the ExchangeRate-API. - Args: + Args: curr1 (str): The base currency code (e.g., "USD"). curr2 (str): The target currency code (e.g., "EUR"). @@ -66,6 +66,10 @@ def check_error(err_type: str) -> None: case "invalid-key": print("Invalid API key! Please check your API key and try again.") case "inactive-account": - print("Inactive account! Please go to exchangerate-api.com and activate your account.") + print( + "Inactive account! Please go to exchangerate-api.com and activate your account." + ) case "quota-reached": - print("Request limit reached! Please try again later or upgrade to exchangerate-api.com.") + print( + "Request limit reached! Please try again later or upgrade to exchangerate-api.com." + ) diff --git a/tests/test_exchangerate_client.py b/tests/test_exchangerate_client.py index 39a70fa..faf0864 100644 --- a/tests/test_exchangerate_client.py +++ b/tests/test_exchangerate_client.py @@ -108,10 +108,7 @@ def test_check_error(capsys): check_error("invalid-key") captured = capsys.readouterr() - assert ( - captured.out - == "Invalid API key! Please check your API key and try again.\n" - ) + assert captured.out == "Invalid API key! Please check your API key and try again.\n" check_error("inactive-account") captured = capsys.readouterr() From 50603bc165ab1fe537be4f7bcff28ba97c43a111 Mon Sep 17 00:00:00 2001 From: Lev Gusiev Date: Wed, 17 Jun 2026 19:56:36 +0200 Subject: [PATCH 09/14] docs(#32): add intro and first data soruce to research --- docs/research-data-sources | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/research-data-sources diff --git a/docs/research-data-sources b/docs/research-data-sources new file mode 100644 index 0000000..e69de29 From 7fe8774ea856e09376ddf37963bac31e667a15f5 Mon Sep 17 00:00:00 2001 From: Lev Gusiev Date: Wed, 17 Jun 2026 19:58:31 +0200 Subject: [PATCH 10/14] docs(#32): add more details to first data sorource --- docs/research-data-sources | 151 +++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/docs/research-data-sources b/docs/research-data-sources index e69de29..e131842 100644 --- a/docs/research-data-sources +++ b/docs/research-data-sources @@ -0,0 +1,151 @@ +# ARGUS Data Source Research + +## Goal + +Research and choose a real data source for ARGUS analytics. + +ARGUS should evolve from a simple FX converter into a broader market analysis tool. + +The first real data source should replace the mock time-series client and provide useful historical data for beginner-friendly analytics. + +The selected source should be: + +* free or usable without relevant cost +* easy to integrate in Python +* pandas-friendly +* useful for historical analysis +* suitable for future market analytics +* not limited to pure experimentation if the project becomes more serious later + +--- + +## Why + +ARGUS currently uses mock time-series data for early analytics development. + +Sprint 2 needs a real data client so market metrics can be calculated from real data. + +The existing ExchangeRate API client was useful for the first live currency conversion feature, but ARGUS now needs stronger historical data support. + +The project should not become a pure FX trading tool. + +FX data is a useful entry point because it is simpler than stock analysis: + +* exchange-rate data is easier to model +* fewer external fundamentals are needed +* one clean time series is enough for first analytics +* beginner-friendly metrics can be implemented quickly + +However, the long-term direction is broader market analysis: + +* stocks +* ETFs +* indices +* currencies +* simple trading-oriented insights +* paper trading +* later possible commercial usage if data licensing allows it + +--- + +## Compared Data Sources + +| Source | Best Use Case | Free / Cost | API Key | Python / pandas Fit | Commercial Suitability | Fit for ARGUS | +|---|---|---:|---:|---|---|---| +| Frankfurter | Historical FX data | Free | No | Good | Better than unofficial sources, open-source/self-hostable | Very good first client | +| yfinance | Broad market data for research | Free | No | Excellent | Limited / check Yahoo terms | Very good later client | +| ExchangeRate API | Live currency conversion | Free tier / paid tiers | Yes | Okay | Depends on plan | Legacy / live conversion only | +| Alpha Vantage | Stocks, FX, crypto, indicators | Free tier + paid | Yes | Good | More API-like, paid plans available | Possible later | +| Twelve Data | Stocks, FX, ETFs, crypto, indices | Free tier + paid | Yes | Good | More suitable for serious API usage | Possible later | + +--- + +## Current ExchangeRate API + +### What it is + +The current ExchangeRate API client is useful for live currency conversion. + +It fits the original project stage: + +* enter an amount +* select source currency +* select target currency +* receive converted result + +### Strengths + +* Already integrated +* Simple for live conversion +* Good for the original FX converter use case +* Easy to understand + +### Limitations + +* Not ideal as the main historical analytics source +* Historical data support is not the strongest free path for this project +* Less useful once ARGUS moves toward market analytics +* Adds less long-term value if Frankfurter covers FX better + +### Role in ARGUS + +The ExchangeRate API should not be the strategic core client anymore. + +It can remain temporarily as: + +* legacy live conversion client +* fallback client +* comparison point during migration + +Long term, it can probably be removed if Frankfurter covers all required FX use cases. + +--- + +## Frankfurter + +### What it is + +Frankfurter is a free and open-source exchange-rate API. + +It provides current and historical exchange-rate data and does not require an API key. + +### Strengths + +* Free +* No API key required +* Simple REST API +* Historical FX data +* Time-series data +* JSON response format +* Easy to transform into pandas DataFrames +* Good fit for beginner-friendly analytics +* Can replace mock FX time-series data directly +* Can also replace parts of the current ExchangeRate API later + +### Limitations + +* Focused on exchange rates +* Not a broad market-data API +* Does not cover stocks, ETFs or company fundamentals +* Not enough for long-term stock or portfolio analysis alone + +### Example Response Structure + +Conceptual response shape: + +```json +{ + "amount": 1.0, + "base": "EUR", + "start_date": "2024-01-01", + "end_date": "2024-01-31", + "rates": { + "2024-01-01": { + "USD": 1.10 + }, + "2024-01-02": { + "USD": 1.11 + } + } +} + From e149da9ff8201f938ab2ce1ab0491ea657219eae Mon Sep 17 00:00:00 2001 From: Lev Gusiev Date: Wed, 17 Jun 2026 20:02:29 +0200 Subject: [PATCH 11/14] docs(#32): add more data sources and plan for implementation --- docs/research-data-sources | 390 +++++++++++++++++++++++++++++++++++++ 1 file changed, 390 insertions(+) diff --git a/docs/research-data-sources b/docs/research-data-sources index e131842..dfbee48 100644 --- a/docs/research-data-sources +++ b/docs/research-data-sources @@ -149,3 +149,393 @@ Conceptual response shape: } } +## Internal Normalized Format + +For ARGUS analytics, API responses should be normalized into simple internal data formats. + +The analytics layer should not depend directly on the original API response structure. + +This makes it easier to switch or add data sources later. + +--- + +### FX Time Series Format + +Used for exchange-rate based analytics. + +| date | base | target | rate | +|---|---|---|---:| +| 2024-01-01 | EUR | USD | 1.10 | +| 2024-01-02 | EUR | USD | 1.11 | + +For single-pair analytics, this can be simplified to: + +| date | rate | +|---|---:| +| 2024-01-01 | 1.10 | +| 2024-01-02 | 1.11 | + +--- + +### General Market Time Series Format + +Used for broader market analysis such as stocks, ETFs, indices or other symbols. + +| date | symbol | value | +|---|---|---:| +| 2024-01-01 | AAPL | 185.64 | +| 2024-01-02 | AAPL | 184.25 | + +This format is useful when only one main price value is needed, usually the closing price. + +--- + +### Optional OHLC Market Data Format + +Used later if ARGUS needs more detailed market analysis. + +| date | symbol | open | high | low | close | volume | +|---|---|---:|---:|---:|---:|---:| +| 2024-01-01 | AAPL | 184.00 | 187.00 | 183.50 | 185.64 | 50200000 | +| 2024-01-02 | AAPL | 185.20 | 186.10 | 182.90 | 184.25 | 48100000 | + +This format is not required for the first Sprint 2 implementation, but it may become useful later for: + +* stock analysis +* ETF analysis +* paper trading +* signal generation +* backtesting +* more advanced chart types + +--- + +## ARGUS Fit + +Frankfurter is the best first real data client for Sprint 2. + +It solves the immediate problem: + +* replace mock time-series data +* fetch real historical exchange-rate data +* calculate the first real analytics metrics +* keep the implementation beginner-friendly +* avoid unnecessary complexity from stock-market data too early + +FX data is a useful entry point because it is simpler than stock analysis. + +However, ARGUS should not stay limited to FX trading. + +The long-term direction is broader market analysis for normal users: + +* stocks +* ETFs +* indices +* currencies +* watchlists +* basic market insights +* paper trading +* later possible commercial usage if data licensing allows it + +--- + +## yfinance + +### What it is + +yfinance is a Python library for downloading market data from Yahoo Finance. + +It is useful for stocks, ETFs, indices and some FX symbols. + +### Strengths + +* Very easy to use in Python +* Excellent pandas compatibility +* Supports broader market data than Frankfurter +* Good for stocks, ETFs and indices +* Useful for future market analysis +* Useful for later signal generation and ML experiments + +### Limitations + +* Not an official Yahoo Finance API +* Intended mainly for research and educational use +* Commercial usage requires checking Yahoo terms +* Data availability depends on Yahoo symbols +* Less predictable than a dedicated paid market-data API +* Not ideal as the first serious commercial data backbone + +### Example Usage Shape + +```python +import yfinance as yf + +data = yf.download("AAPL", start="2024-01-01", end="2024-02-01") +``` +Expected DataFrame-like structure: + +| Date | Open | High | Low | Close | Adj Close | Volume | +|---|---:|---:|---:|---:|---:|---:| + +For ARGUS analytics, the most important fields at the beginning are: + +| date | close | +|---|---:| + +or normalized: + +| date | symbol | value | +|---|---|---:| + +### ARGUS Fit + +yfinance is a very good later client. + +It should be introduced when ARGUS moves from FX-based analytics toward broader market analysis. + +It is especially useful for: + +* stocks +* ETFs +* indices +* market comparisons +* watchlists +* signal experiments +* ML features +* paper trading prototypes + +However, yfinance should not be the first mock-client replacement if the immediate Sprint 2 goal is clean historical FX analytics. + +--- + +## Alpha Vantage + +### What it is + +Alpha Vantage is a financial data API for stocks, FX, crypto, commodities, indicators and more. + +### Strengths + +* Official API-style access +* Supports many market data types +* Has documentation for many endpoints +* More suitable than yfinance if the project later needs a more formal API provider +* Could support more serious long-term data workflows + +### Limitations + +* Requires API key +* Free tier is limited +* Request limits can become annoying for analytics workflows +* More setup than Frankfurter or yfinance +* Some advanced or real-time features require paid plans + +### ARGUS Fit + +Alpha Vantage is not recommended as the first Sprint 2 client. + +It is worth revisiting later if ARGUS needs: + +* more formal market-data API access +* indicators +* broader asset coverage +* a clearer path toward commercial or semi-commercial use + +--- + +## Twelve Data + +### What it is + +Twelve Data is a financial market data API covering stocks, forex, ETFs, indices, crypto and more. + +### Strengths + +* Broad market coverage +* API-first design +* Supports JSON and other formats +* Has SDK support +* Better long-term candidate than unofficial data sources +* More suitable for serious market-data workflows + +### Limitations + +* Requires API key +* Free tier limitations apply +* More platform dependency +* More setup than Frankfurter +* Probably too much for the first Sprint 2 step + +### ARGUS Fit + +Twelve Data is interesting for later. + +It may become relevant when ARGUS moves toward: + +* broader market analysis +* paper trading +* more reliable stock/ETF data +* possible commercial use +* serious dashboard or monitoring workflows + +It should not be the first implementation choice because Frankfurter is simpler for the current phase. + +--- + +## Commercial Usage Consideration + +ARGUS should avoid locking itself into data sources that are only useful for experiments if the project may later become more serious. + +Current interpretation: + +| Source | Commercial Direction | +|---|---| +| Frankfurter | Best first choice; open-source and self-hostable, but source and data terms should still be checked before commercial use | +| yfinance | Great for learning and research, but not ideal for commercial use without checking Yahoo terms | +| ExchangeRate API | Commercial use depends on API plan and terms | +| Alpha Vantage | More realistic commercial path through paid plans | +| Twelve Data | More realistic commercial path through paid plans | +| SerpApi / Google Finance | Better for search, enrichment or RAG context, not first market-data backbone | + +### Practical Decision + +For Sprint 2: + +* Use Frankfurter first. + +For later broader market analysis: + +* Add yfinance for learning and research. + +For possible commercial or serious paper-trading direction: + +* Evaluate Alpha Vantage or Twelve Data later. + +--- + +## Recommended Decision + +### First Client to Replace Mock Time-Series Data + +Frankfurter + +### Why + +* Free +* No API key +* Simple API +* Historical FX data +* Easy pandas transformation +* Perfect first real-data step +* Keeps Sprint 2 manageable +* Can replace mock time-series data directly +* May later replace the existing ExchangeRate API for FX use cases + +--- + +## Recommended Later Client + +yfinance + +### Why + +* Strong Python workflow +* Excellent pandas fit +* Good for stocks, ETFs and indices +* Better fit for broader market analysis +* Useful for signal and ML experiments +* Good bridge from FX analytics to normal-user market analysis + +--- + +## Not Recommended for First Implementation + +SerpApi / Google Finance + +### Why + +* Not the cleanest historical market-data source +* Search/scraping-style API +* Paid usage model +* Less suitable for the first analytics data backbone +* More useful later for enrichment, news, summaries or RAG context + +--- + +## Suggested Client Structure + +```text +clients/ +├─ exchange_rate_client.py # existing live conversion client, legacy/fallback +├─ frankfurter_client.py # first real historical FX data client +├─ yahoo_finance_client.py # later broader market data client +└─ mock_time_series_client.py # deprecated after Frankfurter works +``` + +--- + +## Suggested Internal Data Format + +The analytics layer should not depend on a specific API response format. + +Every client should normalize data into a shared internal structure. + +### FX Time Series + +```text +date | base | target | rate +``` + +### General Market Time Series + +```text +date | symbol | value +``` + +### Optional OHLC Market Data + +```text +date | symbol | open | high | low | close | volume +``` + +This keeps analytics reusable across different sources: + +```text +Frankfurter +yfinance +Alpha Vantage +Twelve Data + ↓ +normalized DataFrame + ↓ +analytics metrics + ↓ +charts / dashboard +``` + +--- + +## Final Recommendation + +Frankfurter should be selected as the first real data source for Sprint 2. + +It should replace the mock time-series client first because it is simple, free, historical and directly useful for the current analytics metrics. + +The existing ExchangeRate API client should remain only as a temporary live conversion or fallback client. + +yfinance should be added later as the broader market-analysis client when ARGUS moves beyond FX into stocks, ETFs and indices. + +Alpha Vantage or Twelve Data should be researched later if ARGUS needs a more serious API provider for commercial, paper-trading or production-like workflows. + +This keeps ARGUS realistic: + +```text +Sprint 2: +real FX analytics with Frankfurter + +Later: +broader market analysis with yfinance + +Future: +commercial-friendly market data provider if needed +``` \ No newline at end of file From cecd397c65dbc304d54ad3c44b4a940202e61f28 Mon Sep 17 00:00:00 2001 From: Lev Gusiev Date: Wed, 17 Jun 2026 20:29:10 +0200 Subject: [PATCH 12/14] docs(#32): add fred to research --- docs/research-data-sources | 255 +++++++++++++++++++++++-------------- 1 file changed, 157 insertions(+), 98 deletions(-) diff --git a/docs/research-data-sources b/docs/research-data-sources index dfbee48..8d99f49 100644 --- a/docs/research-data-sources +++ b/docs/research-data-sources @@ -148,6 +148,7 @@ Conceptual response shape: } } } +``` ## Internal Normalized Format @@ -380,162 +381,220 @@ It may become relevant when ARGUS moves toward: It should not be the first implementation choice because Frankfurter is simpler for the current phase. ---- +## FRED API + +### What it is -## Commercial Usage Consideration +FRED is the Federal Reserve Economic Data API from the Federal Reserve Bank of St. Louis. -ARGUS should avoid locking itself into data sources that are only useful for experiments if the project may later become more serious. +It provides access to economic and macroeconomic time series such as: -Current interpretation: +* interest rates +* inflation indicators +* unemployment data +* GDP-related data +* yield curves +* recession indicators +* money supply +* economic sentiment and macro context data -| Source | Commercial Direction | -|---|---| -| Frankfurter | Best first choice; open-source and self-hostable, but source and data terms should still be checked before commercial use | -| yfinance | Great for learning and research, but not ideal for commercial use without checking Yahoo terms | -| ExchangeRate API | Commercial use depends on API plan and terms | -| Alpha Vantage | More realistic commercial path through paid plans | -| Twelve Data | More realistic commercial path through paid plans | -| SerpApi / Google Finance | Better for search, enrichment or RAG context, not first market-data backbone | +FRED is not mainly a market-price API. -### Practical Decision +It should not replace Frankfurter or yfinance as the main historical price-data client. -For Sprint 2: +Instead, FRED is useful as a macroeconomic context source for ARGUS. -* Use Frankfurter first. +--- + +### Strengths -For later broader market analysis: +* Very relevant for macroeconomic analysis +* Strong fit for market context +* Useful for explaining why markets may move +* Provides historical economic time series +* Good for dashboards, reports and later signal context +* Can support more serious market analysis than pure price charts +* Used by trading/backtesting tools such as Lumibot for macro data context -* Add yfinance for learning and research. +--- -For possible commercial or serious paper-trading direction: +### Limitations -* Evaluate Alpha Vantage or Twelve Data later. +* Requires an API key +* Not a stock, ETF or FX price-data provider +* Some series may be owned by third parties +* Copyrighted series may require additional permission for non-personal or commercial use +* Commercial usage needs careful checking per data series +* Not ideal as the first replacement for the mock time-series client --- -## Recommended Decision +### Data Format and Response Structure -### First Client to Replace Mock Time-Series Data +FRED series data is usually requested by series ID. -Frankfurter +Example concept: -### Why +```text +GET /fred/series/observations?series_id=DGS10 +``` -* Free -* No API key -* Simple API -* Historical FX data -* Easy pandas transformation -* Perfect first real-data step -* Keeps Sprint 2 manageable -* Can replace mock time-series data directly -* May later replace the existing ExchangeRate API for FX use cases +Conceptual response shape: ---- +```json +{ + "observations": [ + { + "date": "2024-01-01", + "value": "3.95" + }, + { + "date": "2024-01-02", + "value": "4.01" + } + ] +} +``` -## Recommended Later Client +For ARGUS, this should be normalized into: -yfinance +| date | indicator | value | +|---|---|---:| +| 2024-01-01 | DGS10 | 3.95 | +| 2024-01-02 | DGS10 | 4.01 | -### Why +or more descriptive: -* Strong Python workflow -* Excellent pandas fit -* Good for stocks, ETFs and indices -* Better fit for broader market analysis -* Useful for signal and ML experiments -* Good bridge from FX analytics to normal-user market analysis +| date | source | category | indicator | value | +|---|---|---|---|---:| +| 2024-01-01 | FRED | interest_rate | DGS10 | 3.95 | +| 2024-01-02 | FRED | interest_rate | DGS10 | 4.01 | --- -## Not Recommended for First Implementation +### ARGUS Fit -SerpApi / Google Finance +FRED is a strong future addition for ARGUS. -### Why +It fits the broader goal better than a pure FX-trading direction because ARGUS should become a market analysis tool for normal users. -* Not the cleanest historical market-data source -* Search/scraping-style API -* Paid usage model -* Less suitable for the first analytics data backbone -* More useful later for enrichment, news, summaries or RAG context +Normal users are more likely to care about: ---- +* stocks +* ETFs +* indices +* inflation +* interest rates +* recession risk +* market environment +* basic portfolio context +* paper trading based on market conditions -## Suggested Client Structure +FRED can help ARGUS answer questions like: -```text -clients/ -├─ exchange_rate_client.py # existing live conversion client, legacy/fallback -├─ frankfurter_client.py # first real historical FX data client -├─ yahoo_finance_client.py # later broader market data client -└─ mock_time_series_client.py # deprecated after Frankfurter works -``` +* Are interest rates rising or falling? +* Is inflation cooling down? +* Is the yield curve inverted? +* Is the macro environment risky? +* Could market weakness be connected to macro conditions? + +This makes FRED valuable for analysis and reporting. --- -## Suggested Internal Data Format +### Commercial Usage Consideration -The analytics layer should not depend on a specific API response format. +FRED is useful, but it should not be treated as automatically commercial-safe for every dataset. -Every client should normalize data into a shared internal structure. +Important points: -### FX Time Series +* The FRED API requires an API key. +* Applications using the FRED API must display the required notice. +* The app must not imply endorsement by the Federal Reserve Bank of St. Louis. +* Some data series may belong to third parties. +* Copyrighted series may require permission from the original data owner for non-personal or commercial use. -```text -date | base | target | rate -``` +Practical conclusion: -### General Market Time Series +FRED is good for learning, research, dashboards and portfolio development. -```text -date | symbol | value -``` +For commercial usage, ARGUS would need to check the terms of the specific series used. -### Optional OHLC Market Data +--- -```text -date | symbol | open | high | low | close | volume -``` +## Data Source Portfolio -This keeps analytics reusable across different sources: +ARGUS should not rely on one data source for everything. -```text -Frankfurter -yfinance -Alpha Vantage -Twelve Data - ↓ -normalized DataFrame - ↓ -analytics metrics - ↓ -charts / dashboard -``` +A better structure is a small data-source portfolio. + +| Source | Role in ARGUS | Priority | +|---|---|---| +| Frankfurter | First real historical FX data client | Sprint 2 | +| yfinance | Broader market data for stocks, ETFs and indices | Later | +| FRED | Macro context and economic indicators | Later / Sprint 3 | +| Alpha Vantage | More formal market-data API option | Future | +| Twelve Data | More commercial-friendly market-data option | Future | +| ExchangeRate API | Existing live conversion client, legacy/fallback | Temporary | --- -## Final Recommendation +## Recommendation -Frankfurter should be selected as the first real data source for Sprint 2. +Frankfurter should still be selected as the first real data source for Sprint 2. -It should replace the mock time-series client first because it is simple, free, historical and directly useful for the current analytics metrics. +Reason: -The existing ExchangeRate API client should remain only as a temporary live conversion or fallback client. +* It directly replaces the mock time-series client. +* It provides clean historical exchange-rate data. +* It keeps the first analytics implementation manageable. +* It is simple, free and beginner-friendly. -yfinance should be added later as the broader market-analysis client when ARGUS moves beyond FX into stocks, ETFs and indices. +yfinance should be added later when ARGUS moves toward broader market analysis: -Alpha Vantage or Twelve Data should be researched later if ARGUS needs a more serious API provider for commercial, paper-trading or production-like workflows. +* stocks +* ETFs +* indices +* watchlists +* simple signals +* paper trading prototypes + +FRED should be added as a macro context client, not as the first historical price-data client. + +It becomes valuable when ARGUS starts connecting market movements with economic conditions. -This keeps ARGUS realistic: +--- + +## Final Portfolio Decision ```text Sprint 2: -real FX analytics with Frankfurter +Frankfurter +→ real historical FX data +→ replaces mock time-series data Later: -broader market analysis with yfinance +yfinance +→ broader market data +→ stocks, ETFs, indices, paper trading prototypes + +Later / Sprint 3: +FRED +→ macroeconomic context +→ inflation, rates, unemployment, GDP, yield curve Future: -commercial-friendly market data provider if needed -``` \ No newline at end of file +Alpha Vantage or Twelve Data +→ more serious market-data provider +→ better candidate for commercial or production-like use +``` + +This portfolio is stronger than using only yfinance or only Frankfurter. + +Frankfurter gives ARGUS a clean first real data source. + +yfinance gives ARGUS broader market coverage. + +FRED gives ARGUS macroeconomic intelligence. + +Alpha Vantage or Twelve Data can be evaluated later if ARGUS becomes more serious, commercial or production-oriented. From 35ea25382e65d2cdffd33ae34e7620dd50113ade Mon Sep 17 00:00:00 2001 From: Lev Gusiev Date: Wed, 17 Jun 2026 20:36:12 +0200 Subject: [PATCH 13/14] docs(#32): add alpaca to research --- docs/research-data-sources | 72 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/docs/research-data-sources b/docs/research-data-sources index 8d99f49..f1179de 100644 --- a/docs/research-data-sources +++ b/docs/research-data-sources @@ -502,6 +502,78 @@ This makes FRED valuable for analysis and reporting. --- +## Alpaca + +### What it is + +Alpaca is a developer-first trading and market data platform. + +It provides APIs for: + +* market data +* paper trading +* live trading +* stocks +* options +* crypto +* order execution +* account state +* portfolio activity + +This makes Alpaca different from Frankfurter or yfinance. + +Frankfurter and yfinance mainly provide data. + +Alpaca provides both: + +```text +market data ++ +broker / execution API +``` + +--- + +### Why Alpaca matters for ARGUS + +Alpaca is relevant if ARGUS eventually moves toward: + +* paper trading +* portfolio simulation +* strategy testing +* order execution +* real broker connection +* live account monitoring +* trading workflow automation + +This is closer to commercial or production-like usage than yfinance. + +--- + +### Alpaca Fit + +Alpaca should not be the first Sprint 2 data client. + +It is too much for the first real analytics step. + +However, it is very relevant later when ARGUS moves from: + +```text +market analysis +``` + +to: + +```text +market analysis ++ +paper trading ++ +strategy execution +``` + +--- + ### Commercial Usage Consideration FRED is useful, but it should not be treated as automatically commercial-safe for every dataset. From 08551d868fe59ca489178df03eca5bddb867cbe0 Mon Sep 17 00:00:00 2001 From: Lev Gusiev Date: Wed, 17 Jun 2026 21:16:58 +0200 Subject: [PATCH 14/14] docs(#32): edit research structure and add more sources --- docs/research-data-sources | 403 +++++++------------------------------ 1 file changed, 75 insertions(+), 328 deletions(-) diff --git a/docs/research-data-sources b/docs/research-data-sources index f1179de..3298d76 100644 --- a/docs/research-data-sources +++ b/docs/research-data-sources @@ -54,7 +54,8 @@ However, the long-term direction is broader market analysis: |---|---|---:|---:|---|---|---| | Frankfurter | Historical FX data | Free | No | Good | Better than unofficial sources, open-source/self-hostable | Very good first client | | yfinance | Broad market data for research | Free | No | Excellent | Limited / check Yahoo terms | Very good later client | -| ExchangeRate API | Live currency conversion | Free tier / paid tiers | Yes | Okay | Depends on plan | Legacy / live conversion only | +| ExchangeRate API | Live currency conversion | Free tier / paid tiers | Yes / depends on endpoint | Okay | Depends on plan and terms | Legacy / live conversion only | +| FRED API | Macroeconomic context data | Free | Yes | Good | Possible, but series-specific rights must be checked | Good later macro context client | | Alpha Vantage | Stocks, FX, crypto, indicators | Free tier + paid | Yes | Good | More API-like, paid plans available | Possible later | | Twelve Data | Stocks, FX, ETFs, crypto, indices | Free tier + paid | Yes | Good | More suitable for serious API usage | Possible later | @@ -87,7 +88,7 @@ It fits the original project stage: * Less useful once ARGUS moves toward market analytics * Adds less long-term value if Frankfurter covers FX better -### Role in ARGUS +### ARGUS Fit The ExchangeRate API should not be the strategic core client anymore. @@ -129,89 +130,7 @@ It provides current and historical exchange-rate data and does not require an AP * Does not cover stocks, ETFs or company fundamentals * Not enough for long-term stock or portfolio analysis alone -### Example Response Structure - -Conceptual response shape: - -```json -{ - "amount": 1.0, - "base": "EUR", - "start_date": "2024-01-01", - "end_date": "2024-01-31", - "rates": { - "2024-01-01": { - "USD": 1.10 - }, - "2024-01-02": { - "USD": 1.11 - } - } -} -``` - -## Internal Normalized Format - -For ARGUS analytics, API responses should be normalized into simple internal data formats. - -The analytics layer should not depend directly on the original API response structure. - -This makes it easier to switch or add data sources later. - ---- - -### FX Time Series Format - -Used for exchange-rate based analytics. - -| date | base | target | rate | -|---|---|---|---:| -| 2024-01-01 | EUR | USD | 1.10 | -| 2024-01-02 | EUR | USD | 1.11 | - -For single-pair analytics, this can be simplified to: - -| date | rate | -|---|---:| -| 2024-01-01 | 1.10 | -| 2024-01-02 | 1.11 | - ---- - -### General Market Time Series Format - -Used for broader market analysis such as stocks, ETFs, indices or other symbols. - -| date | symbol | value | -|---|---|---:| -| 2024-01-01 | AAPL | 185.64 | -| 2024-01-02 | AAPL | 184.25 | - -This format is useful when only one main price value is needed, usually the closing price. - ---- - -### Optional OHLC Market Data Format - -Used later if ARGUS needs more detailed market analysis. - -| date | symbol | open | high | low | close | volume | -|---|---|---:|---:|---:|---:|---:| -| 2024-01-01 | AAPL | 184.00 | 187.00 | 183.50 | 185.64 | 50200000 | -| 2024-01-02 | AAPL | 185.20 | 186.10 | 182.90 | 184.25 | 48100000 | - -This format is not required for the first Sprint 2 implementation, but it may become useful later for: - -* stock analysis -* ETF analysis -* paper trading -* signal generation -* backtesting -* more advanced chart types - ---- - -## ARGUS Fit +### ARGUS Fit Frankfurter is the best first real data client for Sprint 2. @@ -266,28 +185,6 @@ It is useful for stocks, ETFs, indices and some FX symbols. * Less predictable than a dedicated paid market-data API * Not ideal as the first serious commercial data backbone -### Example Usage Shape - -```python -import yfinance as yf - -data = yf.download("AAPL", start="2024-01-01", end="2024-02-01") -``` -Expected DataFrame-like structure: - -| Date | Open | High | Low | Close | Adj Close | Volume | -|---|---:|---:|---:|---:|---:|---:| - -For ARGUS analytics, the most important fields at the beginning are: - -| date | close | -|---|---:| - -or normalized: - -| date | symbol | value | -|---|---|---:| - ### ARGUS Fit yfinance is a very good later client. @@ -309,78 +206,6 @@ However, yfinance should not be the first mock-client replacement if the immedia --- -## Alpha Vantage - -### What it is - -Alpha Vantage is a financial data API for stocks, FX, crypto, commodities, indicators and more. - -### Strengths - -* Official API-style access -* Supports many market data types -* Has documentation for many endpoints -* More suitable than yfinance if the project later needs a more formal API provider -* Could support more serious long-term data workflows - -### Limitations - -* Requires API key -* Free tier is limited -* Request limits can become annoying for analytics workflows -* More setup than Frankfurter or yfinance -* Some advanced or real-time features require paid plans - -### ARGUS Fit - -Alpha Vantage is not recommended as the first Sprint 2 client. - -It is worth revisiting later if ARGUS needs: - -* more formal market-data API access -* indicators -* broader asset coverage -* a clearer path toward commercial or semi-commercial use - ---- - -## Twelve Data - -### What it is - -Twelve Data is a financial market data API covering stocks, forex, ETFs, indices, crypto and more. - -### Strengths - -* Broad market coverage -* API-first design -* Supports JSON and other formats -* Has SDK support -* Better long-term candidate than unofficial data sources -* More suitable for serious market-data workflows - -### Limitations - -* Requires API key -* Free tier limitations apply -* More platform dependency -* More setup than Frankfurter -* Probably too much for the first Sprint 2 step - -### ARGUS Fit - -Twelve Data is interesting for later. - -It may become relevant when ARGUS moves toward: - -* broader market analysis -* paper trading -* more reliable stock/ETF data -* possible commercial use -* serious dashboard or monitoring workflows - -It should not be the first implementation choice because Frankfurter is simpler for the current phase. - ## FRED API ### What it is @@ -404,8 +229,6 @@ It should not replace Frankfurter or yfinance as the main historical price-data Instead, FRED is useful as a macroeconomic context source for ARGUS. ---- - ### Strengths * Very relevant for macroeconomic analysis @@ -414,9 +237,6 @@ Instead, FRED is useful as a macroeconomic context source for ARGUS. * Provides historical economic time series * Good for dashboards, reports and later signal context * Can support more serious market analysis than pure price charts -* Used by trading/backtesting tools such as Lumibot for macro data context - ---- ### Limitations @@ -427,68 +247,11 @@ Instead, FRED is useful as a macroeconomic context source for ARGUS. * Commercial usage needs careful checking per data series * Not ideal as the first replacement for the mock time-series client ---- - -### Data Format and Response Structure - -FRED series data is usually requested by series ID. - -Example concept: - -```text -GET /fred/series/observations?series_id=DGS10 -``` - -Conceptual response shape: - -```json -{ - "observations": [ - { - "date": "2024-01-01", - "value": "3.95" - }, - { - "date": "2024-01-02", - "value": "4.01" - } - ] -} -``` - -For ARGUS, this should be normalized into: - -| date | indicator | value | -|---|---|---:| -| 2024-01-01 | DGS10 | 3.95 | -| 2024-01-02 | DGS10 | 4.01 | - -or more descriptive: - -| date | source | category | indicator | value | -|---|---|---|---|---:| -| 2024-01-01 | FRED | interest_rate | DGS10 | 3.95 | -| 2024-01-02 | FRED | interest_rate | DGS10 | 4.01 | - ---- - ### ARGUS Fit FRED is a strong future addition for ARGUS. -It fits the broader goal better than a pure FX-trading direction because ARGUS should become a market analysis tool for normal users. - -Normal users are more likely to care about: - -* stocks -* ETFs -* indices -* inflation -* interest rates -* recession risk -* market environment -* basic portfolio context -* paper trading based on market conditions +It becomes valuable when ARGUS starts connecting market movements with economic conditions. FRED can help ARGUS answer questions like: @@ -498,120 +261,102 @@ FRED can help ARGUS answer questions like: * Is the macro environment risky? * Could market weakness be connected to macro conditions? -This makes FRED valuable for analysis and reporting. +This makes FRED useful for analysis and reporting, but not as the first Sprint 2 data client. --- -## Alpaca +## Alpha Vantage ### What it is -Alpaca is a developer-first trading and market data platform. - -It provides APIs for: - -* market data -* paper trading -* live trading -* stocks -* options -* crypto -* order execution -* account state -* portfolio activity - -This makes Alpaca different from Frankfurter or yfinance. +Alpha Vantage is a financial data API for stocks, FX, crypto, commodities, indicators and more. -Frankfurter and yfinance mainly provide data. +### Strengths -Alpaca provides both: +* Official API-style access +* Supports many market data types +* Has documentation for many endpoints +* More suitable than yfinance if the project later needs a more formal API provider +* Could support more serious long-term data workflows -```text -market data -+ -broker / execution API -``` +### Limitations ---- +* Requires API key +* Free tier is limited +* Request limits can become annoying for analytics workflows +* More setup than Frankfurter or yfinance +* Some advanced or real-time features require paid plans -### Why Alpaca matters for ARGUS +### ARGUS Fit -Alpaca is relevant if ARGUS eventually moves toward: +Alpha Vantage is not recommended as the first Sprint 2 client. -* paper trading -* portfolio simulation -* strategy testing -* order execution -* real broker connection -* live account monitoring -* trading workflow automation +It is worth revisiting later if ARGUS needs: -This is closer to commercial or production-like usage than yfinance. +* more formal market-data API access +* indicators +* broader asset coverage +* a clearer path toward commercial or semi-commercial use --- -### Alpaca Fit - -Alpaca should not be the first Sprint 2 data client. - -It is too much for the first real analytics step. - -However, it is very relevant later when ARGUS moves from: +## Twelve Data -```text -market analysis -``` +### What it is -to: +Twelve Data is a financial market data API covering stocks, forex, ETFs, indices, crypto and more. -```text -market analysis -+ -paper trading -+ -strategy execution -``` +### Strengths ---- +* Broad market coverage +* API-first design +* Supports JSON and other formats +* Has SDK support +* Better long-term candidate than unofficial data sources +* More suitable for serious market-data workflows -### Commercial Usage Consideration +### Limitations -FRED is useful, but it should not be treated as automatically commercial-safe for every dataset. +* Requires API key +* Free tier limitations apply +* More platform dependency +* More setup than Frankfurter +* Probably too much for the first Sprint 2 step -Important points: +### ARGUS Fit -* The FRED API requires an API key. -* Applications using the FRED API must display the required notice. -* The app must not imply endorsement by the Federal Reserve Bank of St. Louis. -* Some data series may belong to third parties. -* Copyrighted series may require permission from the original data owner for non-personal or commercial use. +Twelve Data is interesting for later. -Practical conclusion: +It may become relevant when ARGUS moves toward: -FRED is good for learning, research, dashboards and portfolio development. +* broader market analysis +* paper trading +* more reliable stock/ETF data +* possible commercial use +* serious dashboard or monitoring workflows -For commercial usage, ARGUS would need to check the terms of the specific series used. +It should not be the first implementation choice because Frankfurter is simpler for the current phase. --- -## Data Source Portfolio +## Commercial Usage Consideration -ARGUS should not rely on one data source for everything. +ARGUS should avoid locking itself into data sources that are only useful for experiments if the project may later become more serious. -A better structure is a small data-source portfolio. +Current interpretation: -| Source | Role in ARGUS | Priority | -|---|---|---| -| Frankfurter | First real historical FX data client | Sprint 2 | -| yfinance | Broader market data for stocks, ETFs and indices | Later | -| FRED | Macro context and economic indicators | Later / Sprint 3 | -| Alpha Vantage | More formal market-data API option | Future | -| Twelve Data | More commercial-friendly market-data option | Future | -| ExchangeRate API | Existing live conversion client, legacy/fallback | Temporary | +| Source | Commercial Direction | +|---|---| +| Frankfurter | Best first choice; open-source/self-hostable, but source and data terms should still be checked before commercial use | +| yfinance | Great for learning and research, but not ideal for commercial use without checking Yahoo terms | +| ExchangeRate API | Commercial use depends on API plan and terms | +| FRED API | Useful for macro context, but series-specific rights must be checked | +| Alpha Vantage | More realistic commercial path through paid plans | +| Twelve Data | More realistic commercial path through paid plans | --- -## Recommendation +## Final Portfolio Decision Frankfurter should still be selected as the first real data source for Sprint 2. @@ -635,9 +380,7 @@ FRED should be added as a macro context client, not as the first historical pric It becomes valuable when ARGUS starts connecting market movements with economic conditions. ---- - -## Final Portfolio Decision +Alpha Vantage or Twelve Data should be evaluated later if ARGUS needs a more serious or commercial-friendly market-data provider. ```text Sprint 2: @@ -650,7 +393,6 @@ yfinance → broader market data → stocks, ETFs, indices, paper trading prototypes -Later / Sprint 3: FRED → macroeconomic context → inflation, rates, unemployment, GDP, yield curve @@ -661,12 +403,17 @@ Alpha Vantage or Twelve Data → better candidate for commercial or production-like use ``` -This portfolio is stronger than using only yfinance or only Frankfurter. +--- + +## Out of Scope for This Ticket -Frankfurter gives ARGUS a clean first real data source. +This research focuses on data sources for analytics. -yfinance gives ARGUS broader market coverage. +The following topics should be handled in later research tickets: -FRED gives ARGUS macroeconomic intelligence. +| Topic | Reason | +|---|---| +| Alpaca | Broker, paper trading and execution API; relevant later, but not first data-source replacement | +| CCXT exchanges | Crypto exchange connector layer; useful later for crypto workflows | +| Broker integrations | Belong to paper trading / execution research | -Alpha Vantage or Twelve Data can be evaluated later if ARGUS becomes more serious, commercial or production-oriented.