增强回测引擎第二版策略与快照层
This commit is contained in:
@@ -14,6 +14,8 @@ pub struct UniverseCandidate {
|
||||
pub symbol: String,
|
||||
pub market_cap_bn: f64,
|
||||
pub free_float_cap_bn: f64,
|
||||
pub band_low: f64,
|
||||
pub band_high: f64,
|
||||
}
|
||||
|
||||
pub struct SelectionContext<'a> {
|
||||
@@ -29,51 +31,54 @@ pub trait UniverseSelector {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DynamicMarketCapBandSelector {
|
||||
pub base_index_level: f64,
|
||||
pub bullish_threshold: f64,
|
||||
pub neutral_threshold: f64,
|
||||
pub bullish_band: (f64, f64),
|
||||
pub neutral_band: (f64, f64),
|
||||
pub defensive_band: (f64, f64),
|
||||
pub base_cap_floor: f64,
|
||||
pub cap_span: f64,
|
||||
pub xs: f64,
|
||||
pub top_n: usize,
|
||||
}
|
||||
|
||||
impl DynamicMarketCapBandSelector {
|
||||
pub fn demo(top_n: usize) -> Self {
|
||||
pub fn new(
|
||||
base_index_level: f64,
|
||||
base_cap_floor: f64,
|
||||
cap_span: f64,
|
||||
xs: f64,
|
||||
top_n: usize,
|
||||
) -> Self {
|
||||
Self {
|
||||
base_index_level: 3000.0,
|
||||
bullish_threshold: 1.02,
|
||||
neutral_threshold: 1.0,
|
||||
bullish_band: (30.0, 60.0),
|
||||
neutral_band: (40.0, 90.0),
|
||||
defensive_band: (60.0, 120.0),
|
||||
base_index_level,
|
||||
base_cap_floor,
|
||||
cap_span,
|
||||
xs,
|
||||
top_n,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn demo(top_n: usize) -> Self {
|
||||
Self::new(2000.0, 7.0, 10.0, 4.0 / 500.0, top_n)
|
||||
}
|
||||
|
||||
pub fn regime(&self, benchmark_level: f64) -> BandRegime {
|
||||
let ratio = benchmark_level / self.base_index_level;
|
||||
if ratio >= self.bullish_threshold {
|
||||
if benchmark_level >= self.base_index_level + 400.0 {
|
||||
BandRegime::Bullish
|
||||
} else if ratio >= self.neutral_threshold {
|
||||
} else if benchmark_level >= self.base_index_level {
|
||||
BandRegime::Neutral
|
||||
} else {
|
||||
BandRegime::Defensive
|
||||
}
|
||||
}
|
||||
|
||||
fn band(&self, regime: BandRegime) -> (f64, f64) {
|
||||
match regime {
|
||||
BandRegime::Bullish => self.bullish_band,
|
||||
BandRegime::Neutral => self.neutral_band,
|
||||
BandRegime::Defensive => self.defensive_band,
|
||||
}
|
||||
pub fn band_for_level(&self, benchmark_level: f64) -> (f64, f64) {
|
||||
let start = ((benchmark_level - self.base_index_level) * self.xs) + self.base_cap_floor;
|
||||
let low = start.round();
|
||||
(low, low + self.cap_span)
|
||||
}
|
||||
}
|
||||
|
||||
impl UniverseSelector for DynamicMarketCapBandSelector {
|
||||
fn select(&self, ctx: &SelectionContext<'_>) -> Vec<UniverseCandidate> {
|
||||
let regime = self.regime(ctx.benchmark.close);
|
||||
let (min_cap, max_cap) = self.band(regime);
|
||||
let _regime = self.regime(ctx.benchmark.close);
|
||||
let (min_cap, max_cap) = self.band_for_level(ctx.benchmark.close);
|
||||
|
||||
let mut selected = ctx
|
||||
.data
|
||||
@@ -94,6 +99,8 @@ impl UniverseSelector for DynamicMarketCapBandSelector {
|
||||
symbol: factor.symbol.clone(),
|
||||
market_cap_bn: factor.market_cap_bn,
|
||||
free_float_cap_bn: factor.free_float_cap_bn,
|
||||
band_low: min_cap,
|
||||
band_high: max_cap,
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Reference in New Issue
Block a user