feat(trading_engine): migrate OrderRequest to FinancialPrice/FinancialQuantity
Replace raw f64 price/quantity in SmallBatchOptimizer with typed financial values. Conversion to f64 happens at the SIMD boundary (_mm256_loadu_pd) only. Delete 3 orphaned dead-code files: financial_safe.rs, simd_optimizations.rs, tests/financial_tests.rs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
)]
|
||||
|
||||
use crate::timing::HardwareTimestamp;
|
||||
use common::{OrderSide, OrderType};
|
||||
use common::{FinancialPrice, FinancialQuantity, OrderSide, OrderType};
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
|
||||
/// Maximum orders in a small batch for specialized processing
|
||||
@@ -59,10 +59,10 @@ pub struct OrderRequest {
|
||||
pub side: OrderSide,
|
||||
/// Order Type
|
||||
pub order_type: OrderType,
|
||||
/// Quantity
|
||||
pub quantity: f64, // Use f64 for SIMD operations
|
||||
/// Price
|
||||
pub price: f64, // Use f64 for SIMD operations
|
||||
/// Quantity (typed fixed-point, converted to f64 at SIMD boundary)
|
||||
pub quantity: FinancialQuantity,
|
||||
/// Price (typed fixed-point, converted to f64 at SIMD boundary)
|
||||
pub price: FinancialPrice,
|
||||
/// Timestamp Ns
|
||||
pub timestamp_ns: u64,
|
||||
}
|
||||
@@ -75,8 +75,8 @@ impl OrderRequest {
|
||||
symbol: &str,
|
||||
side: OrderSide,
|
||||
order_type: OrderType,
|
||||
quantity: f64,
|
||||
price: f64,
|
||||
quantity: FinancialQuantity,
|
||||
price: FinancialPrice,
|
||||
) -> Self {
|
||||
Self {
|
||||
order_id,
|
||||
@@ -222,14 +222,14 @@ impl SmallBatchSimd {
|
||||
return Err("Batch size must be 1-4 orders for SIMD processing");
|
||||
}
|
||||
|
||||
// Pad batch to 4 elements for SIMD
|
||||
// Pad batch to 4 elements for SIMD (convert typed → f64 at SIMD boundary)
|
||||
let mut padded_count = 0;
|
||||
for (i, order) in orders.iter().enumerate() {
|
||||
if let Some(slot) = self.prices.get_mut(i) {
|
||||
*slot = order.price;
|
||||
*slot = order.price.to_f64();
|
||||
}
|
||||
if let Some(slot) = self.quantities.get_mut(i) {
|
||||
*slot = order.quantity;
|
||||
*slot = order.quantity.to_f64();
|
||||
}
|
||||
if let Some(slot) = self.timestamps.get_mut(i) {
|
||||
*slot = order.timestamp_ns;
|
||||
@@ -408,10 +408,10 @@ impl SmallBatchProcessor {
|
||||
// Process with SIMD
|
||||
simd_ops.process_batch(&valid_orders)?;
|
||||
|
||||
// Calculate total notional (simplified for demonstration)
|
||||
// Calculate total notional (convert typed values to f64 at SIMD boundary)
|
||||
let total_notional: f64 = valid_orders
|
||||
.iter()
|
||||
.map(|order| order.price * order.quantity)
|
||||
.map(|order| order.price.to_f64() * order.quantity.to_f64())
|
||||
.sum();
|
||||
|
||||
Ok(BatchProcessingResult {
|
||||
@@ -428,13 +428,13 @@ impl SmallBatchProcessor {
|
||||
|
||||
for &order_opt in self.orders.get(..self.batch_size).unwrap_or(&[]) {
|
||||
if let Some(order) = order_opt {
|
||||
// Validate order
|
||||
if order.price <= 0.0 || order.quantity <= 0.0 {
|
||||
// Validate order (typed values are always valid — NaN/Inf rejected at construction)
|
||||
if !order.price.is_positive() || !order.quantity.is_positive() {
|
||||
return Err("Invalid order parameters");
|
||||
}
|
||||
|
||||
// Calculate notional
|
||||
let notional = order.price * order.quantity;
|
||||
// Calculate notional (convert to f64 at computation boundary)
|
||||
let notional = order.price.to_f64() * order.quantity.to_f64();
|
||||
if notional > 1_000_000_000.0 {
|
||||
return Err("Notional value too large");
|
||||
}
|
||||
@@ -586,6 +586,14 @@ mod tests {
|
||||
assert!(!processor.is_full());
|
||||
}
|
||||
|
||||
fn test_price(val: f64) -> FinancialPrice {
|
||||
FinancialPrice::from_f64(val).unwrap_or(FinancialPrice::ZERO)
|
||||
}
|
||||
|
||||
fn test_qty(val: f64) -> FinancialQuantity {
|
||||
FinancialQuantity::from_f64(val).unwrap_or(FinancialQuantity::ZERO)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_order_request_creation() {
|
||||
let order = OrderRequest::new(
|
||||
@@ -593,15 +601,15 @@ mod tests {
|
||||
"BTCUSD",
|
||||
OrderSide::Buy,
|
||||
OrderType::Limit,
|
||||
1.5,
|
||||
50000.0,
|
||||
test_qty(1.5),
|
||||
test_price(50000.0),
|
||||
);
|
||||
|
||||
assert_eq!(order.order_id, 12345);
|
||||
assert_eq!(order.side, OrderSide::Buy);
|
||||
assert_eq!(order.order_type, OrderType::Limit);
|
||||
assert_eq!(order.quantity, 1.5);
|
||||
assert_eq!(order.price, 50000.0);
|
||||
assert!((order.quantity.to_f64() - 1.5).abs() < 1e-6);
|
||||
assert!((order.price.to_f64() - 50000.0).abs() < 1e-6);
|
||||
assert!(order.timestamp_ns > 0);
|
||||
}
|
||||
|
||||
@@ -609,9 +617,9 @@ mod tests {
|
||||
fn test_add_orders_to_batch() {
|
||||
let mut processor = SmallBatchProcessor::new();
|
||||
|
||||
let order1 = OrderRequest::new(1, "BTCUSD", OrderSide::Buy, OrderType::Limit, 1.0, 50000.0);
|
||||
let order1 = OrderRequest::new(1, "BTCUSD", OrderSide::Buy, OrderType::Limit, test_qty(1.0), test_price(50000.0));
|
||||
let order2 =
|
||||
OrderRequest::new(2, "ETHUSD", OrderSide::Sell, OrderType::Market, 2.0, 3000.0);
|
||||
OrderRequest::new(2, "ETHUSD", OrderSide::Sell, OrderType::Market, test_qty(2.0), test_price(3000.0));
|
||||
|
||||
assert!(processor.add_order(order1).is_ok());
|
||||
assert_eq!(processor.batch_size(), 1);
|
||||
@@ -631,8 +639,8 @@ mod tests {
|
||||
"BTCUSD",
|
||||
OrderSide::Buy,
|
||||
OrderType::Limit,
|
||||
1.0,
|
||||
50000.0 + i as f64,
|
||||
test_qty(1.0),
|
||||
test_price(50000.0 + i as f64),
|
||||
);
|
||||
processor
|
||||
.add_order(order)
|
||||
@@ -683,8 +691,8 @@ mod tests {
|
||||
"BTCUSD",
|
||||
OrderSide::Buy,
|
||||
OrderType::Limit,
|
||||
1.0,
|
||||
50000.0,
|
||||
test_qty(1.0),
|
||||
test_price(50000.0),
|
||||
);
|
||||
assert!(processor.add_order(order).is_ok());
|
||||
}
|
||||
@@ -697,8 +705,8 @@ mod tests {
|
||||
"ETHUSD",
|
||||
OrderSide::Sell,
|
||||
OrderType::Market,
|
||||
1.0,
|
||||
3000.0,
|
||||
test_qty(1.0),
|
||||
test_price(3000.0),
|
||||
);
|
||||
assert!(processor.add_order(overflow_order).is_err());
|
||||
}
|
||||
@@ -709,8 +717,8 @@ mod tests {
|
||||
let mut simd_ops = SmallBatchSimd::new().expect("Test: Failed to create SIMD ops");
|
||||
|
||||
let orders = vec![
|
||||
OrderRequest::new(1, "BTCUSD", OrderSide::Buy, OrderType::Limit, 1.0, 50000.0),
|
||||
OrderRequest::new(2, "ETHUSD", OrderSide::Sell, OrderType::Limit, 2.0, 3000.0),
|
||||
OrderRequest::new(1, "BTCUSD", OrderSide::Buy, OrderType::Limit, test_qty(1.0), test_price(50000.0)),
|
||||
OrderRequest::new(2, "ETHUSD", OrderSide::Sell, OrderType::Limit, test_qty(2.0), test_price(3000.0)),
|
||||
];
|
||||
|
||||
assert!(simd_ops.process_batch(&orders).is_ok());
|
||||
|
||||
Reference in New Issue
Block a user