← back to krejcif__rdex

Function bodies 248 total

All specs Real LLM only Function bodies
pnl_to_reward function · rust · L5-L8 (4 LOC)
src/evaluation/scorer.rs
pub fn pnl_to_reward(pnl_pct: f64, adaptive_k: f64) -> f64 {
    let k = adaptive_k.clamp(0.5, 5.0);
    1.0 / (1.0 + (-k * pnl_pct).exp())
}
score_trade function · rust · L11-L13 (3 LOC)
src/evaluation/scorer.rs
pub fn score_trade(pnl_pct: f64, _max_adverse_pct: f64, _holding_periods: usize, adaptive_k: f64) -> f64 {
    pnl_to_reward(pnl_pct, adaptive_k)
}
test_pnl_to_reward_positive function · rust · L20-L23 (4 LOC)
src/evaluation/scorer.rs
    fn test_pnl_to_reward_positive() {
        assert!(pnl_to_reward(5.0, 2.0) > 0.7);
        assert!(pnl_to_reward(10.0, 2.0) > 0.9);
    }
test_pnl_to_reward_negative function · rust · L26-L29 (4 LOC)
src/evaluation/scorer.rs
    fn test_pnl_to_reward_negative() {
        assert!(pnl_to_reward(-5.0, 2.0) < 0.3);
        assert!(pnl_to_reward(-10.0, 2.0) < 0.1);
    }
test_pnl_to_reward_zero function · rust · L32-L34 (3 LOC)
src/evaluation/scorer.rs
    fn test_pnl_to_reward_zero() {
        assert!((pnl_to_reward(0.0, 2.0) - 0.5).abs() < 0.01);
    }
test_score_trade_good function · rust · L37-L40 (4 LOC)
src/evaluation/scorer.rs
    fn test_score_trade_good() {
        let score = score_trade(3.0, 0.3, 8, 2.0);
        assert!(score > 0.7);
    }
test_score_trade_bad function · rust · L43-L46 (4 LOC)
src/evaluation/scorer.rs
    fn test_score_trade_bad() {
        let score = score_trade(-3.0, 6.0, 200, 2.0);
        assert!(score < 0.3);
    }
