bet_sizing
Concept Overview
Section titled “Concept Overview”The layer between a model’s confidence and an order. bet_size_probability maps class probabilities to a signed size in [-1, 1] through the t-statistic of the probability against the null of no edge, averages sizes across bets that are still active, and discretises to your execution granularity. bet_size_dynamic works from a price forecast instead: given the current and maximum position it returns the target position and the limit price at which that size is justified. bet_size_reserve sizes from a fitted mixture of long/short concurrency rather than from any model score.
When to Use
Section titled “When to Use”Between signal generation and execution, always — a raw model score is not a position. Use the probability path when a classifier emits calibrated probabilities, the dynamic path when you have a price forecast and want a limit-order boundary, and reserve sizing when overlapping books or stacked strategies can accumulate hidden gross exposure. Set step_size to real lot or contract granularity, not an arbitrary decimal, and treat the limit price as a decision boundary rather than a fill you will get.
Mathematical Foundations
Section titled “Mathematical Foundations”From Classification Probability to Signed Bet
Section titled “From Classification Probability to Signed Bet”
Dynamic Position Target and Limit Price
Section titled “Dynamic Position Target and Limit Price”
Budget and Reserve Concurrency Sizing
Section titled “Budget and Reserve Concurrency Sizing”
Usage Examples
Section titled “Usage Examples”End-to-end: Probability Forecasts -> Discrete Executable Bet Sizes
Section titled “End-to-end: Probability Forecasts -> Discrete Executable Bet Sizes”use chrono::{Duration, NaiveDateTime};use openquant::bet_sizing::bet_size_probability;
// 1) Build event stream: (start, end, class probability, trade side)let t0 = NaiveDateTime::parse_from_str("2024-01-01 09:30:00", "%Y-%m-%d %H:%M:%S")?;let events = vec![ (t0, t0 + Duration::minutes(20), 0.56, 1.0), (t0 + Duration::minutes(5), t0 + Duration::minutes(35), 0.62, 1.0), (t0 + Duration::minutes(10), t0 + Duration::minutes(30), 0.48, -1.0), (t0 + Duration::minutes(15), t0 + Duration::minutes(45), 0.67, 1.0),];
// 2) Convert probabilities -> signed signal -> discretized size (step=0.1)let sizes = bet_size_probability(&events, 2, 0.1, true);
// 3) sizes are directly executable as timestamped target exposure in [-1, 1]assert!(!sizes.is_empty());End-to-end: Dynamic + Reserve Sizing for Execution and Inventory Control
Section titled “End-to-end: Dynamic + Reserve Sizing for Execution and Inventory Control”use chrono::{Duration, NaiveDateTime};use openquant::bet_sizing::{bet_size_dynamic, bet_size_reserve_full};
// Dynamic sizing inputs (position, max position, market price, forecast price)let pos = vec![0.0, 1.0, 1.0, 2.0, 1.0];let max_pos = vec![10.0; 5];let market = vec![100.0, 100.1, 100.0, 100.2, 100.15];let forecast = vec![100.3, 100.4, 100.2, 100.5, 100.45];
let dynamic = bet_size_dynamic(&pos, &max_pos, &market, &forecast);// tuple: (bet_size, target_position, limit_price)
// Reserve sizing from overlapping long/short eventslet t0 = NaiveDateTime::parse_from_str("2024-01-01 09:30:00", "%Y-%m-%d %H:%M:%S")?;let t1 = vec![ (t0, t0 + Duration::minutes(30)), (t0 + Duration::minutes(10), t0 + Duration::minutes(40)), (t0 + Duration::minutes(20), t0 + Duration::minutes(50)),];let side = vec![1.0, -1.0, 1.0];let (reserve, fit) = bet_size_reserve_full(&t1, &side, 8, 1e-6, 200, true);
assert_eq!(dynamic.len(), 5);assert!(fit.is_some());assert!(!reserve.is_empty());API Reference
Section titled “API Reference”Python API
Section titled “Python API”bet_sizing.get_signalbet_sizing.discrete_signalbet_sizing.bet_sizebet_sizing.bet_size_sigmoidbet_sizing.bet_size_powerbet_sizing.inv_pricebet_sizing.inv_price_sigmoidbet_sizing.inv_price_powerbet_sizing.get_wbet_sizing.get_w_sigmoidbet_sizing.get_w_powerbet_sizing.get_target_posbet_sizing.get_target_pos_sigmoidbet_sizing.get_target_pos_powerbet_sizing.limit_pricebet_sizing.limit_price_sigmoidbet_sizing.limit_price_powerbet_sizing.avg_active_signalsbet_sizing.bet_size_dynamicbet_sizing.cdf_mixturebet_sizing.single_bet_size_mixedbet_sizing.get_concurrent_sidesbet_sizing.bet_size_budgetbet_sizing.bet_size_probabilitybet_sizing.mp_avg_active_signalsbet_sizing.bet_size_reservebet_sizing.bet_size_reserve_with_fitbet_sizing.bet_size_reserve_full
Rust API
Section titled “Rust API”bet_size_probabilitybet_size_dynamicbet_size_budgetbet_size_reservebet_size_reserve_fullget_target_poslimit_price
Risk Notes and Caveats
Section titled “Risk Notes and Caveats”- Keep sizing logic coupled to latency and fill assumptions; limit price from dynamic sizing is a decision boundary, not a guaranteed fill.
- Use reserve sizing when overlapping books or strategy stacking can create hidden gross exposure.
- Calibrate step_size to real execution granularity (lots/contracts), not arbitrary decimals.