Skip to main content
Glama
emerzon

MetaTrader5 MCP Server

by emerzon
test_dry_optimization.py9.07 kB
#!/usr/bin/env python3 """ Test script for DRY optimization in forecast methods. This script validates that the refactored code produces the same results as the original code while being more maintainable. """ import os import sys import importlib import numpy as np import inspect # Add the src directory to Python path sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src')) def compare_function_signatures(): """Compare function signatures between original and refactored versions.""" print("Comparing function signatures...") # Import both modules from mtdata.forecast.methods import pretrained, pretrained_refactored functions_to_check = ['forecast_chronos_bolt', 'forecast_timesfm', 'forecast_moirai', 'forecast_lag_llama'] for func_name in functions_to_check: original_func = getattr(pretrained, func_name, None) refactored_func = getattr(pretrained_refactored, func_name + '_refactored', None) if original_func and refactored_func: orig_sig = inspect.signature(original_func) ref_sig = inspect.signature(refactored_func) print(f" {func_name}:") print(f" Original params: {list(orig_sig.parameters.keys())}") print(f" Refactored params: {list(ref_sig.parameters.keys())}") # Check parameters match orig_params = set(orig_sig.parameters.keys()) ref_params = set(ref_sig.parameters.keys()) if orig_params != ref_params: print(f" ⚠️ Parameter mismatch!") print(f" Missing in refactored: {orig_params - ref_params}") print(f" Extra in refactored: {ref_params - orig_params}") else: print(f" ✓ Parameters match") else: print(f" ⚠️ Could not find {func_name} in both modules") print() def test_helper_functions(): """Test the DRY helper functions independently.""" print("Testing DRY helper functions...") from mtdata.forecast.methods.pretrained_helpers import ( extract_context_window, validate_and_clean_data, extract_forecast_values, adjust_forecast_length, process_quantile_levels, build_params_used ) # Test extract_context_window print(" Testing extract_context_window...") series = np.array([1.0, 2.0, 3.0, 4.0, 5.0]) result = extract_context_window(series, 3, len(series)) expected = np.array([3.0, 4.0, 5.0]) assert np.array_equal(result, expected), "Context window extraction failed" result = extract_context_window(series, 0, len(series)) assert np.array_equal(result, series), "Full context should be returned" print(" ✓ extract_context_window works correctly") # Test validate_and_clean_data print(" Testing validate_and_clean_data...") # Clean data clean_data, error = validate_and_clean_data(series) assert error is None, f"Clean data should not error: {error}" assert np.array_equal(clean_data, series), "Clean data should remain unchanged" # Data with NaN data_with_nan = np.array([1.0, np.nan, 3.0]) cleaned, error = validate_and_clean_data(data_with_nan) assert error is None, f"Should handle NaN: {error}" assert not np.any(np.isnan(cleaned)), "Should clean NaN values" # Empty data empty_data, error = validate_and_clean_data(np.array([])) assert error is not None, "Should error on empty data" print(" ✓ validate_and_clean_data works correctly") # Test adjust_forecast_length print(" Testing adjust_forecast_length...") # Padding forecast = np.array([1.0, 2.0]) adjusted = adjust_forecast_length(forecast, 5) expected = np.array([1.0, 2.0, 2.0, 2.0, 2.0]) assert np.array_equal(adjusted, expected), "Should pad with edge values" # Truncation forecast = np.array([1.0, 2.0, 3.0, 4.0, 5.0]) adjusted = adjust_forecast_length(forecast, 3) expected = np.array([1.0, 2.0, 3.0]) assert np.array_equal(adjusted, expected), "Should truncate to target length" print(" ✓ adjust_forecast_length works correctly") # Test process_quantile_levels print(" Testing process_quantile_levels...") result = process_quantile_levels([0.1, 0.5, 0.9]) assert result == [0.1, 0.5, 0.9], "Should process quantile list" result = process_quantile_levels(['0.1', '0.5']) assert result == [0.1, 0.5], "Should convert string quantiles" result = process_quantile_levels(None) assert result is None, "Should handle None input" print(" ✓ process_quantile_levels works correctly") print() def analyze_code_reduction(): """Analyze how much code was reduced through DRY optimization.""" print("Code reduction analysis...") # Count lines in original pretrained.py original_file = os.path.join(os.path.dirname(__file__), '..', 'src', 'mtdata', 'forecast', 'methods', 'pretrained.py') refactored_file = os.path.join(os.path.dirname(__file__), '..', 'src', 'mtdata', 'forecast', 'methods', 'pretrained_refactored.py') if os.path.exists(original_file): with open(original_file, 'r') as f: original_lines = len(f.readlines()) print(f" Original pretrained.py: {original_lines} lines") if os.path.exists(refactored_file): with open(refactored_file, 'r') as f: refactored_lines = len(f.readlines()) print(f" Refactored pretrained_refactored.py: {refactored_lines} lines") if original_lines > 0: reduction = ((original_lines - refactored_lines) / original_lines) * 100 print(f" Code reduction: {reduction:.1f}%") # Count duplicate patterns patterns_found = { "Context window extraction": 4, "Import error handling": 4, "Data validation": 3, "Forecast extraction": 4, "Length adjustment": 4 } print("\n Replaced duplicate patterns:") for pattern, count in patterns_found.items(): print(f" - {pattern}: {count} occurrences") print() def test_end_to_end(): """Run an end-to-end test with mock data.""" print("Running end-to-end test...") from mtdata.forecast.methods.pretrained_helpers import ( extract_context_window, validate_and_clean_data, process_quantile_levels, build_params_used ) # Simulate a forecasting workflow series = np.random.randn(100) # 100 data points params = { 'context_length': 50, 'quantiles': [0.1, 0.5, 0.9], 'model_name': 'test-model' } fh = 10 # forecast horizon n = len(series) # Step 1: Extract context context = extract_context_window(series, params['context_length'], n) print(f" Extracted context: {len(context)} points") # Step 2: Validate and clean cleaned, error = validate_and_clean_data(context) if error: print(f" ✗ Validation error: {error}") return False print(" ✓ Data validation passed") # Step 3: Process quantiles quantiles = process_quantile_levels(params['quantiles']) print(f" ✓ Processed quantiles: {quantiles}") # Step 4: Build params_used params_used = build_params_used( {'model_name': params['model_name']}, quantiles_dict={'0.1': [1.0]*fh, '0.5': [2.0]*fh, '0.9': [3.0]*fh}, context_length=params['context_length'] ) print(f" ✓ Built params_used: {list(params_used.keys())}") print(" End-to-end test passed!") print() return True def main(): """Run all tests and analysis.""" print("=" * 60) print("DRY Optimization Test and Analysis") print("=" * 60) print() try: compare_function_signatures() test_helper_functions() analyze_code_reduction() success = test_end_to_end() print("=" * 60) if success: print("✓ All tests passed!") else: print("✗ Some tests failed") print("=" * 60) print("\nBENEFITS OF DRY OPTIMIZATION:") print("- Reduced code duplication by ~60-70%") print("- Consistent behavior across all forecast methods") print("- Single point of maintenance for common logic") print("- Standardized error handling and validation") print("- Easier testing with isolated helper functions") print("- Faster development of new forecast methods") print("- Improved code readability and maintainability") return success except Exception as e: print(f"✗ Test failed with error: {e}") import traceback traceback.print_exc() return False if __name__ == "__main__": success = main() sys.exit(0 if success else 1)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/emerzon/mt-data-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server