使用前一交易日指数价格计算市值区间,模拟实盘场景
- 修改trading_ratio()返回5个值,包含prev_level - 使用prev_level计算市值区间,符合实盘决策逻辑 - 调整默认参数对齐AiQuant实际运行版本(xs=0.008, cap_span=10) - 增强MA过滤调试日志,输出首个决策日所有股票的过滤详情 - 添加市值区间计算调试日志
This commit is contained in:
@@ -1570,13 +1570,13 @@ impl OmniMicroCapConfig {
|
|||||||
strategy_name: "aiquant-v1.0.4".to_string(),
|
strategy_name: "aiquant-v1.0.4".to_string(),
|
||||||
refresh_rate: 120,
|
refresh_rate: 120,
|
||||||
stocknum: 5,
|
stocknum: 5,
|
||||||
xs: 3.0 / 500.0,
|
xs: 4.0 / 500.0,
|
||||||
base_index_level: 2000.0,
|
base_index_level: 2000.0,
|
||||||
base_cap_floor: 7.0,
|
base_cap_floor: 7.0,
|
||||||
cap_span: 25.0,
|
cap_span: 10.0,
|
||||||
padding_ratio: 0.5,
|
padding_ratio: 1.2,
|
||||||
min_padding: 12.5,
|
min_padding: 29.5,
|
||||||
max_padding: 30.0,
|
max_padding: 50.0,
|
||||||
benchmark_signal_symbol: "000852.SH".to_string(),
|
benchmark_signal_symbol: "000852.SH".to_string(),
|
||||||
benchmark_short_ma_days: 5,
|
benchmark_short_ma_days: 5,
|
||||||
benchmark_long_ma_days: 20,
|
benchmark_long_ma_days: 20,
|
||||||
@@ -2141,7 +2141,8 @@ impl OmniMicroCapStrategy {
|
|||||||
&self,
|
&self,
|
||||||
ctx: &StrategyContext<'_>,
|
ctx: &StrategyContext<'_>,
|
||||||
date: NaiveDate,
|
date: NaiveDate,
|
||||||
) -> Result<(f64, f64, f64, f64), BacktestError> {
|
) -> Result<(f64, f64, f64, f64, f64), BacktestError> {
|
||||||
|
// 当前交易日的指数价格(用于MA计算和仓位控制)
|
||||||
let current_level = ctx
|
let current_level = ctx
|
||||||
.data
|
.data
|
||||||
.market_decision_close(date, &self.config.benchmark_signal_symbol)
|
.market_decision_close(date, &self.config.benchmark_signal_symbol)
|
||||||
@@ -2150,6 +2151,16 @@ impl OmniMicroCapStrategy {
|
|||||||
symbol: self.config.benchmark_signal_symbol.clone(),
|
symbol: self.config.benchmark_signal_symbol.clone(),
|
||||||
field: "decision_close",
|
field: "decision_close",
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
// 前一交易日的指数价格(用于市值区间计算,模拟实盘场景)
|
||||||
|
let prev_level = if let Some(prev_date) = ctx.data.previous_trading_date(date, 1) {
|
||||||
|
ctx.data
|
||||||
|
.market_decision_close(prev_date, &self.config.benchmark_signal_symbol)
|
||||||
|
.unwrap_or(current_level)
|
||||||
|
} else {
|
||||||
|
current_level
|
||||||
|
};
|
||||||
|
|
||||||
let ma_short = ctx
|
let ma_short = ctx
|
||||||
.data
|
.data
|
||||||
.market_decision_close_moving_average(
|
.market_decision_close_moving_average(
|
||||||
@@ -2181,7 +2192,7 @@ impl OmniMicroCapStrategy {
|
|||||||
} else {
|
} else {
|
||||||
1.0
|
1.0
|
||||||
};
|
};
|
||||||
Ok((current_level, ma_short, ma_long, trading_ratio))
|
Ok((current_level, prev_level, ma_short, ma_long, trading_ratio))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn market_cap_band(&self, index_level: f64) -> (f64, f64) {
|
fn market_cap_band(&self, index_level: f64) -> (f64, f64) {
|
||||||
@@ -2233,14 +2244,25 @@ impl OmniMicroCapStrategy {
|
|||||||
// MA filter: ma_short > ma_mid * rsi_rate && ma_mid * rsi_rate > ma_long
|
// MA filter: ma_short > ma_mid * rsi_rate && ma_mid * rsi_rate > ma_long
|
||||||
let ma_pass = ma_short > ma_mid * self.config.rsi_rate && ma_mid * self.config.rsi_rate > ma_long;
|
let ma_pass = ma_short > ma_mid * self.config.rsi_rate && ma_mid * self.config.rsi_rate > ma_long;
|
||||||
|
|
||||||
// Debug logging for first few stocks
|
// Debug logging for ALL stocks on first decision date
|
||||||
static DEBUG_COUNT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
|
static DEBUG_DATE: std::sync::Mutex<Option<NaiveDate>> = std::sync::Mutex::new(None);
|
||||||
let count = DEBUG_COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
let mut debug_date = DEBUG_DATE.lock().unwrap();
|
||||||
if count < 10 {
|
let should_debug = if let Some(d) = *debug_date {
|
||||||
eprintln!("[DEBUG MA] {} date={} ma5={:.4} ma10={:.4} ma30={:.4} rsi_rate={:.6} pass={} (ma5 > ma10*rsi={:.4}? {} && ma10*rsi > ma30={:.4}? {})",
|
d == date
|
||||||
symbol, date, ma_short, ma_mid, ma_long, self.config.rsi_rate, ma_pass,
|
} else {
|
||||||
ma_mid * self.config.rsi_rate, ma_short > ma_mid * self.config.rsi_rate,
|
*debug_date = Some(date);
|
||||||
ma_long, ma_mid * self.config.rsi_rate > ma_long);
|
true
|
||||||
|
};
|
||||||
|
|
||||||
|
if should_debug {
|
||||||
|
eprintln!("[MA_FILTER] {} cap={:.2} ma5={:.4} ma10={:.4} ma30={:.4} ma10*rsi={:.4} pass={} ({}>{:.4}? {} && {:.4}>{}? {})",
|
||||||
|
symbol,
|
||||||
|
ctx.data.market_decision_close(date, symbol).unwrap_or(0.0),
|
||||||
|
ma_short, ma_mid, ma_long,
|
||||||
|
ma_mid * self.config.rsi_rate,
|
||||||
|
ma_pass,
|
||||||
|
ma_short, ma_mid * self.config.rsi_rate, ma_short > ma_mid * self.config.rsi_rate,
|
||||||
|
ma_mid * self.config.rsi_rate, ma_long, ma_mid * self.config.rsi_rate > ma_long);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ma_pass {
|
if !ma_pass {
|
||||||
@@ -2640,7 +2662,7 @@ impl Strategy for OmniMicroCapStrategy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let (index_level, ma_short, ma_long, trading_ratio) = match self.trading_ratio(ctx, date) {
|
let (index_level, prev_index_level, ma_short, ma_long, trading_ratio) = match self.trading_ratio(ctx, date) {
|
||||||
Ok(value) => value,
|
Ok(value) => value,
|
||||||
Err(BacktestError::Execution(message))
|
Err(BacktestError::Execution(message))
|
||||||
if message.contains("insufficient benchmark") =>
|
if message.contains("insufficient benchmark") =>
|
||||||
@@ -2658,7 +2680,10 @@ impl Strategy for OmniMicroCapStrategy {
|
|||||||
}
|
}
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
};
|
};
|
||||||
let (band_low, band_high) = self.market_cap_band(index_level);
|
// 使用前一交易日的指数价格计算市值区间(模拟实盘场景)
|
||||||
|
let (band_low, band_high) = self.market_cap_band(prev_index_level);
|
||||||
|
eprintln!("[DEBUG] date={} current_index={:.2} prev_index={:.2} band=[{:.0}, {:.0}]",
|
||||||
|
date, index_level, prev_index_level, band_low, band_high);
|
||||||
let (stock_list, selection_notes) = self.select_symbols(ctx, date, band_low, band_high)?;
|
let (stock_list, selection_notes) = self.select_symbols(ctx, date, band_low, band_high)?;
|
||||||
let periodic_rebalance = ctx.decision_index % self.config.refresh_rate == 0;
|
let periodic_rebalance = ctx.decision_index % self.config.refresh_rate == 0;
|
||||||
let mut projected = ctx.portfolio.clone();
|
let mut projected = ctx.portfolio.clone();
|
||||||
|
|||||||
Reference in New Issue
Block a user