fix: downgrade DQN warn noise to debug, fix clippy warnings, default dev-release
- DQN portfolio_tracker: Phase 1/2 complete logs warn→debug (noisy per-epoch) - risk: lazy_static→LazyLock, .map→.inspect, midpoint overflow fixes - risk: remove unused POSITION_PROCESSING_LATENCY, lazy_static dep - CI: default DEV_RELEASE=true for fast iteration (thin LTO, 24% faster) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -41,9 +41,10 @@ variables:
|
||||
# sccache base dir on PVC — GPU stages override to /mnt/sccache/sm_<cap>
|
||||
SCCACHE_DIR: "/mnt/sccache"
|
||||
RUSTC_WRAPPER: /usr/local/bin/sccache
|
||||
# Build profile: "release" (default, fat LTO) or "dev-release" (thin LTO, fast)
|
||||
# Set DEV_RELEASE=true in pipeline vars or CI/CD settings to use fast profile
|
||||
CARGO_BUILD_PROFILE: release
|
||||
# Build profile: "dev-release" (thin LTO, fast) is default for quick iteration
|
||||
# Set DEV_RELEASE=false in pipeline vars to use full "release" (fat LTO) profile
|
||||
DEV_RELEASE: "true"
|
||||
CARGO_BUILD_PROFILE: dev-release
|
||||
# S3 credentials for Kaniko registry auth and Dockerfile builds
|
||||
AWS_ACCESS_KEY_ID: $SCW_ACCESS_KEY
|
||||
AWS_SECRET_ACCESS_KEY: $SCW_SECRET_KEY
|
||||
|
||||
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -8252,7 +8252,6 @@ dependencies = [
|
||||
"fastrand",
|
||||
"futures",
|
||||
"hdrhistogram",
|
||||
"lazy_static",
|
||||
"nalgebra 0.33.2",
|
||||
"ndarray",
|
||||
"num",
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
use super::action_space::FactoredAction;
|
||||
use super::agent::TradingAction;
|
||||
use tracing::warn;
|
||||
use tracing::{debug, warn};
|
||||
|
||||
/// Trade action enum with quantities for TradeExecutor
|
||||
///
|
||||
@@ -290,7 +290,7 @@ impl PortfolioTracker {
|
||||
self.position_size = 0.0;
|
||||
self.position_entry_price = 0.0;
|
||||
|
||||
warn!(
|
||||
debug!(
|
||||
"P2-C: Phase 1 complete - Closed position {:.2} → 0.0, Cash: ${:.2} → ${:.2}",
|
||||
old_position, self.cash - phase1_cash_change, self.cash
|
||||
);
|
||||
@@ -343,7 +343,7 @@ impl PortfolioTracker {
|
||||
self.position_size = actual_phase2_position;
|
||||
self.position_entry_price = price;
|
||||
|
||||
warn!(
|
||||
debug!(
|
||||
"P2-C: Phase 2 complete - Opened position {:.2} (target: {:.2}), Cash: ${:.2}",
|
||||
actual_phase2_position, phase2_target, self.cash
|
||||
);
|
||||
|
||||
@@ -50,7 +50,6 @@ redis.workspace = true
|
||||
serde_json.workspace = true
|
||||
nalgebra.workspace = true
|
||||
prometheus.workspace = true
|
||||
lazy_static.workspace = true
|
||||
async-trait.workspace = true
|
||||
reqwest.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
|
||||
@@ -191,14 +191,13 @@ pub fn decimal_to_f64_safe(value: Decimal, context: &str) -> RiskResult<f64> {
|
||||
reason: format!("Conversion failed for value {value} in {context}"),
|
||||
}
|
||||
})
|
||||
.map(|result| {
|
||||
.inspect(|result| {
|
||||
debug!(
|
||||
value = %value,
|
||||
context = context,
|
||||
result = result,
|
||||
"Decimal to f64 conversion successful"
|
||||
);
|
||||
result
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -626,7 +626,7 @@ impl PortfolioOptimizer {
|
||||
let target_return = if num_points > 1 {
|
||||
min_return + (max_return - min_return) * (i as f64) / ((num_points - 1) as f64)
|
||||
} else {
|
||||
(min_return + max_return) / 2.0
|
||||
f64::midpoint(min_return, max_return)
|
||||
};
|
||||
|
||||
// For each target return, find minimum variance portfolio
|
||||
|
||||
@@ -18,7 +18,7 @@ use common::types::{Price, Quantity, Symbol};
|
||||
use rust_decimal::Decimal;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::{broadcast, RwLock};
|
||||
use tracing::{debug, error, info, warn};
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use crate::error::{decimal_to_f64_safe, f64_to_price_safe, RiskError, RiskResult};
|
||||
use crate::risk_types::{
|
||||
@@ -28,183 +28,56 @@ use config::AssetClassificationConfig;
|
||||
// CANONICAL TYPE IMPORTS - ENFORCED BY TYPE SYSTEM AGENT
|
||||
|
||||
// Prometheus metrics integration
|
||||
use lazy_static::lazy_static;
|
||||
use prometheus::{
|
||||
register_counter, register_gauge, register_histogram, register_int_gauge, Counter, Gauge,
|
||||
Histogram, HistogramOpts, IntGauge,
|
||||
register_counter, register_gauge, register_int_gauge, Counter, Gauge, IntGauge,
|
||||
};
|
||||
use std::sync::LazyLock;
|
||||
|
||||
lazy_static! {
|
||||
static ref POSITION_UPDATES_COUNTER: Counter = register_counter!(
|
||||
"foxhunt_position_updates_total",
|
||||
"Total position updates processed"
|
||||
).unwrap_or_else(|e| {
|
||||
warn!("Failed to register position updates counter: {}", e);
|
||||
// Safe fallback: If even basic counter creation fails, return a default counter
|
||||
// This should never happen in practice, but eliminates panic possibility
|
||||
Counter::new("position_updates_fallback", "Fallback counter").unwrap_or_else(|_| {
|
||||
error!("Critical: All counter creation failed - using no-op metrics");
|
||||
// Create a dummy counter that won't panic - metrics will be lost but system stays up
|
||||
Counter::new("noop_counter", "No-op counter for safety").unwrap_or_else(|_| {
|
||||
// Absolute fallback - create a minimal counter and log the error but continue operating
|
||||
error!("CRITICAL: Complete metrics subsystem failure - continuing without metrics");
|
||||
// Create the simplest possible counter that should always work
|
||||
Counter::new("emergency", "Emergency fallback counter")
|
||||
.unwrap_or_else(|_| {
|
||||
error!("FATAL: Cannot create any metrics - system continuing with no-op metrics");
|
||||
// Last resort: use a basic counter implementation
|
||||
prometheus::core::GenericCounter::new("basic", "basic counter")
|
||||
.unwrap_or_else(|_| {
|
||||
// Ultimate fallback - if this fails, we create a default counter
|
||||
prometheus::core::GenericCounter::new("fallback", "fallback counter")
|
||||
.unwrap_or_else(|_| {
|
||||
// Create a basic counter as last resort
|
||||
Counter::new("emergency_fallback", "emergency fallback counter")
|
||||
.unwrap_or_else(|_| {
|
||||
match Counter::new("emergency_fallback_fallback", "emergency fallback") {
|
||||
Ok(c) => c,
|
||||
Err(_) => std::process::abort(),
|
||||
}
|
||||
})
|
||||
})
|
||||
}) })
|
||||
static POSITION_UPDATES_COUNTER: LazyLock<Counter> = LazyLock::new(|| {
|
||||
register_counter!("foxhunt_position_updates_total", "Total position updates processed")
|
||||
.unwrap_or_else(|e| {
|
||||
warn!("Failed to register position updates counter: {}", e);
|
||||
Counter::new("position_updates_fallback", "Fallback counter")
|
||||
.unwrap_or_else(|_| std::process::abort())
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
static ref POSITION_VALUE_GAUGE: Gauge = register_gauge!(
|
||||
"foxhunt_current_position_value_usd",
|
||||
"Current total position value in USD"
|
||||
).unwrap_or_else(|e| {
|
||||
warn!("Failed to register position value gauge: {}", e);
|
||||
Gauge::new("position_value_fallback", "Fallback gauge").unwrap_or_else(|_| {
|
||||
error!("Critical: All gauge creation failed - using no-op metrics");
|
||||
Gauge::new("noop_gauge", "No-op gauge for safety").unwrap_or_else(|_| {
|
||||
error!("CRITICAL: Complete gauge metrics failure - continuing without position value metrics");
|
||||
Gauge::new("emergency_gauge", "Emergency fallback gauge")
|
||||
.unwrap_or_else(|_| {
|
||||
error!("FATAL: Cannot create any gauge metrics - system continuing");
|
||||
prometheus::core::GenericGauge::new("basic_gauge", "basic gauge")
|
||||
.unwrap_or_else(|_| {
|
||||
prometheus::core::GenericGauge::new("fallback_gauge", "fallback gauge")
|
||||
.unwrap_or_else(|_| {
|
||||
// Create a basic gauge as last resort
|
||||
match Gauge::new("emergency_fallback_gauge", "emergency fallback gauge") {
|
||||
Ok(g) => g,
|
||||
Err(_) => std::process::abort(),
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
static POSITION_VALUE_GAUGE: LazyLock<Gauge> = LazyLock::new(|| {
|
||||
register_gauge!("foxhunt_current_position_value_usd", "Current total position value in USD")
|
||||
.unwrap_or_else(|e| {
|
||||
warn!("Failed to register position value gauge: {}", e);
|
||||
Gauge::new("position_value_fallback", "Fallback gauge")
|
||||
.unwrap_or_else(|_| std::process::abort())
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
static ref CONCENTRATION_RISK_GAUGE: Gauge = register_gauge!(
|
||||
"foxhunt_concentration_risk_score",
|
||||
"Portfolio concentration risk score (HHI)"
|
||||
).unwrap_or_else(|e| {
|
||||
warn!("Failed to register concentration risk gauge: {}", e);
|
||||
Gauge::new("concentration_risk_fallback", "Fallback gauge").unwrap_or_else(|_| {
|
||||
error!("Critical: All concentration gauge creation failed - using no-op metrics");
|
||||
Gauge::new("noop_concentration", "No-op concentration gauge").unwrap_or_else(|_| {
|
||||
error!("CRITICAL: Complete concentration gauge failure - continuing without concentration metrics");
|
||||
Gauge::new("emergency_concentration", "Emergency concentration gauge")
|
||||
.unwrap_or_else(|_| {
|
||||
error!("FATAL: Cannot create any concentration gauge - system continuing");
|
||||
prometheus::core::GenericGauge::new("basic_concentration", "basic")
|
||||
.unwrap_or_else(|_| {
|
||||
match prometheus::core::GenericGauge::new("fallback_concentration", "fallback") {
|
||||
Ok(g) => g,
|
||||
Err(_) => std::process::abort(),
|
||||
}
|
||||
})
|
||||
})
|
||||
static CONCENTRATION_RISK_GAUGE: LazyLock<Gauge> = LazyLock::new(|| {
|
||||
register_gauge!("foxhunt_concentration_risk_score", "Portfolio concentration risk score (HHI)")
|
||||
.unwrap_or_else(|e| {
|
||||
warn!("Failed to register concentration risk gauge: {}", e);
|
||||
Gauge::new("concentration_risk_fallback", "Fallback gauge")
|
||||
.unwrap_or_else(|_| std::process::abort())
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
static ref PORTFOLIO_COUNT_GAUGE: IntGauge = register_int_gauge!(
|
||||
"foxhunt_active_portfolios",
|
||||
"Number of active portfolios"
|
||||
).unwrap_or_else(|e| {
|
||||
warn!("Failed to register portfolio count gauge: {}", e);
|
||||
IntGauge::new("portfolio_count_fallback", "Fallback gauge").unwrap_or_else(|_| {
|
||||
error!("Critical: All portfolio gauge creation failed - using no-op metrics");
|
||||
IntGauge::new("noop_portfolio", "No-op portfolio gauge").unwrap_or_else(|_| {
|
||||
error!("CRITICAL: Complete portfolio gauge failure - continuing without portfolio count metrics");
|
||||
IntGauge::new("emergency_portfolio", "Emergency portfolio gauge")
|
||||
.unwrap_or_else(|_| {
|
||||
error!("FATAL: Cannot create any portfolio gauge - system continuing");
|
||||
prometheus::core::GenericGauge::new("basic_portfolio", "basic")
|
||||
.unwrap_or_else(|_| {
|
||||
match prometheus::core::GenericGauge::new("fallback_portfolio", "fallback") {
|
||||
Ok(g) => g,
|
||||
Err(_) => std::process::abort(),
|
||||
}
|
||||
})
|
||||
})
|
||||
static PORTFOLIO_COUNT_GAUGE: LazyLock<IntGauge> = LazyLock::new(|| {
|
||||
register_int_gauge!("foxhunt_active_portfolios", "Number of active portfolios")
|
||||
.unwrap_or_else(|e| {
|
||||
warn!("Failed to register portfolio count gauge: {}", e);
|
||||
IntGauge::new("portfolio_count_fallback", "Fallback gauge")
|
||||
.unwrap_or_else(|_| std::process::abort())
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
static ref RISK_BREACHES_COUNTER: Counter = register_counter!(
|
||||
"foxhunt_concentration_breaches_total",
|
||||
"Total concentration limit breaches"
|
||||
).unwrap_or_else(|e| {
|
||||
warn!("Failed to register concentration breaches counter: {}", e);
|
||||
if let Ok(counter) = Counter::new("concentration_breaches_fallback", "Fallback counter") { counter } else {
|
||||
error!("Critical: Breaches counter creation failed - metrics may be inaccurate");
|
||||
Counter::new("emergency_breaches_fallback", "Emergency fallback").unwrap_or_else(|_| {
|
||||
error!("FATAL: Complete breaches counter creation failed - system continuing with no-op counter");
|
||||
// Last resort: Create the simplest possible counter that should always work
|
||||
prometheus::core::GenericCounter::new("noop_breaches", "no-op breaches counter")
|
||||
.unwrap_or_else(|_| {
|
||||
match prometheus::core::GenericCounter::new("ultimate_fallback", "ultimate fallback") {
|
||||
Ok(c) => c,
|
||||
Err(_) => std::process::abort(),
|
||||
}
|
||||
})
|
||||
static RISK_BREACHES_COUNTER: LazyLock<Counter> = LazyLock::new(|| {
|
||||
register_counter!("foxhunt_concentration_breaches_total", "Total concentration limit breaches")
|
||||
.unwrap_or_else(|e| {
|
||||
warn!("Failed to register concentration breaches counter: {}", e);
|
||||
Counter::new("concentration_breaches_fallback", "Fallback counter")
|
||||
.unwrap_or_else(|_| std::process::abort())
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
static ref POSITION_PROCESSING_LATENCY: Histogram = register_histogram!(
|
||||
HistogramOpts::new(
|
||||
"foxhunt_position_processing_latency_microseconds",
|
||||
"Position update processing latency"
|
||||
).buckets(vec![1.0, 5.0, 10.0, 25.0, 50.0, 100.0, 250.0, 500.0])
|
||||
).unwrap_or_else(|e| {
|
||||
warn!("Failed to register position processing latency histogram: {}", e);
|
||||
if let Ok(histogram) = Histogram::with_opts(HistogramOpts::new(
|
||||
"position_processing_latency_fallback",
|
||||
"Fallback histogram"
|
||||
)) { histogram } else {
|
||||
error!("Critical: Even fallback histogram creation failed - metrics may be inaccurate");
|
||||
Histogram::with_opts(HistogramOpts::new(
|
||||
"emergency_histogram_fallback",
|
||||
"Emergency fallback"
|
||||
)).unwrap_or_else(|_| {
|
||||
error!("FATAL: Complete histogram creation failed - system continuing with no-op histogram");
|
||||
// Last resort: Create the simplest possible histogram that should always work
|
||||
Histogram::with_opts(HistogramOpts::new(
|
||||
"noop_histogram",
|
||||
"No-op histogram for safety"
|
||||
)).unwrap_or_else(|_| {
|
||||
error!("CRITICAL: Cannot create any histogram - using basic histogram implementation");
|
||||
// Use default histogram with basic configuration
|
||||
Histogram::with_opts(
|
||||
HistogramOpts::new("basic_histogram", "basic")
|
||||
).unwrap_or_else(|_| match Histogram::with_opts(
|
||||
HistogramOpts::new("fallback_histogram", "fallback")
|
||||
) {
|
||||
Ok(h) => h,
|
||||
Err(_) => std::process::abort(),
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
});}
|
||||
|
||||
/// **Position Concentration Limits and Monitoring Configuration**
|
||||
///
|
||||
|
||||
@@ -393,7 +393,7 @@ impl ExpectedShortfall {
|
||||
bootstrap_es.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
|
||||
|
||||
let lower_idx = ((1.0 - confidence_interval) / 2.0 * f64::from(n_bootstrap)) as usize;
|
||||
let upper_idx = ((1.0 + confidence_interval) / 2.0 * f64::from(n_bootstrap)) as usize;
|
||||
let upper_idx = (f64::midpoint(1.0, confidence_interval) * f64::from(n_bootstrap)) as usize;
|
||||
|
||||
Ok(ESResult {
|
||||
expected_shortfall: base_es.into(),
|
||||
|
||||
Reference in New Issue
Block a user