🚀 Wave 34: 12 Parallel Agents - 88% Error Reduction (200→24)

Agent Results:
 Agent 1: Verified ML CheckpointMetadata (no errors found)
 Agent 2: Fixed 12 ML error handling issues (E0533, E0277, E0282)
 Agent 3: Fixed 10 ML type mismatches (E0308)
 Agent 4: Fixed 5 trading service test errors (E0599, E0308)
 Agent 5: Restored 5 tests crate infrastructure types
 Agent 6: Fixed 3 tests dependencies (OrderSide/Status, tempfile)
 Agent 7: Fixed TradingEventType re-export
 Agent 8: Fixed 7 E2E test files (proto namespaces)
 Agent 9: Verified ML crate clean compilation
 Agent 10: Fixed 4 trading service/engine errors
 Agent 11: Completed integration test analysis
 Agent 12: Generated comprehensive verification report

Files Modified: 30 files
Error Reduction: ~200 errors → 24 errors (88%)
Remaining: 16 ML + 5 E2E + 3 tests = 24 errors

Documentation:
- WAVE34_COMPLETION_REPORT.md (447 lines)
- WAVE35_ACTION_PLAN.md (detailed fixes)

Next: Wave 35 with 3 targeted agents to achieve 0 errors
This commit is contained in:
jgrusewski
2025-10-01 22:56:27 +02:00
parent bb48d3216c
commit e40c7715bb
34 changed files with 1845 additions and 261 deletions

View File

@@ -66,6 +66,9 @@ influxdb2 = { workspace = true, optional = true }
tracing.workspace = true
tracing-subscriber.workspace = true
# File system utilities (needed for non-test modules that create temp files)
tempfile = "3.8"
# Memory profiling (optional)
dhat = { version = "0.3", optional = true }
jemalloc_pprof = { version = "0.4", optional = true }

View File

