feat: Add comprehensive trading days validation and record count analysis

- Add trading days validation to check expected vs actual data points per year
- Implement calculate_expected_trading_days() accounting for weekends and Czech holidays
- Add validate_trading_days_count() with discrepancy analysis and severity classification
- Integrate trading days validation into main validation workflow
- Add record count analysis by time periods (week, month, quarter, half year, year)
- Implement get_record_counts_by_period() with detailed breakdowns
- Add --record-counts CLI command for standalone period analysis
- Enhance format_validation_text() to display trading days and record count information
- Update data quality scoring to include trading days compliance
- Add comprehensive JSON output support for all new validation features

Trading Days Validation:
- Calculates expected trading days excluding weekends and Czech holidays
- Compares actual data points against expected counts
- Provides discrepancy analysis with severity levels (ok, minor, moderate, severe)
- Shows data completeness percentage

Record Count Analysis:
- Breaks down data by multiple time periods simultaneously
- Supports week-by-week, monthly, quarterly, half-yearly, and yearly counts
- Handles leap years and varying month lengths correctly
- Provides both summary and detailed views

Integration Features:
- Seamlessly integrated with existing price change and gap validation
- Enhanced data quality scoring considers all validation aspects
- Comprehensive JSON schema for programmatic consumption
- Backward compatible with existing validation commands

Usage Examples:
  python src/cli.py --validate --currency USD --year 2025  # Shows all validations
  python src/cli.py --record-counts --currency USD --year 2025  # Period breakdown only
  python src/cli.py --validate --currency EUR --json  # Full validation in JSON

Quality Assurance:
-  Pyright type checking: 0 errors, 0 warnings
-  Syntax validation: No compilation errors
-  Functional testing: All features working correctly
-  Czech holiday integration: Proper weekend/holiday exclusion
-  Leap year handling: Correctly accounts for 366-day years
This commit is contained in:
kdusek
2026-01-12 23:19:33 +01:00
parent 65a1485ff9
commit 7ce88e6e4a
2 changed files with 328 additions and 1 deletions

View File

@@ -202,6 +202,11 @@ def main():
action="store_true",
help="Validuje data pro měnu nebo všechny měny. Zkontroluje konzistenci kurzů a detekuje možné chyby.",
)
parser.add_argument(
"--record-counts",
action="store_true",
help="Zobrazí počet záznamů podle časových období (týden, měsíc, čtvrtletí, pololetí, rok).",
)
parser.add_argument(
"--change-threshold",
type=float,
@@ -289,6 +294,67 @@ def main():
else:
text_output = data_validator.format_validation_text(results)
print(text_output)
elif args.record_counts:
# Record counts command
if not args.currency:
print(
"Chyba: Pro --record-counts je nutné zadat měnu pomocí -c/--currency."
)
sys.exit(1)
debug_print(f"Získávám počty záznamů pro měnu {args.currency}...")
record_counts = data_validator.get_record_counts_by_period(
args.currency, args.year
)
if args.json:
output_json({"currency": args.currency, "record_counts": record_counts})
else:
print(f"Record Counts for {args.currency}:")
print("=" * 50)
for year_key, periods in record_counts.items():
print(f"\nYear {year_key}:")
print(f" Total records: {periods.get('year', 0)}")
# Half years
half_years = periods.get("half_year", {})
if half_years:
print(
f" Half years: H1={half_years.get('H1', 0)}, H2={half_years.get('H2', 0)}"
)
# Quarters
quarters = periods.get("quarter", {})
if quarters:
quarter_str = ", ".join(
[f"Q{q}={quarters.get(f'Q{q}', 0)}" for q in range(1, 5)]
)
print(f" Quarters: {quarter_str}")
# Months
months = periods.get("month", {})
if months:
month_list = []
for month in range(1, 13):
month_key = f"{month:02d}"
count = months.get(month_key, 0)
month_list.append(f"{month}={count}")
print(f" Months: {', '.join(month_list)}")
# Weeks summary
weeks = periods.get("week", {})
if weeks:
total_weeks = len(weeks)
if total_weeks <= 10:
week_list = sorted([f"{w}={weeks[w]}" for w in weeks.keys()])
print(f" Weeks: {', '.join(week_list)}")
else:
sample_weeks = sorted(list(weeks.keys())[:5])
week_sample = [f"{w}={weeks[w]}" for w in sample_weeks]
print(
f" Weeks: {', '.join(week_sample)}... ({total_weeks} total weeks)"
)
elif args.year:
# Validation command
base_threshold = args.change_threshold