Want this analysis on your repo? https://repobility.com/scan/
main function · rust · L33-L50 (18 LOC)
src/main.rs
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    tracing_subscriber::fmt()
        .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
        .init();

    let cli = Cli::parse();

    match cli.command {
        Commands::Backtest { days, symbols, equity, leverage } => {
            run_backtest(days, &symbols, equity, leverage).await?;
        }
        Commands::Fetch { days, symbols } => {
            run_fetch(days, &symbols).await?;
        }
    }

    Ok(())
}
run_fetch function · rust · L51-L70 (20 LOC)
src/main.rs
async fn run_fetch(days: i64, symbols: &str) -> Result<(), Box<dyn std::error::Error>> {
    let symbols: Vec<&str> = symbols.split(',').collect();
    for symbol in &symbols {
        let candles = rdex::data::fetch_last_n_days(symbol, days).await?;
        rdex::data::save_to_csv(
            &candles,
            &rdex::data::cache_path(symbol, "data"),
        )?;
        println!("Fetched and cached {} candles for {}", candles.len(), symbol);

        let funding = rdex::data::fetch_funding_last_n_days(symbol, days).await?;
        rdex::data::save_funding_csv(
            &funding,
            &rdex::data::funding_cache_path(symbol, "data"),
        )?;
        println!("Fetched and cached {} funding rates for {}", funding.len(), symbol);
    }
    Ok(())
}
run_backtest function · rust · L71-L213 (143 LOC)
src/main.rs
async fn run_backtest(
    days: i64,
    symbols_str: &str,
    equity: f64,
    leverage: f64,
) -> Result<(), Box<dyn std::error::Error>> {
    use rdex::domain::*;
    use rdex::engine::*;
    use rdex::backtest::*;

    let symbols: Vec<String> = symbols_str.split(',').map(|s| s.to_string()).collect();

    println!("=== RDEX Self-Learning Crypto Trading System ===");
    println!("Symbols: {:?}", symbols);
    println!("Days: {}, Equity: ${}, Leverage: {}x", days, equity, leverage);

    // Fetch candle data + funding rates
    let mut all_data: Vec<(String, Vec<Candle>)> = Vec::new();
    let mut all_funding: std::collections::HashMap<String, Vec<FundingRate>> = std::collections::HashMap::new();
    for symbol in &symbols {
        let candles = rdex::data::load_or_fetch(symbol, days, "data").await?;
        println!("{}: {} candles ({:.1} days)", symbol, candles.len(),
            candles.len() as f64 / 96.0);

        let funding = rdex::data::load_or_fetch_funding(symbol, da
generate_signal function · rust · L9-L51 (43 LOC)
src/strategy/arms.rs
    fn generate_signal(&self, state: &MarketState) -> TradingDecision {
        let ind = &state.indicators;

        // Need sufficient indicator data
        if ind.atr_14 < 1e-10 || ind.sma_20 < 1e-10 {
            return hold_decision("momentum");
        }

        let price = state.current_candle.close;
        let atr = ind.atr_14;

        // Momentum conditions — strict filters to avoid overtrading
        let strong_trend = ind.adx_14 > 30.0;
        let macd_bullish = ind.macd_histogram > 0.0 && ind.macd_line > ind.macd_signal;
        let rsi_ok_long = ind.rsi_14 > 45.0 && ind.rsi_14 < 70.0;
        let rsi_ok_short = ind.rsi_14 < 55.0 && ind.rsi_14 > 30.0;
        let above_sma = price > ind.sma_20 && ind.sma_20 > ind.sma_50;
        let below_sma = price < ind.sma_20 && ind.sma_20 < ind.sma_50;
        let volume_confirms = state.current_candle.volume > ind.volume_sma_20 * 1.2;

        if strong_trend && macd_bullish && rsi_ok_long && above_sma && volume_confirms {
    
generate_signal function · rust · L59-L98 (40 LOC)
src/strategy/arms.rs
    fn generate_signal(&self, state: &MarketState) -> TradingDecision {
        let ind = &state.indicators;

        if ind.atr_14 < 1e-10 || ind.bb_middle < 1e-10 {
            return hold_decision("mean_reversion");
        }

        let price = state.current_candle.close;
        let atr = ind.atr_14;
        let ranging = ind.adx_14 < 25.0;

        // Mean reversion: strict — need BOTH BB and RSI confirmation
        let at_lower_bb = price <= ind.bb_lower;
        let at_upper_bb = price >= ind.bb_upper;
        let rsi_oversold = ind.rsi_14 < 25.0;
        let rsi_overbought = ind.rsi_14 > 75.0;

        if ranging && at_lower_bb && rsi_oversold {
            TradingDecision {
                signal: TradeSignal::Long,
                size: position_size_conservative(atr, price),
                stop_loss: Some(price - 1.5 * atr),
                take_profit: Some(ind.bb_middle),
                confidence: 0.75,
                strategy_name: "mean_reversion".into(),
       
generate_signal function · rust · L106-L145 (40 LOC)
src/strategy/arms.rs
    fn generate_signal(&self, state: &MarketState) -> TradingDecision {
        let ind = &state.indicators;

        if ind.atr_14 < 1e-10 || ind.bb_middle < 1e-10 || state.history.len() < 20 {
            return hold_decision("breakout");
        }

        let price = state.current_candle.close;
        let atr = ind.atr_14;

        // Detect breakout: BB squeeze then expansion + volume surge
        let bb_width = (ind.bb_upper - ind.bb_lower) / ind.bb_middle;
        let squeeze = bb_width < 0.03; // tight bands
        let volume_surge = state.current_candle.volume > ind.volume_sma_20 * 1.5;
        let strong_candle = state.current_candle.body_ratio() > 0.6;

        // Breakout above upper BB with volume
        if price > ind.bb_upper && (volume_surge || squeeze) && strong_candle {
            TradingDecision {
                signal: TradeSignal::Long,
                size: position_size(30.0, atr, price), // moderate size
                stop_loss: Some(ind.bb_middle),
   
generate_signal function · rust · L153-L193 (41 LOC)
src/strategy/arms.rs
    fn generate_signal(&self, state: &MarketState) -> TradingDecision {
        let ind = &state.indicators;

        if ind.atr_14 < 1e-10 || ind.ema_12 < 1e-10 {
            return hold_decision("scalping");
        }

        let price = state.current_candle.close;
        let atr = ind.atr_14;

        // Quick scalp: EMA crossover + MACD alignment
        let ema_bull_cross = ind.ema_12 > ind.ema_26
            && (ind.ema_12 - ind.ema_26) / ind.ema_26 < 0.002; // just crossed
        let ema_bear_cross = ind.ema_12 < ind.ema_26
            && (ind.ema_26 - ind.ema_12) / ind.ema_26 < 0.002;
        let macd_confirms_long = ind.macd_histogram > 0.0;
        let macd_confirms_short = ind.macd_histogram < 0.0;

        if ema_bull_cross && macd_confirms_long {
            TradingDecision {
                signal: TradeSignal::Long,
                size: 0.3, // smaller size for scalps
                stop_loss: Some(price - 1.0 * atr),
                take_profit: Some(price + 1.5 *
all_strategies function · rust · L197-L204 (8 LOC)
src/strategy/arms.rs
pub fn all_strategies() -> Vec<Box<dyn TradingStrategy>> {
    vec![
        Box::new(MomentumStrategy),
        Box::new(MeanReversionStrategy),
        Box::new(BreakoutStrategy),
        Box::new(ScalpingStrategy),
    ]
}
Repobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
hold_decision function · rust · L205-L215 (11 LOC)
src/strategy/arms.rs
fn hold_decision(name: &str) -> TradingDecision {
    TradingDecision {
        signal: TradeSignal::Hold,
        size: 0.0,
        stop_loss: None,
        take_profit: None,
        confidence: 0.0,
        strategy_name: name.into(),
    }
}
position_size function · rust · L218-L226 (9 LOC)
src/strategy/arms.rs
fn position_size(adx: f64, atr: f64, price: f64) -> f64 {
    // Risk 1-2% of equity per trade, scaled by trend strength
    let risk_per_unit = atr * 2.0 / price; // SL distance as fraction
    if risk_per_unit < 1e-10 { return 0.0; }
    let base_risk = 0.02; // 2% equity risk
    let kelly_fraction = (base_risk / risk_per_unit).min(0.5);
    let trend_scale = (adx / 50.0).min(1.0);
    (kelly_fraction * trend_scale).clamp(0.05, 0.5)
}
position_size_conservative function · rust · L227-L233 (7 LOC)
src/strategy/arms.rs
fn position_size_conservative(atr: f64, price: f64) -> f64 {
    let risk_per_unit = atr * 1.5 / price;
    if risk_per_unit < 1e-10 { return 0.0; }
    let base_risk = 0.01; // 1% for mean reversion (tighter)
    (base_risk / risk_per_unit).clamp(0.05, 0.3)
}
make_market_state function · rust · L239-L253 (15 LOC)
src/strategy/arms.rs
    fn make_market_state(price: f64, ind: IndicatorSet) -> MarketState {
        let candle = Candle {
            open_time: 0, open: price - 0.5, high: price + 1.0,
            low: price - 1.0, close: price, volume: 2000.0,
            close_time: 900_000, quote_volume: price * 2000.0, trades: 500,
        };
        MarketState {
            symbol: Symbol("BTCUSDT".into()),
            timestamp: 900_000,
            current_candle: candle.clone(),
            history: vec![candle],
            indicators: ind,
        }
    }
test_momentum_long_signal function · rust · L256-L270 (15 LOC)
src/strategy/arms.rs
    fn test_momentum_long_signal() {
        let ind = IndicatorSet {
            adx_14: 35.0, sma_20: 99.0, sma_50: 95.0,
            ema_12: 99.0, ema_26: 97.0, rsi_14: 55.0,
            atr_14: 2.0, macd_line: 1.0, macd_signal: 0.5,
            macd_histogram: 0.5, bb_upper: 105.0, bb_middle: 100.0,
            bb_lower: 95.0, volume_sma_20: 1000.0,
        };
        let state = make_market_state(100.0, ind);
        let decision = MomentumStrategy.generate_signal(&state);
        assert_eq!(decision.signal, TradeSignal::Long);
        assert!(decision.stop_loss.unwrap() < 100.0);
        assert!(decision.take_profit.unwrap() > 100.0);
        assert!(decision.size > 0.0 && decision.size <= 0.5);
    }
test_mean_reversion_at_lower_bb function · rust · L273-L284 (12 LOC)
src/strategy/arms.rs
    fn test_mean_reversion_at_lower_bb() {
        let ind = IndicatorSet {
            adx_14: 15.0, // ranging
            rsi_14: 22.0, // oversold (below 25 threshold)
            bb_upper: 110.0, bb_middle: 100.0, bb_lower: 90.0,
            atr_14: 2.0, sma_20: 100.0, sma_50: 100.0,
            ..Default::default()
        };
        let state = make_market_state(89.5, ind);
        let decision = MeanReversionStrategy.generate_signal(&state);
        assert_eq!(decision.signal, TradeSignal::Long);
    }
test_hold_when_no_signal function · rust · L287-L303 (17 LOC)
src/strategy/arms.rs
    fn test_hold_when_no_signal() {
        let ind = IndicatorSet {
            adx_14: 20.0, rsi_14: 50.0,
            bb_upper: 105.0, bb_middle: 100.0, bb_lower: 95.0,
            atr_14: 2.0, sma_20: 100.0, sma_50: 100.0,
            ema_12: 100.0, ema_26: 100.0,
            macd_histogram: 0.0, volume_sma_20: 1000.0,
            ..Default::default()
        };
        let state = make_market_state(100.0, ind);

        for strategy in all_strategies() {
            let d = strategy.generate_signal(&state);
            assert_eq!(d.signal, TradeSignal::Hold,
                "Strategy {} should hold in neutral market", strategy.name());
        }
    }
test_all_strategies_exist function · rust · L306-L314 (9 LOC)
src/strategy/arms.rs
    fn test_all_strategies_exist() {
        let strats = all_strategies();
        assert_eq!(strats.len(), 4);
        let names: Vec<&str> = strats.iter().map(|s| s.name()).collect();
        assert!(names.contains(&"momentum"));
        assert!(names.contains(&"mean_reversion"));
        assert!(names.contains(&"breakout"));
        assert!(names.contains(&"scalping"));
    }
Repobility — the code-quality scanner for AI-generated software · https://repobility.com
test_position_sizing_bounds function · rust · L317-L321 (5 LOC)
src/strategy/arms.rs
    fn test_position_sizing_bounds() {
        assert!(position_size(50.0, 100.0, 50000.0) > 0.0);
        assert!(position_size(50.0, 100.0, 50000.0) <= 0.5);
        assert!(position_size_conservative(100.0, 50000.0) <= 0.3);
    }
extract function · rust · L32-L111 (80 LOC)
src/strategy/features.rs
    pub fn extract(state: &MarketState) -> Option<Self> {
        let ind = &state.indicators;
        let c = &state.current_candle;

        if ind.atr_14 < 1e-10 || ind.sma_20 < 1e-10 || ind.bb_middle < 1e-10 {
            return None;
        }

        let price = c.close;
        let atr = ind.atr_14;

        // Trend: distance from SMAs normalized by ATR, compressed via tanh
        let dist_sma20 = (price - ind.sma_20) / atr;
        let dist_sma50 = if ind.sma_50 > 1e-10 {
            (price - ind.sma_50) / atr
        } else {
            dist_sma20
        };
        let ma_spread = if ind.sma_50 > 1e-10 {
            (ind.sma_20 - ind.sma_50) / atr
        } else {
            0.0
        };
        let trend = (dist_sma20 * 0.4 + dist_sma50 * 0.3 + ma_spread * 0.3).tanh();

        // Momentum: RSI + MACD histogram
        let rsi_norm = (ind.rsi_14 - 50.0) / 50.0;
        let macd_norm = (ind.macd_histogram / atr).clamp(-2.0, 2.0) / 2.0;
        let momentum = (rsi_norm 
make_state function · rust · L137-L172 (36 LOC)
src/strategy/features.rs
    fn make_state(price: f64) -> MarketState {
        let candle = Candle {
            open_time: 0, open: price - 0.5, high: price + 1.0,
            low: price - 1.0, close: price, volume: 2000.0,
            close_time: 900_000, quote_volume: price * 2000.0, trades: 500,
        };
        let mut history = Vec::new();
        for i in 0..10 {
            history.push(Candle {
                open_time: i * 900_000,
                open: price - 5.0 + i as f64 * 0.5,
                high: price - 4.0 + i as f64 * 0.5,
                low: price - 6.0 + i as f64 * 0.5,
                close: price - 5.0 + i as f64 * 0.5 + 0.3,
                volume: 1500.0,
                close_time: (i + 1) * 900_000 - 1,
                quote_volume: 100_000.0, trades: 400,
            });
        }
        history.push(candle.clone());
        MarketState {
            symbol: Symbol("BTCUSDT".into()),
            timestamp: 900_000,
            current_candle: candle,
            history,
  
test_feature_extraction function · rust · L175-L187 (13 LOC)
src/strategy/features.rs
    fn test_feature_extraction() {
        let state = make_state(50000.0);
        let f = MarketFeatures::extract(&state).unwrap();
        assert!(f.trend >= -1.0 && f.trend <= 1.0);
        assert!(f.momentum >= -1.0 && f.momentum <= 1.0);
        assert!(f.volatility >= 0.0 && f.volatility <= 1.0);
        assert!(f.volume >= 0.0 && f.volume <= 1.0);
        assert!(f.candle_character >= -1.0 && f.candle_character <= 1.0);
        assert!(f.bb_position >= 0.0 && f.bb_position <= 1.0);
        assert!(f.short_momentum >= -1.0 && f.short_momentum <= 1.0);
        assert!(f.atr > 0.0);
        assert!(f.price > 0.0);
    }
test_feature_extraction_insufficient_data function · rust · L190-L203 (14 LOC)
src/strategy/features.rs
    fn test_feature_extraction_insufficient_data() {
        let state = MarketState {
            symbol: Symbol("BTCUSDT".into()),
            timestamp: 0,
            current_candle: Candle {
                open_time: 0, open: 100.0, high: 101.0, low: 99.0,
                close: 100.5, volume: 1000.0, close_time: 0,
                quote_volume: 0.0, trades: 0,
            },
            history: vec![],
            indicators: IndicatorSet::default(),
        };
        assert!(MarketFeatures::extract(&state).is_none());
    }
test_as_array_length function · rust · L206-L210 (5 LOC)
src/strategy/features.rs
    fn test_as_array_length() {
        let state = make_state(50000.0);
        let f = MarketFeatures::extract(&state).unwrap();
        assert_eq!(f.as_array().len(), 7);
    }
new function · rust · L22-L28 (7 LOC)
src/strategy/patterns.rs
    fn new(initial_median: f64) -> Self {
        Self {
            recent: Vec::new(),
            median: initial_median,
            max_samples: 3000,
        }
    }
observe function · rust · L29-L39 (11 LOC)
src/strategy/patterns.rs
    fn observe(&mut self, val: f64) {
        self.recent.push(val);
        if self.recent.len() > self.max_samples {
            let half = self.max_samples / 2;
            self.recent.drain(0..half);
        }
        if self.recent.len() >= 20 {
            self.update_median();
        }
    }
Want fix-PRs on findings? Install Repobility's GitHub App · github.com/apps/repobility-bot
update_median function · rust · L40-L45 (6 LOC)
src/strategy/patterns.rs
    fn update_median(&mut self) {
        let mut sorted = self.recent.clone();
        sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
        self.median = sorted[sorted.len() / 2];
    }
bin function · rust · L46-L49 (4 LOC)
src/strategy/patterns.rs
    fn bin(&self, val: f64) -> u8 {
        if val <= self.median { 0 } else { 1 }
    }
sample_count function · rust · L50-L53 (4 LOC)
src/strategy/patterns.rs
    fn sample_count(&self) -> usize {
        self.recent.len()
    }
new function · rust · L57-L66 (10 LOC)
src/strategy/patterns.rs
    pub fn new() -> Self {
        // 4 key features: trend, momentum, volatility, volume
        let binners = vec![
            MedianBinner::new(0.0),    // trend: negative/positive
            MedianBinner::new(0.0),    // momentum: weak/strong
            MedianBinner::new(0.5),    // volatility: low/high
            MedianBinner::new(0.5),    // volume: low/high
        ];
        Self { binners }
    }
observe function · rust · L69-L74 (6 LOC)
src/strategy/patterns.rs
    pub fn observe(&mut self, features: &MarketFeatures) {
        let vals = features.key_features();
        for (binner, &val) in self.binners.iter_mut().zip(vals.iter()) {
            binner.observe(val);
        }
    }
discretize function · rust · L77-L89 (13 LOC)
src/strategy/patterns.rs
    pub fn discretize(&self, features: &MarketFeatures) -> MarketContext {
        let vals = features.key_features();
        let bins: Vec<u8> = self.binners.iter()
            .zip(vals.iter())
            .map(|(binner, &val)| binner.bin(val))
            .collect();

        // Encode as compact pattern: "TMVV" where T=trend, M=momentum, V=vol, V=volume
        MarketContext {
            volatility_tier: format!("{}{}", bins[0], bins[1]),
            trend_regime: format!("{}{}", bins[2], bins[3]),
        }
    }
pattern_key function · rust · L92-L94 (3 LOC)
src/strategy/patterns.rs
    pub fn pattern_key(ctx: &MarketContext) -> String {
        format!("{}_{}", ctx.volatility_tier, ctx.trend_regime)
    }
sample_count function · rust · L95-L98 (4 LOC)
src/strategy/patterns.rs
    pub fn sample_count(&self) -> usize {
        self.binners.first().map(|b| b.sample_count()).unwrap_or(0)
    }
Want this analysis on your repo? https://repobility.com/scan/
is_warmed_up function · rust · L99-L102 (4 LOC)
src/strategy/patterns.rs
    pub fn is_warmed_up(&self) -> bool {
        self.sample_count() >= 20
    }
make_features function · rust · L108-L116 (9 LOC)
src/strategy/patterns.rs
    fn make_features(trend: f64, momentum: f64) -> MarketFeatures {
        MarketFeatures {
            trend, momentum,
            volatility: 0.5, volume: 0.5, candle_character: 0.0,
            bb_position: 0.5, short_momentum: 0.0,
            atr: 100.0, price: 50000.0,
        }
    }
test_discretizer_produces_valid_context function · rust · L119-L124 (6 LOC)
src/strategy/patterns.rs
    fn test_discretizer_produces_valid_context() {
        let disc = PatternDiscretizer::new();
        let ctx = disc.discretize(&make_features(0.5, 0.3));
        assert_eq!(ctx.volatility_tier.len(), 2);
        assert_eq!(ctx.trend_regime.len(), 2);
    }
test_discretizer_adapts_boundaries function · rust · L127-L137 (11 LOC)
src/strategy/patterns.rs
    fn test_discretizer_adapts_boundaries() {
        let mut disc = PatternDiscretizer::new();
        for i in 0..100 {
            disc.observe(&make_features(0.5 + i as f64 * 0.005, 0.3));
        }
        assert!(disc.is_warmed_up());

        let ctx_low = disc.discretize(&make_features(0.3, 0.0));
        let ctx_high = disc.discretize(&make_features(0.9, 0.0));
        assert_ne!(ctx_low.volatility_tier, ctx_high.volatility_tier);
    }
test_discretizer_deterministic function · rust · L140-L144 (5 LOC)
src/strategy/patterns.rs
    fn test_discretizer_deterministic() {
        let disc = PatternDiscretizer::new();
        let f = make_features(0.3, -0.2);
        assert_eq!(disc.discretize(&f), disc.discretize(&f));
    }
test_pattern_key function · rust · L147-L153 (7 LOC)
src/strategy/patterns.rs
    fn test_pattern_key() {
        let ctx = MarketContext {
            volatility_tier: "01".into(),
            trend_regime: "10".into(),
        };
        assert_eq!(PatternDiscretizer::pattern_key(&ctx), "01_10");
    }
test_16_patterns_max function · rust · L156-L177 (22 LOC)
src/strategy/patterns.rs
    fn test_16_patterns_max() {
        let disc = PatternDiscretizer::new();
        let mut patterns = std::collections::HashSet::new();
        // Try extreme combinations
        for t in [-1.0, 1.0] {
            for m in [-1.0, 1.0] {
                for v in [0.0, 1.0] {
                    for vol in [0.0, 1.0] {
                        let f = MarketFeatures {
                            trend: t, momentum: m,
                            volatility: v, volume: vol,
                            candle_character: 0.0, bb_position: 0.5,
                            short_momentum: 0.0, atr: 100.0, price: 50000.0,
                        };
                        let ctx = disc.discretize(&f);
                        patterns.insert(PatternDiscretizer::pattern_key(&ctx));
                    }
                }
            }
        }
        assert!(patterns.len() <= 16);
    }
detect_regime function · rust · L12-L24 (13 LOC)
src/strategy/regime.rs
pub fn detect_regime(ind: &IndicatorSet) -> MarketRegime {
    let trend_strength = ind.adx_14;
    let ma_bullish = ind.sma_20 > ind.sma_50;

    match (trend_strength > 25.0, trend_strength > 40.0, ma_bullish) {
        (_, true, true) => MarketRegime::StrongUptrend,
        (true, false, true) => MarketRegime::WeakUptrend,
        (_, true, false) => MarketRegime::StrongDowntrend,
        (true, false, false) => MarketRegime::WeakDowntrend,
        (false, _, _) => MarketRegime::Ranging,
    }
}
Repobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
test_regime_detection function · rust · L31-L43 (13 LOC)
src/strategy/regime.rs
    fn test_regime_detection() {
        let mut ind = IndicatorSet::default();
        ind.adx_14 = 45.0;
        ind.sma_20 = 105.0;
        ind.sma_50 = 100.0;
        assert_eq!(detect_regime(&ind), MarketRegime::StrongUptrend);

        ind.sma_20 = 95.0;
        assert_eq!(detect_regime(&ind), MarketRegime::StrongDowntrend);

        ind.adx_14 = 15.0;
        assert_eq!(detect_regime(&ind), MarketRegime::Ranging);
    }
‹ prevpage 5 / 5