增强回测demo输出与分区加载
This commit is contained in:
@@ -87,6 +87,8 @@ pub struct DailyFactorSnapshot {
|
||||
pub market_cap_bn: f64,
|
||||
pub free_float_cap_bn: f64,
|
||||
pub pe_ttm: f64,
|
||||
pub turnover_ratio: Option<f64>,
|
||||
pub effective_turnover_ratio: Option<f64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@@ -303,6 +305,14 @@ impl DataSet {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn market_closes_up_to(&self, date: NaiveDate, symbol: &str, lookback: usize) -> Vec<f64> {
|
||||
self.calendar
|
||||
.trailing_days(date, lookback)
|
||||
.into_iter()
|
||||
.filter_map(|day| self.market(day, symbol).map(|row| row.close))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn require_market(
|
||||
&self,
|
||||
date: NaiveDate,
|
||||
@@ -347,6 +357,8 @@ fn read_market(path: &Path) -> Result<Vec<DailyMarketSnapshot>, DataSetError> {
|
||||
let mut snapshots = Vec::new();
|
||||
for row in rows {
|
||||
let prev_close = row.parse_f64(6)?;
|
||||
let derived_upper_limit = round2(prev_close * 1.10);
|
||||
let derived_lower_limit = round2(prev_close * 0.90);
|
||||
snapshots.push(DailyMarketSnapshot {
|
||||
date: row.parse_date(0)?,
|
||||
symbol: row.get(1)?.to_string(),
|
||||
@@ -357,8 +369,8 @@ fn read_market(path: &Path) -> Result<Vec<DailyMarketSnapshot>, DataSetError> {
|
||||
prev_close,
|
||||
volume: row.parse_u64(7)?,
|
||||
paused: row.parse_bool(8)?,
|
||||
upper_limit: round2(prev_close * 1.10),
|
||||
lower_limit: round2(prev_close * 0.90),
|
||||
upper_limit: row.parse_optional_f64(9).unwrap_or(derived_upper_limit),
|
||||
lower_limit: row.parse_optional_f64(10).unwrap_or(derived_lower_limit),
|
||||
});
|
||||
}
|
||||
Ok(snapshots)
|
||||
@@ -374,6 +386,8 @@ fn read_factors(path: &Path) -> Result<Vec<DailyFactorSnapshot>, DataSetError> {
|
||||
market_cap_bn: row.parse_f64(2)?,
|
||||
free_float_cap_bn: row.parse_f64(3)?,
|
||||
pe_ttm: row.parse_f64(4)?,
|
||||
turnover_ratio: row.parse_optional_f64(5),
|
||||
effective_turnover_ratio: row.parse_optional_f64(6),
|
||||
});
|
||||
}
|
||||
Ok(snapshots)
|
||||
@@ -457,6 +471,17 @@ impl CsvRow {
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_optional_f64(&self, index: usize) -> Option<f64> {
|
||||
self.fields.get(index).and_then(|value| {
|
||||
let trimmed = value.trim();
|
||||
if trimmed.is_empty() {
|
||||
None
|
||||
} else {
|
||||
trimmed.parse::<f64>().ok()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_bool(&self, index: usize) -> Result<bool, DataSetError> {
|
||||
self.get(index)?
|
||||
.parse::<bool>()
|
||||
@@ -478,26 +503,35 @@ fn read_partitioned_dir<T, F>(dir: &Path, mut loader: F) -> Result<Vec<T>, DataS
|
||||
where
|
||||
F: FnMut(&Path) -> Result<Vec<T>, DataSetError>,
|
||||
{
|
||||
let mut files = fs::read_dir(dir)
|
||||
.map_err(|source| DataSetError::Io {
|
||||
path: dir.display().to_string(),
|
||||
source,
|
||||
})?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|source| DataSetError::Io {
|
||||
path: dir.display().to_string(),
|
||||
source,
|
||||
})?;
|
||||
files.sort_by_key(|entry| entry.path());
|
||||
|
||||
let mut rows = Vec::new();
|
||||
for entry in files {
|
||||
let path = entry.path();
|
||||
if path.extension().and_then(|x| x.to_str()) != Some("csv") {
|
||||
continue;
|
||||
let mut stack = vec![dir.to_path_buf()];
|
||||
|
||||
while let Some(current_dir) = stack.pop() {
|
||||
let mut entries = fs::read_dir(¤t_dir)
|
||||
.map_err(|source| DataSetError::Io {
|
||||
path: current_dir.display().to_string(),
|
||||
source,
|
||||
})?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|source| DataSetError::Io {
|
||||
path: current_dir.display().to_string(),
|
||||
source,
|
||||
})?;
|
||||
entries.sort_by_key(|entry| entry.path());
|
||||
|
||||
for entry in entries.into_iter().rev() {
|
||||
let path = entry.path();
|
||||
if path.is_dir() {
|
||||
stack.push(path);
|
||||
continue;
|
||||
}
|
||||
if path.extension().and_then(|x| x.to_str()) != Some("csv") {
|
||||
continue;
|
||||
}
|
||||
rows.extend(loader(&path)?);
|
||||
}
|
||||
rows.extend(loader(&path)?);
|
||||
}
|
||||
|
||||
Ok(rows)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user