← back to krejcif__rdex

Function bodies 248 total

All specs Real LLM only Function bodies
transfer_priors function · rust · L250-L275 (26 LOC)
src/engine/thompson.rs
    pub fn transfer_priors(
        &mut self,
        source: &str,
        target: &str,
    ) {
        let priors = self.extract_priors(source);
        for (ctx, arms) in priors {
            for (arm, params) in arms {
                let dampened = BetaParams {
                    alpha: 1.0 + (params.alpha - 1.0).sqrt(),
                    beta: 1.0 + (params.beta - 1.0).sqrt(),
                };
                self.arms
                    .entry(target.to_string())
                    .or_default()
                    .entry(ctx.clone())
                    .or_default()
                    .entry(arm)
                    .or_insert_with(|| {
                        let mut db = DecayingBeta::new(self.decay_factor);
                        db.params = dampened;
                        db
                    });
            }
        }
    }
test_context function · rust · L281-L287 (7 LOC)
src/engine/thompson.rs
    fn test_context() -> MarketContext {
        MarketContext {
            volatility_tier: "medium".into(),
            trend_regime: "uptrend".into(),
        }
    }
test_beta_params function · rust · L290-L295 (6 LOC)
src/engine/thompson.rs
    fn test_beta_params() {
        let mut b = BetaParams::uniform();
        assert!((b.mean() - 0.5).abs() < 1e-10);
        b.update(1.0);
        assert!(b.mean() > 0.5);
    }
test_beta_sampling_in_range function · rust · L298-L305 (8 LOC)
src/engine/thompson.rs
    fn test_beta_sampling_in_range() {
        let b = BetaParams { alpha: 10.0, beta: 5.0 };
        let mut rng = rand::thread_rng();
        for _ in 0..100 {
            let s = b.sample(&mut rng);
            assert!(s >= 0.0 && s <= 1.0);
        }
    }
test_decaying_beta function · rust · L308-L315 (8 LOC)
src/engine/thompson.rs
    fn test_decaying_beta() {
        let mut db = DecayingBeta::new(0.995);
        for _ in 0..100 {
            db.update(0.8);
        }
        assert!(db.params.mean() > 0.7);
        assert!((db.effective_window() - 200.0).abs() < 1.0);
    }
test_thompson_engine_select function · rust · L318-L328 (11 LOC)
src/engine/thompson.rs
    fn test_thompson_engine_select() {
        let mut engine = ThompsonEngine::new(
            vec!["momentum".into(), "mean_reversion".into(), "breakout".into(), "scalping".into()],
            0.995,
        );
        let ctx = test_context();
        let mut rng = rand::thread_rng();

        let arm = engine.select_arm("BTCUSDT", &ctx, &mut rng);
        assert!(!arm.0.is_empty());
    }
