Improve jq microcap execution semantics
This commit is contained in:
@@ -2,12 +2,8 @@ use chrono::NaiveDate;
|
||||
use fidc_core::cost::CostModel;
|
||||
use fidc_core::rules::EquityRuleHooks;
|
||||
use fidc_core::{
|
||||
CandidateEligibility,
|
||||
ChinaAShareCostModel,
|
||||
ChinaEquityRuleHooks,
|
||||
DailyMarketSnapshot,
|
||||
OrderSide,
|
||||
Position,
|
||||
CandidateEligibility, ChinaAShareCostModel, ChinaEquityRuleHooks, DailyMarketSnapshot,
|
||||
OrderSide, Position, PriceField,
|
||||
};
|
||||
|
||||
fn d(year: i32, month: u32, day: u32) -> NaiveDate {
|
||||
@@ -32,15 +28,25 @@ fn snapshot(open: f64, upper_limit: f64, lower_limit: f64) -> DailyMarketSnapsho
|
||||
DailyMarketSnapshot {
|
||||
date: d(2024, 1, 3),
|
||||
symbol: "000001.SZ".to_string(),
|
||||
timestamp: Some("2024-01-03 10:18:00".to_string()),
|
||||
day_open: open,
|
||||
open,
|
||||
high: open,
|
||||
low: open,
|
||||
close: open,
|
||||
last_price: open,
|
||||
bid1: open,
|
||||
ask1: open,
|
||||
prev_close: 10.0,
|
||||
volume: 1_000_000,
|
||||
tick_volume: 100_000,
|
||||
bid1_volume: 50_000,
|
||||
ask1_volume: 50_000,
|
||||
trading_phase: Some("continuous".to_string()),
|
||||
paused: false,
|
||||
upper_limit,
|
||||
lower_limit,
|
||||
price_tick: 0.01,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,14 +75,11 @@ fn china_rule_hooks_block_same_day_sell_under_t_plus_one() {
|
||||
&snapshot(10.1, 11.0, 9.0),
|
||||
&candidate(),
|
||||
&position,
|
||||
PriceField::Open,
|
||||
);
|
||||
|
||||
assert!(!check.allowed);
|
||||
assert!(check
|
||||
.reason
|
||||
.as_deref()
|
||||
.unwrap_or_default()
|
||||
.contains("t+1"));
|
||||
assert!(check.reason.as_deref().unwrap_or_default().contains("t+1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -86,20 +89,62 @@ fn china_rule_hooks_block_buy_at_limit_up_and_sell_at_limit_down() {
|
||||
let mut position = Position::new("000001.SZ");
|
||||
position.buy(d(2024, 1, 2), 1_000, 10.0);
|
||||
|
||||
let buy_check = hooks.can_buy(d(2024, 1, 3), &snapshot(11.0, 11.0, 9.0), &candidate);
|
||||
let buy_check = hooks.can_buy(
|
||||
d(2024, 1, 3),
|
||||
&snapshot(11.0, 11.0, 9.0),
|
||||
&candidate,
|
||||
PriceField::Open,
|
||||
);
|
||||
assert!(!buy_check.allowed);
|
||||
assert!(buy_check
|
||||
.reason
|
||||
.as_deref()
|
||||
.unwrap_or_default()
|
||||
.contains("upper limit"));
|
||||
assert!(
|
||||
buy_check
|
||||
.reason
|
||||
.as_deref()
|
||||
.unwrap_or_default()
|
||||
.contains("upper limit")
|
||||
);
|
||||
|
||||
let sell_check =
|
||||
hooks.can_sell(d(2024, 1, 3), &snapshot(9.0, 11.0, 9.0), &candidate, &position);
|
||||
let sell_check = hooks.can_sell(
|
||||
d(2024, 1, 3),
|
||||
&snapshot(9.0, 11.0, 9.0),
|
||||
&candidate,
|
||||
&position,
|
||||
PriceField::Open,
|
||||
);
|
||||
assert!(!sell_check.allowed);
|
||||
assert!(
|
||||
sell_check
|
||||
.reason
|
||||
.as_deref()
|
||||
.unwrap_or_default()
|
||||
.contains("lower limit")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn china_rule_hooks_use_tick_size_tolerance_for_price_limits() {
|
||||
let hooks = ChinaEquityRuleHooks;
|
||||
let candidate = candidate();
|
||||
|
||||
let near_upper = DailyMarketSnapshot {
|
||||
price_tick: 0.001,
|
||||
..snapshot(10.9995, 11.0, 9.0)
|
||||
};
|
||||
let buy_check = hooks.can_buy(d(2024, 1, 3), &near_upper, &candidate, PriceField::Open);
|
||||
assert!(!buy_check.allowed);
|
||||
|
||||
let near_lower = DailyMarketSnapshot {
|
||||
price_tick: 0.001,
|
||||
..snapshot(9.0005, 11.0, 9.0)
|
||||
};
|
||||
let mut position = Position::new("000001.SZ");
|
||||
position.buy(d(2024, 1, 2), 1_000, 10.0);
|
||||
let sell_check = hooks.can_sell(
|
||||
d(2024, 1, 3),
|
||||
&near_lower,
|
||||
&candidate,
|
||||
&position,
|
||||
PriceField::Open,
|
||||
);
|
||||
assert!(!sell_check.allowed);
|
||||
assert!(sell_check
|
||||
.reason
|
||||
.as_deref()
|
||||
.unwrap_or_default()
|
||||
.contains("lower limit"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user