use deadeye_collateral::{MinimizationPolicy, lambda, normal_collateral};
use deadeye_core::{Distribution, NormalDistribution, Sq128};
const N_SIGMA_SAMPLES: u32 = 50;
const N_MEAN_SAMPLES: u32 = 50;
const DEFAULT_MAX_SIGMA_RATIO: f64 = 4.0_f64;
const DEFAULT_MAX_MEAN_SEP_SIGMAS: f64 = 4.0_f64;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct OptimizerConstraints {
pub max_sigma_ratio: f64,
pub max_mean_sep_sigmas: f64,
}
impl Default for OptimizerConstraints {
fn default() -> Self {
Self {
max_sigma_ratio: DEFAULT_MAX_SIGMA_RATIO,
max_mean_sep_sigmas: DEFAULT_MAX_MEAN_SEP_SIGMAS,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct NormalOptimizationInput {
pub budget: f64,
pub belief_mean: f64,
pub belief_sigma: f64,
pub market_mean: f64,
pub market_sigma: f64,
pub effective_k: f64,
pub payout_amplifier: f64,
pub constraints: OptimizerConstraints,
}
impl NormalOptimizationInput {
#[must_use]
pub fn new(
budget: f64,
belief_mean: f64,
belief_sigma: f64,
market_mean: f64,
market_sigma: f64,
effective_k: f64,
) -> Self {
Self {
budget,
belief_mean,
belief_sigma,
market_mean,
market_sigma,
effective_k,
payout_amplifier: 1.0,
constraints: OptimizerConstraints::default(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct NormalOptimizationResult {
pub optimized_mean: f64,
pub optimized_sigma: f64,
pub optimized_variance: f64,
pub collateral_required: f64,
pub expected_value: f64,
pub belief_utilization: f64,
pub is_budget_sufficient: bool,
pub budget_surplus: f64,
pub roi: f64,
}
fn gaussian_product_integral(mu1: f64, sigma1: f64, mu2: f64, sigma2: f64) -> f64 {
let sum_var = sigma1.mul_add(sigma1, sigma2 * sigma2);
if sum_var <= 0.0 {
return 0.0;
}
let diff_mu = mu1 - mu2;
(1.0 / (2.0 * core::f64::consts::PI * sum_var).sqrt())
* (-(diff_mu * diff_mu) / (2.0 * sum_var)).exp()
}
fn collateral_number(mu_f: f64, sigma_f: f64, mu_g: f64, sigma_g: f64, k: f64) -> f64 {
if (mu_f - mu_g).abs() < 1e-12_f64 && (sigma_f - sigma_g).abs() < 1e-12_f64 {
return 0.0;
}
let Ok(mean_f) = Sq128::from_f64(mu_f) else {
return f64::INFINITY;
};
let Ok(var_f) = Sq128::from_f64(sigma_f * sigma_f) else {
return f64::INFINITY;
};
let Ok(mean_g) = Sq128::from_f64(mu_g) else {
return f64::INFINITY;
};
let Ok(var_g) = Sq128::from_f64(sigma_g * sigma_g) else {
return f64::INFINITY;
};
let Ok(f) = NormalDistribution::from_variance(mean_f, var_f) else {
return f64::INFINITY;
};
let Ok(g) = NormalDistribution::from_variance(mean_g, var_g) else {
return f64::INFINITY;
};
let verified = match normal_collateral(&f, &g, MinimizationPolicy::unrestricted()) {
Ok(v) if v.collateral.is_finite() => v,
_ => return f64::INFINITY,
};
if verified.collateral <= 0.0 {
return 0.0;
}
let lam_f = lambda(sigma_f, k);
let lam_g = lambda(sigma_g, k);
let Ok(x_q) = Sq128::from_f64(verified.x_min) else {
return f64::INFINITY;
};
let f_at = f.pdf(x_q).map(Sq128::to_f64).unwrap_or(0.0);
let g_at = g.pdf(x_q).map(Sq128::to_f64).unwrap_or(0.0);
let scaled = lam_f.mul_add(f_at, -(lam_g * g_at)).max(0.0);
if scaled.is_finite() { scaled } else { f64::INFINITY }
}
#[expect(
clippy::too_many_arguments,
reason = "EV depends on 8 distinct numeric inputs; bundling them adds churn without value"
)]
fn expected_value(
mu_f: f64,
sigma_f: f64,
mu_g: f64,
sigma_g: f64,
k: f64,
belief_mu: f64,
belief_sigma: f64,
amplifier: f64,
) -> f64 {
let lam_g = lambda(sigma_g, k);
let lam_f = lambda(sigma_f, k);
let raw_ev = lam_g.mul_add(
gaussian_product_integral(mu_g, sigma_g, belief_mu, belief_sigma),
-(lam_f * gaussian_product_integral(mu_f, sigma_f, belief_mu, belief_sigma)),
);
amplifier * raw_ev
}
#[must_use]
pub fn optimize_normal_trade(input: NormalOptimizationInput) -> NormalOptimizationResult {
let no_trade = NormalOptimizationResult {
optimized_mean: input.market_mean,
optimized_sigma: input.market_sigma,
optimized_variance: input.market_sigma * input.market_sigma,
collateral_required: 0.0,
expected_value: 0.0,
belief_utilization: 0.0,
is_budget_sufficient: false,
budget_surplus: input.budget,
roi: 0.0,
};
if input.budget <= 0.0 || input.market_sigma <= 0.0 || input.effective_k <= 0.0 {
return no_trade;
}
let sigma_min = (input.market_sigma / input.constraints.max_sigma_ratio).max(1e-6_f64);
let sigma_max = input.market_sigma * input.constraints.max_sigma_ratio;
let sigma_step = (sigma_max - sigma_min) / f64::from(N_SIGMA_SAMPLES);
let mean_dir = if input.belief_mean >= input.market_mean {
1.0_f64
} else {
-1.0_f64
};
let max_shift = input.constraints.max_mean_sep_sigmas * input.market_sigma;
let mut best_net = f64::NEG_INFINITY;
let mut best_mu = input.market_mean;
let mut best_sigma = input.market_sigma;
let mut best_coll = 0.0_f64;
let mut best_ev = 0.0_f64;
for i in 0..=N_SIGMA_SAMPLES {
let cand_sigma = f64::from(i).mul_add(sigma_step, sigma_min);
for j in 0..=N_MEAN_SAMPLES {
let shift = (f64::from(j) / f64::from(N_MEAN_SAMPLES)) * max_shift;
let cand_mu = mean_dir.mul_add(shift, input.market_mean);
let coll = collateral_number(
input.market_mean,
input.market_sigma,
cand_mu,
cand_sigma,
input.effective_k,
);
if coll < 0.0 || coll > input.budget {
continue;
}
let ev = expected_value(
input.market_mean,
input.market_sigma,
cand_mu,
cand_sigma,
input.effective_k,
input.belief_mean,
input.belief_sigma,
input.payout_amplifier,
);
let net = ev - coll;
if net > best_net {
best_net = net;
best_mu = cand_mu;
best_sigma = cand_sigma;
best_coll = coll;
best_ev = ev;
}
}
}
if best_net <= 0.0 || best_coll <= 0.0 {
return no_trade;
}
let full_shift = (input.belief_mean - input.market_mean).abs();
let achieved_shift = (best_mu - input.market_mean).abs();
let utilization = if full_shift > 1e-6_f64 {
(achieved_shift / full_shift).min(1.0)
} else {
1.0
};
NormalOptimizationResult {
optimized_mean: best_mu,
optimized_sigma: best_sigma,
optimized_variance: best_sigma * best_sigma,
collateral_required: best_coll,
expected_value: best_ev,
belief_utilization: utilization,
is_budget_sufficient: (best_mu - input.belief_mean).abs() < sigma_step * 0.5
&& (best_sigma - input.belief_sigma).abs() < sigma_step * 0.5,
budget_surplus: input.budget - best_coll,
roi: best_net / best_coll,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zero_budget_yields_no_trade() {
let input = NormalOptimizationInput::new(0.0, 105.0, 1.0, 100.0, 2.0, 50.0);
let r = optimize_normal_trade(input);
assert!(r.collateral_required.abs() < 1e-12);
assert!((r.optimized_mean - 100.0).abs() < 1e-12);
}
#[test]
fn zero_market_sigma_yields_no_trade() {
let input = NormalOptimizationInput::new(100.0, 105.0, 1.0, 100.0, 0.0, 50.0);
let r = optimize_normal_trade(input);
assert!(r.collateral_required.abs() < 1e-12);
}
#[test]
fn picks_a_trade_under_reasonable_budget() {
let input = NormalOptimizationInput::new(100.0, 105.0, 1.0, 100.0, 2.0, 50.0);
let r = optimize_normal_trade(input);
assert!(r.collateral_required >= 0.0);
assert!(r.budget_surplus <= input.budget);
assert!(r.optimized_mean >= input.market_mean);
}
#[test]
fn sigma_arb_with_equal_mu_returns_no_trade_under_chain_pricing() {
let input = NormalOptimizationInput::new(
50.0, 4.3274, 0.2143, 4.2900, 0.3500, 75.07, );
let r = optimize_normal_trade(input);
assert!(
r.collateral_required.abs() < 1e-12,
"expected no-trade under chain pricing, got coll={}",
r.collateral_required,
);
}
#[test]
fn pure_sigma_arb_returns_no_trade_under_chain_pricing() {
let input = NormalOptimizationInput::new(50.0, 4.29, 0.21, 4.29, 0.35, 75.07);
let r = optimize_normal_trade(input);
assert!(
r.collateral_required.abs() < 1e-12,
"expected no-trade under chain pricing, got coll={}",
r.collateral_required,
);
}
#[test]
fn low_k_sigma_arb_finds_trade() {
let input = NormalOptimizationInput::new(
100.0, 0.0, 0.5, 0.0, 4.0, 1.0, );
let r = optimize_normal_trade(input);
assert!(
r.collateral_required > 0.0,
"expected positive trade at low-k, got coll={}",
r.collateral_required,
);
assert!(
r.expected_value > r.collateral_required,
"expected positive net (ev={} > coll={})",
r.expected_value, r.collateral_required,
);
assert!(r.optimized_sigma < input.market_sigma * 0.9);
assert!(r.collateral_required <= input.budget + 1e-9);
}
#[test]
fn test_budget_filter_must_use_lambda_scaled_cost() {
let input = NormalOptimizationInput::new(
5.0, 4.29, 0.10, 4.29, 0.35, 75.07, );
let r = optimize_normal_trade(input);
assert!(
r.collateral_required <= input.budget + 1e-9,
"budget filter leak: returned coll={} > budget={}",
r.collateral_required,
input.budget,
);
assert!(
r.expected_value >= r.collateral_required,
"filter accepted a negative-net candidate",
);
}
#[test]
fn test_candidate_selection_must_use_lambda_scaled_units() {
let mu_m = 0.0_f64;
let sigma_m = 1.0_f64;
let k = 100.0_f64;
let mu_b = 1.5_f64;
let sigma_b = 0.4_f64;
let budget = 50.0_f64;
let r = optimize_normal_trade(NormalOptimizationInput::new(
budget, mu_b, sigma_b, mu_m, sigma_m, k,
));
let net = r.expected_value - r.collateral_required;
assert!(
net >= 0.0,
"λ-scaled net must be non-negative (got ev={} coll={})",
r.expected_value,
r.collateral_required,
);
let recomputed = collateral_number(
mu_m, sigma_m, r.optimized_mean, r.optimized_sigma, k,
);
let diff = (recomputed - r.collateral_required).abs();
let tol = 1e-6_f64.max(r.collateral_required.abs() * 1e-9);
assert!(
diff < tol,
"reported λ-scaled coll {} disagrees with re-derivation {} (diff {})",
r.collateral_required, recomputed, diff,
);
assert!(r.collateral_required <= budget + 1e-9);
}
}