实现类型化订单有效期合同
This commit is contained in:
@@ -1014,6 +1014,35 @@ pub enum AlgoOrderStyle {
|
||||
Twap,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum OrderTimeInForce {
|
||||
Day,
|
||||
Ioc,
|
||||
Fok,
|
||||
Gtc,
|
||||
}
|
||||
|
||||
impl OrderTimeInForce {
|
||||
pub fn parse(value: &str) -> Option<Self> {
|
||||
match value.trim().to_ascii_lowercase().as_str() {
|
||||
"day" => Some(Self::Day),
|
||||
"ioc" | "immediate_or_cancel" | "immediate-or-cancel" => Some(Self::Ioc),
|
||||
"fok" | "fill_or_kill" | "fill-or-kill" => Some(Self::Fok),
|
||||
"gtc" | "good_til_canceled" | "good-til-canceled" => Some(Self::Gtc),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Day => "day",
|
||||
Self::Ioc => "ioc",
|
||||
Self::Fok => "fok",
|
||||
Self::Gtc => "gtc",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TargetPortfolioOrderPricing {
|
||||
LimitPrices(BTreeMap<String, f64>),
|
||||
@@ -1026,6 +1055,10 @@ pub enum TargetPortfolioOrderPricing {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum OrderIntent {
|
||||
WithTimeInForce {
|
||||
intent: Box<OrderIntent>,
|
||||
time_in_force: OrderTimeInForce,
|
||||
},
|
||||
Shares {
|
||||
symbol: String,
|
||||
quantity: i32,
|
||||
@@ -1174,6 +1207,100 @@ pub enum OrderIntent {
|
||||
},
|
||||
}
|
||||
|
||||
impl OrderIntent {
|
||||
pub fn with_time_in_force(self, time_in_force: OrderTimeInForce) -> Self {
|
||||
match self {
|
||||
Self::WithTimeInForce { intent, .. } => Self::WithTimeInForce {
|
||||
intent,
|
||||
time_in_force,
|
||||
},
|
||||
intent => Self::WithTimeInForce {
|
||||
intent: Box::new(intent),
|
||||
time_in_force,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn time_in_force(&self) -> Option<OrderTimeInForce> {
|
||||
match self {
|
||||
Self::WithTimeInForce { time_in_force, .. } => Some(*time_in_force),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_time_in_force_parts(self) -> (Self, Option<OrderTimeInForce>) {
|
||||
match self {
|
||||
Self::WithTimeInForce {
|
||||
intent,
|
||||
time_in_force,
|
||||
} => (*intent, Some(time_in_force)),
|
||||
intent => (intent, None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_time_in_force(self, time_in_force: Option<OrderTimeInForce>) -> Self {
|
||||
match time_in_force {
|
||||
Some(time_in_force) => self.with_time_in_force(time_in_force),
|
||||
None => self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrapped(&self) -> &Self {
|
||||
match self {
|
||||
Self::WithTimeInForce { intent, .. } => intent.unwrapped(),
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn supports_time_in_force(&self, time_in_force: OrderTimeInForce) -> bool {
|
||||
let intent = self.unwrapped();
|
||||
if matches!(
|
||||
intent,
|
||||
Self::CancelOrder { .. }
|
||||
| Self::CancelSymbol { .. }
|
||||
| Self::CancelAll { .. }
|
||||
| Self::UpdateUniverse { .. }
|
||||
| Self::Subscribe { .. }
|
||||
| Self::Unsubscribe { .. }
|
||||
| Self::DepositWithdraw { .. }
|
||||
| Self::FinanceRepay { .. }
|
||||
| Self::SetManagementFeeRate { .. }
|
||||
| Self::Futures { .. }
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
let is_algo = matches!(
|
||||
intent,
|
||||
Self::AlgoValue { .. } | Self::AlgoPercent { .. } | Self::TimedTargetValue { .. }
|
||||
) || matches!(
|
||||
intent,
|
||||
Self::TargetPortfolioSmart {
|
||||
order_prices: Some(TargetPortfolioOrderPricing::AlgoOrder { .. }),
|
||||
..
|
||||
}
|
||||
);
|
||||
let is_limit = matches!(
|
||||
intent,
|
||||
Self::LimitShares { .. }
|
||||
| Self::LimitLots { .. }
|
||||
| Self::LimitTargetShares { .. }
|
||||
| Self::LimitTargetValue { .. }
|
||||
| Self::LimitValue { .. }
|
||||
| Self::LimitPercent { .. }
|
||||
| Self::LimitTargetPercent { .. }
|
||||
| Self::TargetPortfolioSmart {
|
||||
order_prices: Some(TargetPortfolioOrderPricing::LimitPrices(_)),
|
||||
..
|
||||
}
|
||||
);
|
||||
match time_in_force {
|
||||
OrderTimeInForce::Day | OrderTimeInForce::Ioc => true,
|
||||
OrderTimeInForce::Fok => !is_algo,
|
||||
OrderTimeInForce::Gtc => is_limit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CnSmallCapRotationConfig {
|
||||
pub strategy_name: String,
|
||||
@@ -2909,6 +3036,53 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::{BenchmarkSnapshot, CandidateEligibility, DailyFactorSnapshot};
|
||||
|
||||
#[test]
|
||||
fn order_time_in_force_parsing_and_order_type_contract_are_explicit() {
|
||||
assert_eq!(OrderTimeInForce::parse("DAY"), Some(OrderTimeInForce::Day));
|
||||
assert_eq!(
|
||||
OrderTimeInForce::parse("immediate_or_cancel"),
|
||||
Some(OrderTimeInForce::Ioc)
|
||||
);
|
||||
assert_eq!(
|
||||
OrderTimeInForce::parse("fill-or-kill"),
|
||||
Some(OrderTimeInForce::Fok)
|
||||
);
|
||||
assert_eq!(
|
||||
OrderTimeInForce::parse("good_til_canceled"),
|
||||
Some(OrderTimeInForce::Gtc)
|
||||
);
|
||||
assert_eq!(OrderTimeInForce::parse("unknown"), None);
|
||||
|
||||
let market = OrderIntent::Shares {
|
||||
symbol: "000001.SZ".to_string(),
|
||||
quantity: 100,
|
||||
reason: "market".to_string(),
|
||||
};
|
||||
assert!(market.supports_time_in_force(OrderTimeInForce::Day));
|
||||
assert!(market.supports_time_in_force(OrderTimeInForce::Ioc));
|
||||
assert!(market.supports_time_in_force(OrderTimeInForce::Fok));
|
||||
assert!(!market.supports_time_in_force(OrderTimeInForce::Gtc));
|
||||
|
||||
let limit = OrderIntent::LimitShares {
|
||||
symbol: "000001.SZ".to_string(),
|
||||
quantity: 100,
|
||||
limit_price: 10.0,
|
||||
reason: "limit".to_string(),
|
||||
};
|
||||
assert!(limit.supports_time_in_force(OrderTimeInForce::Gtc));
|
||||
|
||||
let algo = OrderIntent::AlgoValue {
|
||||
symbol: "000001.SZ".to_string(),
|
||||
value: 10_000.0,
|
||||
style: AlgoOrderStyle::Vwap,
|
||||
start_time: None,
|
||||
end_time: None,
|
||||
reason: "algo".to_string(),
|
||||
};
|
||||
assert!(!algo.supports_time_in_force(OrderTimeInForce::Fok));
|
||||
assert!(!algo.supports_time_in_force(OrderTimeInForce::Gtc));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn omni_microcap_projection_uses_configured_trading_cost() {
|
||||
let mut cfg = OmniMicroCapConfig::omni_microcap();
|
||||
|
||||
Reference in New Issue
Block a user