优化等价市值排序的选股路径
This commit is contained in:
@@ -9219,6 +9219,15 @@ impl PlatformExprStrategy {
|
|||||||
.unwrap_or_else(|| self.field_value(candidate)))
|
.unwrap_or_else(|| self.field_value(candidate)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rank_reuses_market_cap_order(&self) -> bool {
|
||||||
|
self.config.rank_expr.trim().is_empty()
|
||||||
|
&& !self.config.rank_desc
|
||||||
|
&& matches!(
|
||||||
|
self.config.rank_by.trim(),
|
||||||
|
"market_cap" | "market_cap_bn"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn can_sell_position(&self, ctx: &StrategyContext<'_>, date: NaiveDate, symbol: &str) -> bool {
|
fn can_sell_position(&self, ctx: &StrategyContext<'_>, date: NaiveDate, symbol: &str) -> bool {
|
||||||
self.can_sell_position_at_time(ctx, date, symbol, None)
|
self.can_sell_position_at_time(ctx, date, symbol, None)
|
||||||
}
|
}
|
||||||
@@ -9429,24 +9438,26 @@ impl PlatformExprStrategy {
|
|||||||
}
|
}
|
||||||
candidates.push((candidate, stock, rank_value));
|
candidates.push((candidate, stock, rank_value));
|
||||||
}
|
}
|
||||||
candidates.sort_by(|lhs, rhs| {
|
if !self.rank_reuses_market_cap_order() {
|
||||||
let lhs_value = lhs.2;
|
candidates.sort_by(|lhs, rhs| {
|
||||||
let rhs_value = rhs.2;
|
let lhs_value = lhs.2;
|
||||||
let ordering = if self.config.rank_desc {
|
let rhs_value = rhs.2;
|
||||||
rhs_value
|
let ordering = if self.config.rank_desc {
|
||||||
.partial_cmp(&lhs_value)
|
rhs_value
|
||||||
.unwrap_or(std::cmp::Ordering::Equal)
|
.partial_cmp(&lhs_value)
|
||||||
} else {
|
.unwrap_or(std::cmp::Ordering::Equal)
|
||||||
lhs_value
|
} else {
|
||||||
.partial_cmp(&rhs_value)
|
lhs_value
|
||||||
.unwrap_or(std::cmp::Ordering::Equal)
|
.partial_cmp(&rhs_value)
|
||||||
};
|
.unwrap_or(std::cmp::Ordering::Equal)
|
||||||
if ordering == std::cmp::Ordering::Equal {
|
};
|
||||||
lhs.0.symbol.cmp(&rhs.0.symbol)
|
if ordering == std::cmp::Ordering::Equal {
|
||||||
} else {
|
lhs.0.symbol.cmp(&rhs.0.symbol)
|
||||||
ordering
|
} else {
|
||||||
}
|
ordering
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let mut selected = Vec::new();
|
let mut selected = Vec::new();
|
||||||
for (candidate, stock, _) in candidates {
|
for (candidate, stock, _) in candidates {
|
||||||
@@ -13749,6 +13760,28 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn market_cap_ascending_rank_reuses_only_equivalent_universe_order() {
|
||||||
|
let mut cfg = PlatformExprStrategyConfig::microcap_rotation();
|
||||||
|
cfg.rank_by = "market_cap".to_string();
|
||||||
|
let strategy = PlatformExprStrategy::new(cfg.clone());
|
||||||
|
assert!(strategy.rank_reuses_market_cap_order());
|
||||||
|
|
||||||
|
cfg.rank_by = "market_cap_bn".to_string();
|
||||||
|
assert!(PlatformExprStrategy::new(cfg.clone()).rank_reuses_market_cap_order());
|
||||||
|
|
||||||
|
cfg.rank_desc = true;
|
||||||
|
assert!(!PlatformExprStrategy::new(cfg.clone()).rank_reuses_market_cap_order());
|
||||||
|
|
||||||
|
cfg.rank_desc = false;
|
||||||
|
cfg.rank_expr = "close".to_string();
|
||||||
|
assert!(!PlatformExprStrategy::new(cfg.clone()).rank_reuses_market_cap_order());
|
||||||
|
|
||||||
|
cfg.rank_expr.clear();
|
||||||
|
cfg.rank_by = "free_float_cap".to_string();
|
||||||
|
assert!(!PlatformExprStrategy::new(cfg).rank_reuses_market_cap_order());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn current_rolling_helpers_do_not_load_factor_maps_or_decision_rollings() {
|
fn current_rolling_helpers_do_not_load_factor_maps_or_decision_rollings() {
|
||||||
let mut cfg = PlatformExprStrategyConfig::microcap_rotation();
|
let mut cfg = PlatformExprStrategyConfig::microcap_rotation();
|
||||||
|
|||||||
Reference in New Issue
Block a user