#![allow( clippy::assertions_on_constants, clippy::assertions_on_result_states, clippy::clone_on_copy, clippy::decimal_literal_representation, clippy::doc_markdown, clippy::empty_line_after_doc_comments, clippy::field_reassign_with_default, clippy::get_unwrap, clippy::identity_op, clippy::inconsistent_digit_grouping, clippy::indexing_slicing, clippy::integer_division, clippy::len_zero, clippy::let_underscore_must_use, clippy::manual_div_ceil, clippy::manual_let_else, clippy::manual_range_contains, clippy::modulo_arithmetic, clippy::needless_range_loop, clippy::non_ascii_literal, clippy::redundant_clone, clippy::shadow_reuse, clippy::shadow_same, clippy::shadow_unrelated, clippy::single_match_else, clippy::str_to_string, clippy::string_slice, clippy::tests_outside_test_module, clippy::too_many_lines, clippy::unnecessary_wraps, clippy::unseparated_literal_suffix, clippy::use_debug, clippy::useless_vec, clippy::wildcard_enum_match_arm, clippy::else_if_without_else, clippy::expect_used, clippy::missing_const_for_fn, clippy::similar_names, clippy::type_complexity, clippy::collapsible_else_if, clippy::doc_lazy_continuation, clippy::items_after_test_module, clippy::map_clone, clippy::multiple_unsafe_ops_per_block, clippy::unwrap_or_default, clippy::assign_op_pattern, clippy::needless_borrow, clippy::println_empty_string, clippy::unnecessary_cast, clippy::used_underscore_binding, clippy::create_dir, clippy::implicit_saturating_sub, clippy::exit, clippy::expect_fun_call, clippy::too_many_arguments, clippy::unnecessary_map_or, clippy::unwrap_used, dead_code, unused_imports, unused_variables, clippy::cloned_ref_to_slice_refs, clippy::neg_multiply, clippy::while_let_loop, clippy::bool_assert_comparison, clippy::excessive_precision, clippy::trivially_copy_pass_by_ref, clippy::op_ref, clippy::redundant_closure, clippy::unnecessary_lazy_evaluations, clippy::if_then_some_else_none, clippy::unnecessary_to_owned, clippy::single_component_path_imports, )] //! Test Suite: DQN Hyperparameters Kelly Fields Validation //! //! Purpose: Verify that DQNHyperparameters struct has all 4 Kelly sizing fields //! and that they are correctly configured with sensible defaults. //! //! This test validates WAVE 19 Agent 2's requirement that Kelly parameters //! are properly integrated into the hyperparameters struct. #[cfg(test)] mod dqn_hyperparams_kelly_tests { use ml::trainers::dqn::DQNHyperparameters; #[test] fn test_hyperparams_has_kelly_fractional() { let hyperparams = DQNHyperparameters::conservative(); // Should compile if field exists let _kelly = hyperparams.kelly_fractional; // Verify it's accessible assert!(hyperparams.kelly_fractional > 0.0); } #[test] fn test_hyperparams_has_kelly_max_fraction() { let hyperparams = DQNHyperparameters::conservative(); let _kelly_max = hyperparams.kelly_max_fraction; // Verify it's accessible assert!(hyperparams.kelly_max_fraction > 0.0); } #[test] fn test_hyperparams_has_kelly_min_trades() { let hyperparams = DQNHyperparameters::conservative(); let _min_trades = hyperparams.kelly_min_trades; // Verify it's accessible assert!(hyperparams.kelly_min_trades > 0); } #[test] fn test_hyperparams_has_volatility_window() { let hyperparams = DQNHyperparameters::conservative(); let _vol_window = hyperparams.volatility_window; // Verify it's accessible assert!(hyperparams.volatility_window > 0); } #[test] fn test_custom_kelly_params_can_be_set() { let mut hyperparams = DQNHyperparameters::conservative(); // Set custom values hyperparams.kelly_fractional = 0.75; hyperparams.kelly_max_fraction = 0.4; hyperparams.kelly_min_trades = 35; hyperparams.volatility_window = 25; // Verify they were set correctly assert_eq!(hyperparams.kelly_fractional, 0.75); assert_eq!(hyperparams.kelly_max_fraction, 0.4); assert_eq!(hyperparams.kelly_min_trades, 35); assert_eq!(hyperparams.volatility_window, 25); } #[test] fn test_default_kelly_params_are_reasonable() { let hyperparams = DQNHyperparameters::conservative(); // Check defaults are within hyperopt bounds (from Agent 1 specification) // kelly_fractional: [0.25, 1.0] assert!(hyperparams.kelly_fractional >= 0.25 && hyperparams.kelly_fractional <= 1.0, "Default kelly_fractional ({}) should be in [0.25, 1.0]", hyperparams.kelly_fractional); // kelly_max_fraction: [0.1, 0.5] assert!(hyperparams.kelly_max_fraction >= 0.1 && hyperparams.kelly_max_fraction <= 0.5, "Default kelly_max_fraction ({}) should be in [0.1, 0.5]", hyperparams.kelly_max_fraction); // kelly_min_trades: [10, 50] assert!(hyperparams.kelly_min_trades >= 10 && hyperparams.kelly_min_trades <= 50, "Default kelly_min_trades ({}) should be in [10, 50]", hyperparams.kelly_min_trades); // volatility_window: [10, 30] assert!(hyperparams.volatility_window >= 10 && hyperparams.volatility_window <= 30, "Default volatility_window ({}) should be in [10, 30]", hyperparams.volatility_window); } #[test] fn test_kelly_fields_are_public() { // This test verifies that all Kelly fields are pub (accessible to hyperopt adapter) let hyperparams = DQNHyperparameters::conservative(); // If these compile, the fields are public let _: f64 = hyperparams.kelly_fractional; let _: f64 = hyperparams.kelly_max_fraction; let _: usize = hyperparams.kelly_min_trades; let _: usize = hyperparams.volatility_window; } #[test] fn test_expected_default_values() { let hyperparams = DQNHyperparameters::conservative(); // From trainer code (lines 629-632): // kelly_fractional: 0.5 (half-Kelly, conservative) // kelly_max_fraction: 0.25 (max 25% of portfolio) // kelly_min_trades: 20 (20 trades minimum) // volatility_window: 20 (20-period rolling window) assert_eq!(hyperparams.kelly_fractional, 0.5, "Expected default kelly_fractional=0.5 (half-Kelly)"); assert_eq!(hyperparams.kelly_max_fraction, 0.25, "Expected default kelly_max_fraction=0.25 (25% max)"); assert_eq!(hyperparams.kelly_min_trades, 20, "Expected default kelly_min_trades=20"); assert_eq!(hyperparams.volatility_window, 20, "Expected default volatility_window=20"); } }