Files
foxhunt/ml/tests/ppo_transaction_costs_tests.rs
jgrusewski c645e6222d Wave 11: Rainbow DQN integration + 23/23 tests passing
CRITICAL FINDINGS from 3-trial validation:
- 85,120 gradient clipping warnings (81.6% of logs) - REGRESSION
- Rainbow features DISABLED: use_dueling=false, use_distributional=false, use_noisy_nets=false
- Negative Q-values confirmed: HOLD -1000 to -3250
- Performance: Sharpe 0.29 (target 0.77)

Changes:
- Fixed N-Step compilation (7/7 tests passing)
- Fixed Distributional compilation (6/6 tests passing)
- Fixed Dueling CUDA errors (10/10 tests passing)
- Added TDD validation for state_dim=225
- Total: 23/23 Wave 11 tests passing (100%)

Issues requiring investigation:
1. Why are Dueling/Distributional/Noisy disabled in hyperopt?
2. Why gradient explosion despite previous fixes?
3. Test coverage gaps - unit tests pass but integration fails

🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 13:53:59 +01:00

89 lines
3.4 KiB
Rust

//! Transaction Cost Tests for PPO
//!
//! Test-driven development (TDD) - Tests written FIRST before implementation.
//! These tests verify that PPO transaction cost calculations match DQN behavior.
use ml::ppo::transaction_costs::{calculate_transaction_cost, OrderType};
#[test]
fn test_transaction_cost_maker_fee() {
// LimitMaker: 0.05% (0.0005)
let trade_value = 10_000.0; // $10,000 trade
let cost = calculate_transaction_cost(OrderType::LimitMaker, trade_value);
// Expected: 0.0005 * 10,000 = $5.00
assert_eq!(cost, 5.0, "LimitMaker fee should be 0.05%");
// Test larger trade
let large_trade = 100_000.0; // $100K trade
let large_cost = calculate_transaction_cost(OrderType::LimitMaker, large_trade);
assert_eq!(large_cost, 50.0, "LimitMaker fee on $100K should be $50");
}
#[test]
fn test_transaction_cost_taker_fee() {
// Market: 0.15% (0.0015)
let trade_value = 10_000.0; // $10,000 trade
let cost = calculate_transaction_cost(OrderType::Market, trade_value);
// Expected: 0.0015 * 10,000 = $15.00
assert_eq!(cost, 15.0, "Market fee should be 0.15%");
// Test smaller trade
let small_trade = 1_000.0; // $1K trade
let small_cost = calculate_transaction_cost(OrderType::Market, small_trade);
assert_eq!(small_cost, 1.5, "Market fee on $1K should be $1.50");
}
#[test]
fn test_transaction_cost_ioc_fee() {
// IoC (Immediate-or-Cancel): 0.10% (0.0010)
let trade_value = 10_000.0; // $10,000 trade
let cost = calculate_transaction_cost(OrderType::IoC, trade_value);
// Expected: 0.0010 * 10,000 = $10.00
assert_eq!(cost, 10.0, "IoC fee should be 0.10%");
// Test edge case: zero trade value
let zero_cost = calculate_transaction_cost(OrderType::IoC, 0.0);
assert_eq!(zero_cost, 0.0, "Zero trade value should have zero cost");
}
#[test]
fn test_transaction_cost_negative_trade_value() {
// Transaction costs should be based on absolute value
let trade_value = -10_000.0; // Negative trade value (shouldn't happen, but test defensively)
let cost = calculate_transaction_cost(OrderType::Market, trade_value);
// Expected: 0.0015 * |-10,000| = $15.00
assert_eq!(cost, 15.0, "Transaction cost should use absolute trade value");
}
#[test]
fn test_transaction_cost_fee_ordering() {
// Verify fee ordering: Market (0.15%) > IoC (0.10%) > LimitMaker (0.05%)
let trade_value = 10_000.0;
let market_cost = calculate_transaction_cost(OrderType::Market, trade_value);
let ioc_cost = calculate_transaction_cost(OrderType::IoC, trade_value);
let maker_cost = calculate_transaction_cost(OrderType::LimitMaker, trade_value);
assert!(market_cost > ioc_cost, "Market fee should be higher than IoC");
assert!(ioc_cost > maker_cost, "IoC fee should be higher than LimitMaker");
assert_eq!(market_cost, 15.0, "Market: 0.15%");
assert_eq!(ioc_cost, 10.0, "IoC: 0.10%");
assert_eq!(maker_cost, 5.0, "LimitMaker: 0.05%");
}
#[test]
fn test_transaction_cost_large_values() {
// Test with large trade values to verify no overflow
let large_trade = 1_000_000.0; // $1M trade
let market_cost = calculate_transaction_cost(OrderType::Market, large_trade);
assert_eq!(market_cost, 1_500.0, "Market fee on $1M should be $1,500");
let maker_cost = calculate_transaction_cost(OrderType::LimitMaker, large_trade);
assert_eq!(maker_cost, 500.0, "LimitMaker fee on $1M should be $500");
}