@@ -13,6 +13,7 @@ fn main() -> Result<()> {
&[
"../../services/trading_service/proto/trading.proto",
"../../services/trading_service/proto/config.proto",
"../../services/trading_service/proto/risk.proto",
"../../services/ml_training_service/proto/ml_training.proto",
],
&[

View File

@@ -6,4 +6,5 @@
pub mod backtesting;
pub mod config;
pub mod ml_training;
pub mod risk;
pub mod trading;

946
tests/e2e/src/proto/risk.rs Normal file
View File

@@ -0,0 +1,946 @@
// This file is @generated by prost-build.
/// Request to calculate portfolio VaR
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetVaRRequest {
/// Symbols to include in VaR calculation (empty = all positions)
#[prost(string, repeated, tag = "1")]
pub symbols: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
/// Confidence level (e.g., 0.95 for 95% VaR)
#[prost(double, tag = "2")]
pub confidence_level: f64,
/// Historical data period for calculation
#[prost(int32, tag = "3")]
pub lookback_days: i32,
/// VaR calculation method (historical, parametric, Monte Carlo)
#[prost(enumeration = "VaRMethod", tag = "4")]
pub method: i32,
}
/// Response containing VaR calculation results
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetVaRResponse {
/// Total portfolio VaR value
#[prost(double, tag = "1")]
pub portfolio_var: f64,
/// Individual symbol VaR contributions
#[prost(message, repeated, tag = "2")]
pub symbol_vars: ::prost::alloc::vec::Vec<SymbolVaR>,
/// Confidence level used in calculation
#[prost(double, tag = "3")]
pub confidence_level: f64,
/// Historical period used
#[prost(int32, tag = "4")]
pub lookback_days: i32,
/// Calculation method used
#[prost(enumeration = "VaRMethod", tag = "5")]
pub method: i32,
/// Calculation timestamp (nanoseconds)
#[prost(int64, tag = "6")]
pub calculated_at: i64,
}
/// Request to stream real-time VaR updates
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct StreamVaRRequest {
/// Confidence level for VaR calculation
#[prost(double, tag = "1")]
pub confidence_level: f64,
/// How often to send updates
#[prost(int32, tag = "2")]
pub update_frequency_seconds: i32,
}
/// VaR contribution for a specific symbol
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SymbolVaR {
/// Trading symbol
#[prost(string, tag = "1")]
pub symbol: ::prost::alloc::string::String,
/// VaR value for this symbol
#[prost(double, tag = "2")]
pub var_value: f64,
/// Current position size
#[prost(double, tag = "3")]
pub position_size: f64,
/// Percentage contribution to total portfolio VaR
#[prost(double, tag = "4")]
pub contribution_pct: f64,
}
/// Request for position risk analysis
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetPositionRiskRequest {
/// Filter by symbol (all symbols if not specified)
#[prost(string, optional, tag = "1")]
pub symbol: ::core::option::Option<::prost::alloc::string::String>,
/// Filter by account (all accounts if not specified)
#[prost(string, optional, tag = "2")]
pub account_id: ::core::option::Option<::prost::alloc::string::String>,
}
/// Response containing position risk analysis
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetPositionRiskResponse {
/// Risk analysis for each position
#[prost(message, repeated, tag = "1")]
pub position_risks: ::prost::alloc::vec::Vec<PositionRisk>,
/// Overall portfolio risk score (0-100)
#[prost(double, tag = "2")]
pub portfolio_risk_score: f64,
}
/// Request to validate order against risk limits
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ValidateOrderRequest {
/// Trading symbol
#[prost(string, tag = "1")]
pub symbol: ::prost::alloc::string::String,
/// Order quantity
#[prost(double, tag = "2")]
pub quantity: f64,
/// Order price
#[prost(double, tag = "3")]
pub price: f64,
/// Buy or sell
#[prost(string, tag = "4")]
pub side: ::prost::alloc::string::String,
/// Trading account
#[prost(string, tag = "5")]
pub account_id: ::prost::alloc::string::String,
}
/// Response containing order validation results
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ValidateOrderResponse {
/// True if order passes all risk checks
#[prost(bool, tag = "1")]
pub is_valid: bool,
/// List of risk violations (if any)
#[prost(message, repeated, tag = "2")]
pub violations: ::prost::alloc::vec::Vec<RiskViolation>,
/// Risk assessment for this order
#[prost(message, optional, tag = "3")]
pub risk_score: ::core::option::Option<RiskScore>,
/// Human-readable validation message
#[prost(string, tag = "4")]
pub message: ::prost::alloc::string::String,
}
/// Request for comprehensive risk metrics
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetRiskMetricsRequest {
/// Portfolio identifier (default portfolio if not specified)
#[prost(string, optional, tag = "1")]
pub portfolio_id: ::core::option::Option<::prost::alloc::string::String>,
}
/// Response containing comprehensive risk metrics
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetRiskMetricsResponse {
/// Complete risk metrics and statistics
#[prost(message, optional, tag = "1")]
pub metrics: ::core::option::Option<RiskMetrics>,
/// Metrics calculation timestamp (nanoseconds)
#[prost(int64, tag = "2")]
pub calculated_at: i64,
}
/// Request to stream real-time risk alerts
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct StreamRiskAlertsRequest {
/// Minimum alert severity to receive
#[prost(enumeration = "RiskAlertSeverity", tag = "1")]
pub min_severity: i32,
/// Types of alerts to receive (empty = all types)
#[prost(enumeration = "RiskAlertType", repeated, tag = "2")]
pub alert_types: ::prost::alloc::vec::Vec<i32>,
}
/// Request to trigger emergency stop
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct EmergencyStopRequest {
/// Type of emergency stop (all trading, symbol, account, etc.)
#[prost(enumeration = "EmergencyStopType", tag = "1")]
pub stop_type: i32,
/// Reason for emergency stop
#[prost(string, tag = "2")]
pub reason: ::prost::alloc::string::String,
/// Symbol to stop (for symbol-specific stops)
#[prost(string, optional, tag = "3")]
pub symbol: ::core::option::Option<::prost::alloc::string::String>,
/// Account to stop (for account-specific stops)
#[prost(string, optional, tag = "4")]
pub account_id: ::core::option::Option<::prost::alloc::string::String>,
}
/// Response after emergency stop execution
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct EmergencyStopResponse {
/// True if emergency stop was successful
#[prost(bool, tag = "1")]
pub success: bool,
/// Status message or error description
#[prost(string, tag = "2")]
pub message: ::prost::alloc::string::String,
/// Emergency stop timestamp (nanoseconds)
#[prost(int64, tag = "3")]
pub timestamp: i64,
/// List of order IDs affected by the stop
#[prost(string, repeated, tag = "4")]
pub affected_orders: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
}
/// Request for circuit breaker status
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetCircuitBreakerStatusRequest {
/// Filter by symbol (all symbols if not specified)
#[prost(string, optional, tag = "1")]
pub symbol: ::core::option::Option<::prost::alloc::string::String>,
}
/// Response containing circuit breaker status
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetCircuitBreakerStatusResponse {
/// Status of all circuit breakers
#[prost(message, repeated, tag = "1")]
pub circuit_breakers: ::prost::alloc::vec::Vec<CircuitBreakerStatus>,
}
/// Risk analysis for a specific position
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct PositionRisk {
/// Trading symbol
#[prost(string, tag = "1")]
pub symbol: ::prost::alloc::string::String,
/// Current position size
#[prost(double, tag = "2")]
pub position_size: f64,
/// Market value of position
#[prost(double, tag = "3")]
pub market_value: f64,
/// Contribution to portfolio VaR
#[prost(double, tag = "4")]
pub var_contribution: f64,
/// Position concentration risk (0-100)
#[prost(double, tag = "5")]
pub concentration_risk: f64,
/// Liquidity risk score (0-100)
#[prost(double, tag = "6")]
pub liquidity_risk: f64,
/// Overall risk assessment
#[prost(message, optional, tag = "7")]
pub overall_score: ::core::option::Option<RiskScore>,
/// Additional risk metrics
#[prost(message, repeated, tag = "8")]
pub metrics: ::prost::alloc::vec::Vec<RiskMetric>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RiskViolation {
#[prost(enumeration = "RiskViolationType", tag = "1")]
pub violation_type: i32,
#[prost(string, tag = "2")]
pub description: ::prost::alloc::string::String,
#[prost(double, tag = "3")]
pub current_value: f64,
#[prost(double, tag = "4")]
pub limit_value: f64,
#[prost(enumeration = "RiskAlertSeverity", tag = "5")]
pub severity: i32,
}
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct RiskScore {
#[prost(double, tag = "1")]
pub overall_score: f64,
#[prost(double, tag = "2")]
pub concentration_score: f64,
#[prost(double, tag = "3")]
pub liquidity_score: f64,
#[prost(double, tag = "4")]
pub volatility_score: f64,
#[prost(double, tag = "5")]
pub correlation_score: f64,
#[prost(enumeration = "RiskLevel", tag = "6")]
pub risk_level: i32,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RiskMetrics {
#[prost(double, tag = "1")]
pub portfolio_var_1d: f64,
#[prost(double, tag = "2")]
pub portfolio_var_5d: f64,
#[prost(double, tag = "3")]
pub portfolio_var_30d: f64,
#[prost(double, tag = "4")]
pub max_drawdown: f64,
#[prost(double, tag = "5")]
pub current_drawdown: f64,
#[prost(double, tag = "6")]
pub sharpe_ratio: f64,
#[prost(double, tag = "7")]
pub sortino_ratio: f64,
#[prost(double, tag = "8")]
pub beta: f64,
#[prost(double, tag = "9")]
pub alpha: f64,
#[prost(double, tag = "10")]
pub volatility: f64,
#[prost(message, repeated, tag = "11")]
pub position_risks: ::prost::alloc::vec::Vec<PositionRisk>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RiskMetric {
#[prost(string, tag = "1")]
pub name: ::prost::alloc::string::String,
#[prost(double, tag = "2")]
pub value: f64,
#[prost(string, tag = "3")]
pub unit: ::prost::alloc::string::String,
#[prost(enumeration = "RiskLevel", tag = "4")]
pub risk_level: i32,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CircuitBreakerStatus {
#[prost(string, tag = "1")]
pub name: ::prost::alloc::string::String,
#[prost(bool, tag = "2")]
pub is_triggered: bool,
#[prost(string, optional, tag = "3")]
pub trigger_reason: ::core::option::Option<::prost::alloc::string::String>,
#[prost(int64, optional, tag = "4")]
pub triggered_at: ::core::option::Option<i64>,
#[prost(int64, optional, tag = "5")]
pub reset_at: ::core::option::Option<i64>,
#[prost(enumeration = "CircuitBreakerType", tag = "6")]
pub breaker_type: i32,
}
/// Event Messages
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct VaREvent {
#[prost(double, tag = "1")]
pub portfolio_var: f64,
#[prost(message, repeated, tag = "2")]
pub symbol_vars: ::prost::alloc::vec::Vec<SymbolVaR>,
#[prost(enumeration = "VaRChangeType", tag = "3")]
pub change_type: i32,
#[prost(int64, tag = "4")]
pub timestamp: i64,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RiskAlertEvent {
#[prost(string, tag = "1")]
pub alert_id: ::prost::alloc::string::String,
#[prost(enumeration = "RiskAlertType", tag = "2")]
pub alert_type: i32,
#[prost(enumeration = "RiskAlertSeverity", tag = "3")]
pub severity: i32,
#[prost(string, tag = "4")]
pub message: ::prost::alloc::string::String,
#[prost(string, optional, tag = "5")]
pub symbol: ::core::option::Option<::prost::alloc::string::String>,
#[prost(string, optional, tag = "6")]
pub account_id: ::core::option::Option<::prost::alloc::string::String>,
#[prost(map = "string, string", tag = "7")]
pub metadata: ::std::collections::HashMap<
::prost::alloc::string::String,
::prost::alloc::string::String,
>,
#[prost(int64, tag = "8")]
pub timestamp: i64,
}
/// VaR calculation methodology
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum VaRMethod {
/// Default/unknown method
VarMethodUnspecified = 0,
/// Historical simulation method
VarMethodHistorical = 1,
/// Parametric (variance-covariance) method
VarMethodParametric = 2,
/// Monte Carlo simulation method
VarMethodMonteCarlo = 3,
}
impl VaRMethod {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Self::VarMethodUnspecified => "VAR_METHOD_UNSPECIFIED",
Self::VarMethodHistorical => "VAR_METHOD_HISTORICAL",
Self::VarMethodParametric => "VAR_METHOD_PARAMETRIC",
Self::VarMethodMonteCarlo => "VAR_METHOD_MONTE_CARLO",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"VAR_METHOD_UNSPECIFIED" => Some(Self::VarMethodUnspecified),
"VAR_METHOD_HISTORICAL" => Some(Self::VarMethodHistorical),
"VAR_METHOD_PARAMETRIC" => Some(Self::VarMethodParametric),
"VAR_METHOD_MONTE_CARLO" => Some(Self::VarMethodMonteCarlo),
_ => None,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum RiskViolationType {
Unspecified = 0,
PositionLimit = 1,
Concentration = 2,
VarLimit = 3,
Drawdown = 4,
Liquidity = 5,
Correlation = 6,
}
impl RiskViolationType {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Self::Unspecified => "RISK_VIOLATION_TYPE_UNSPECIFIED",
Self::PositionLimit => "RISK_VIOLATION_TYPE_POSITION_LIMIT",
Self::Concentration => "RISK_VIOLATION_TYPE_CONCENTRATION",
Self::VarLimit => "RISK_VIOLATION_TYPE_VAR_LIMIT",
Self::Drawdown => "RISK_VIOLATION_TYPE_DRAWDOWN",
Self::Liquidity => "RISK_VIOLATION_TYPE_LIQUIDITY",
Self::Correlation => "RISK_VIOLATION_TYPE_CORRELATION",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"RISK_VIOLATION_TYPE_UNSPECIFIED" => Some(Self::Unspecified),
"RISK_VIOLATION_TYPE_POSITION_LIMIT" => Some(Self::PositionLimit),
"RISK_VIOLATION_TYPE_CONCENTRATION" => Some(Self::Concentration),
"RISK_VIOLATION_TYPE_VAR_LIMIT" => Some(Self::VarLimit),
"RISK_VIOLATION_TYPE_DRAWDOWN" => Some(Self::Drawdown),
"RISK_VIOLATION_TYPE_LIQUIDITY" => Some(Self::Liquidity),
"RISK_VIOLATION_TYPE_CORRELATION" => Some(Self::Correlation),
_ => None,
}
}
}
/// Risk assessment levels
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum RiskLevel {
/// Default/unknown level
Unspecified = 0,
/// Low risk (green)
Low = 1,
/// Medium risk (yellow)
Medium = 2,
/// High risk (orange)
High = 3,
/// Critical risk (red)
Critical = 4,
}
impl RiskLevel {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Self::Unspecified => "RISK_LEVEL_UNSPECIFIED",
Self::Low => "RISK_LEVEL_LOW",
Self::Medium => "RISK_LEVEL_MEDIUM",
Self::High => "RISK_LEVEL_HIGH",
Self::Critical => "RISK_LEVEL_CRITICAL",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"RISK_LEVEL_UNSPECIFIED" => Some(Self::Unspecified),
"RISK_LEVEL_LOW" => Some(Self::Low),
"RISK_LEVEL_MEDIUM" => Some(Self::Medium),
"RISK_LEVEL_HIGH" => Some(Self::High),
"RISK_LEVEL_CRITICAL" => Some(Self::Critical),
_ => None,
}
}
}
/// Severity levels for risk alerts
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum RiskAlertSeverity {
/// Default/unknown severity
Unspecified = 0,
/// Informational alert
Info = 1,
/// Warning alert
Warning = 2,
/// Critical alert requiring attention
Critical = 3,
/// Emergency alert requiring immediate action
Emergency = 4,
}
impl RiskAlertSeverity {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Self::Unspecified => "RISK_ALERT_SEVERITY_UNSPECIFIED",
Self::Info => "RISK_ALERT_SEVERITY_INFO",
Self::Warning => "RISK_ALERT_SEVERITY_WARNING",
Self::Critical => "RISK_ALERT_SEVERITY_CRITICAL",
Self::Emergency => "RISK_ALERT_SEVERITY_EMERGENCY",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"RISK_ALERT_SEVERITY_UNSPECIFIED" => Some(Self::Unspecified),
"RISK_ALERT_SEVERITY_INFO" => Some(Self::Info),
"RISK_ALERT_SEVERITY_WARNING" => Some(Self::Warning),
"RISK_ALERT_SEVERITY_CRITICAL" => Some(Self::Critical),
"RISK_ALERT_SEVERITY_EMERGENCY" => Some(Self::Emergency),
_ => None,
}
}
}
/// Types of risk alerts
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum RiskAlertType {
/// Default/unknown type
Unspecified = 0,
/// VaR limit breach
VarBreach = 1,
/// Position size limit breach
PositionLimit = 2,
/// Drawdown limit breach
Drawdown = 3,
/// Portfolio concentration risk
Concentration = 4,
/// Liquidity risk alert
Liquidity = 5,
/// Correlation risk alert
Correlation = 6,
}
impl RiskAlertType {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Self::Unspecified => "RISK_ALERT_TYPE_UNSPECIFIED",
Self::VarBreach => "RISK_ALERT_TYPE_VAR_BREACH",
Self::PositionLimit => "RISK_ALERT_TYPE_POSITION_LIMIT",
Self::Drawdown => "RISK_ALERT_TYPE_DRAWDOWN",
Self::Concentration => "RISK_ALERT_TYPE_CONCENTRATION",
Self::Liquidity => "RISK_ALERT_TYPE_LIQUIDITY",
Self::Correlation => "RISK_ALERT_TYPE_CORRELATION",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"RISK_ALERT_TYPE_UNSPECIFIED" => Some(Self::Unspecified),
"RISK_ALERT_TYPE_VAR_BREACH" => Some(Self::VarBreach),
"RISK_ALERT_TYPE_POSITION_LIMIT" => Some(Self::PositionLimit),
"RISK_ALERT_TYPE_DRAWDOWN" => Some(Self::Drawdown),
"RISK_ALERT_TYPE_CONCENTRATION" => Some(Self::Concentration),
"RISK_ALERT_TYPE_LIQUIDITY" => Some(Self::Liquidity),
"RISK_ALERT_TYPE_CORRELATION" => Some(Self::Correlation),
_ => None,
}
}
}
/// Types of emergency stops
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum EmergencyStopType {
/// Default/unknown type
Unspecified = 0,
/// Stop all trading activity
AllTrading = 1,
/// Stop trading for specific symbol
Symbol = 2,
/// Stop trading for specific account
Account = 3,
/// Stop specific trading strategy
Strategy = 4,
}
impl EmergencyStopType {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Self::Unspecified => "EMERGENCY_STOP_TYPE_UNSPECIFIED",
Self::AllTrading => "EMERGENCY_STOP_TYPE_ALL_TRADING",
Self::Symbol => "EMERGENCY_STOP_TYPE_SYMBOL",
Self::Account => "EMERGENCY_STOP_TYPE_ACCOUNT",
Self::Strategy => "EMERGENCY_STOP_TYPE_STRATEGY",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"EMERGENCY_STOP_TYPE_UNSPECIFIED" => Some(Self::Unspecified),
"EMERGENCY_STOP_TYPE_ALL_TRADING" => Some(Self::AllTrading),
"EMERGENCY_STOP_TYPE_SYMBOL" => Some(Self::Symbol),
"EMERGENCY_STOP_TYPE_ACCOUNT" => Some(Self::Account),
"EMERGENCY_STOP_TYPE_STRATEGY" => Some(Self::Strategy),
_ => None,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum CircuitBreakerType {
Unspecified = 0,
PortfolioLoss = 1,
SymbolVolatility = 2,
PositionSize = 3,
Drawdown = 4,
}
impl CircuitBreakerType {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Self::Unspecified => "CIRCUIT_BREAKER_TYPE_UNSPECIFIED",
Self::PortfolioLoss => "CIRCUIT_BREAKER_TYPE_PORTFOLIO_LOSS",
Self::SymbolVolatility => "CIRCUIT_BREAKER_TYPE_SYMBOL_VOLATILITY",
Self::PositionSize => "CIRCUIT_BREAKER_TYPE_POSITION_SIZE",
Self::Drawdown => "CIRCUIT_BREAKER_TYPE_DRAWDOWN",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"CIRCUIT_BREAKER_TYPE_UNSPECIFIED" => Some(Self::Unspecified),
"CIRCUIT_BREAKER_TYPE_PORTFOLIO_LOSS" => Some(Self::PortfolioLoss),
"CIRCUIT_BREAKER_TYPE_SYMBOL_VOLATILITY" => Some(Self::SymbolVolatility),
"CIRCUIT_BREAKER_TYPE_POSITION_SIZE" => Some(Self::PositionSize),
"CIRCUIT_BREAKER_TYPE_DRAWDOWN" => Some(Self::Drawdown),
_ => None,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum VaRChangeType {
VarChangeTypeUnspecified = 0,
VarChangeTypeIncreased = 1,
VarChangeTypeDecreased = 2,
VarChangeTypeBreach = 3,
}
impl VaRChangeType {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Self::VarChangeTypeUnspecified => "VAR_CHANGE_TYPE_UNSPECIFIED",
Self::VarChangeTypeIncreased => "VAR_CHANGE_TYPE_INCREASED",
Self::VarChangeTypeDecreased => "VAR_CHANGE_TYPE_DECREASED",
Self::VarChangeTypeBreach => "VAR_CHANGE_TYPE_BREACH",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"VAR_CHANGE_TYPE_UNSPECIFIED" => Some(Self::VarChangeTypeUnspecified),
"VAR_CHANGE_TYPE_INCREASED" => Some(Self::VarChangeTypeIncreased),
"VAR_CHANGE_TYPE_DECREASED" => Some(Self::VarChangeTypeDecreased),
"VAR_CHANGE_TYPE_BREACH" => Some(Self::VarChangeTypeBreach),
_ => None,
}
}
}
/// Generated client implementations.
#[allow(unused_qualifications)]
pub mod risk_service_client {
#![allow(
unused_variables,
dead_code,
missing_docs,
clippy::wildcard_imports,
clippy::let_unit_value,
)]
use tonic::codegen::*;
use tonic::codegen::http::Uri;
/// Risk Management Service provides comprehensive risk assessment, monitoring, and control capabilities
/// for high-frequency trading operations. This service integrates real-time VaR calculations,
/// position risk analysis, compliance monitoring, and emergency controls.
#[derive(Debug, Clone)]
pub struct RiskServiceClient<T> {
inner: tonic::client::Grpc<T>,
}
impl RiskServiceClient<tonic::transport::Channel> {
/// Attempt to create a new client by connecting to a given endpoint.
pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
where
D: TryInto<tonic::transport::Endpoint>,
D::Error: Into<StdError>,
{
let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
Ok(Self::new(conn))
}
}
impl<T> RiskServiceClient<T>
where
T: tonic::client::GrpcService<tonic::body::BoxBody>,
T::Error: Into<StdError>,
T::ResponseBody: Body<Data = Bytes> + std::marker::Send + 'static,
<T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send,
{
pub fn new(inner: T) -> Self {
let inner = tonic::client::Grpc::new(inner);
Self { inner }
}
pub fn with_origin(inner: T, origin: Uri) -> Self {
let inner = tonic::client::Grpc::with_origin(inner, origin);
Self { inner }
}
pub fn with_interceptor<F>(
inner: T,
interceptor: F,
) -> RiskServiceClient<InterceptedService<T, F>>
where
F: tonic::service::Interceptor,
T::ResponseBody: Default,
T: tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
Response = http::Response<
<T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody,
>,
>,
<T as tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
>>::Error: Into<StdError> + std::marker::Send + std::marker::Sync,
{
RiskServiceClient::new(InterceptedService::new(inner, interceptor))
}
/// Compress requests with the given encoding.
///
/// This requires the server to support it otherwise it might respond with an
/// error.
#[must_use]
pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.inner = self.inner.send_compressed(encoding);
self
}
/// Enable decompressing responses.
#[must_use]
pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.inner = self.inner.accept_compressed(encoding);
self
}
/// Limits the maximum size of a decoded message.
///
/// Default: `4MB`
#[must_use]
pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_decoding_message_size(limit);
self
}
/// Limits the maximum size of an encoded message.
///
/// Default: `usize::MAX`
#[must_use]
pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_encoding_message_size(limit);
self
}
/// Value at Risk (VaR) Calculations
/// Calculate current portfolio VaR using specified method and parameters
pub async fn get_va_r(
&mut self,
request: impl tonic::IntoRequest<super::GetVaRRequest>,
) -> std::result::Result<tonic::Response<super::GetVaRResponse>, tonic::Status> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static("/risk.RiskService/GetVaR");
let mut req = request.into_request();
req.extensions_mut().insert(GrpcMethod::new("risk.RiskService", "GetVaR"));
self.inner.unary(req, path, codec).await
}
/// Stream real-time VaR updates as market conditions change
pub async fn stream_va_r_updates(
&mut self,
request: impl tonic::IntoRequest<super::StreamVaRRequest>,
) -> std::result::Result<
tonic::Response<tonic::codec::Streaming<super::VaREvent>>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/risk.RiskService/StreamVaRUpdates",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("risk.RiskService", "StreamVaRUpdates"));
self.inner.server_streaming(req, path, codec).await
}
/// Position Risk Analysis
/// Get comprehensive risk analysis for current positions
pub async fn get_position_risk(
&mut self,
request: impl tonic::IntoRequest<super::GetPositionRiskRequest>,
) -> std::result::Result<
tonic::Response<super::GetPositionRiskResponse>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/risk.RiskService/GetPositionRisk",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("risk.RiskService", "GetPositionRisk"));
self.inner.unary(req, path, codec).await
}
/// Validate order against risk limits before execution
pub async fn validate_order(
&mut self,
request: impl tonic::IntoRequest<super::ValidateOrderRequest>,
) -> std::result::Result<
tonic::Response<super::ValidateOrderResponse>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/risk.RiskService/ValidateOrder",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("risk.RiskService", "ValidateOrder"));
self.inner.unary(req, path, codec).await
}
/// Risk Metrics and Monitoring
/// Get comprehensive portfolio risk metrics and statistics
pub async fn get_risk_metrics(
&mut self,
request: impl tonic::IntoRequest<super::GetRiskMetricsRequest>,
) -> std::result::Result<
tonic::Response<super::GetRiskMetricsResponse>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/risk.RiskService/GetRiskMetrics",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("risk.RiskService", "GetRiskMetrics"));
self.inner.unary(req, path, codec).await
}
/// Stream real-time risk alerts and violations
pub async fn stream_risk_alerts(
&mut self,
request: impl tonic::IntoRequest<super::StreamRiskAlertsRequest>,
) -> std::result::Result<
tonic::Response<tonic::codec::Streaming<super::RiskAlertEvent>>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/risk.RiskService/StreamRiskAlerts",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("risk.RiskService", "StreamRiskAlerts"));
self.inner.server_streaming(req, path, codec).await
}
/// Emergency Controls and Circuit Breakers
/// Trigger emergency stop to halt trading activities
pub async fn emergency_stop(
&mut self,
request: impl tonic::IntoRequest<super::EmergencyStopRequest>,
) -> std::result::Result<
tonic::Response<super::EmergencyStopResponse>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/risk.RiskService/EmergencyStop",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("risk.RiskService", "EmergencyStop"));
self.inner.unary(req, path, codec).await
}
/// Get status of all circuit breakers and safety mechanisms
pub async fn get_circuit_breaker_status(
&mut self,
request: impl tonic::IntoRequest<super::GetCircuitBreakerStatusRequest>,
) -> std::result::Result<
tonic::Response<super::GetCircuitBreakerStatusResponse>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/risk.RiskService/GetCircuitBreakerStatus",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("risk.RiskService", "GetCircuitBreakerStatus"));
self.inner.unary(req, path, codec).await
}
}
}

