diff --git a/src/cli.py b/src/cli.py index 408aa6a..d76d42c 100755 --- a/src/cli.py +++ b/src/cli.py @@ -12,6 +12,7 @@ import data_fetcher import database import rate_finder import rate_reporter +import rate_stats import holidays # Global debug flag @@ -35,6 +36,7 @@ def check_and_update_yearly_data(): holidays.set_debug_mode(DEBUG) rate_finder.set_debug_mode(DEBUG) rate_reporter.set_debug_mode(DEBUG) + rate_stats.set_debug_mode(DEBUG) # Zkontrolujeme konzistenci dat is_consistent = data_fetcher.check_yearly_data_consistency(current_year, output_dir="data") @@ -63,7 +65,7 @@ def main(): parser.add_argument( "-c", "--currency", type=str, - help="Kód měny (např. USD) pro měsíční stahování, vyhledání kurzu nebo generování reportu." + help="Kód měny (např. USD) pro měsíční stahování, vyhledání kurzu, generování reportu nebo statistik." ) parser.add_argument( "--start-date", @@ -106,6 +108,11 @@ def main(): metavar=('START_DATE', 'END_DATE'), help="Období, pro které se má vygenerovat report kurzů. Formát: DD.MM.YYYY DD.MM.YYYY" ) + parser.add_argument( + "--stats", + type=int, + help="Vygeneruje statistiky pro zadaný rok. Formát: ROK" + ) parser.add_argument( "--debug", action="store_true", @@ -123,13 +130,14 @@ def main(): holidays.set_debug_mode(DEBUG) rate_finder.set_debug_mode(DEBUG) rate_reporter.set_debug_mode(DEBUG) + rate_stats.set_debug_mode(DEBUG) # Kontrola a případná aktualizace ročních dat pro aktuální rok (pouze v debug módu) if DEBUG: check_and_update_yearly_data() else: # V normálním módu zkontrolujeme pouze při stahování dat - if args.year or args.start_date or args.date or args.get_rate or args.report_year or args.report_period: + if args.year or args.start_date or args.date or args.get_rate or args.report_year or args.report_period or args.stats: current_year = datetime.now().year # Pro jednoduchost v normálním módu nebudeme kontrolovat konzistenci automaticky pass @@ -228,6 +236,12 @@ def main(): start_date, end_date = args.report_period debug_print(f"Generuji report pro {args.currency} za období {start_date} - {end_date}...") rate_reporter.generate_period_report(start_date, end_date, args.currency, output_dir="data") + elif args.stats and args.currency: + # Generování statistik + year = args.stats + debug_print(f"Generuji statistiky pro {args.currency} za rok {year}...") + stats = rate_stats.generate_yearly_stats(year, args.currency, output_dir="data") + rate_stats.print_stats(stats) else: if DEBUG: parser.print_help() diff --git a/src/rate_stats.py b/src/rate_stats.py new file mode 100644 index 0000000..ab85856 --- /dev/null +++ b/src/rate_stats.py @@ -0,0 +1,211 @@ +import sys +import os +from datetime import datetime, timedelta +import calendar + +# Přidání adresáře src do sys.path, aby bylo možné importovat moduly +sys.path.insert(0, os.path.join(os.path.dirname(__file__))) + +import database +import data_fetcher +import holidays + +# Global debug flag +DEBUG = False + +def debug_print(*args, **kwargs): + """Print debug messages only if debug mode is enabled.""" + if DEBUG: + print(*args, **kwargs) + +def set_debug_mode(debug): + """Set the debug mode for this module.""" + global DEBUG + DEBUG = debug + +def get_working_days_in_month(year, month): + """ + Vrátí seznam pracovních dní v daném měsíci. + + :param year: Rok + :param month: Měsíc (1-12) + :return: Seznam pracovních dnů ve formátu DD.MM.YYYY + """ + working_days = [] + + # Poslední den měsíce + last_day = calendar.monthrange(year, month)[1] + + for day in range(1, last_day + 1): + date_str = f"{day:02d}.{month:02d}.{year}" + # Zkontrolujeme, zda je to pracovní den (není víkend ani svátek) + if not holidays.is_weekend(date_str) and not holidays.is_holiday(date_str): + working_days.append(date_str) + + return working_days + +def get_working_days_in_quarter(year, quarter): + """ + Vrátí seznam pracovních dní ve čtvrtletí. + + :param year: Rok + :param quarter: Čtvrtletí (1-4) + :return: Seznam pracovních dnů ve formátu DD.MM.YYYY + """ + working_days = [] + + # Určíme měsíce v čtvrtletí + start_month = (quarter - 1) * 3 + 1 + end_month = start_month + 2 + + for month in range(start_month, end_month + 1): + working_days.extend(get_working_days_in_month(year, month)) + + return working_days + +def get_working_days_in_year(year): + """ + Vrátí seznam pracovních dní v roce. + + :param year: Rok + :return: Seznam pracovních dnů ve formátu DD.MM.YYYY + """ + working_days = [] + + for month in range(1, 13): + working_days.extend(get_working_days_in_month(year, month)) + + return working_days + +def calculate_average_rate_for_dates(dates, currency_code): + """ + Vypočítá průměrný kurz pro zadané datumy. + + :param dates: Seznam datumů ve formátu DD.MM.YYYY + :param currency_code: Kód měny (např. USD) + :return: Průměrný kurz nebo None pokud nejsou k dispozici žádné kurzy + """ + if not dates: + return None + + rates = [] + for date in dates: + rate = database.get_rate(date, currency_code) + if rate is not None: + rates.append(rate) + + if not rates: + return None + + return sum(rates) / len(rates) + +def generate_yearly_stats(year, currency_code, output_dir="data"): + """ + Vygeneruje statistiky pro zadaný rok a měnu. + + :param year: Rok + :param currency_code: Kód měny (např. USD) + :param output_dir: Adresář pro ukládání dat + :return: Slovník se statistikami + """ + debug_print(f"Generuji statistiky pro {currency_code} za rok {year}...") + + # Zkontrolujeme, zda databáze obsahuje data pro daný rok + debug_print(f"Stahuji roční data pro rok {year}...") + os.makedirs("data", exist_ok=True) + data_fetcher.download_yearly_data(year, output_dir="data", force=False) + + # Získáme pracovní dny v roce + working_days = get_working_days_in_year(year) + debug_print(f"Počet pracovních dní v roce {year}: {len(working_days)}") + + # Vypočítáme průměrný kurz pro celý rok + yearly_avg = calculate_average_rate_for_dates(working_days, currency_code) + + # Vypočítáme průměrné kurzy pro jednotlivé měsíce + monthly_stats = {} + for month in range(1, 13): + month_working_days = get_working_days_in_month(year, month) + if month_working_days: + month_avg = calculate_average_rate_for_dates(month_working_days, currency_code) + monthly_stats[month] = { + 'average': month_avg, + 'working_days_count': len(month_working_days) + } + + # Vypočítáme průměrné kurzy pro čtvrtletí + quarterly_stats = {} + for quarter in range(1, 5): + quarter_working_days = get_working_days_in_quarter(year, quarter) + if quarter_working_days: + quarter_avg = calculate_average_rate_for_dates(quarter_working_days, currency_code) + quarterly_stats[quarter] = { + 'average': quarter_avg, + 'working_days_count': len(quarter_working_days) + } + + return { + 'year': year, + 'currency': currency_code, + 'yearly_average': yearly_avg, + 'monthly_stats': monthly_stats, + 'quarterly_stats': quarterly_stats, + 'total_working_days': len(working_days) + } + +def print_stats(stats): + """ + Vytiskne statistiky ve formátované podobě. + + :param stats: Slovník se statistikami + """ + year = stats['year'] + currency = stats['currency'] + + print(f"\nStatistiky pro {currency} za rok {year}:") + print("=" * 50) + + if stats['yearly_average']: + print(f"Roční průměr: {stats['yearly_average']:.3f}") + else: + print("Roční průměr: N/A") + + print(f"Celkový počet pracovních dní: {stats['total_working_days']}") + + print("\nPrůměry podle čtvrtletí:") + print("-" * 30) + for quarter in range(1, 5): + if quarter in stats['quarterly_stats']: + q_stats = stats['quarterly_stats'][quarter] + if q_stats['average']: + print(f" Q{quarter}: {q_stats['average']:.3f} ({q_stats['working_days_count']} pracovních dní)") + else: + print(f" Q{quarter}: N/A ({q_stats['working_days_count']} pracovních dní)") + else: + print(f" Q{quarter}: N/A") + + print("\nPrůměry podle měsíců:") + print("-" * 30) + czech_months = [ + "", "Leden", "Únor", "Březen", "Duben", "Květen", "Červen", + "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec" + ] + + for month in range(1, 13): + if month in stats['monthly_stats']: + m_stats = stats['monthly_stats'][month] + if m_stats['average']: + print(f" {czech_months[month]}: {m_stats['average']:.3f} ({m_stats['working_days_count']} pracovních dní)") + else: + print(f" {czech_months[month]}: N/A ({m_stats['working_days_count']} pracovních dní)") + else: + print(f" {czech_months[month]}: N/A") + +# Příklad použití +if __name__ == "__main__": + # Inicializace databáze (pro případ spuštění samostatně) + database.init_db() + + # Test + # stats = generate_yearly_stats(2020, "USD") + # print_stats(stats) \ No newline at end of file