Align jq microcap sizing and snapshot pricing

This commit is contained in:
boris
2026-04-21 06:36:17 -07:00
parent ba36bd5981
commit 3652f80d85
2 changed files with 16 additions and 52 deletions

View File

@@ -121,23 +121,10 @@ where
if self.execution_price_field == PriceField::Last if self.execution_price_field == PriceField::Last
&& self.intraday_execution_start_time.is_some() && self.intraday_execution_start_time.is_some()
{ {
let tick = snapshot.effective_price_tick(); return match side {
let base_price = snapshot.price(PriceField::Last); OrderSide::Buy => self.buy_price(snapshot),
let adjusted = match side { OrderSide::Sell => self.sell_price(snapshot),
OrderSide::Buy => base_price + tick * 2.0,
OrderSide::Sell => base_price - tick,
}; };
let lower = if snapshot.lower_limit.is_finite() && snapshot.lower_limit > 0.0 {
snapshot.lower_limit
} else {
tick
};
let upper = if snapshot.upper_limit.is_finite() && snapshot.upper_limit > 0.0 {
snapshot.upper_limit
} else {
f64::INFINITY
};
return adjusted.clamp(lower, upper);
} }
match side { match side {
@@ -1053,8 +1040,7 @@ where
quantity = quantity.saturating_sub(lot); quantity = quantity.saturating_sub(lot);
continue; continue;
} }
let cost = self.cost_model.calculate(OrderSide::Buy, gross); if gross <= cash + 1e-6 {
if gross + cost.total() <= cash + 1e-6 {
return quantity; return quantity;
} }
quantity = quantity.saturating_sub(lot); quantity = quantity.saturating_sub(lot);
@@ -1251,8 +1237,7 @@ where
take_qty = take_qty.saturating_sub(lot); take_qty = take_qty.saturating_sub(lot);
continue; continue;
} }
let candidate_cost = self.cost_model.calculate(OrderSide::Buy, candidate_gross); if candidate_gross <= cash + 1e-6 {
if candidate_gross + candidate_cost.total() <= cash + 1e-6 {
break; break;
} }
take_qty = take_qty.saturating_sub(lot); take_qty = take_qty.saturating_sub(lot);
@@ -1284,9 +1269,7 @@ where
residual_qty = residual_qty.saturating_sub(lot); residual_qty = residual_qty.saturating_sub(lot);
continue; continue;
} }
let candidate_cost = if candidate_gross <= cash + 1e-6 {
self.cost_model.calculate(OrderSide::Buy, candidate_gross);
if candidate_gross + candidate_cost.total() <= cash + 1e-6 {
break; break;
} }
residual_qty = residual_qty.saturating_sub(lot); residual_qty = residual_qty.saturating_sub(lot);

View File

@@ -580,8 +580,7 @@ impl JqMicroCapStrategy {
let mut quantity = self.round_lot_quantity((cash / sizing_price).floor() as u32, 100); let mut quantity = self.round_lot_quantity((cash / sizing_price).floor() as u32, 100);
while quantity > 0 { while quantity > 0 {
let gross_amount = execution_price * quantity as f64; let gross_amount = execution_price * quantity as f64;
let cash_out = gross_amount + self.buy_commission(gross_amount); if gross_amount <= cash + 1e-6 {
if cash_out <= cash + 1e-6 {
return quantity; return quantity;
} }
quantity = quantity.saturating_sub(100); quantity = quantity.saturating_sub(100);
@@ -594,23 +593,10 @@ impl JqMicroCapStrategy {
market: &crate::data::DailyMarketSnapshot, market: &crate::data::DailyMarketSnapshot,
side: OrderSide, side: OrderSide,
) -> f64 { ) -> f64 {
let tick = market.effective_price_tick(); match side {
let base_price = market.price(PriceField::Last); OrderSide::Buy => market.buy_price(PriceField::Last),
let adjusted = match side { OrderSide::Sell => market.sell_price(PriceField::Last),
OrderSide::Buy => base_price + tick * 2.0, }
OrderSide::Sell => base_price - tick,
};
let lower = if market.lower_limit.is_finite() && market.lower_limit > 0.0 {
market.lower_limit
} else {
tick
};
let upper = if market.upper_limit.is_finite() && market.upper_limit > 0.0 {
market.upper_limit
} else {
f64::INFINITY
};
adjusted.clamp(lower, upper)
} }
fn project_order_value( fn project_order_value(
@@ -654,9 +640,8 @@ impl JqMicroCapStrategy {
let mut quantity = snapshot_requested_qty; let mut quantity = snapshot_requested_qty;
while quantity > 0 { while quantity > 0 {
let gross_amount = projected_execution_price * quantity as f64; let gross_amount = projected_execution_price * quantity as f64;
let cash_out = gross_amount + self.buy_commission(gross_amount);
if gross_amount <= order_value + 400.0 if gross_amount <= order_value + 400.0
&& cash_out <= projected.cash() + 1e-6 && gross_amount <= projected.cash() + 1e-6
{ {
break; break;
} }
@@ -671,8 +656,7 @@ impl JqMicroCapStrategy {
.unwrap_or(projected_execution_price); .unwrap_or(projected_execution_price);
while quantity > 0 { while quantity > 0 {
let gross_amount = execution_price * quantity as f64; let gross_amount = execution_price * quantity as f64;
let cash_out = gross_amount + self.buy_commission(gross_amount); if gross_amount <= projected.cash() + 1e-6 {
if cash_out <= projected.cash() + 1e-6 {
break; break;
} }
quantity = quantity.saturating_sub(round_lot); quantity = quantity.saturating_sub(round_lot);
@@ -687,7 +671,7 @@ impl JqMicroCapStrategy {
}; };
let gross_amount = fill.price * fill.quantity as f64; let gross_amount = fill.price * fill.quantity as f64;
let cash_out = gross_amount + self.buy_commission(gross_amount); let cash_out = gross_amount + self.buy_commission(gross_amount);
if cash_out > projected.cash() + 1e-6 { if gross_amount > projected.cash() + 1e-6 {
return 0; return 0;
} }
projected.apply_cash_delta(-cash_out); projected.apply_cash_delta(-cash_out);
@@ -890,8 +874,7 @@ impl JqMicroCapStrategy {
take_qty = take_qty.saturating_sub(lot); take_qty = take_qty.saturating_sub(lot);
continue; continue;
} }
let candidate_cash_out = candidate_gross + self.buy_commission(candidate_gross); if candidate_gross <= cash + 1e-6 {
if candidate_cash_out <= cash + 1e-6 {
break; break;
} }
take_qty = take_qty.saturating_sub(lot); take_qty = take_qty.saturating_sub(lot);
@@ -923,9 +906,7 @@ impl JqMicroCapStrategy {
residual_qty = residual_qty.saturating_sub(lot); residual_qty = residual_qty.saturating_sub(lot);
continue; continue;
} }
let candidate_cash_out = if candidate_gross <= cash + 1e-6 {
candidate_gross + self.buy_commission(candidate_gross);
if candidate_cash_out <= cash + 1e-6 {
break; break;
} }
residual_qty = residual_qty.saturating_sub(lot); residual_qty = residual_qty.saturating_sub(lot);