View File

@@ -63,7 +63,7 @@ impl ComprehensiveTradingWorkflows {
// Step 2: Subscribe to real-time market data
if let Some(trading_client) = client.trading() {
let symbols = vec!["AAPL".to_string(), "GOOGL".to_string(), "MSFT".to_string()];
let mut stream = trading_client.subscribe_market_data(symbols).await?;
let mut stream = trading_client.stream_market_data(symbols).await?;
info!("✓ Market data stream established");
// Collect initial market data for feature generation
@@ -135,8 +135,6 @@ impl ComprehensiveTradingWorkflows {
quantity: 100.0,
price: None,
stop_price: None,
time_in_force: "IOC".to_string(), // Immediate or Cancel for HFT
client_order_id: format!("HFT_ORDER_{}", Uuid::new_v4()),
};
let response = trading_client.submit_order(order_request).await?;
@@ -192,7 +190,7 @@ impl ComprehensiveTradingWorkflows {
);
let account_info = trading_client
.get_account_info("TEST_ACCOUNT_HFT".to_string())
.get_portfolio_summary("TEST_ACCOUNT_HFT".to_string())
.await?;
metrics.insert("account_value".to_string(), account_info.total_value);
info!(
@@ -642,7 +640,7 @@ impl ComprehensiveTradingWorkflows {
// Step 1: Portfolio initialization
if let Some(trading_client) = client.trading() {
let account_info = trading_client
.get_account_info("MULTI_ASSET_TEST".to_string())
.get_portfolio_summary("MULTI_ASSET_TEST".to_string())
.await?;
metrics.insert("initial_balance".to_string(), account_info.cash_balance);
info!(
@@ -682,8 +680,6 @@ impl ComprehensiveTradingWorkflows {
quantity: 50.0 + (i as f64 * 10.0),
price: None,
stop_price: None,
time_in_force: "DAY".to_string(),
client_order_id: format!("MULTI_{}_{}", symbol, Uuid::new_v4()),
};
let response = trading_client.submit_order(order_request).await?;
@@ -726,8 +722,6 @@ impl ComprehensiveTradingWorkflows {
} else {
None
},
time_in_force: tif.to_string(),
client_order_id: format!("LIMIT_{}_{}", symbol, Uuid::new_v4()),
};
let response = trading_client.submit_order(order_request).await?;
@@ -806,7 +800,7 @@ impl ComprehensiveTradingWorkflows {
// Step 7: Real-time P&L calculation
if let Some(trading_client) = client.trading() {
let account_info = trading_client
.get_account_info("MULTI_ASSET_TEST".to_string())
.get_portfolio_summary("MULTI_ASSET_TEST".to_string())
.await?;
let current_balance = account_info.cash_balance;
let initial_balance = metrics.get("initial_balance").copied().unwrap_or(0.0);
@@ -903,7 +897,7 @@ impl ComprehensiveTradingWorkflows {
if let Some(trading_client) = client.trading() {
// Subscribe briefly to market data to analyze impact
match trading_client
.subscribe_market_data(symbols.iter().map(|s| s.to_string()).collect())
.stream_market_data(symbols.iter().map(|s| s.to_string()).collect())
.await
{
Ok(mut stream) => {
@@ -1066,8 +1060,6 @@ impl ComprehensiveTradingWorkflows {
quantity: 100.0,
price: Some(150.0 + (i as f64)),
stop_price: None,
time_in_force: "GTC".to_string(),
client_order_id: format!("EMERGENCY_TEST_{}", i),
};
match trading_client.submit_order(order_request).await {
@@ -1103,8 +1095,6 @@ impl ComprehensiveTradingWorkflows {
quantity: 1_000_000.0, // Intentionally huge to trigger risk limits
price: None,
stop_price: None,
time_in_force: "DAY".to_string(),
client_order_id: format!("RISK_BREACH_TEST_{}", Uuid::new_v4()),
};
match trading_client.submit_order(large_order).await {
@@ -1243,7 +1233,7 @@ impl ComprehensiveTradingWorkflows {
// Step 7: Test market data continuity during emergency
if let Some(trading_client) = client.trading() {
match trading_client
.subscribe_market_data(vec!["AAPL".to_string()])
.stream_market_data(vec!["AAPL".to_string()])
.await
{
Ok(mut stream) => {
@@ -1292,8 +1282,6 @@ impl ComprehensiveTradingWorkflows {
quantity: 100.0,
price: None,
stop_price: None,
time_in_force: "DAY".to_string(),
client_order_id: format!("EMERGENCY_ATTEMPT_{}", Uuid::new_v4()),
};
match trading_client.submit_order(emergency_order).await {
@@ -1412,8 +1400,6 @@ impl ComprehensiveTradingWorkflows {
quantity: 1.0, // Very small order for recovery test
price: Some(120.0), // Below market to avoid immediate fill
stop_price: None,
time_in_force: "IOC".to_string(), // Will cancel if not immediately filled
client_order_id: format!("RECOVERY_TEST_{}", Uuid::new_v4()),
};
match trading_client.submit_order(recovery_test_order).await {

View File

@@ -39,7 +39,7 @@ e2e_test!(
// Step 3: Subscribe to configuration changes
info!("📡 Subscribing to configuration change notifications");
let config_stream_request = tli::proto::trading::SubscribeConfigRequest {};
let config_stream_request = e2e_tests::proto::trading::SubscribeConfigRequest {};
let mut config_stream = trading_client
.subscribe_config(config_stream_request)
.await?
@@ -48,7 +48,7 @@ e2e_test!(
// Step 4: Get initial configuration state
info!("📋 Getting initial configuration state");
let initial_config = trading_client
.get_config(tli::proto::trading::GetConfigRequest {})
.get_config(e2e_tests::proto::trading::GetConfigRequest {})
.await?
.into_inner();
@@ -98,7 +98,7 @@ e2e_test!(
update_params.len()
);
let update_response = trading_client
.update_parameters(tli::proto::trading::UpdateParametersRequest {
.update_parameters(e2e_tests::proto::trading::UpdateParametersRequest {
parameters: update_params.clone(),
})
.await?
@@ -174,7 +174,7 @@ e2e_test!(
// Step 7: Verify updated configuration via direct query
info!("🔍 Verifying updated configuration");
let updated_config = trading_client
.get_config(tli::proto::trading::GetConfigRequest {})
.get_config(e2e_tests::proto::trading::GetConfigRequest {})
.await?
.into_inner();
@@ -208,7 +208,7 @@ e2e_test!(
invalid_params.insert("max_position_size".to_string(), "not_a_number".to_string()); // Invalid number format
let invalid_update_response = trading_client
.update_parameters(tli::proto::trading::UpdateParametersRequest {
.update_parameters(e2e_tests::proto::trading::UpdateParametersRequest {
parameters: invalid_params,
})
.await;
@@ -235,7 +235,7 @@ e2e_test!(
// Check service system status before configuration change
let pre_reload_status = trading_client
.get_system_status(tli::proto::trading::GetSystemStatusRequest {})
.get_system_status(e2e_tests::proto::trading::GetSystemStatusRequest {})
.await?
.into_inner();
@@ -249,7 +249,7 @@ e2e_test!(
);
let hot_reload_response = trading_client
.update_parameters(tli::proto::trading::UpdateParametersRequest {
.update_parameters(e2e_tests::proto::trading::UpdateParametersRequest {
parameters: hot_reload_params,
})
.await?
@@ -265,7 +265,7 @@ e2e_test!(
// Check service status after configuration change
let post_reload_status = trading_client
.get_system_status(tli::proto::trading::GetSystemStatusRequest {})
.get_system_status(e2e_tests::proto::trading::GetSystemStatusRequest {})
.await?
.into_inner();
@@ -298,7 +298,7 @@ e2e_test!(
);
let rollback_response = trading_client
.update_parameters(tli::proto::trading::UpdateParametersRequest {
.update_parameters(e2e_tests::proto::trading::UpdateParametersRequest {
parameters: original_values,
})
.await?
@@ -312,7 +312,7 @@ e2e_test!(
// Verify rollback
let rollback_config = trading_client
.get_config(tli::proto::trading::GetConfigRequest {})
.get_config(e2e_tests::proto::trading::GetConfigRequest {})
.await?
.into_inner();
@@ -421,7 +421,7 @@ e2e_test!(
info!("📋 Getting initial configurations from multiple services");
let trading_config = trading_client
.get_config(tli::proto::trading::GetConfigRequest {})
.get_config(e2e_tests::proto::trading::GetConfigRequest {})
.await?
.into_inner();
@@ -440,7 +440,7 @@ e2e_test!(
// Update configuration via trading service
let sync_response = trading_client
.update_parameters(tli::proto::trading::UpdateParametersRequest {
.update_parameters(e2e_tests::proto::trading::UpdateParametersRequest {
parameters: sync_params,
})
.await?
@@ -456,7 +456,7 @@ e2e_test!(
// Verify the configuration is synchronized across services
let updated_trading_config = trading_client
.get_config(tli::proto::trading::GetConfigRequest {})
.get_config(e2e_tests::proto::trading::GetConfigRequest {})
.await?
.into_inner();
@@ -492,7 +492,7 @@ e2e_test!(
for i in 0..retrieval_count {
let config = trading_client
.get_config(tli::proto::trading::GetConfigRequest {})
.get_config(e2e_tests::proto::trading::GetConfigRequest {})
.await?;
assert!(
@@ -533,7 +533,7 @@ e2e_test!(
);
let update_response = trading_client
.update_parameters(tli::proto::trading::UpdateParametersRequest {
.update_parameters(e2e_tests::proto::trading::UpdateParametersRequest {
parameters: params,
})
.await?

View File

@@ -96,7 +96,7 @@ impl DataFlowPerformanceTests {
if let Some(trading_client) = client.trading() {
match trading_client
.subscribe_market_data(symbols.iter().map(|s| s.to_string()).collect())
.stream_market_data(symbols.iter().map(|s| s.to_string()).collect())
.await
{
Ok(mut stream) => {

View File

@@ -24,14 +24,12 @@ e2e_test!(
// Test 1: Empty symbol
info!("Testing empty symbol rejection");
let invalid_order = tli::proto::trading::SubmitOrderRequest {
let invalid_order = e2e_tests::proto::trading::SubmitOrderRequest {
symbol: "".to_string(),
side: tli::proto::trading::OrderSide::Buy as i32,
order_type: tli::proto::trading::OrderType::Market as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
order_type: e2e_tests::proto::trading::OrderType::Market as i32,
quantity: 100.0,
price: None,
time_in_force: tli::proto::trading::TimeInForce::Day as i32,
client_order_id: "INVALID_SYMBOL_TEST".to_string(),
};
let result = trading_client.submit_order(invalid_order).await;
@@ -49,14 +47,12 @@ e2e_test!(
// Test 2: Zero quantity
info!("Testing zero quantity rejection");
let zero_qty_order = tli::proto::trading::SubmitOrderRequest {
let zero_qty_order = e2e_tests::proto::trading::SubmitOrderRequest {
symbol: "AAPL".to_string(),
side: tli::proto::trading::OrderSide::Buy as i32,
order_type: tli::proto::trading::OrderType::Market as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
order_type: e2e_tests::proto::trading::OrderType::Market as i32,
quantity: 0.0,
price: None,
time_in_force: tli::proto::trading::TimeInForce::Day as i32,
client_order_id: "ZERO_QTY_TEST".to_string(),
};
let result = trading_client.submit_order(zero_qty_order).await;
@@ -74,14 +70,12 @@ e2e_test!(
// Test 3: Negative price
info!("Testing negative price rejection");
let negative_price_order = tli::proto::trading::SubmitOrderRequest {
let negative_price_order = e2e_tests::proto::trading::SubmitOrderRequest {
symbol: "AAPL".to_string(),
side: tli::proto::trading::OrderSide::Buy as i32,
order_type: tli::proto::trading::OrderType::Limit as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
order_type: e2e_tests::proto::trading::OrderType::Limit as i32,
quantity: 100.0,
price: Some(-150.0),
time_in_force: tli::proto::trading::TimeInForce::Day as i32,
client_order_id: "NEGATIVE_PRICE_TEST".to_string(),
};
let result = trading_client.submit_order(negative_price_order).await;
@@ -99,14 +93,12 @@ e2e_test!(
// Test 4: Invalid symbol format
info!("Testing invalid symbol format rejection");
let invalid_symbol_order = tli::proto::trading::SubmitOrderRequest {
let invalid_symbol_order = e2e_tests::proto::trading::SubmitOrderRequest {
symbol: "INVALID@SYMBOL#123".to_string(),
side: tli::proto::trading::OrderSide::Buy as i32,
order_type: tli::proto::trading::OrderType::Market as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
order_type: e2e_tests::proto::trading::OrderType::Market as i32,
quantity: 100.0,
price: None,
time_in_force: tli::proto::trading::TimeInForce::Day as i32,
client_order_id: "INVALID_SYMBOL_FORMAT_TEST".to_string(),
};
let result = trading_client.submit_order(invalid_symbol_order).await;
@@ -157,7 +149,7 @@ e2e_test!(
// This should complete quickly
let result = tokio::time::timeout(
Duration::from_secs(5),
trading_client.get_account_info(tli::proto::trading::GetAccountInfoRequest {}),
trading_client.get_portfolio_summary(e2e_tests::proto::trading::GetPortfolioSummaryRequest {}),
)
.await;
@@ -288,25 +280,21 @@ e2e_test!(
// Mix of valid and invalid orders
let order = if i % 3 == 0 {
// Invalid order - zero quantity
tli::proto::trading::SubmitOrderRequest {
e2e_tests::proto::trading::SubmitOrderRequest {
symbol: format!("TEST{}", i),
side: tli::proto::trading::OrderSide::Buy as i32,
order_type: tli::proto::trading::OrderType::Market as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
order_type: e2e_tests::proto::trading::OrderType::Market as i32,
quantity: 0.0,
price: None,
time_in_force: tli::proto::trading::TimeInForce::Day as i32,
client_order_id: format!("CONCURRENT_INVALID_{}", i),
}
} else {
// Valid order
tli::proto::trading::SubmitOrderRequest {
e2e_tests::proto::trading::SubmitOrderRequest {
symbol: format!("TEST{}", i),
side: tli::proto::trading::OrderSide::Buy as i32,
order_type: tli::proto::trading::OrderType::Market as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
order_type: e2e_tests::proto::trading::OrderType::Market as i32,
quantity: 100.0,
price: None,
time_in_force: tli::proto::trading::TimeInForce::Day as i32,
client_order_id: format!("CONCURRENT_VALID_{}", i),
}
};
@@ -383,14 +371,12 @@ e2e_test!(
// Test 1: Very large quantity
info!("Testing very large quantity handling");
let large_qty_order = tli::proto::trading::SubmitOrderRequest {
let large_qty_order = e2e_tests::proto::trading::SubmitOrderRequest {
symbol: "AAPL".to_string(),
side: tli::proto::trading::OrderSide::Buy as i32,
order_type: tli::proto::trading::OrderType::Market as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
order_type: e2e_tests::proto::trading::OrderType::Market as i32,
quantity: 1_000_000_000.0,
price: None,
time_in_force: tli::proto::trading::TimeInForce::Day as i32,
client_order_id: "LARGE_QTY_TEST".to_string(),
};
let result = trading_client.submit_order(large_qty_order).await;
@@ -411,14 +397,12 @@ e2e_test!(
// Test 2: Very high price
info!("Testing very high price handling");
let high_price_order = tli::proto::trading::SubmitOrderRequest {
let high_price_order = e2e_tests::proto::trading::SubmitOrderRequest {
symbol: "AAPL".to_string(),
side: tli::proto::trading::OrderSide::Buy as i32,
order_type: tli::proto::trading::OrderType::Limit as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
order_type: e2e_tests::proto::trading::OrderType::Limit as i32,
quantity: 100.0,
price: Some(1_000_000.0),
time_in_force: tli::proto::trading::TimeInForce::Day as i32,
client_order_id: "HIGH_PRICE_TEST".to_string(),
};
let result = trading_client.submit_order(high_price_order).await;
@@ -439,14 +423,12 @@ e2e_test!(
// Test 3: Special characters in client order ID
info!("Testing special characters in order ID");
let special_char_order = tli::proto::trading::SubmitOrderRequest {
let special_char_order = e2e_tests::proto::trading::SubmitOrderRequest {
symbol: "AAPL".to_string(),
side: tli::proto::trading::OrderSide::Buy as i32,
order_type: tli::proto::trading::OrderType::Market as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
order_type: e2e_tests::proto::trading::OrderType::Market as i32,
quantity: 100.0,
price: None,
time_in_force: tli::proto::trading::TimeInForce::Day as i32,
client_order_id: "TEST<>?/\\|!@#$%".to_string(),
};
let result = trading_client.submit_order(special_char_order).await;

View File

@@ -39,13 +39,16 @@ e2e_test!(
// Step 3: Subscribe to market data
info!("📊 Subscribing to market data for AAPL");
let market_data_request = tli::proto::trading::SubscribeMarketDataRequest {
let market_data_request = e2e_tests::proto::trading::StreamMarketDataRequest {
symbols: vec!["AAPL".to_string()],
data_types: vec!["trades".to_string(), "quotes".to_string()],
data_types: vec![
e2e_tests::proto::trading::MarketDataType::MarketDataTypeTrade as i32,
e2e_tests::proto::trading::MarketDataType::MarketDataTypeQuote as i32,
],
};
let mut market_data_stream = trading_client
.subscribe_market_data(market_data_request)
.stream_market_data(market_data_request)
.await
.context("Failed to subscribe to market data")?
.into_inner();
@@ -61,7 +64,7 @@ e2e_test!(
Some(Ok(market_event)) => {
info!("📈 Received market data: {:?}", market_event);
if let Some(event) = market_event.event {
if let tli::proto::trading::market_data_event::Event::Tick(tick) = event {
if let e2e_tests::proto::trading::market_data_event::Event::Tick(tick) = event {
last_price = tick.price;
market_data_received = true;
info!("Current AAPL price: ${:.2}", last_price);
@@ -85,7 +88,7 @@ e2e_test!(
// Step 5: Get initial account information
info!("💼 Getting initial account information");
let initial_account = trading_client
.get_account_info(tli::proto::trading::GetAccountInfoRequest {})
.get_portfolio_summary(e2e_tests::proto::trading::GetPortfolioSummaryRequest {})
.await
.context("Failed to get initial account info")?
.into_inner();
@@ -100,7 +103,7 @@ e2e_test!(
// Step 6: Check initial positions
info!("📊 Getting initial positions");
let initial_positions = trading_client
.get_positions(tli::proto::trading::GetPositionsRequest {})
.get_positions(e2e_tests::proto::trading::GetPositionsRequest {})
.await
.context("Failed to get initial positions")?
.into_inner();
@@ -116,20 +119,18 @@ e2e_test!(
// Step 7: Create and validate order
info!("📝 Creating test order");
let test_order = tli::proto::trading::SubmitOrderRequest {
let test_order = e2e_tests::proto::trading::SubmitOrderRequest {
symbol: "AAPL".to_string(),
side: tli::proto::trading::OrderSide::Buy as i32,
order_type: tli::proto::trading::OrderType::Market as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
order_type: e2e_tests::proto::trading::OrderType::Market as i32,
quantity: 100.0,
price: None, // Market order
time_in_force: tli::proto::trading::TimeInForce::Day as i32,
client_order_id: format!("TEST_ORDER_{}", chrono::Utc::now().timestamp_millis()),
};
// Step 8: Validate order with risk management
info!("⚖️ Validating order with risk management");
let validation_response = trading_client
.validate_order(tli::proto::trading::ValidateOrderRequest {
.validate_order(e2e_tests::proto::risk::ValidateOrderRequest {
symbol: test_order.symbol.clone(),
side: test_order.side,
quantity: test_order.quantity,
@@ -164,12 +165,12 @@ e2e_test!(
// Step 10: Subscribe to order updates
info!("📡 Subscribing to order updates");
let order_updates_request = tli::proto::trading::SubscribeOrderUpdatesRequest {
let order_updates_request = e2e_tests::proto::trading::StreamOrdersRequest {
filter_by_symbol: Some("AAPL".to_string()),
};
let mut order_updates_stream = trading_client
.subscribe_order_updates(order_updates_request)
.stream_orders(order_updates_request)
.await
.context("Failed to subscribe to order updates")?
.into_inner();
@@ -187,7 +188,7 @@ e2e_test!(
Some(Ok(order_update)) => {
info!("📋 Order update: {:?}", order_update);
if order_update.order_id == order_id {
if order_update.status == tli::proto::trading::OrderStatus::Filled as i32 {
if order_update.status == e2e_tests::proto::trading::OrderStatus::Filled as i32 {
order_filled = true;
fill_price = order_update.last_fill_price;
filled_quantity = order_update.filled_quantity;
@@ -217,7 +218,7 @@ e2e_test!(
// Step 12: Verify order status
info!("🔍 Checking final order status");
let order_status = trading_client
.get_order_status(tli::proto::trading::GetOrderStatusRequest {
.get_order_status(e2e_tests::proto::trading::GetOrderStatusRequest {
order_id: order_id.clone(),
})
.await
@@ -231,7 +232,7 @@ e2e_test!(
// Step 13: Verify position update
info!("📊 Verifying position update");
let updated_positions = trading_client
.get_positions(tli::proto::trading::GetPositionsRequest {})
.get_positions(e2e_tests::proto::trading::GetPositionsRequest {})
.await
.context("Failed to get updated positions")?
.into_inner();
@@ -261,7 +262,7 @@ e2e_test!(
// Step 14: Verify account balance update
info!("💰 Verifying account balance update");
let final_account = trading_client
.get_account_info(tli::proto::trading::GetAccountInfoRequest {})
.get_portfolio_summary(e2e_tests::proto::trading::GetPortfolioSummaryRequest {})
.await
.context("Failed to get final account info")?
.into_inner();
@@ -286,7 +287,7 @@ e2e_test!(
// Step 15: Check risk metrics after trade
info!("⚖️ Checking risk metrics after trade");
let risk_metrics = trading_client
.get_risk_metrics(tli::proto::trading::GetRiskMetricsRequest {})
.get_risk_metrics(e2e_tests::proto::risk::GetRiskMetricsRequest {})
.await
.context("Failed to get risk metrics")?
.into_inner();
@@ -349,14 +350,12 @@ e2e_test!(
let trading_client = framework.get_trading_client().await?;
// Submit a limit order that won't fill immediately
let test_order = tli::proto::trading::SubmitOrderRequest {
let test_order = e2e_tests::proto::trading::SubmitOrderRequest {
symbol: "AAPL".to_string(),
side: tli::proto::trading::OrderSide::Buy as i32,
order_type: tli::proto::trading::OrderType::Limit as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
order_type: e2e_tests::proto::trading::OrderType::Limit as i32,
quantity: 100.0,
price: Some(50.0), // Very low price that won't fill
time_in_force: tli::proto::trading::TimeInForce::Day as i32,
client_order_id: format!("CANCEL_TEST_{}", chrono::Utc::now().timestamp_millis()),
};
info!("📝 Submitting limit order that won't fill");
@@ -374,7 +373,7 @@ e2e_test!(
// Check order status - should be pending
let order_status = trading_client
.get_order_status(tli::proto::trading::GetOrderStatusRequest {
.get_order_status(e2e_tests::proto::trading::GetOrderStatusRequest {
order_id: order_id.clone(),
})
.await?
@@ -385,7 +384,7 @@ e2e_test!(
// Cancel the order
info!("❌ Cancelling order");
let cancel_response = trading_client
.cancel_order(tli::proto::trading::CancelOrderRequest {
.cancel_order(e2e_tests::proto::trading::CancelOrderRequest {
order_id: order_id.clone(),
})
.await?
@@ -396,7 +395,7 @@ e2e_test!(
// Verify cancellation
let final_status = trading_client
.get_order_status(tli::proto::trading::GetOrderStatusRequest {
.get_order_status(e2e_tests::proto::trading::GetOrderStatusRequest {
order_id: order_id.clone(),
})
.await?
@@ -416,20 +415,18 @@ e2e_test!(
let trading_client = framework.get_trading_client().await?;
// Try to submit a very large order that should be rejected
let large_order = tli::proto::trading::SubmitOrderRequest {
let large_order = e2e_tests::proto::trading::SubmitOrderRequest {
symbol: "AAPL".to_string(),
side: tli::proto::trading::OrderSide::Buy as i32,
order_type: tli::proto::trading::OrderType::Market as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
order_type: e2e_tests::proto::trading::OrderType::Market as i32,
quantity: 1000000.0, // 1 million shares - should be rejected
price: None,
time_in_force: tli::proto::trading::TimeInForce::Day as i32,
client_order_id: format!("RISK_TEST_{}", chrono::Utc::now().timestamp_millis()),
};
// First validate the order - should be rejected
info!("🚫 Validating large order (should be rejected)");
let validation = trading_client
.validate_order(tli::proto::trading::ValidateOrderRequest {
.validate_order(e2e_tests::proto::risk::ValidateOrderRequest {
symbol: large_order.symbol.clone(),
side: large_order.side,
quantity: large_order.quantity,

View File

@@ -177,13 +177,15 @@ e2e_test!(
let trading_client = framework.get_trading_client().await?;
// Subscribe to market data
let market_data_request = tli::proto::trading::SubscribeMarketDataRequest {
let market_data_request = e2e_tests::proto::trading::StreamMarketDataRequest {
symbols: vec!["AAPL".to_string()],
data_types: vec!["trades".to_string()],
data_types: vec![
e2e_tests::proto::trading::MarketDataType::MarketDataTypeTrade as i32,
],
};
let mut market_stream = trading_client
.subscribe_market_data(market_data_request)
.stream_market_data(market_data_request)
.await?
.into_inner();
@@ -199,7 +201,7 @@ e2e_test!(
market_event = market_stream.next() => {
match market_event {
Some(Ok(event)) => {
if let Some(tli::proto::trading::market_data_event::Event::Tick(tick)) = event.event {
if let Some(e2e_tests::proto::trading::market_data_event::Event::Tick(tick)) = event.event {
let inference_start = Instant::now();
// Convert to our MarketTick format

View File

@@ -105,19 +105,19 @@ e2e_test!(
info!("🎯 ML signal strong enough to generate trading order");
let side = if prediction.signal > 0.0 {
tli::proto::trading::OrderSide::Buy
e2e_tests::proto::trading::OrderSide::Buy
} else {
tli::proto::trading::OrderSide::Sell
e2e_tests::proto::trading::OrderSide::Sell
};
// Validate potential order with risk management
let validation = trading_client
.validate_order(tli::proto::trading::ValidateOrderRequest {
.validate_order(e2e_tests::proto::risk::ValidateOrderRequest {
symbol: "AAPL".to_string(),
side: side as i32,
quantity: 100.0,
price: 150.0,
order_type: tli::proto::trading::OrderType::Limit as i32,
order_type: e2e_tests::proto::trading::OrderType::Limit as i32,
})
.await?
.into_inner();
@@ -166,7 +166,7 @@ e2e_test!(
// Get current trading configuration
let trading_config = trading_client
.get_config(tli::proto::trading::GetConfigRequest {})
.get_config(e2e_tests::proto::trading::GetConfigRequest {})
.await?
.into_inner();
@@ -270,9 +270,9 @@ e2e_test!(
for symbol in &symbols {
if prediction.signal.abs() > 0.5 {
let side = if prediction.signal > 0.0 {
tli::proto::trading::OrderSide::Buy
e2e_tests::proto::trading::OrderSide::Buy
} else {
tli::proto::trading::OrderSide::Sell
e2e_tests::proto::trading::OrderSide::Sell
};
orders_to_execute.push((symbol.to_string(), side, 100.0));
@@ -286,12 +286,12 @@ e2e_test!(
for (symbol, side, quantity) in orders_to_execute {
let validation = trading_client
.validate_order(tli::proto::trading::ValidateOrderRequest {
.validate_order(e2e_tests::proto::risk::ValidateOrderRequest {
symbol: symbol.clone(),
side: side as i32,
quantity,
price: 150.0,
order_type: tli::proto::trading::OrderType::Limit as i32,
order_type: e2e_tests::proto::trading::OrderType::Limit as i32,
})
.await?
.into_inner();

View File

@@ -29,18 +29,16 @@ e2e_test!(
let mut failed_orders = 0;
for i in 0..num_orders {
let order = tli::proto::trading::SubmitOrderRequest {
let order = e2e_tests::proto::trading::SubmitOrderRequest {
symbol: "AAPL".to_string(),
side: if i % 2 == 0 {
tli::proto::trading::OrderSide::Buy
e2e_tests::proto::trading::OrderSide::Buy
} else {
tli::proto::trading::OrderSide::Sell
e2e_tests::proto::trading::OrderSide::Sell
} as i32,
order_type: tli::proto::trading::OrderType::Limit as i32,
order_type: e2e_tests::proto::trading::OrderType::Limit as i32,
quantity: 100.0,
price: Some(150.0 + (i as f64 * 0.1)),
time_in_force: tli::proto::trading::TimeInForce::Day as i32,
client_order_id: format!("THROUGHPUT_TEST_{}", i),
};
let result = trading_client.submit_order(order).await;
@@ -117,14 +115,12 @@ e2e_test!(
let handle = tokio::spawn(async move {
for order_id in 0..orders_per_user {
let order = tli::proto::trading::SubmitOrderRequest {
let order = e2e_tests::proto::trading::SubmitOrderRequest {
symbol: "MSFT".to_string(),
side: tli::proto::trading::OrderSide::Buy as i32,
order_type: tli::proto::trading::OrderType::Market as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
order_type: e2e_tests::proto::trading::OrderType::Market as i32,
quantity: 50.0 + (order_id as f64 * 10.0),
price: None,
time_in_force: tli::proto::trading::TimeInForce::Day as i32,
client_order_id: format!("CONCURRENT_U{}_O{}", user_id, order_id),
};
match client.submit_order(order).await {
@@ -325,12 +321,12 @@ e2e_test!(
let start = Instant::now();
let _result = trading_client
.validate_order(tli::proto::trading::ValidateOrderRequest {
.validate_order(e2e_tests::proto::risk::ValidateOrderRequest {
symbol: "AAPL".to_string(),
side: tli::proto::trading::OrderSide::Buy as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
quantity: 100.0,
price: 150.0,
order_type: tli::proto::trading::OrderType::Limit as i32,
order_type: e2e_tests::proto::trading::OrderType::Limit as i32,
})
.await;
@@ -417,7 +413,7 @@ e2e_test!(
while start.elapsed() < test_duration {
let _result = trading_client
.get_account_info(tli::proto::trading::GetAccountInfoRequest {})
.get_portfolio_summary(e2e_tests::proto::trading::GetPortfolioSummaryRequest {})
.await;
match _result {

View File

@@ -32,7 +32,7 @@ e2e_test!(
// Step 2: Get initial risk metrics baseline
info!("📊 Getting initial risk metrics baseline");
let initial_metrics = trading_client
.get_risk_metrics(tli::proto::trading::GetRiskMetricsRequest {})
.get_risk_metrics(e2e_tests::proto::risk::GetRiskMetricsRequest {})
.await?
.into_inner();
@@ -62,7 +62,7 @@ e2e_test!(
// Step 3: Test portfolio VaR calculation
info!("💼 Testing portfolio VaR calculation");
let var_response = trading_client
.get_va_r(tli::proto::trading::GetVaRRequest {})
.get_va_r(e2e_tests::proto::trading::GetVaRRequest {})
.await?
.into_inner();
@@ -82,7 +82,7 @@ e2e_test!(
// Step 4: Test position risk assessment
info!("🎯 Testing position risk assessment");
let position_risk = trading_client
.get_position_risk(tli::proto::trading::GetPositionRiskRequest {
.get_position_risk(e2e_tests::proto::trading::GetPositionRiskRequest {
symbol: Some("AAPL".to_string()),
})
.await?
@@ -121,12 +121,12 @@ e2e_test!(
// Test a normal order that should pass
let normal_order_validation = trading_client
.validate_order(tli::proto::trading::ValidateOrderRequest {
.validate_order(e2e_tests::proto::risk::ValidateOrderRequest {
symbol: "AAPL".to_string(),
side: tli::proto::trading::OrderSide::Buy as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
quantity: 100.0,
price: 150.0,
order_type: tli::proto::trading::OrderType::Market as i32,
order_type: e2e_tests::proto::trading::OrderType::Market as i32,
})
.await?
.into_inner();
@@ -142,12 +142,12 @@ e2e_test!(
// Test a large order that might be rejected
let large_order_validation = trading_client
.validate_order(tli::proto::trading::ValidateOrderRequest {
.validate_order(e2e_tests::proto::risk::ValidateOrderRequest {
symbol: "AAPL".to_string(),
side: tli::proto::trading::OrderSide::Buy as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
quantity: 100000.0, // Very large order
price: 150.0,
order_type: tli::proto::trading::OrderType::Market as i32,
order_type: e2e_tests::proto::trading::OrderType::Market as i32,
})
.await?
.into_inner();
@@ -183,7 +183,7 @@ e2e_test!(
// Step 6: Test real-time risk alerts
info!("🚨 Testing real-time risk alert system");
let risk_alerts_request = tli::proto::trading::SubscribeRiskAlertsRequest {};
let risk_alerts_request = e2e_tests::proto::trading::SubscribeRiskAlertsRequest {};
let mut risk_alerts_stream = trading_client
.subscribe_risk_alerts(risk_alerts_request)
.await?
@@ -238,14 +238,12 @@ e2e_test!(
let test_orders = 5;
for i in 0..test_orders {
let large_order = tli::proto::trading::SubmitOrderRequest {
let large_order = e2e_tests::proto::trading::SubmitOrderRequest {
symbol: "AAPL".to_string(),
side: tli::proto::trading::OrderSide::Buy as i32,
order_type: tli::proto::trading::OrderType::Market as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
order_type: e2e_tests::proto::trading::OrderType::Market as i32,
quantity: 50000.0, // Large quantity
price: None,
time_in_force: tli::proto::trading::TimeInForce::Day as i32,
client_order_id: format!("CIRCUIT_TEST_{}", i),
};
let result = trading_client.submit_order(large_order).await;
@@ -290,7 +288,7 @@ e2e_test!(
// Trigger emergency stop
let emergency_response = trading_client
.emergency_stop(tli::proto::trading::EmergencyStopRequest {})
.emergency_stop(e2e_tests::proto::trading::EmergencyStopRequest {})
.await?
.into_inner();
@@ -319,14 +317,12 @@ e2e_test!(
info!("🔍 Verifying system state after emergency stop");
// Try to submit an order after emergency stop - should be rejected
let post_emergency_order = tli::proto::trading::SubmitOrderRequest {
let post_emergency_order = e2e_tests::proto::trading::SubmitOrderRequest {
symbol: "AAPL".to_string(),
side: tli::proto::trading::OrderSide::Buy as i32,
order_type: tli::proto::trading::OrderType::Market as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
order_type: e2e_tests::proto::trading::OrderType::Market as i32,
quantity: 100.0,
price: None,
time_in_force: tli::proto::trading::TimeInForce::Day as i32,
client_order_id: format!("POST_EMERGENCY_TEST"),
};
let post_emergency_result = trading_client.submit_order(post_emergency_order).await;
@@ -351,7 +347,7 @@ e2e_test!(
// Step 10: Test final risk metrics
info!("📈 Getting final risk metrics");
let final_metrics = trading_client
.get_risk_metrics(tli::proto::trading::GetRiskMetricsRequest {})
.get_risk_metrics(e2e_tests::proto::risk::GetRiskMetricsRequest {})
.await?
.into_inner();
@@ -424,12 +420,12 @@ e2e_test!(
info!("🎯 Testing scenario: {}", scenario.name);
let validation = trading_client
.validate_order(tli::proto::trading::ValidateOrderRequest {
.validate_order(e2e_tests::proto::risk::ValidateOrderRequest {
symbol: scenario.symbol.clone(),
side: tli::proto::trading::OrderSide::Buy as i32,
side: e2e_tests::proto::trading::OrderSide::Buy as i32,
quantity: scenario.quantity,
price: 100.0,
order_type: tli::proto::trading::OrderType::Market as i32,
order_type: e2e_tests::proto::trading::OrderType::Market as i32,
})
.await?
.into_inner();
@@ -475,16 +471,16 @@ e2e_test!(
let mut failed_validations = 0;
for i in 0..validation_count {
let validation_request = tli::proto::trading::ValidateOrderRequest {
let validation_request = e2e_tests::proto::risk::ValidateOrderRequest {
symbol: "AAPL".to_string(),
side: if i % 2 == 0 {
tli::proto::trading::OrderSide::Buy as i32
e2e_tests::proto::trading::OrderSide::Buy as i32
} else {
tli::proto::trading::OrderSide::Sell as i32
e2e_tests::proto::trading::OrderSide::Sell as i32
},
quantity: 100.0 + (i as f64 * 10.0),
price: 150.0,
order_type: tli::proto::trading::OrderType::Market as i32,
order_type: e2e_tests::proto::trading::OrderType::Market as i32,
};
match trading_client.validate_order(validation_request).await {
@@ -537,7 +533,7 @@ e2e_test!(
let client = framework.get_trading_client().await?.clone();
let handle = tokio::spawn(async move {
client
.get_risk_metrics(tli::proto::trading::GetRiskMetricsRequest {})
.get_risk_metrics(e2e_tests::proto::risk::GetRiskMetricsRequest {})
.await
.map(|r| r.into_inner())
});

View File

@@ -365,8 +365,7 @@ pub mod config {
///
/// # Returns
/// A string in the format "TEST_{counter}"
#[allow(dead_code)]
fn generate_test_id() -> String {
pub fn generate_test_id() -> String {
use std::sync::atomic::{AtomicU64, Ordering};
static COUNTER: AtomicU64 = AtomicU64::new(1);
format!("TEST_{}", COUNTER.fetch_add(1, Ordering::SeqCst))
@@ -374,6 +373,10 @@ fn generate_test_id() -> String {
#[cfg(test)]
mod tests {
use super::*;
use crate::config::TestConfig;
use crate::mocks::MockMarketDataProvider;
use rust_decimal::Decimal;
#[test]
fn test_lib_imports() {

View File

@@ -24,16 +24,7 @@ pub fn init_test_logging() {
/// Test configuration constants
pub mod constants {
use common::error::CommonError;
use common::error::CommonResult;
use common::database::DatabaseConfig;
use common::database::DatabasePool;
use common::Order;
use common::Position;
use common::Symbol;
use common::Price;
use common::Quantity;
use common::HftTimestamp;
use rust_decimal::Decimal;
use std::time::Duration;
pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);