test_thompson_engine_learns function · rust · L331-L353 (23 LOC)
src/engine/thompson.rs
    fn test_thompson_engine_learns() {
        let mut engine = ThompsonEngine::new(
            vec!["good".into(), "bad".into()],
            0.995,
        );
        let ctx = test_context();

        // Train: "good" arm always wins
        for _ in 0..100 {
            engine.record_outcome("BTCUSDT", &ctx, &StrategyId("good".into()), 0.9);
            engine.record_outcome("BTCUSDT", &ctx, &StrategyId("bad".into()), 0.1);
        }

        // Engine should now prefer "good"
        let mut rng = rand::thread_rng();
        let mut good_count = 0;
        for _ in 0..100 {
            if engine.select_arm("BTCUSDT", &ctx, &mut rng).0 == "good" {
                good_count += 1;
            }
        }
        assert!(good_count > 80, "Engine should select good arm most of the time, got {}", good_count);
    }
Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
test_transfer_priors function · rust · L356-L380 (25 LOC)
src/engine/thompson.rs
    fn test_transfer_priors() {
        let mut engine = ThompsonEngine::new(
            vec!["a".into(), "b".into()],
            // Use higher decay so evidence doesn't decay away
            0.999,
        );
        let ctx = test_context();

        // Train on BTC with lots of observations to accumulate evidence > 10
        for _ in 0..100 {
            engine.record_outcome("BTCUSDT", &ctx, &StrategyId("a".into()), 0.85);
            engine.record_outcome("BTCUSDT", &ctx, &StrategyId("b".into()), 0.3);
        }

        // Verify source has enough evidence
        let src_priors = engine.extract_priors("BTCUSDT");
        assert!(!src_priors.is_empty(), "BTC should have priors with sufficient evidence");

        // Transfer to ETH
        engine.transfer_priors("BTCUSDT", "ETHUSDT");

        // ETH should now have informative priors
        let eth_a = engine.get_beta("ETHUSDT", &ctx, &StrategyId("a".into()));
        assert!(eth_a.params.mean() > 0.5, "Transferred prior sh
test_uncertainty_detection function · rust · L383-L399 (17 LOC)
src/engine/thompson.rs
    fn test_uncertainty_detection() {
        let mut engine = ThompsonEngine::new(
            vec!["a".into(), "b".into()],
            0.995,
        );
        let ctx = test_context();

        // Uniform priors -> uncertain
        assert!(engine.is_uncertain("BTCUSDT", &ctx, 0.1));

        // After training, should be certain
        for _ in 0..100 {
            engine.record_outcome("BTCUSDT", &ctx, &StrategyId("a".into()), 0.95);
            engine.record_outcome("BTCUSDT", &ctx, &StrategyId("b".into()), 0.1);
        }
        assert!(!engine.is_uncertain("BTCUSDT", &ctx, 0.1));
    }
new function · rust · L50-L67 (18 LOC)
src/engine/trade_manager.rs
    pub fn new() -> Self {
        Self {
            current_sl: None,
            current_tp: None,
            current_strategy: String::new(),
            candles_held: 0,
            max_adverse: 0.0,
            max_favorable: 0.0,
            cooldown_remaining: 0,
            current_pattern: None,
            entry_atr: 0.0,
            accumulated_funding: 0.0,
            entry_confidence: 0.0,
            equity_at_entry: 0.0,
            position_size_frac: 0.0,
            exit_reason: String::new(),
        }
    }
tick_cooldown function · rust · L70-L77 (8 LOC)
src/engine/trade_manager.rs
    pub fn tick_cooldown(&mut self) -> bool {
        if self.cooldown_remaining > 0 {
            self.cooldown_remaining -= 1;
            true
        } else {
            false
        }
    }
on_candle function · rust · L82-L120 (39 LOC)
src/engine/trade_manager.rs
    pub fn on_candle(
        &mut self,
        candle: &Candle,
        position: &Position,
        learning: &LearningEngine,
    ) -> TradeAction {
        self.candles_held += 1;

        // Track excursions
        let adverse = match position.side {
            PositionSide::Long => (position.entry_price - candle.low) / position.entry_price * 100.0,
            PositionSide::Short => (candle.high - position.entry_price) / position.entry_price * 100.0,
            PositionSide::Flat => 0.0,
        };
        self.max_adverse = self.max_adverse.max(adverse);

        let favorable = match position.side {
            PositionSide::Long => (candle.high - position.entry_price) / position.entry_price * 100.0,
            PositionSide::Short => (position.entry_price - candle.low) / position.entry_price * 100.0,
            PositionSide::Flat => 0.0,
        };
        self.max_favorable = self.max_favorable.max(favorable.max(0.0));

        // Adaptive trailing stop
        if self.e
check_sl_tp function · rust · L124-L151 (28 LOC)
src/engine/trade_manager.rs
    pub fn check_sl_tp(&self, candle: &Candle, position: &Position, learning: &LearningEngine) -> Option<f64> {
        let min_hold = learning.adaptive.min_hold();
        if self.candles_held < min_hold {
            return None;
        }

        match position.side {
            PositionSide::Long => {
                if let Some(sl) = self.current_sl {
                    if candle.low <= sl { return Some(sl); }
                }
                if let Some(tp) = self.current_tp {
                    if candle.high >= tp { return Some(tp); }
                }
            }
            PositionSide::Short => {
                if let Some(sl) = self.current_sl {
                    if candle.high >= sl { return Some(sl); }
                }
                if let Some(tp) = self.current_tp {
                    if candle.low <= tp { return Some(tp); }
                }
            }
            PositionSide::Flat => {}
        }

        None
    }
on_entry function · rust · L154-L163 (10 LOC)
src/engine/trade_manager.rs
    pub fn on_entry(&mut self, decision: &TradingDecision, atr: f64, pattern: Option<MarketContext>, equity: f64) {
        self.current_sl = decision.stop_loss;
        self.current_tp = decision.take_profit;
        self.current_strategy = decision.strategy_name.clone();
        self.current_pattern = pattern;
        self.entry_atr = atr;
        self.entry_confidence = decision.confidence;
        self.equity_at_entry = equity;
        self.position_size_frac = decision.size;
    }
on_exit function · rust · L166-L207 (42 LOC)
src/engine/trade_manager.rs
    pub fn on_exit(&mut self, symbol: &Symbol, record: &crate::backtest::portfolio::TradeRecord, learning: &mut LearningEngine) {
        let adaptive_k = learning.adaptive.reward_k();
        let reward = scorer::pnl_to_reward(record.pnl_pct, adaptive_k);

        // Compute ATR-normalized excursions
        let atr = self.entry_atr.max(1e-10);
        let entry = record.entry_price;
        let favorable_atr = (self.max_favorable / 100.0 * entry) / atr;
        let adverse_atr = (self.max_adverse / 100.0 * entry) / atr;

        // Feed adaptive parameter engine
        learning.adaptive.record_trade(
            record.pnl_pct,
            record.holding_periods,
            favorable_atr,
            adverse_atr,
        );

        if let Some(ref pattern) = self.current_pattern {
            let action = match record.side {
                PositionSide::Long => "long",
                PositionSide::Short => "short",
                _ => return,
            };

            learnin
Repobility analyzer · published findings · https://repobility.com
reset function · rust · L210-L221 (12 LOC)
src/engine/trade_manager.rs
    pub fn reset(&mut self, learning: &LearningEngine) {
        self.current_sl = None;
        self.current_tp = None;
        self.current_strategy.clear();
        self.candles_held = 0;
        self.max_adverse = 0.0;
        self.max_favorable = 0.0;
        self.current_pattern = None;
        self.entry_atr = 0.0;
        self.accumulated_funding = 0.0;
        self.cooldown_remaining = learning.adaptive.cooldown();
    }
reset_with_cooldown function · rust · L224-L227 (4 LOC)
src/engine/trade_manager.rs
    pub fn reset_with_cooldown(&mut self, learning: &LearningEngine, cooldown: usize) {
        self.reset(learning);
        self.cooldown_remaining = cooldown;
    }
add_funding function · rust · L230-L232 (3 LOC)
src/engine/trade_manager.rs
    pub fn add_funding(&mut self, fee: f64) {
        self.accumulated_funding += fee;
    }
update_trailing_stop function · rust · L235-L290 (56 LOC)
src/engine/trade_manager.rs
    fn update_trailing_stop(&mut self, candle: &Candle, position: &Position, learning: &LearningEngine) {
        let entry = position.entry_price;
        let atr = self.entry_atr;
        let profit_atr = match position.side {
            PositionSide::Long => (candle.close - entry) / atr,
            PositionSide::Short => (entry - candle.close) / atr,
            PositionSide::Flat => 0.0,
        };

        let trail_activation = learning.adaptive.trail_activation_atr();
        let trail_dist = learning.adaptive.trail_distance_atr();
        let breakeven_activation = learning.adaptive.breakeven_activation_atr();

        if profit_atr > trail_activation {
            let best_price = match position.side {
                PositionSide::Long => candle.high,
                PositionSide::Short => candle.low,
                PositionSide::Flat => entry,
            };
            let trail_distance = trail_dist * atr;
            let new_sl = match position.side {
                
make_learning function · rust · L297-L300 (4 LOC)
src/engine/trade_manager.rs
    fn make_learning() -> LearningEngine {
        LearningEngine::new(vec!["BTCUSDT".into()], LearnerConfig::default())
    }
test_trade_manager_initial_state function · rust · L303-L308 (6 LOC)
src/engine/trade_manager.rs
    fn test_trade_manager_initial_state() {
        let tm = TradeManager::new();
        assert_eq!(tm.candles_held, 0);
        assert_eq!(tm.cooldown_remaining, 0);
        assert!(tm.current_sl.is_none());
    }
test_cooldown_ticks_down function · rust · L311-L318 (8 LOC)
src/engine/trade_manager.rs
    fn test_cooldown_ticks_down() {
        let mut tm = TradeManager::new();
        tm.cooldown_remaining = 3;
        assert!(tm.tick_cooldown());  // 3 -> 2
        assert!(tm.tick_cooldown());  // 2 -> 1
        assert!(tm.tick_cooldown());  // 1 -> 0
        assert!(!tm.tick_cooldown()); // 0 -> stays 0
    }
test_reset_sets_cooldown function · rust · L321-L330 (10 LOC)
src/engine/trade_manager.rs
    fn test_reset_sets_cooldown() {
        let mut tm = TradeManager::new();
        tm.candles_held = 50;
        tm.max_adverse = 5.0;
        let learning = make_learning();
        tm.reset(&learning);
        assert_eq!(tm.candles_held, 0);
        assert_eq!(tm.max_adverse, 0.0);
        assert!(tm.cooldown_remaining > 0);
    }
Source: Repobility analyzer · https://repobility.com
test_excursion_tracking function · rust · L333-L354 (22 LOC)
src/engine/trade_manager.rs
    fn test_excursion_tracking() {
        let mut tm = TradeManager::new();
        tm.entry_atr = 1000.0;
        let learning = make_learning();
        let pos = Position {
            symbol: Symbol("BTCUSDT".into()),
            side: PositionSide::Long,
            entry_price: 50000.0,
            size: 0.1,
            unrealized_pnl: 0.0,
            entry_time: 0,
        };
        let candle = Candle {
            open_time: 0, open: 50000.0, high: 51000.0, low: 49000.0,
            close: 50500.0, volume: 1000.0, close_time: 900_000,
            quote_volume: 0.0, trades: 0,
        };
        tm.on_candle(&candle, &pos, &learning);
        assert!(tm.max_favorable > 0.0);
        assert!(tm.max_adverse > 0.0);
        assert_eq!(tm.candles_held, 1);
    }
test_max_hold_exit function · rust · L357-L381 (25 LOC)
src/engine/trade_manager.rs
    fn test_max_hold_exit() {
        let mut tm = TradeManager::new();
        tm.entry_atr = 1000.0;
        // Use candles_held just under max_hold, then push over
        tm.candles_held = 95; // default max_hold is 96
        let learning = make_learning();
        let pos = Position {
            symbol: Symbol("BTCUSDT".into()),
            side: PositionSide::Long,
            entry_price: 50000.0,
            size: 0.1,
            unrealized_pnl: 0.0,
            entry_time: 0,
        };
        let candle = Candle {
            open_time: 0, open: 50000.0, high: 50100.0, low: 49900.0,
            close: 50000.0, volume: 1000.0, close_time: 900_000,
            quote_volume: 0.0, trades: 0,
        };
        let action = tm.on_candle(&candle, &pos, &learning);
        assert_eq!(action, TradeAction::Exit {
            price: 50000.0,
            reason: ExitReason::MaxHold,
        });
    }
test_sl_tp_respects_min_hold function · rust · L384-L404 (21 LOC)
src/engine/trade_manager.rs
    fn test_sl_tp_respects_min_hold() {
        let mut tm = TradeManager::new();
        tm.current_sl = Some(49000.0);
        tm.candles_held = 1; // below min_hold
        let learning = make_learning();
        let pos = Position {
            symbol: Symbol("BTCUSDT".into()),
            side: PositionSide::Long,
            entry_price: 50000.0,
            size: 0.1,
            unrealized_pnl: 0.0,
            entry_time: 0,
        };
        let candle = Candle {
            open_time: 0, open: 49500.0, high: 49600.0, low: 48000.0,
            close: 48500.0, volume: 1000.0, close_time: 900_000,
            quote_volume: 0.0, trades: 0,
        };
        // SL at 49000, low at 48000 — would trigger, but min_hold not met
        assert!(tm.check_sl_tp(&candle, &pos, &learning).is_none());
    }
verify function · rust · L19-L45 (27 LOC)
src/engine/transfer.rs
    pub fn verify(
        source_symbol: String,
        target_symbol: String,
        source_before: f64,
        source_after: f64,
        target_before: f64,
        target_after: f64,
        baseline_cycles: u64,
        transfer_cycles: u64,
    ) -> Self {
        let improved_target = target_after > target_before;
        let regressed_source = source_after < source_before - 0.01;
        let promotable = improved_target && !regressed_source;
        let acceleration_factor = if transfer_cycles > 0 {
            baseline_cycles as f64 / transfer_cycles as f64
        } else {
            1.0
        };

        Self {
            source_symbol, target_symbol,
            source_before, source_after,
            target_before, target_after,
            improved_target, regressed_source,
            promotable, acceleration_factor,
        }
    }
record function · rust · L57-L64 (8 LOC)
src/engine/transfer.rs
    pub fn record(&mut self, reward: f64) {
        if reward > self.best_reward_seen {
            self.best_reward_seen = reward;
        }
        let regret = (self.best_reward_seen - reward).max(0.0);
        self.total_regret += regret;
        self.total_observations += 1;
    }
growth_rate function · rust · L67-L72 (6 LOC)
src/engine/transfer.rs
    pub fn growth_rate(&self) -> f64 {
        if self.total_observations < 10 || self.total_regret < 1e-10 {
            return 1.0;
        }
        self.total_regret.ln() / (self.total_observations as f64).ln()
    }
average_regret function · rust · L73-L77 (5 LOC)
src/engine/transfer.rs
    pub fn average_regret(&self) -> f64 {
        if self.total_observations == 0 { return 0.0; }
        self.total_regret / self.total_observations as f64
    }
new function · rust · L98-L105 (8 LOC)
src/engine/transfer.rs
    pub fn new(window_size: usize, threshold: f64) -> Self {
        Self {
            scores: Vec::new(),
            window_size: window_size.max(3),
            threshold,
            consecutive_plateaus: 0,
        }
    }
Methodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
record function · rust · L106-L109 (4 LOC)
src/engine/transfer.rs
    pub fn record(&mut self, score: f64) {
        self.scores.push(score);
    }
check function · rust · L110-L136 (27 LOC)
src/engine/transfer.rs
    pub fn check(&mut self) -> PlateauAction {
        let n = self.scores.len();
        if n < self.window_size * 2 {
            self.consecutive_plateaus = 0;
            return PlateauAction::Continue;
        }

        let recent: f64 = self.scores[n - self.window_size..].iter().sum::<f64>()
            / self.window_size as f64;
        let prior: f64 = self.scores[n - 2 * self.window_size..n - self.window_size]
            .iter().sum::<f64>() / self.window_size as f64;

        let improvement = (recent - prior).abs();

        if improvement < self.threshold {
            self.consecutive_plateaus += 1;
            match self.consecutive_plateaus {
                1 => PlateauAction::IncreaseExploration,
                2..=3 => PlateauAction::TriggerTransfer,
                _ => PlateauAction::InjectDiversity,
            }
        } else {
            self.consecutive_plateaus = 0;
            PlateauAction::Continue
        }
    }
test_transfer_verification_promotable function · rust · L144-L153 (10 LOC)
src/engine/transfer.rs
    fn test_transfer_verification_promotable() {
        let v = TransferVerification::verify(
            "BTCUSDT".into(), "ETHUSDT".into(),
            0.8, 0.79, // source stable
            0.3, 0.7,  // target improved
            100, 40,
        );
        assert!(v.promotable);
        assert!((v.acceleration_factor - 2.5).abs() < 0.01);
    }
test_transfer_verification_regression function · rust · L156-L164 (9 LOC)
src/engine/transfer.rs
    fn test_transfer_verification_regression() {
        let v = TransferVerification::verify(
            "BTCUSDT".into(), "ETHUSDT".into(),
            0.8, 0.5, // source regressed!
            0.3, 0.7,
            100, 40,
        );
        assert!(!v.promotable);
    }
test_regret_tracker function · rust · L167-L180 (14 LOC)
src/engine/transfer.rs
    fn test_regret_tracker() {
        let mut tracker = RegretTracker::default();
        // Optimal arm: always 0.9
        for _ in 0..100 {
            tracker.record(0.9);
        }
        assert!(tracker.total_regret < 1e-10); // no regret when always best

        // Now some bad decisions
        for _ in 0..50 {
            tracker.record(0.3);
        }
        assert!(tracker.total_regret > 0.0);
    }
test_plateau_detector function · rust · L183-L198 (16 LOC)
src/engine/transfer.rs
    fn test_plateau_detector() {
        let mut pd = PlateauDetector::new(5, 0.01);

        // Improving scores
        for i in 0..10 {
            pd.record(0.5 + i as f64 * 0.05);
        }
        assert_eq!(pd.check(), PlateauAction::Continue);

        // Flat scores
        for _ in 0..20 {
            pd.record(0.95);
        }
        let action = pd.check();
        assert_ne!(action, PlateauAction::Continue);
    }
calculate_metrics function · rust · L25-L101 (77 LOC)
src/evaluation/metrics.rs
pub fn calculate_metrics(
    equity_curve: &[f64],
    trade_pnls: &[f64],
    trade_holding_periods: &[usize],
    days: f64,
) -> PerformanceMetrics {
    let total_return_pct = if equity_curve.len() >= 2 {
        (equity_curve.last().unwrap() / equity_curve[0] - 1.0) * 100.0
    } else {
        0.0
    };

    let annualized_return_pct = if days > 0.0 {
        ((1.0 + total_return_pct / 100.0).powf(365.0 / days) - 1.0) * 100.0
    } else {
        0.0
    };

    // Daily returns for Sharpe/Sortino
    let daily_returns = compute_daily_returns(equity_curve);
    let sharpe_ratio = sharpe(&daily_returns);
    let sortino_ratio = sortino(&daily_returns);
    let max_drawdown_pct = max_drawdown(equity_curve);
    let calmar_ratio = if max_drawdown_pct > 0.01 {
        annualized_return_pct / max_drawdown_pct
    } else {
        0.0
    };

    let winning: Vec<f64> = trade_pnls.iter().filter(|&&p| p > 0.0).copied().collect();
    let losing: Vec<f64> = trade_pnls.iter().filter(|&&
compute_daily_returns function · rust · L102-L121 (20 LOC)
src/evaluation/metrics.rs
fn compute_daily_returns(equity: &[f64]) -> Vec<f64> {
    if equity.len() < 2 { return vec![]; }
    // Group by approximate daily intervals (96 x 15min candles per day)
    let candles_per_day = 96;
    let mut daily = Vec::new();
    let mut i = 0;
    while i + candles_per_day < equity.len() {
        let ret = equity[i + candles_per_day] / equity[i] - 1.0;
        daily.push(ret);
        i += candles_per_day;
    }
    if daily.is_empty() && equity.len() >= 2 {
        // Fallback: use per-candle returns
        for i in 1..equity.len() {
            daily.push(equity[i] / equity[i - 1] - 1.0);
        }
    }
    daily
}
Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
sharpe function · rust · L122-L132 (11 LOC)
src/evaluation/metrics.rs
fn sharpe(returns: &[f64]) -> f64 {
    if returns.len() < 2 { return 0.0; }
    let mean = returns.iter().sum::<f64>() / returns.len() as f64;
    let variance = returns.iter().map(|r| (r - mean).powi(2)).sum::<f64>()
        / (returns.len() - 1) as f64;
    let std = variance.sqrt();
    if std < 1e-10 { return 0.0; }
    // Annualize: assume daily returns
    (mean / std) * (365.0_f64).sqrt()
}
sortino function · rust · L133-L144 (12 LOC)
src/evaluation/metrics.rs
fn sortino(returns: &[f64]) -> f64 {
    if returns.len() < 2 { return 0.0; }
    let mean = returns.iter().sum::<f64>() / returns.len() as f64;
    let downside_variance = returns.iter()
        .filter(|&&r| r < 0.0)
        .map(|r| r.powi(2))
        .sum::<f64>() / returns.len() as f64;
    let downside_std = downside_variance.sqrt();
    if downside_std < 1e-10 { return 0.0; }
    (mean / downside_std) * (365.0_f64).sqrt()
}
max_drawdown function · rust · L145-L157 (13 LOC)
src/evaluation/metrics.rs
fn max_drawdown(equity: &[f64]) -> f64 {
    if equity.is_empty() { return 0.0; }
    let mut peak = equity[0];
    let mut max_dd = 0.0;

    for &val in equity {
        if val > peak { peak = val; }
        let dd = (peak - val) / peak * 100.0;
        if dd > max_dd { max_dd = dd; }
    }
    max_dd
}
max_consecutive_neg function · rust · L158-L171 (14 LOC)
src/evaluation/metrics.rs
fn max_consecutive_neg(pnls: &[f64]) -> usize {
    let mut max_run = 0;
    let mut current_run = 0;
    for &pnl in pnls {
        if pnl < 0.0 {
            current_run += 1;
            max_run = max_run.max(current_run);
        } else {
            current_run = 0;
        }
    }
    max_run
}
test_sharpe_positive function · rust · L178-L182 (5 LOC)
src/evaluation/metrics.rs
    fn test_sharpe_positive() {
        // Vary returns slightly to have non-zero std
        let returns: Vec<f64> = (0..100).map(|i| 0.001 + (i as f64 * 0.0001).sin() * 0.0002).collect();
        assert!(sharpe(&returns) > 0.0);
    }
test_sharpe_zero_std function · rust · L185-L188 (4 LOC)
src/evaluation/metrics.rs
    fn test_sharpe_zero_std() {
        let returns = vec![0.0; 100];
        assert_eq!(sharpe(&returns), 0.0);
    }
test_max_drawdown function · rust · L191-L196 (6 LOC)
src/evaluation/metrics.rs
    fn test_max_drawdown() {
        let equity = vec![100.0, 110.0, 95.0, 105.0, 80.0, 90.0];
        let dd = max_drawdown(&equity);
        // Peak at 110, trough at 80 -> (110-80)/110 * 100 = 27.27%
        assert!((dd - 27.27).abs() < 0.1);
    }
test_max_drawdown_no_drawdown function · rust · L199-L202 (4 LOC)
src/evaluation/metrics.rs
    fn test_max_drawdown_no_drawdown() {
        let equity = vec![100.0, 101.0, 102.0, 103.0];
        assert_eq!(max_drawdown(&equity), 0.0);
    }
Repobility analyzer · published findings · https://repobility.com
test_consecutive_losses function · rust · L205-L208 (4 LOC)
src/evaluation/metrics.rs
    fn test_consecutive_losses() {
        let pnls = vec![1.0, -1.0, -2.0, -3.0, 1.0, -1.0, -1.0];
        assert_eq!(max_consecutive_neg(&pnls), 3);
    }
test_calculate_metrics_profitable function · rust · L211-L220 (10 LOC)
src/evaluation/metrics.rs
    fn test_calculate_metrics_profitable() {
        let equity: Vec<f64> = (0..200).map(|i| 10000.0 + i as f64 * 10.0).collect();
        let pnls = vec![100.0, -30.0, 80.0, -20.0, 150.0, -40.0, 120.0];
        let periods = vec![5, 3, 8, 2, 6, 4, 7];
        let metrics = calculate_metrics(&equity, &pnls, &periods, 30.0);

        assert!(metrics.total_return_pct > 0.0);
        assert!(metrics.win_rate > 0.5);
        assert!(metrics.profit_factor > 1.0);
    }
test_profit_factor function · rust · L223-L229 (7 LOC)
src/evaluation/metrics.rs
    fn test_profit_factor() {
        let pnls = vec![100.0, -50.0, 80.0, -30.0];
        let equity = vec![10000.0; 2];
        let metrics = calculate_metrics(&equity, &pnls, &[1; 4], 1.0);
        // Gross profit = 180, gross loss = 80, PF = 2.25
        assert!((metrics.profit_factor - 2.25).abs() < 0.01);
    }
‹ prevpage 4 / 5next ›