vaquum-limen 2.5.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vaquum_limen-2.5.5/LICENSE +21 -0
- vaquum_limen-2.5.5/PKG-INFO +148 -0
- vaquum_limen-2.5.5/README.md +117 -0
- vaquum_limen-2.5.5/limen/__init__.py +42 -0
- vaquum_limen-2.5.5/limen/backtest/__init__.py +0 -0
- vaquum_limen-2.5.5/limen/backtest/backtest_sequential.py +116 -0
- vaquum_limen-2.5.5/limen/backtest/backtest_snapshot.py +181 -0
- vaquum_limen-2.5.5/limen/cohort/__init__.py +7 -0
- vaquum_limen-2.5.5/limen/cohort/cohort.py +553 -0
- vaquum_limen-2.5.5/limen/cohort/regime_pools.py +473 -0
- vaquum_limen-2.5.5/limen/data/__init__.py +7 -0
- vaquum_limen-2.5.5/limen/data/_internal/binance_file_to_polars.py +32 -0
- vaquum_limen-2.5.5/limen/data/bars/__init__.py +7 -0
- vaquum_limen-2.5.5/limen/data/bars/standard_bars.py +147 -0
- vaquum_limen-2.5.5/limen/data/historical_data.py +499 -0
- vaquum_limen-2.5.5/limen/data/utils/__init__.py +16 -0
- vaquum_limen-2.5.5/limen/data/utils/compute_data_bars.py +40 -0
- vaquum_limen-2.5.5/limen/data/utils/random_slice.py +37 -0
- vaquum_limen-2.5.5/limen/data/utils/splits.py +137 -0
- vaquum_limen-2.5.5/limen/experiment/__init__.py +19 -0
- vaquum_limen-2.5.5/limen/experiment/checkpoint_manager.py +302 -0
- vaquum_limen-2.5.5/limen/experiment/experiment_core.py +962 -0
- vaquum_limen-2.5.5/limen/experiment/feedback_controller.py +387 -0
- vaquum_limen-2.5.5/limen/experiment/manifest_core.py +1199 -0
- vaquum_limen-2.5.5/limen/experiment/msq.py +489 -0
- vaquum_limen-2.5.5/limen/experiment/param_domain.py +323 -0
- vaquum_limen-2.5.5/limen/experiment/param_search/__init__.py +11 -0
- vaquum_limen-2.5.5/limen/experiment/param_search/grid_strategy.py +169 -0
- vaquum_limen-2.5.5/limen/experiment/param_search/random_strategy.py +76 -0
- vaquum_limen-2.5.5/limen/experiment/param_search/registry.py +10 -0
- vaquum_limen-2.5.5/limen/experiment/param_search/search_strategy.py +202 -0
- vaquum_limen-2.5.5/limen/experiment/reducer/__init__.py +31 -0
- vaquum_limen-2.5.5/limen/experiment/reducer/budget_reducer.py +299 -0
- vaquum_limen-2.5.5/limen/experiment/reducer/correlation_reducer.py +328 -0
- vaquum_limen-2.5.5/limen/experiment/reducer/filter_types.py +64 -0
- vaquum_limen-2.5.5/limen/experiment/reducer/focus_reducer.py +415 -0
- vaquum_limen-2.5.5/limen/experiment/reducer/pruning_strategy.py +82 -0
- vaquum_limen-2.5.5/limen/experiment/reducer/registry.py +14 -0
- vaquum_limen-2.5.5/limen/experiment/reducer/sanity_reducer.py +229 -0
- vaquum_limen-2.5.5/limen/experiment/reducer/saturation_reducer.py +173 -0
- vaquum_limen-2.5.5/limen/experiment/trainer/__init__.py +9 -0
- vaquum_limen-2.5.5/limen/experiment/trainer/errors.py +3 -0
- vaquum_limen-2.5.5/limen/experiment/trainer/sensor.py +88 -0
- vaquum_limen-2.5.5/limen/experiment/trainer/trainer.py +326 -0
- vaquum_limen-2.5.5/limen/features/__init__.py +119 -0
- vaquum_limen-2.5.5/limen/features/absorption_intensity.py +40 -0
- vaquum_limen-2.5.5/limen/features/active_lines.py +47 -0
- vaquum_limen-2.5.5/limen/features/active_quantile_count.py +46 -0
- vaquum_limen-2.5.5/limen/features/amihud_illiquidity.py +30 -0
- vaquum_limen-2.5.5/limen/features/atr_percent_sma.py +37 -0
- vaquum_limen-2.5.5/limen/features/atr_sma.py +36 -0
- vaquum_limen-2.5.5/limen/features/body_to_range.py +31 -0
- vaquum_limen-2.5.5/limen/features/breakout_features.py +161 -0
- vaquum_limen-2.5.5/limen/features/breakout_percentile_regime.py +31 -0
- vaquum_limen-2.5.5/limen/features/calendar_time_features.py +35 -0
- vaquum_limen-2.5.5/limen/features/close_position.py +16 -0
- vaquum_limen-2.5.5/limen/features/close_to_extremes.py +19 -0
- vaquum_limen-2.5.5/limen/features/conserved_flux_renormalization.py +122 -0
- vaquum_limen-2.5.5/limen/features/cyclical_time_features.py +61 -0
- vaquum_limen-2.5.5/limen/features/distance_from_high.py +20 -0
- vaquum_limen-2.5.5/limen/features/distance_from_low.py +20 -0
- vaquum_limen-2.5.5/limen/features/dollar_volume.py +22 -0
- vaquum_limen-2.5.5/limen/features/dynamic_stop_loss.py +28 -0
- vaquum_limen-2.5.5/limen/features/dynamic_target.py +28 -0
- vaquum_limen-2.5.5/limen/features/ema_alignment.py +28 -0
- vaquum_limen-2.5.5/limen/features/ema_breakout.py +35 -0
- vaquum_limen-2.5.5/limen/features/entry_score_microstructure.py +94 -0
- vaquum_limen-2.5.5/limen/features/exit_quality.py +30 -0
- vaquum_limen-2.5.5/limen/features/feature_aliases.py +36 -0
- vaquum_limen-2.5.5/limen/features/forward_breakout_target.py +37 -0
- vaquum_limen-2.5.5/limen/features/fractional_diff.py +192 -0
- vaquum_limen-2.5.5/limen/features/gap_high.py +16 -0
- vaquum_limen-2.5.5/limen/features/garman_klass_volatility.py +46 -0
- vaquum_limen-2.5.5/limen/features/hh_hl_structure_regime.py +31 -0
- vaquum_limen-2.5.5/limen/features/hours_since_big_move.py +43 -0
- vaquum_limen-2.5.5/limen/features/hours_since_quantile_line.py +43 -0
- vaquum_limen-2.5.5/limen/features/ichimoku_cloud.py +44 -0
- vaquum_limen-2.5.5/limen/features/illiquidity_shock.py +38 -0
- vaquum_limen-2.5.5/limen/features/jump_variation_proxy.py +50 -0
- vaquum_limen-2.5.5/limen/features/kline_imbalance.py +30 -0
- vaquum_limen-2.5.5/limen/features/lagged_features.py +107 -0
- vaquum_limen-2.5.5/limen/features/log_returns.py +19 -0
- vaquum_limen-2.5.5/limen/features/ma_slope_regime.py +32 -0
- vaquum_limen-2.5.5/limen/features/market_regime.py +58 -0
- vaquum_limen-2.5.5/limen/features/micro_momentum.py +19 -0
- vaquum_limen-2.5.5/limen/features/momentum_confirmation.py +37 -0
- vaquum_limen-2.5.5/limen/features/momentum_periods.py +28 -0
- vaquum_limen-2.5.5/limen/features/momentum_weight.py +22 -0
- vaquum_limen-2.5.5/limen/features/parkinson_volatility.py +41 -0
- vaquum_limen-2.5.5/limen/features/position_in_candle.py +23 -0
- vaquum_limen-2.5.5/limen/features/position_in_range.py +20 -0
- vaquum_limen-2.5.5/limen/features/price_range_position.py +24 -0
- vaquum_limen-2.5.5/limen/features/price_vs_band_regime.py +38 -0
- vaquum_limen-2.5.5/limen/features/quantile_flag.py +35 -0
- vaquum_limen-2.5.5/limen/features/quantile_line_density.py +42 -0
- vaquum_limen-2.5.5/limen/features/range_overlap.py +31 -0
- vaquum_limen-2.5.5/limen/features/range_pct.py +16 -0
- vaquum_limen-2.5.5/limen/features/range_per_dollar_volume.py +33 -0
- vaquum_limen-2.5.5/limen/features/realized_kurtosis.py +57 -0
- vaquum_limen-2.5.5/limen/features/realized_semivariance.py +42 -0
- vaquum_limen-2.5.5/limen/features/realized_skewness.py +54 -0
- vaquum_limen-2.5.5/limen/features/regime_multiplier.py +30 -0
- vaquum_limen-2.5.5/limen/features/rejection_intensity.py +40 -0
- vaquum_limen-2.5.5/limen/features/relative_range_seasonality.py +59 -0
- vaquum_limen-2.5.5/limen/features/relative_volatility_seasonality.py +55 -0
- vaquum_limen-2.5.5/limen/features/relative_volume_seasonality.py +53 -0
- vaquum_limen-2.5.5/limen/features/return_per_dollar_volume.py +28 -0
- vaquum_limen-2.5.5/limen/features/returns_lags.py +26 -0
- vaquum_limen-2.5.5/limen/features/risk_reward_ratio.py +22 -0
- vaquum_limen-2.5.5/limen/features/rogers_satchell_volatility.py +45 -0
- vaquum_limen-2.5.5/limen/features/sma_crossover.py +49 -0
- vaquum_limen-2.5.5/limen/features/sma_ratios.py +37 -0
- vaquum_limen-2.5.5/limen/features/spread.py +17 -0
- vaquum_limen-2.5.5/limen/features/spread_percent.py +19 -0
- vaquum_limen-2.5.5/limen/features/tail_event_intensity.py +37 -0
- vaquum_limen-2.5.5/limen/features/trend_coherence.py +32 -0
- vaquum_limen-2.5.5/limen/features/trend_strength.py +28 -0
- vaquum_limen-2.5.5/limen/features/volatility_1h.py +18 -0
- vaquum_limen-2.5.5/limen/features/volatility_measure.py +19 -0
- vaquum_limen-2.5.5/limen/features/volatility_of_volatility.py +34 -0
- vaquum_limen-2.5.5/limen/features/volatility_term_structure.py +52 -0
- vaquum_limen-2.5.5/limen/features/volatility_weight.py +37 -0
- vaquum_limen-2.5.5/limen/features/volume_ratio.py +26 -0
- vaquum_limen-2.5.5/limen/features/volume_regime.py +27 -0
- vaquum_limen-2.5.5/limen/features/volume_spike.py +27 -0
- vaquum_limen-2.5.5/limen/features/volume_trend.py +32 -0
- vaquum_limen-2.5.5/limen/features/volume_weight.py +30 -0
- vaquum_limen-2.5.5/limen/features/vwap.py +40 -0
- vaquum_limen-2.5.5/limen/features/wick_imbalance.py +33 -0
- vaquum_limen-2.5.5/limen/features/window_return_regime.py +30 -0
- vaquum_limen-2.5.5/limen/features/yang_zhang_volatility.py +63 -0
- vaquum_limen-2.5.5/limen/indicators/__init__.py +237 -0
- vaquum_limen-2.5.5/limen/indicators/_atr.py +49 -0
- vaquum_limen-2.5.5/limen/indicators/_bbands.py +85 -0
- vaquum_limen-2.5.5/limen/indicators/_ema.py +45 -0
- vaquum_limen-2.5.5/limen/indicators/_hilbert.py +40 -0
- vaquum_limen-2.5.5/limen/indicators/ad.py +38 -0
- vaquum_limen-2.5.5/limen/indicators/adosc.py +71 -0
- vaquum_limen-2.5.5/limen/indicators/apo.py +62 -0
- vaquum_limen-2.5.5/limen/indicators/atr.py +47 -0
- vaquum_limen-2.5.5/limen/indicators/avgprice.py +33 -0
- vaquum_limen-2.5.5/limen/indicators/bbands.py +108 -0
- vaquum_limen-2.5.5/limen/indicators/body_pct.py +16 -0
- vaquum_limen-2.5.5/limen/indicators/bollinger_bands.py +42 -0
- vaquum_limen-2.5.5/limen/indicators/bollinger_position.py +28 -0
- vaquum_limen-2.5.5/limen/indicators/bop.py +37 -0
- vaquum_limen-2.5.5/limen/indicators/cci.py +82 -0
- vaquum_limen-2.5.5/limen/indicators/cdl2crows.py +117 -0
- vaquum_limen-2.5.5/limen/indicators/cdl3blackcrows.py +116 -0
- vaquum_limen-2.5.5/limen/indicators/cdl3inside.py +125 -0
- vaquum_limen-2.5.5/limen/indicators/cdl3linestrike.py +123 -0
- vaquum_limen-2.5.5/limen/indicators/cdl3starsinsouth.py +175 -0
- vaquum_limen-2.5.5/limen/indicators/cdl3whitesoldiers.py +180 -0
- vaquum_limen-2.5.5/limen/indicators/cdlabandonedbaby.py +168 -0
- vaquum_limen-2.5.5/limen/indicators/cdladvancedblock.py +253 -0
- vaquum_limen-2.5.5/limen/indicators/cdlbelthold.py +117 -0
- vaquum_limen-2.5.5/limen/indicators/cdlclosingmarubozu.py +117 -0
- vaquum_limen-2.5.5/limen/indicators/cdlconcealbabyswall.py +124 -0
- vaquum_limen-2.5.5/limen/indicators/cdlcounterattack.py +123 -0
- vaquum_limen-2.5.5/limen/indicators/cdldarkcloudcover.py +110 -0
- vaquum_limen-2.5.5/limen/indicators/cdldoji.py +93 -0
- vaquum_limen-2.5.5/limen/indicators/cdldragonflydoji.py +118 -0
- vaquum_limen-2.5.5/limen/indicators/cdlengulfing.py +93 -0
- vaquum_limen-2.5.5/limen/indicators/cdlgravestonedoji.py +118 -0
- vaquum_limen-2.5.5/limen/indicators/cdlhammer.py +160 -0
- vaquum_limen-2.5.5/limen/indicators/cdlhangingman.py +160 -0
- vaquum_limen-2.5.5/limen/indicators/cdlharami.py +116 -0
- vaquum_limen-2.5.5/limen/indicators/cdlharamicross.py +119 -0
- vaquum_limen-2.5.5/limen/indicators/cdlhighwave.py +120 -0
- vaquum_limen-2.5.5/limen/indicators/cdlhikkake.py +115 -0
- vaquum_limen-2.5.5/limen/indicators/cdlhikkakemod.py +161 -0
- vaquum_limen-2.5.5/limen/indicators/cdlhomingpigeon.py +116 -0
- vaquum_limen-2.5.5/limen/indicators/cdlidentical3crows.py +138 -0
- vaquum_limen-2.5.5/limen/indicators/cdlinvertedhammer.py +140 -0
- vaquum_limen-2.5.5/limen/indicators/cdlladderbottom.py +112 -0
- vaquum_limen-2.5.5/limen/indicators/cdllongleggeddoji.py +117 -0
- vaquum_limen-2.5.5/limen/indicators/cdllongline.py +120 -0
- vaquum_limen-2.5.5/limen/indicators/cdlmarubozu.py +118 -0
- vaquum_limen-2.5.5/limen/indicators/cdlmatchinglow.py +99 -0
- vaquum_limen-2.5.5/limen/indicators/cdlmathold.py +153 -0
- vaquum_limen-2.5.5/limen/indicators/cdlonneck.py +118 -0
- vaquum_limen-2.5.5/limen/indicators/cdlpiercing.py +104 -0
- vaquum_limen-2.5.5/limen/indicators/cdlrickshawman.py +146 -0
- vaquum_limen-2.5.5/limen/indicators/cdlrisefall3methods.py +147 -0
- vaquum_limen-2.5.5/limen/indicators/cdlseparatinglines.py +142 -0
- vaquum_limen-2.5.5/limen/indicators/cdlshootingstar.py +140 -0
- vaquum_limen-2.5.5/limen/indicators/cdlshortline.py +120 -0
- vaquum_limen-2.5.5/limen/indicators/cdlspinningtop.py +98 -0
- vaquum_limen-2.5.5/limen/indicators/cdlstalledpattern.py +167 -0
- vaquum_limen-2.5.5/limen/indicators/cdlsticksandwich.py +102 -0
- vaquum_limen-2.5.5/limen/indicators/cdltakuri.py +140 -0
- vaquum_limen-2.5.5/limen/indicators/cdlthrusting.py +119 -0
- vaquum_limen-2.5.5/limen/indicators/cdltristar.py +111 -0
- vaquum_limen-2.5.5/limen/indicators/cdlunique3river.py +123 -0
- vaquum_limen-2.5.5/limen/indicators/cmo.py +109 -0
- vaquum_limen-2.5.5/limen/indicators/dema.py +69 -0
- vaquum_limen-2.5.5/limen/indicators/ema.py +57 -0
- vaquum_limen-2.5.5/limen/indicators/ht_dcperiod.py +220 -0
- vaquum_limen-2.5.5/limen/indicators/ht_dcphase.py +266 -0
- vaquum_limen-2.5.5/limen/indicators/ht_phasor.py +235 -0
- vaquum_limen-2.5.5/limen/indicators/ht_sine.py +280 -0
- vaquum_limen-2.5.5/limen/indicators/ht_trendline.py +252 -0
- vaquum_limen-2.5.5/limen/indicators/ht_trendmode.py +326 -0
- vaquum_limen-2.5.5/limen/indicators/kama.py +133 -0
- vaquum_limen-2.5.5/limen/indicators/linearreg.py +75 -0
- vaquum_limen-2.5.5/limen/indicators/linearreg_angle.py +76 -0
- vaquum_limen-2.5.5/limen/indicators/linearreg_intercept.py +74 -0
- vaquum_limen-2.5.5/limen/indicators/linearreg_slope.py +73 -0
- vaquum_limen-2.5.5/limen/indicators/ma.py +146 -0
- vaquum_limen-2.5.5/limen/indicators/macd.py +97 -0
- vaquum_limen-2.5.5/limen/indicators/macdext.py +185 -0
- vaquum_limen-2.5.5/limen/indicators/macdfix.py +95 -0
- vaquum_limen-2.5.5/limen/indicators/mama.py +274 -0
- vaquum_limen-2.5.5/limen/indicators/medprice.py +27 -0
- vaquum_limen-2.5.5/limen/indicators/mfi.py +87 -0
- vaquum_limen-2.5.5/limen/indicators/midpoint.py +69 -0
- vaquum_limen-2.5.5/limen/indicators/midprice.py +71 -0
- vaquum_limen-2.5.5/limen/indicators/mom.py +34 -0
- vaquum_limen-2.5.5/limen/indicators/natr.py +66 -0
- vaquum_limen-2.5.5/limen/indicators/obv.py +32 -0
- vaquum_limen-2.5.5/limen/indicators/ppo.py +72 -0
- vaquum_limen-2.5.5/limen/indicators/price_change_pct.py +23 -0
- vaquum_limen-2.5.5/limen/indicators/returns.py +16 -0
- vaquum_limen-2.5.5/limen/indicators/roc.py +37 -0
- vaquum_limen-2.5.5/limen/indicators/rocp.py +37 -0
- vaquum_limen-2.5.5/limen/indicators/rocr.py +37 -0
- vaquum_limen-2.5.5/limen/indicators/rocr100.py +37 -0
- vaquum_limen-2.5.5/limen/indicators/rolling_volatility.py +22 -0
- vaquum_limen-2.5.5/limen/indicators/rsi.py +89 -0
- vaquum_limen-2.5.5/limen/indicators/rsi_sma.py +37 -0
- vaquum_limen-2.5.5/limen/indicators/sar.py +157 -0
- vaquum_limen-2.5.5/limen/indicators/sarext.py +218 -0
- vaquum_limen-2.5.5/limen/indicators/sma.py +78 -0
- vaquum_limen-2.5.5/limen/indicators/sma_deviation_std.py +36 -0
- vaquum_limen-2.5.5/limen/indicators/stddev.py +101 -0
- vaquum_limen-2.5.5/limen/indicators/stoch.py +203 -0
- vaquum_limen-2.5.5/limen/indicators/stochastic_oscillator.py +43 -0
- vaquum_limen-2.5.5/limen/indicators/stochf.py +179 -0
- vaquum_limen-2.5.5/limen/indicators/stochrsi.py +91 -0
- vaquum_limen-2.5.5/limen/indicators/t3.py +157 -0
- vaquum_limen-2.5.5/limen/indicators/tema.py +69 -0
- vaquum_limen-2.5.5/limen/indicators/trange.py +37 -0
- vaquum_limen-2.5.5/limen/indicators/trima.py +160 -0
- vaquum_limen-2.5.5/limen/indicators/trix.py +76 -0
- vaquum_limen-2.5.5/limen/indicators/tsf.py +75 -0
- vaquum_limen-2.5.5/limen/indicators/typprice.py +30 -0
- vaquum_limen-2.5.5/limen/indicators/ultosc.py +164 -0
- vaquum_limen-2.5.5/limen/indicators/var.py +92 -0
- vaquum_limen-2.5.5/limen/indicators/wclprice.py +30 -0
- vaquum_limen-2.5.5/limen/indicators/wilder_rsi.py +35 -0
- vaquum_limen-2.5.5/limen/indicators/willr.py +48 -0
- vaquum_limen-2.5.5/limen/indicators/window_return.py +20 -0
- vaquum_limen-2.5.5/limen/indicators/wma.py +92 -0
- vaquum_limen-2.5.5/limen/log/__init__.py +13 -0
- vaquum_limen-2.5.5/limen/log/_experiment_backtest_results.py +109 -0
- vaquum_limen-2.5.5/limen/log/_experiment_confusion_metrics.py +32 -0
- vaquum_limen-2.5.5/limen/log/_experiment_parameter_correlation.py +172 -0
- vaquum_limen-2.5.5/limen/log/_permutation_confusion_metrics.py +232 -0
- vaquum_limen-2.5.5/limen/log/_permutation_prediction_performance.py +38 -0
- vaquum_limen-2.5.5/limen/log/_read_from_file.py +44 -0
- vaquum_limen-2.5.5/limen/log/log.py +109 -0
- vaquum_limen-2.5.5/limen/metrics/__init__.py +16 -0
- vaquum_limen-2.5.5/limen/metrics/balanced_metric.py +29 -0
- vaquum_limen-2.5.5/limen/metrics/binary_metrics.py +25 -0
- vaquum_limen-2.5.5/limen/metrics/continuous_metrics.py +37 -0
- vaquum_limen-2.5.5/limen/metrics/multiclass_metrics.py +27 -0
- vaquum_limen-2.5.5/limen/metrics/rule_based_metrics.py +74 -0
- vaquum_limen-2.5.5/limen/metrics/safe_ovr_auc.py +29 -0
- vaquum_limen-2.5.5/limen/scalers/__init__.py +13 -0
- vaquum_limen-2.5.5/limen/scalers/linear_scaler.py +196 -0
- vaquum_limen-2.5.5/limen/scalers/logreg_scaler.py +133 -0
- vaquum_limen-2.5.5/limen/scalers/rank_gauss_scaler.py +124 -0
- vaquum_limen-2.5.5/limen/scalers/registry.py +11 -0
- vaquum_limen-2.5.5/limen/scalers/robust_scaler.py +96 -0
- vaquum_limen-2.5.5/limen/sfd/__init__.py +13 -0
- vaquum_limen-2.5.5/limen/sfd/foundational_sfd/__init__.py +18 -0
- vaquum_limen-2.5.5/limen/sfd/foundational_sfd/logreg_binary.py +72 -0
- vaquum_limen-2.5.5/limen/sfd/foundational_sfd/random_binary.py +40 -0
- vaquum_limen-2.5.5/limen/sfd/foundational_sfd/rule_based.py +58 -0
- vaquum_limen-2.5.5/limen/sfd/foundational_sfd/tabpfn_binary.py +80 -0
- vaquum_limen-2.5.5/limen/sfd/foundational_sfd/xgboost_regressor.py +85 -0
- vaquum_limen-2.5.5/limen/sfd/loop/__init__.py +10 -0
- vaquum_limen-2.5.5/limen/sfd/loop/loop_sfd.py +562 -0
- vaquum_limen-2.5.5/limen/sfd/loop/meta.py +103 -0
- vaquum_limen-2.5.5/limen/sfd/loop/progress.py +65 -0
- vaquum_limen-2.5.5/limen/sfd/loop/registry.py +46 -0
- vaquum_limen-2.5.5/limen/sfd/loop/run.py +311 -0
- vaquum_limen-2.5.5/limen/sfd/reference_architecture/__init__.py +31 -0
- vaquum_limen-2.5.5/limen/sfd/reference_architecture/base.py +158 -0
- vaquum_limen-2.5.5/limen/sfd/reference_architecture/logreg_binary.py +138 -0
- vaquum_limen-2.5.5/limen/sfd/reference_architecture/random_binary.py +100 -0
- vaquum_limen-2.5.5/limen/sfd/reference_architecture/rule_based.py +149 -0
- vaquum_limen-2.5.5/limen/sfd/reference_architecture/tabpfn_binary.py +174 -0
- vaquum_limen-2.5.5/limen/sfd/reference_architecture/xgboost_regressor.py +150 -0
- vaquum_limen-2.5.5/limen/sfd/rule_based/__init__.py +4 -0
- vaquum_limen-2.5.5/limen/sfd/rule_based/config.py +107 -0
- vaquum_limen-2.5.5/limen/sfd/rule_based/predicates.py +254 -0
- vaquum_limen-2.5.5/limen/trading/__init__.py +5 -0
- vaquum_limen-2.5.5/limen/trading/account.py +179 -0
- vaquum_limen-2.5.5/limen/transforms/__init__.py +17 -0
- vaquum_limen-2.5.5/limen/transforms/calibrate_classifier.py +29 -0
- vaquum_limen-2.5.5/limen/transforms/mad_transform.py +34 -0
- vaquum_limen-2.5.5/limen/transforms/optimize_binary_threshold.py +51 -0
- vaquum_limen-2.5.5/limen/transforms/quantile_trim_transform.py +41 -0
- vaquum_limen-2.5.5/limen/transforms/shift_column_transform.py +20 -0
- vaquum_limen-2.5.5/limen/transforms/winsorize_transform.py +42 -0
- vaquum_limen-2.5.5/limen/transforms/zscore_transform.py +38 -0
- vaquum_limen-2.5.5/limen/utils/__init__.py +23 -0
- vaquum_limen-2.5.5/limen/utils/adf_test.py +60 -0
- vaquum_limen-2.5.5/limen/utils/confidence_filtering_system.py +185 -0
- vaquum_limen-2.5.5/limen/utils/data_dict_to_numpy.py +23 -0
- vaquum_limen-2.5.5/limen/utils/param_space.py +137 -0
- vaquum_limen-2.5.5/limen/utils/reporting.py +45 -0
- vaquum_limen-2.5.5/pyproject.toml +136 -0
- vaquum_limen-2.5.5/setup.cfg +4 -0
- vaquum_limen-2.5.5/tests/test_account_conviction.py +264 -0
- vaquum_limen-2.5.5/tests/test_backtest_conviction.py +267 -0
- vaquum_limen-2.5.5/tests/test_bars.py +152 -0
- vaquum_limen-2.5.5/tests/test_budget_reducer.py +415 -0
- vaquum_limen-2.5.5/tests/test_checkpoint_manager.py +522 -0
- vaquum_limen-2.5.5/tests/test_confidence_filtering_system.py +181 -0
- vaquum_limen-2.5.5/tests/test_conserved_flux_renormalization.py +14 -0
- vaquum_limen-2.5.5/tests/test_correlation_reducer.py +213 -0
- vaquum_limen-2.5.5/tests/test_experiment_core_msq.py +596 -0
- vaquum_limen-2.5.5/tests/test_experiment_core_standard_csv.py +173 -0
- vaquum_limen-2.5.5/tests/test_feature_library_candle_structure.py +34 -0
- vaquum_limen-2.5.5/tests/test_feature_library_composites.py +198 -0
- vaquum_limen-2.5.5/tests/test_feature_library_context.py +107 -0
- vaquum_limen-2.5.5/tests/test_feature_library_cross_timescale.py +30 -0
- vaquum_limen-2.5.5/tests/test_feature_library_liquidity.py +54 -0
- vaquum_limen-2.5.5/tests/test_feature_library_primitives.py +139 -0
- vaquum_limen-2.5.5/tests/test_feature_library_range_volatility.py +76 -0
- vaquum_limen-2.5.5/tests/test_feature_library_realized_risk.py +77 -0
- vaquum_limen-2.5.5/tests/test_feature_library_regimes.py +296 -0
- vaquum_limen-2.5.5/tests/test_feature_library_seasonality.py +79 -0
- vaquum_limen-2.5.5/tests/test_feature_perturbation.py +269 -0
- vaquum_limen-2.5.5/tests/test_feedback_controller.py +446 -0
- vaquum_limen-2.5.5/tests/test_focus_reducer.py +434 -0
- vaquum_limen-2.5.5/tests/test_foundational_sfd.py +79 -0
- vaquum_limen-2.5.5/tests/test_fractional_diff.py +181 -0
- vaquum_limen-2.5.5/tests/test_historical_data.py +173 -0
- vaquum_limen-2.5.5/tests/test_indicator_and_data_helpers.py +319 -0
- vaquum_limen-2.5.5/tests/test_indicator_api.py +30 -0
- vaquum_limen-2.5.5/tests/test_indicators_vs_talib.py +1990 -0
- vaquum_limen-2.5.5/tests/test_inline_metrics.py +96 -0
- vaquum_limen-2.5.5/tests/test_klines_data_maker_fields.py +35 -0
- vaquum_limen-2.5.5/tests/test_large_param_space.py +48 -0
- vaquum_limen-2.5.5/tests/test_log_read_from_file.py +68 -0
- vaquum_limen-2.5.5/tests/test_loop_sfd.py +1072 -0
- vaquum_limen-2.5.5/tests/test_manifest_pre_split_random_selector.py +47 -0
- vaquum_limen-2.5.5/tests/test_manifest_prepare_data.py +264 -0
- vaquum_limen-2.5.5/tests/test_manifest_rule_based.py +105 -0
- vaquum_limen-2.5.5/tests/test_metrics_and_log_helpers.py +499 -0
- vaquum_limen-2.5.5/tests/test_msq.py +401 -0
- vaquum_limen-2.5.5/tests/test_param_domain.py +266 -0
- vaquum_limen-2.5.5/tests/test_param_space.py +218 -0
- vaquum_limen-2.5.5/tests/test_predicates.py +141 -0
- vaquum_limen-2.5.5/tests/test_proto_cohort.py +837 -0
- vaquum_limen-2.5.5/tests/test_pruning_strategy.py +34 -0
- vaquum_limen-2.5.5/tests/test_reducer_factory.py +34 -0
- vaquum_limen-2.5.5/tests/test_reference_architecture.py +286 -0
- vaquum_limen-2.5.5/tests/test_regime_diversified_opinion_pools.py +86 -0
- vaquum_limen-2.5.5/tests/test_regime_pools_helpers.py +262 -0
- vaquum_limen-2.5.5/tests/test_rule_based_metrics.py +85 -0
- vaquum_limen-2.5.5/tests/test_runtime_tracking.py +194 -0
- vaquum_limen-2.5.5/tests/test_sanity_reducer.py +237 -0
- vaquum_limen-2.5.5/tests/test_saturation_reducer.py +218 -0
- vaquum_limen-2.5.5/tests/test_scalers.py +238 -0
- vaquum_limen-2.5.5/tests/test_search_strategies.py +289 -0
- vaquum_limen-2.5.5/tests/test_splits.py +48 -0
- vaquum_limen-2.5.5/tests/test_tabpfn.py +52 -0
- vaquum_limen-2.5.5/tests/test_trainer.py +484 -0
- vaquum_limen-2.5.5/tests/test_transforms.py +114 -0
- vaquum_limen-2.5.5/vaquum_limen.egg-info/PKG-INFO +148 -0
- vaquum_limen-2.5.5/vaquum_limen.egg-info/SOURCES.txt +376 -0
- vaquum_limen-2.5.5/vaquum_limen.egg-info/dependency_links.txt +1 -0
- vaquum_limen-2.5.5/vaquum_limen.egg-info/requires.txt +17 -0
- vaquum_limen-2.5.5/vaquum_limen.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Vaquum
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vaquum_limen
|
|
3
|
+
Version: 2.5.5
|
|
4
|
+
Summary: Bitcoin-first research and trading platform.
|
|
5
|
+
Author: Prasenjit Dey, Arun Raguraman, Jatin Thakur, Soujanyaa Boruah, Ng Wei Da
|
|
6
|
+
Author-email: Mikko Kotila <mailme@mikkokotila.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://vaquum.fi
|
|
9
|
+
Project-URL: Documentation, https://docs.vaquum.fi/limen/
|
|
10
|
+
Project-URL: Repository, https://github.com/vaquum/limen
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: pandas>=2.3.1
|
|
15
|
+
Requires-Dist: polars>=1.0.0
|
|
16
|
+
Requires-Dist: scikit-learn>=1.6.1
|
|
17
|
+
Requires-Dist: tqdm>=4.67.0
|
|
18
|
+
Requires-Dist: xgboost
|
|
19
|
+
Requires-Dist: python-dotenv
|
|
20
|
+
Requires-Dist: scipy
|
|
21
|
+
Requires-Dist: statsmodels
|
|
22
|
+
Requires-Dist: tslearn
|
|
23
|
+
Requires-Dist: lightgbm
|
|
24
|
+
Requires-Dist: pyarrow
|
|
25
|
+
Requires-Dist: numpy>=2.2.6
|
|
26
|
+
Requires-Dist: ta-lib
|
|
27
|
+
Requires-Dist: requests
|
|
28
|
+
Provides-Extra: tabpfn
|
|
29
|
+
Requires-Dist: tabpfn>=6; extra == "tabpfn"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
<div align="center">
|
|
33
|
+
<br />
|
|
34
|
+
<a href="https://github.com/Vaquum"><img src="https://github.com/Vaquum/Home/raw/main/assets/Logo.png" alt="Vaquum" width="150" /></a>
|
|
35
|
+
<br />
|
|
36
|
+
</div>
|
|
37
|
+
<br />
|
|
38
|
+
<div align="center"><strong>Vaquum Limen turns Bitcoin market data into searchable signals, backtested outcomes, and decoder cohorts.</strong></div>
|
|
39
|
+
|
|
40
|
+
<div align="center">
|
|
41
|
+
<a href="#limen">Limen</a> •
|
|
42
|
+
<a href="#what-limen-is-not">What Limen Is Not</a> •
|
|
43
|
+
<a href="#capabilities">Capabilities</a> •
|
|
44
|
+
<a href="#first-experiment">First Experiment</a> •
|
|
45
|
+
<a href="#learn-more">Learn More</a>
|
|
46
|
+
</div>
|
|
47
|
+
<br />
|
|
48
|
+
<div align="center">
|
|
49
|
+
<a href="https://www.bestpractices.dev/projects/11898"><img src="https://www.bestpractices.dev/projects/11898/badge" alt="OpenSSF Best Practices" /></a>
|
|
50
|
+
<a href="https://scorecard.dev/viewer/?uri=github.com/Vaquum/Limen"><img src="https://img.shields.io/ossf-scorecard/github.com/Vaquum/Limen?label=openssf+scorecard&style=flat" alt="OpenSSF Scorecard" /></a>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<hr />
|
|
54
|
+
|
|
55
|
+
<a id="limen"></a>
|
|
56
|
+
|
|
57
|
+
# Limen — The Research Engine
|
|
58
|
+
|
|
59
|
+
*Manifest-driven Bitcoin alpha research engine that turns market data into searchable signals, backtested outcomes, and decoder cohorts.*
|
|
60
|
+
|
|
61
|
+
Limen unifies parameter search across machine learning and rule-based strategies, with built-in analytics that show not just what works, but why it works. It evolves from Talos, the hyperparameter optimization framework for TensorFlow and Keras cited in over 1,000 scientific papers with zero breaking bugs in six years.
|
|
62
|
+
|
|
63
|
+
## What Limen Is Not
|
|
64
|
+
|
|
65
|
+
Limen is not:
|
|
66
|
+
|
|
67
|
+
- a trade execution system
|
|
68
|
+
- a downstream trade decision engine
|
|
69
|
+
- a generic multi-asset research platform
|
|
70
|
+
|
|
71
|
+
In the wider Vaquum architecture, Origo sits upstream as the data layer. Nexus, Praxis, and Veritas sit downstream for decisioning, execution, and oversight.
|
|
72
|
+
|
|
73
|
+
## Capabilities
|
|
74
|
+
|
|
75
|
+
- Manifest-driven experiment pipelines
|
|
76
|
+
- Search across models, rules, features, targets, and hyperparameters
|
|
77
|
+
- Extensive built-in indicator and feature library for Bitcoin research
|
|
78
|
+
- Support for both machine learning and rule-based strategy research
|
|
79
|
+
- Bitcoin-native transforms, scaling, and target construction
|
|
80
|
+
- Leakage-safe train, validation, and test workflows
|
|
81
|
+
- Built-in backtesting, confusion analytics, and parameter diagnostics
|
|
82
|
+
- Decoder cohort construction and regime-diversified model pooling
|
|
83
|
+
- Reproducible runs with checkpointing, resumption, and retraining
|
|
84
|
+
|
|
85
|
+
## First Experiment
|
|
86
|
+
|
|
87
|
+
The fastest first success is a small parameter sweep on the bundled BTC/USDT kline dataset with the built-in logistic-regression decoder.
|
|
88
|
+
|
|
89
|
+
1. Install the package:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
pip install vaquum_limen
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
2. Load data and run a first experiment:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
import limen
|
|
99
|
+
|
|
100
|
+
historical = limen.HistoricalData()
|
|
101
|
+
data = historical.get_spot_klines(kline_size=7200, n_rows=2000)
|
|
102
|
+
|
|
103
|
+
uel = limen.UniversalExperimentLoop(data=data, sfd=limen.sfd.logreg_binary)
|
|
104
|
+
|
|
105
|
+
uel.run(
|
|
106
|
+
experiment_name="logreg-first",
|
|
107
|
+
n_permutations=25,
|
|
108
|
+
prep_each_round=True,
|
|
109
|
+
)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
3. Inspect the core outputs:
|
|
113
|
+
|
|
114
|
+
- `uel.experiment_log` for the parameter sweep results
|
|
115
|
+
- `uel.experiment_confusion_metrics` for confusion analytics
|
|
116
|
+
- `uel.experiment_backtest_results` for backtest results
|
|
117
|
+
|
|
118
|
+
That path is the simplest way to get a real Limen run on your machine without relying on repo-local fixture files. If you want richer run directories, checkpoints, resumability, and stored round artefacts, continue into the UEL documentation below.
|
|
119
|
+
|
|
120
|
+
## Learn More
|
|
121
|
+
|
|
122
|
+
- Start with the full docs hub in [docs/README.md](docs/README.md)
|
|
123
|
+
- Define research units in [docs/Single-File-Decoder.md](docs/Single-File-Decoder.md), [docs/Built-In-SFDs.md](docs/Built-In-SFDs.md), and [docs/Experiment-Manifest.md](docs/Experiment-Manifest.md)
|
|
124
|
+
- Run experiments in [docs/Universal-Experiment-Loop.md](docs/Universal-Experiment-Loop.md) and extend the artifact-rich path through [docs/Advanced-Search.md](docs/Advanced-Search.md) and [docs/Reducers-And-Feedback.md](docs/Reducers-And-Feedback.md)
|
|
125
|
+
- Analyze results in [docs/Log.md](docs/Log.md), [docs/Benchmark.md](docs/Benchmark.md), and [docs/Backtest.md](docs/Backtest.md)
|
|
126
|
+
- Understand the model layer in [docs/Reference-Architecture.md](docs/Reference-Architecture.md) and the helper layer in [docs/Utilities.md](docs/Utilities.md)
|
|
127
|
+
- Promote finished runs into reusable outputs with [docs/Trainer.md](docs/Trainer.md) and [docs/Regime-Diversified-Opinion-Pools.md](docs/Regime-Diversified-Opinion-Pools.md)
|
|
128
|
+
- Contribute through [docs/Developer/README.md](docs/Developer/README.md)
|
|
129
|
+
|
|
130
|
+
## Contributing
|
|
131
|
+
|
|
132
|
+
The simplest way to start contributing is by [joining an open discussion](https://github.com/Vaquum/Limen/issues?q=is%3Aissue%20state%3Aopen%20label%3Aquestion%2Fdiscussion), contributing to [the docs](https://github.com/Vaquum/Limen/tree/main/docs), or by [picking up an open issue](https://github.com/Vaquum/Limen/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug%20OR%20label%3Aenhancement%20OR%20label%3A%22good%20first%20issue%22%20OR%20label%3A%22help%20wanted%22%20OR%20label%3APriority%20OR%20label%3Aprocess).
|
|
133
|
+
|
|
134
|
+
Before contributing, start with [docs/Developer/README.md](docs/Developer/README.md).
|
|
135
|
+
|
|
136
|
+
## Vulnerabilities
|
|
137
|
+
|
|
138
|
+
Report vulnerabilities privately through [GitHub Security Advisories](https://github.com/Vaquum/Limen/security/advisories/new).
|
|
139
|
+
|
|
140
|
+
## Citations
|
|
141
|
+
|
|
142
|
+
If you use Limen for published work, please cite:
|
|
143
|
+
|
|
144
|
+
Vaquum Limen [Computer software]. (2026). Retrieved from https://github.com/Vaquum/Limen.
|
|
145
|
+
|
|
146
|
+
## License
|
|
147
|
+
|
|
148
|
+
[MIT License](https://github.com/Vaquum/Limen/blob/main/LICENSE).
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<br />
|
|
3
|
+
<a href="https://github.com/Vaquum"><img src="https://github.com/Vaquum/Home/raw/main/assets/Logo.png" alt="Vaquum" width="150" /></a>
|
|
4
|
+
<br />
|
|
5
|
+
</div>
|
|
6
|
+
<br />
|
|
7
|
+
<div align="center"><strong>Vaquum Limen turns Bitcoin market data into searchable signals, backtested outcomes, and decoder cohorts.</strong></div>
|
|
8
|
+
|
|
9
|
+
<div align="center">
|
|
10
|
+
<a href="#limen">Limen</a> •
|
|
11
|
+
<a href="#what-limen-is-not">What Limen Is Not</a> •
|
|
12
|
+
<a href="#capabilities">Capabilities</a> •
|
|
13
|
+
<a href="#first-experiment">First Experiment</a> •
|
|
14
|
+
<a href="#learn-more">Learn More</a>
|
|
15
|
+
</div>
|
|
16
|
+
<br />
|
|
17
|
+
<div align="center">
|
|
18
|
+
<a href="https://www.bestpractices.dev/projects/11898"><img src="https://www.bestpractices.dev/projects/11898/badge" alt="OpenSSF Best Practices" /></a>
|
|
19
|
+
<a href="https://scorecard.dev/viewer/?uri=github.com/Vaquum/Limen"><img src="https://img.shields.io/ossf-scorecard/github.com/Vaquum/Limen?label=openssf+scorecard&style=flat" alt="OpenSSF Scorecard" /></a>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<hr />
|
|
23
|
+
|
|
24
|
+
<a id="limen"></a>
|
|
25
|
+
|
|
26
|
+
# Limen — The Research Engine
|
|
27
|
+
|
|
28
|
+
*Manifest-driven Bitcoin alpha research engine that turns market data into searchable signals, backtested outcomes, and decoder cohorts.*
|
|
29
|
+
|
|
30
|
+
Limen unifies parameter search across machine learning and rule-based strategies, with built-in analytics that show not just what works, but why it works. It evolves from Talos, the hyperparameter optimization framework for TensorFlow and Keras cited in over 1,000 scientific papers with zero breaking bugs in six years.
|
|
31
|
+
|
|
32
|
+
## What Limen Is Not
|
|
33
|
+
|
|
34
|
+
Limen is not:
|
|
35
|
+
|
|
36
|
+
- a trade execution system
|
|
37
|
+
- a downstream trade decision engine
|
|
38
|
+
- a generic multi-asset research platform
|
|
39
|
+
|
|
40
|
+
In the wider Vaquum architecture, Origo sits upstream as the data layer. Nexus, Praxis, and Veritas sit downstream for decisioning, execution, and oversight.
|
|
41
|
+
|
|
42
|
+
## Capabilities
|
|
43
|
+
|
|
44
|
+
- Manifest-driven experiment pipelines
|
|
45
|
+
- Search across models, rules, features, targets, and hyperparameters
|
|
46
|
+
- Extensive built-in indicator and feature library for Bitcoin research
|
|
47
|
+
- Support for both machine learning and rule-based strategy research
|
|
48
|
+
- Bitcoin-native transforms, scaling, and target construction
|
|
49
|
+
- Leakage-safe train, validation, and test workflows
|
|
50
|
+
- Built-in backtesting, confusion analytics, and parameter diagnostics
|
|
51
|
+
- Decoder cohort construction and regime-diversified model pooling
|
|
52
|
+
- Reproducible runs with checkpointing, resumption, and retraining
|
|
53
|
+
|
|
54
|
+
## First Experiment
|
|
55
|
+
|
|
56
|
+
The fastest first success is a small parameter sweep on the bundled BTC/USDT kline dataset with the built-in logistic-regression decoder.
|
|
57
|
+
|
|
58
|
+
1. Install the package:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install vaquum_limen
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
2. Load data and run a first experiment:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
import limen
|
|
68
|
+
|
|
69
|
+
historical = limen.HistoricalData()
|
|
70
|
+
data = historical.get_spot_klines(kline_size=7200, n_rows=2000)
|
|
71
|
+
|
|
72
|
+
uel = limen.UniversalExperimentLoop(data=data, sfd=limen.sfd.logreg_binary)
|
|
73
|
+
|
|
74
|
+
uel.run(
|
|
75
|
+
experiment_name="logreg-first",
|
|
76
|
+
n_permutations=25,
|
|
77
|
+
prep_each_round=True,
|
|
78
|
+
)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
3. Inspect the core outputs:
|
|
82
|
+
|
|
83
|
+
- `uel.experiment_log` for the parameter sweep results
|
|
84
|
+
- `uel.experiment_confusion_metrics` for confusion analytics
|
|
85
|
+
- `uel.experiment_backtest_results` for backtest results
|
|
86
|
+
|
|
87
|
+
That path is the simplest way to get a real Limen run on your machine without relying on repo-local fixture files. If you want richer run directories, checkpoints, resumability, and stored round artefacts, continue into the UEL documentation below.
|
|
88
|
+
|
|
89
|
+
## Learn More
|
|
90
|
+
|
|
91
|
+
- Start with the full docs hub in [docs/README.md](docs/README.md)
|
|
92
|
+
- Define research units in [docs/Single-File-Decoder.md](docs/Single-File-Decoder.md), [docs/Built-In-SFDs.md](docs/Built-In-SFDs.md), and [docs/Experiment-Manifest.md](docs/Experiment-Manifest.md)
|
|
93
|
+
- Run experiments in [docs/Universal-Experiment-Loop.md](docs/Universal-Experiment-Loop.md) and extend the artifact-rich path through [docs/Advanced-Search.md](docs/Advanced-Search.md) and [docs/Reducers-And-Feedback.md](docs/Reducers-And-Feedback.md)
|
|
94
|
+
- Analyze results in [docs/Log.md](docs/Log.md), [docs/Benchmark.md](docs/Benchmark.md), and [docs/Backtest.md](docs/Backtest.md)
|
|
95
|
+
- Understand the model layer in [docs/Reference-Architecture.md](docs/Reference-Architecture.md) and the helper layer in [docs/Utilities.md](docs/Utilities.md)
|
|
96
|
+
- Promote finished runs into reusable outputs with [docs/Trainer.md](docs/Trainer.md) and [docs/Regime-Diversified-Opinion-Pools.md](docs/Regime-Diversified-Opinion-Pools.md)
|
|
97
|
+
- Contribute through [docs/Developer/README.md](docs/Developer/README.md)
|
|
98
|
+
|
|
99
|
+
## Contributing
|
|
100
|
+
|
|
101
|
+
The simplest way to start contributing is by [joining an open discussion](https://github.com/Vaquum/Limen/issues?q=is%3Aissue%20state%3Aopen%20label%3Aquestion%2Fdiscussion), contributing to [the docs](https://github.com/Vaquum/Limen/tree/main/docs), or by [picking up an open issue](https://github.com/Vaquum/Limen/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug%20OR%20label%3Aenhancement%20OR%20label%3A%22good%20first%20issue%22%20OR%20label%3A%22help%20wanted%22%20OR%20label%3APriority%20OR%20label%3Aprocess).
|
|
102
|
+
|
|
103
|
+
Before contributing, start with [docs/Developer/README.md](docs/Developer/README.md).
|
|
104
|
+
|
|
105
|
+
## Vulnerabilities
|
|
106
|
+
|
|
107
|
+
Report vulnerabilities privately through [GitHub Security Advisories](https://github.com/Vaquum/Limen/security/advisories/new).
|
|
108
|
+
|
|
109
|
+
## Citations
|
|
110
|
+
|
|
111
|
+
If you use Limen for published work, please cite:
|
|
112
|
+
|
|
113
|
+
Vaquum Limen [Computer software]. (2026). Retrieved from https://github.com/Vaquum/Limen.
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
[MIT License](https://github.com/Vaquum/Limen/blob/main/LICENSE).
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from limen.data import HistoricalData
|
|
2
|
+
from limen.log.log import Log
|
|
3
|
+
from limen.trading import Account
|
|
4
|
+
from limen.backtest.backtest_sequential import BacktestSequential
|
|
5
|
+
from limen.experiment import Manifest
|
|
6
|
+
from limen.experiment import ReconstructionError
|
|
7
|
+
from limen.experiment import Sensor
|
|
8
|
+
from limen.experiment import Trainer
|
|
9
|
+
from limen.experiment import UniversalExperimentLoop
|
|
10
|
+
from limen.cohort import Cohort
|
|
11
|
+
from limen.cohort import RegimeDiversifiedOpinionPools
|
|
12
|
+
|
|
13
|
+
from limen import features
|
|
14
|
+
from limen import indicators
|
|
15
|
+
from limen import metrics
|
|
16
|
+
from limen import sfd
|
|
17
|
+
from limen import scalers
|
|
18
|
+
from limen import transforms
|
|
19
|
+
from limen import utils
|
|
20
|
+
from limen import log
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
'Account',
|
|
24
|
+
'BacktestSequential',
|
|
25
|
+
'Cohort',
|
|
26
|
+
'HistoricalData',
|
|
27
|
+
'Log',
|
|
28
|
+
'Manifest',
|
|
29
|
+
'ReconstructionError',
|
|
30
|
+
'RegimeDiversifiedOpinionPools',
|
|
31
|
+
'Sensor',
|
|
32
|
+
'Trainer',
|
|
33
|
+
'UniversalExperimentLoop',
|
|
34
|
+
'features',
|
|
35
|
+
'indicators',
|
|
36
|
+
'log',
|
|
37
|
+
'metrics',
|
|
38
|
+
'scalers',
|
|
39
|
+
'sfd',
|
|
40
|
+
'transforms',
|
|
41
|
+
'utils'
|
|
42
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from collections.abc import Sequence
|
|
3
|
+
from limen.trading import Account
|
|
4
|
+
|
|
5
|
+
class BacktestSequential:
|
|
6
|
+
|
|
7
|
+
def __init__(self, start_usdt: float = 30000) -> None:
|
|
8
|
+
|
|
9
|
+
self.fee_rate = 0.001
|
|
10
|
+
|
|
11
|
+
self.account = Account(start_usdt)
|
|
12
|
+
self.start_usdt = start_usdt
|
|
13
|
+
self.trades = []
|
|
14
|
+
self.equity_curve = []
|
|
15
|
+
|
|
16
|
+
def run(self,
|
|
17
|
+
actual: Sequence[int | float],
|
|
18
|
+
prediction: Sequence[int | float],
|
|
19
|
+
price_change: Sequence[float],
|
|
20
|
+
open_prices: Sequence[float],
|
|
21
|
+
close_prices: Sequence[float]) -> dict:
|
|
22
|
+
|
|
23
|
+
if not all(len(arr) == len(actual) for arr in [prediction, price_change, open_prices, close_prices]):
|
|
24
|
+
raise ValueError('ERROR: Arrays must have same length')
|
|
25
|
+
|
|
26
|
+
for i in range(len(actual)):
|
|
27
|
+
pred = prediction[i]
|
|
28
|
+
act = actual[i]
|
|
29
|
+
open_price = open_prices[i]
|
|
30
|
+
close_price = close_prices[i]
|
|
31
|
+
|
|
32
|
+
if open_price <= 0 or close_price <= 0:
|
|
33
|
+
continue
|
|
34
|
+
|
|
35
|
+
current_usdt = self.account.account['total_usdt'][-1]
|
|
36
|
+
|
|
37
|
+
if pred == 1 and current_usdt > 1:
|
|
38
|
+
buy_fee = current_usdt * self.fee_rate
|
|
39
|
+
usdt_after_buy_fee = current_usdt - buy_fee
|
|
40
|
+
if usdt_after_buy_fee <= 0:
|
|
41
|
+
continue
|
|
42
|
+
self.account.update_account('buy', usdt_after_buy_fee, open_price)
|
|
43
|
+
btc_held = self.account.long_position
|
|
44
|
+
gross_sell_amount = btc_held * close_price
|
|
45
|
+
sell_fee = gross_sell_amount * self.fee_rate
|
|
46
|
+
net_sell_amount = gross_sell_amount - sell_fee
|
|
47
|
+
self.account.update_account('sell', net_sell_amount, close_price)
|
|
48
|
+
final_usdt = self.account.account['total_usdt'][-1]
|
|
49
|
+
profit = final_usdt - current_usdt
|
|
50
|
+
self.trades.append({'type': 'long', 'hit': act == pred, 'pnl': profit, 'volume': usdt_after_buy_fee})
|
|
51
|
+
self.equity_curve.append(final_usdt)
|
|
52
|
+
|
|
53
|
+
return self._calculate_metrics()
|
|
54
|
+
|
|
55
|
+
def _calculate_metrics(self) -> dict:
|
|
56
|
+
|
|
57
|
+
if not self.trades:
|
|
58
|
+
return {
|
|
59
|
+
'PnL': 0,
|
|
60
|
+
'win_rate': 0,
|
|
61
|
+
'max_drawdown': 0,
|
|
62
|
+
'expected_value': 0,
|
|
63
|
+
'sharpe_ratio': 0,
|
|
64
|
+
'net_long_volume': 0,
|
|
65
|
+
'net_short_volume': 0,
|
|
66
|
+
'net_trade_volume': 0
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
final_usdt = self.account.account['total_usdt'][-1]
|
|
70
|
+
pnl = final_usdt - self.start_usdt
|
|
71
|
+
|
|
72
|
+
wins = sum(1 for t in self.trades if t['pnl'] > 0)
|
|
73
|
+
total_trades = len(self.trades)
|
|
74
|
+
win_rate = wins / total_trades if total_trades > 0 else 0
|
|
75
|
+
|
|
76
|
+
max_drawdown = 0
|
|
77
|
+
if self.equity_curve:
|
|
78
|
+
peak = self.equity_curve[0]
|
|
79
|
+
for equity in self.equity_curve:
|
|
80
|
+
peak = max(peak, equity)
|
|
81
|
+
drawdown = (peak - equity) / peak
|
|
82
|
+
max_drawdown = max(max_drawdown, drawdown)
|
|
83
|
+
|
|
84
|
+
expected_value = sum(t['pnl'] for t in self.trades) / total_trades if total_trades > 0 else 0
|
|
85
|
+
|
|
86
|
+
net_long_volume = sum(t['volume'] for t in self.trades if t['type'] == 'long')
|
|
87
|
+
net_short_volume = sum(t['volume'] for t in self.trades if t['type'] == 'short')
|
|
88
|
+
net_trade_volume = net_long_volume + net_short_volume
|
|
89
|
+
|
|
90
|
+
returns = []
|
|
91
|
+
if len(self.equity_curve) > 1:
|
|
92
|
+
prev_equity = self.start_usdt
|
|
93
|
+
for equity in self.equity_curve:
|
|
94
|
+
if prev_equity != 0:
|
|
95
|
+
returns.append((equity - prev_equity) / prev_equity)
|
|
96
|
+
prev_equity = equity
|
|
97
|
+
|
|
98
|
+
if len(returns) > 1:
|
|
99
|
+
mean_return = sum(returns) / len(returns)
|
|
100
|
+
variance = sum((r - mean_return) ** 2 for r in returns) / (len(returns) - 1)
|
|
101
|
+
std_return = math.sqrt(variance)
|
|
102
|
+
sharpe_ratio = mean_return / std_return if std_return != 0 else 0
|
|
103
|
+
else:
|
|
104
|
+
sharpe_ratio = 0
|
|
105
|
+
|
|
106
|
+
# NOTE: These must all be rounded to 2 decimal places.
|
|
107
|
+
return {
|
|
108
|
+
'PnL': round(pnl, 2),
|
|
109
|
+
'win_rate': round(win_rate, 2),
|
|
110
|
+
'max_drawdown': round(max_drawdown, 2),
|
|
111
|
+
'expected_value': round(expected_value, 2),
|
|
112
|
+
'sharpe_ratio': round(sharpe_ratio, 2),
|
|
113
|
+
'net_long_volume': round(net_long_volume, 2),
|
|
114
|
+
'net_short_volume': round(net_short_volume, 2),
|
|
115
|
+
'net_trade_volume': round(net_trade_volume, 2)
|
|
116
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
|
|
4
|
+
PRICE_CHANGE_RTOL = 1e-09
|
|
5
|
+
PRICE_CHANGE_ATOL = 1e-12
|
|
6
|
+
|
|
7
|
+
def backtest_snapshot(df: pd.DataFrame,
|
|
8
|
+
*,
|
|
9
|
+
pred_col: str = 'predictions',
|
|
10
|
+
open_col: str = 'open',
|
|
11
|
+
close_col: str = 'close',
|
|
12
|
+
price_change_col: str = 'price_change',
|
|
13
|
+
execution_lag_bars: int = 1,
|
|
14
|
+
fee_bps: float = 5.0,
|
|
15
|
+
slip_bps: float = 5.0) -> pd.DataFrame:
|
|
16
|
+
|
|
17
|
+
'''
|
|
18
|
+
Long-only, HOLD-WHILE-1 evaluation using pre-aligned intrabar returns.
|
|
19
|
+
All percentage fields are in % units (not fractions). Sharpe is per bar (unitless).
|
|
20
|
+
|
|
21
|
+
Takes in output of log.permutation_prediction_performance and returns backtest results.
|
|
22
|
+
|
|
23
|
+
Logic
|
|
24
|
+
- Predictions are shifted forward by `execution_lag_bars` onto the execution bar sequence.
|
|
25
|
+
- Position pos = 1 wherever the lagged predictions==1 on a tradable execution row.
|
|
26
|
+
- Price columns must be numeric; missing price rows are treated as non-tradable gaps.
|
|
27
|
+
- Entry bar gross return: r_entry = price_change / open (≈ close/open - 1).
|
|
28
|
+
- Continuation bar gross return: r_cont = close_t / close_{t-1} - 1 (holding across bars).
|
|
29
|
+
- Fee/slippage costs are applied multiplicatively on entry and exit fills.
|
|
30
|
+
- Trade metrics are computed from compounded consecutive 1-run returns.
|
|
31
|
+
- Equity compounds over R_net; drawdown is computed from net equity.
|
|
32
|
+
|
|
33
|
+
Returns a one-row DataFrame with columns (in order):
|
|
34
|
+
[
|
|
35
|
+
'trade_win_rate_pct',
|
|
36
|
+
'trade_expectancy_pct',
|
|
37
|
+
'max_drawdown_pct',
|
|
38
|
+
'total_return_gross_pct',
|
|
39
|
+
'total_return_net_pct',
|
|
40
|
+
'trade_return_mean_win_pct',
|
|
41
|
+
'trade_return_mean_loss_pct',
|
|
42
|
+
'mean_kelly_pct',
|
|
43
|
+
'bars_total',
|
|
44
|
+
'sharpe_per_bar',
|
|
45
|
+
'bars_in_market_pct',
|
|
46
|
+
'trades_count',
|
|
47
|
+
'cost_round_trip_bps',
|
|
48
|
+
]
|
|
49
|
+
'''
|
|
50
|
+
|
|
51
|
+
df = df.copy()
|
|
52
|
+
|
|
53
|
+
if df.empty:
|
|
54
|
+
raise ValueError('backtest_snapshot requires at least one row')
|
|
55
|
+
|
|
56
|
+
if execution_lag_bars < 0:
|
|
57
|
+
raise ValueError('execution_lag_bars must be >= 0')
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
pred = pd.to_numeric(df[pred_col], errors='raise')
|
|
61
|
+
except (TypeError, ValueError) as exc:
|
|
62
|
+
raise ValueError('predictions must contain only 0 or 1') from exc
|
|
63
|
+
|
|
64
|
+
if pred.isna().any() or (~pred.isin([0, 1])).any():
|
|
65
|
+
raise ValueError('predictions must contain only 0 or 1')
|
|
66
|
+
|
|
67
|
+
pred = pred.astype(int)
|
|
68
|
+
try:
|
|
69
|
+
open_px = pd.to_numeric(df[open_col], errors='raise')
|
|
70
|
+
close_px = pd.to_numeric(df[close_col], errors='raise')
|
|
71
|
+
dpx = pd.to_numeric(df[price_change_col], errors='raise')
|
|
72
|
+
except (TypeError, ValueError) as exc:
|
|
73
|
+
raise ValueError('open, close, and price_change must be numeric') from exc
|
|
74
|
+
|
|
75
|
+
price_check_mask = open_px.notna() & close_px.notna() & dpx.notna()
|
|
76
|
+
expected_dpx = close_px - open_px
|
|
77
|
+
|
|
78
|
+
if price_check_mask.any() and not np.isclose(
|
|
79
|
+
dpx[price_check_mask],
|
|
80
|
+
expected_dpx[price_check_mask],
|
|
81
|
+
rtol=PRICE_CHANGE_RTOL,
|
|
82
|
+
atol=PRICE_CHANGE_ATOL,
|
|
83
|
+
).all():
|
|
84
|
+
raise ValueError('price_change must equal close - open')
|
|
85
|
+
|
|
86
|
+
tradable = open_px.notna() & close_px.notna() & dpx.notna() & (open_px != 0)
|
|
87
|
+
execution_rows = pd.Series(False, index=df.index)
|
|
88
|
+
if execution_lag_bars < len(df):
|
|
89
|
+
execution_rows.iloc[execution_lag_bars:] = True
|
|
90
|
+
|
|
91
|
+
pred = pred.shift(execution_lag_bars, fill_value=0)
|
|
92
|
+
eval_mask = execution_rows & tradable
|
|
93
|
+
pos = (pred == 1) & eval_mask
|
|
94
|
+
|
|
95
|
+
bars_total = int(eval_mask.sum())
|
|
96
|
+
bars_in_market_pct = float((pos.sum() / bars_total) * 100.0) if bars_total else np.nan
|
|
97
|
+
|
|
98
|
+
entry_mask = pos & (~pos.shift(1, fill_value=False))
|
|
99
|
+
cont_mask = pos & ( pos.shift(1, fill_value=False))
|
|
100
|
+
|
|
101
|
+
trades_count = int(entry_mask.sum())
|
|
102
|
+
|
|
103
|
+
r_entry = dpx / open_px
|
|
104
|
+
r_cont = (close_px / close_px.shift(1)) - 1.0
|
|
105
|
+
|
|
106
|
+
R_gross = np.where(entry_mask, r_entry, 0.0) + np.where(cont_mask, r_cont, 0.0)
|
|
107
|
+
R_gross = pd.Series(R_gross, index=df.index).fillna(0.0)
|
|
108
|
+
|
|
109
|
+
fee = fee_bps / 10_000.0
|
|
110
|
+
slip = slip_bps / 10_000.0
|
|
111
|
+
entry_mult = (1.0 - fee) / (1.0 + slip)
|
|
112
|
+
exit_mult = (1.0 - fee) * (1.0 - slip)
|
|
113
|
+
|
|
114
|
+
exit_mask = pos & (~pos.shift(-1, fill_value=False))
|
|
115
|
+
cost_mult = pd.Series(1.0, index=df.index)
|
|
116
|
+
cost_mult.loc[entry_mask] *= entry_mult
|
|
117
|
+
cost_mult.loc[exit_mask] *= exit_mult
|
|
118
|
+
|
|
119
|
+
R_net = (((1.0 + R_gross) * cost_mult) - 1.0).fillna(0.0)
|
|
120
|
+
eq_gross = (1.0 + R_gross).cumprod()
|
|
121
|
+
eq_net = (1.0 + R_net).cumprod()
|
|
122
|
+
|
|
123
|
+
peak = eq_net.cummax().clip(lower=1.0)
|
|
124
|
+
max_drawdown_pct = float((eq_net / peak - 1.0).min() * 100.0)
|
|
125
|
+
|
|
126
|
+
total_return_gross_pct = float((eq_gross.iloc[-1] - 1.0) * 100.0)
|
|
127
|
+
total_return_net_pct = float((eq_net.iloc[-1] - 1.0) * 100.0)
|
|
128
|
+
|
|
129
|
+
run_ids = entry_mask.cumsum()
|
|
130
|
+
trade_returns = (
|
|
131
|
+
(1.0 + R_net[pos]).groupby(run_ids[pos]).prod() - 1.0
|
|
132
|
+
) if entry_mask.any() else pd.Series(dtype=float)
|
|
133
|
+
|
|
134
|
+
if trade_returns.size:
|
|
135
|
+
wins = trade_returns[trade_returns > 0]
|
|
136
|
+
losses = trade_returns[trade_returns < 0]
|
|
137
|
+
trade_win_rate_pct = float((wins.size / trade_returns.size) * 100.0)
|
|
138
|
+
trade_expectancy_pct = float(trade_returns.mean() * 100.0)
|
|
139
|
+
trade_return_mean_win_pct = float(wins.mean() * 100.0) if wins.size else np.nan
|
|
140
|
+
trade_return_mean_loss_pct = float(losses.mean() * 100.0) if losses.size else np.nan
|
|
141
|
+
else:
|
|
142
|
+
trade_win_rate_pct = trade_expectancy_pct = np.nan
|
|
143
|
+
trade_return_mean_win_pct = trade_return_mean_loss_pct = np.nan
|
|
144
|
+
|
|
145
|
+
kelly_returns = trade_returns
|
|
146
|
+
|
|
147
|
+
kelly_wins = kelly_returns[kelly_returns > 0]
|
|
148
|
+
kelly_losses = kelly_returns[kelly_returns < 0]
|
|
149
|
+
if kelly_wins.size and kelly_losses.size:
|
|
150
|
+
win_rate = float(kelly_wins.size / kelly_returns.size)
|
|
151
|
+
loss_rate = float(kelly_losses.size / kelly_returns.size)
|
|
152
|
+
avg_win = float(kelly_wins.mean())
|
|
153
|
+
avg_loss = abs(float(kelly_losses.mean()))
|
|
154
|
+
payout_ratio = avg_win / avg_loss if avg_loss > 0 else np.nan
|
|
155
|
+
mean_kelly_pct = float((win_rate - (loss_rate / payout_ratio)) * 100.0) if payout_ratio > 0 else np.nan
|
|
156
|
+
else:
|
|
157
|
+
mean_kelly_pct = np.nan
|
|
158
|
+
|
|
159
|
+
eval_returns = R_net[eval_mask]
|
|
160
|
+
mu = float(eval_returns.mean()) if eval_returns.size else np.nan
|
|
161
|
+
sd = float(eval_returns.std(ddof=1)) if eval_returns.size > 1 else np.nan
|
|
162
|
+
|
|
163
|
+
sharpe_per_bar = float(mu / sd) if sd > 0 else np.nan
|
|
164
|
+
|
|
165
|
+
data = pd.DataFrame.from_records([{
|
|
166
|
+
'trade_win_rate_pct': round(trade_win_rate_pct, 1),
|
|
167
|
+
'trade_expectancy_pct': round(trade_expectancy_pct, 3),
|
|
168
|
+
'max_drawdown_pct': round(max_drawdown_pct, 1),
|
|
169
|
+
'total_return_gross_pct': round(total_return_gross_pct, 1),
|
|
170
|
+
'total_return_net_pct': round(total_return_net_pct, 1),
|
|
171
|
+
'trade_return_mean_win_pct': round(trade_return_mean_win_pct, 1),
|
|
172
|
+
'trade_return_mean_loss_pct': round(trade_return_mean_loss_pct, 1),
|
|
173
|
+
'mean_kelly_pct': round(mean_kelly_pct, 3),
|
|
174
|
+
'bars_total': int(bars_total),
|
|
175
|
+
'sharpe_per_bar': round(sharpe_per_bar, 2),
|
|
176
|
+
'bars_in_market_pct': round(bars_in_market_pct, 1),
|
|
177
|
+
'trades_count': int(trades_count),
|
|
178
|
+
'cost_round_trip_bps': round((1.0 - (entry_mult * exit_mult)) * 10_000),
|
|
179
|
+
}])
|
|
180
|
+
|
|
181
|
+
return data
|