清理CSV回测demo入口
This commit is contained in:
@@ -1,15 +1,582 @@
|
||||
use chrono::NaiveDate;
|
||||
use fidc_core::{
|
||||
CnSmallCapRotationConfig, CnSmallCapRotationStrategy, DataSet, OmniMicroCapConfig,
|
||||
BenchmarkSnapshot, CandidateEligibility, CnSmallCapRotationConfig, CnSmallCapRotationStrategy,
|
||||
DailyFactorSnapshot, DailyMarketSnapshot, DataSet, Instrument, OmniMicroCapConfig,
|
||||
OmniMicroCapStrategy, PortfolioState, Strategy, StrategyContext,
|
||||
};
|
||||
use std::collections::BTreeSet;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn d(value: &str) -> NaiveDate {
|
||||
NaiveDate::parse_from_str(value, "%Y-%m-%d").unwrap()
|
||||
}
|
||||
|
||||
fn instrument(symbol: &str, name: &str) -> Instrument {
|
||||
Instrument {
|
||||
symbol: symbol.to_string(),
|
||||
name: name.to_string(),
|
||||
board: "Main".to_string(),
|
||||
round_lot: 100,
|
||||
listed_at: None,
|
||||
delisted_at: None,
|
||||
status: "active".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn market(
|
||||
date: &str,
|
||||
symbol: &str,
|
||||
open: f64,
|
||||
high: f64,
|
||||
low: f64,
|
||||
close: f64,
|
||||
prev_close: f64,
|
||||
volume: u64,
|
||||
paused: bool,
|
||||
) -> DailyMarketSnapshot {
|
||||
DailyMarketSnapshot {
|
||||
date: d(date),
|
||||
symbol: symbol.to_string(),
|
||||
timestamp: None,
|
||||
day_open: open,
|
||||
open,
|
||||
high,
|
||||
low,
|
||||
close,
|
||||
last_price: close,
|
||||
bid1: close,
|
||||
ask1: close,
|
||||
prev_close,
|
||||
volume,
|
||||
minute_volume: 0,
|
||||
bid1_volume: 0,
|
||||
ask1_volume: 0,
|
||||
trading_phase: None,
|
||||
paused,
|
||||
upper_limit: (prev_close * 1.10 * 100.0).round() / 100.0,
|
||||
lower_limit: (prev_close * 0.90 * 100.0).round() / 100.0,
|
||||
price_tick: 0.01,
|
||||
}
|
||||
}
|
||||
|
||||
fn factor(
|
||||
date: &str,
|
||||
symbol: &str,
|
||||
market_cap_bn: f64,
|
||||
free_float_cap_bn: f64,
|
||||
) -> DailyFactorSnapshot {
|
||||
DailyFactorSnapshot {
|
||||
date: d(date),
|
||||
symbol: symbol.to_string(),
|
||||
market_cap_bn,
|
||||
free_float_cap_bn,
|
||||
pe_ttm: 18.0,
|
||||
turnover_ratio: None,
|
||||
effective_turnover_ratio: None,
|
||||
extra_factors: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn candidate(
|
||||
date: &str,
|
||||
symbol: &str,
|
||||
is_new_listing: bool,
|
||||
is_paused: bool,
|
||||
allow_buy: bool,
|
||||
allow_sell: bool,
|
||||
) -> CandidateEligibility {
|
||||
CandidateEligibility {
|
||||
date: d(date),
|
||||
symbol: symbol.to_string(),
|
||||
is_st: false,
|
||||
is_star_st: false,
|
||||
is_new_listing,
|
||||
is_paused,
|
||||
allow_buy,
|
||||
allow_sell,
|
||||
is_kcb: false,
|
||||
is_one_yuan: false,
|
||||
risk_level_code: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn benchmark(date: &str, open: f64, close: f64, prev_close: f64, volume: u64) -> BenchmarkSnapshot {
|
||||
BenchmarkSnapshot {
|
||||
date: d(date),
|
||||
benchmark: "CSI300.DEMO".to_string(),
|
||||
open,
|
||||
close,
|
||||
prev_close,
|
||||
volume,
|
||||
}
|
||||
}
|
||||
|
||||
fn strategy_test_dataset() -> DataSet {
|
||||
let dates = [
|
||||
"2024-01-02",
|
||||
"2024-01-03",
|
||||
"2024-01-04",
|
||||
"2024-01-05",
|
||||
"2024-01-08",
|
||||
"2024-01-09",
|
||||
"2024-01-10",
|
||||
"2024-01-11",
|
||||
"2024-01-12",
|
||||
];
|
||||
let instruments = vec![
|
||||
instrument("000001.SZ", "Alpha Components"),
|
||||
instrument("000002.SZ", "Beta Precision"),
|
||||
instrument("000003.SZ", "Charlie Materials"),
|
||||
instrument("600001.SH", "Delta Industrials"),
|
||||
];
|
||||
let market = vec![
|
||||
market(
|
||||
"2024-01-02",
|
||||
"000001.SZ",
|
||||
10.0,
|
||||
10.2,
|
||||
9.9,
|
||||
10.1,
|
||||
9.8,
|
||||
1_200_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-02",
|
||||
"000002.SZ",
|
||||
11.0,
|
||||
11.3,
|
||||
10.9,
|
||||
11.2,
|
||||
10.8,
|
||||
1_100_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-02",
|
||||
"000003.SZ",
|
||||
8.0,
|
||||
8.1,
|
||||
7.8,
|
||||
7.9,
|
||||
8.0,
|
||||
900_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-02",
|
||||
"600001.SH",
|
||||
15.0,
|
||||
15.2,
|
||||
14.9,
|
||||
15.1,
|
||||
15.0,
|
||||
800_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-03",
|
||||
"000001.SZ",
|
||||
10.2,
|
||||
10.5,
|
||||
10.1,
|
||||
10.4,
|
||||
10.1,
|
||||
1_250_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-03",
|
||||
"000002.SZ",
|
||||
11.2,
|
||||
11.6,
|
||||
11.1,
|
||||
11.5,
|
||||
11.2,
|
||||
1_120_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-03",
|
||||
"000003.SZ",
|
||||
7.8,
|
||||
7.9,
|
||||
7.3,
|
||||
7.4,
|
||||
7.9,
|
||||
930_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-03",
|
||||
"600001.SH",
|
||||
15.1,
|
||||
15.3,
|
||||
15.0,
|
||||
15.2,
|
||||
15.1,
|
||||
820_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-04",
|
||||
"000001.SZ",
|
||||
10.5,
|
||||
10.8,
|
||||
10.4,
|
||||
10.7,
|
||||
10.4,
|
||||
1_280_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-04",
|
||||
"000002.SZ",
|
||||
11.4,
|
||||
11.9,
|
||||
11.3,
|
||||
11.8,
|
||||
11.5,
|
||||
1_150_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-04",
|
||||
"000003.SZ",
|
||||
7.3,
|
||||
7.4,
|
||||
7.0,
|
||||
7.1,
|
||||
7.4,
|
||||
940_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-04",
|
||||
"600001.SH",
|
||||
15.2,
|
||||
15.5,
|
||||
15.1,
|
||||
15.4,
|
||||
15.2,
|
||||
830_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-05",
|
||||
"000001.SZ",
|
||||
10.8,
|
||||
11.1,
|
||||
10.7,
|
||||
11.0,
|
||||
10.7,
|
||||
1_300_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-05",
|
||||
"000002.SZ",
|
||||
11.9,
|
||||
12.1,
|
||||
11.8,
|
||||
12.0,
|
||||
11.8,
|
||||
1_180_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-05",
|
||||
"000003.SZ",
|
||||
7.0,
|
||||
7.1,
|
||||
6.8,
|
||||
6.9,
|
||||
7.1,
|
||||
950_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-05",
|
||||
"600001.SH",
|
||||
15.4,
|
||||
15.6,
|
||||
15.3,
|
||||
15.5,
|
||||
15.4,
|
||||
840_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-08",
|
||||
"000001.SZ",
|
||||
11.1,
|
||||
11.6,
|
||||
11.0,
|
||||
11.5,
|
||||
11.0,
|
||||
1_400_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-08",
|
||||
"000002.SZ",
|
||||
12.1,
|
||||
12.5,
|
||||
12.0,
|
||||
12.4,
|
||||
12.0,
|
||||
1_200_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-08",
|
||||
"000003.SZ",
|
||||
7.0,
|
||||
7.3,
|
||||
6.9,
|
||||
7.2,
|
||||
6.9,
|
||||
980_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-08",
|
||||
"600001.SH",
|
||||
15.5,
|
||||
15.7,
|
||||
15.4,
|
||||
15.6,
|
||||
15.5,
|
||||
850_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-09",
|
||||
"000001.SZ",
|
||||
11.6,
|
||||
12.4,
|
||||
11.5,
|
||||
12.3,
|
||||
11.5,
|
||||
1_500_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-09",
|
||||
"000002.SZ",
|
||||
12.5,
|
||||
12.9,
|
||||
12.4,
|
||||
12.8,
|
||||
12.4,
|
||||
1_250_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-09",
|
||||
"000003.SZ",
|
||||
7.2,
|
||||
7.5,
|
||||
7.1,
|
||||
7.4,
|
||||
7.2,
|
||||
990_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-09",
|
||||
"600001.SH",
|
||||
15.6,
|
||||
15.7,
|
||||
15.4,
|
||||
15.5,
|
||||
15.6,
|
||||
860_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-10",
|
||||
"000001.SZ",
|
||||
12.2,
|
||||
12.3,
|
||||
11.9,
|
||||
12.0,
|
||||
12.3,
|
||||
1_450_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-10",
|
||||
"000002.SZ",
|
||||
12.7,
|
||||
12.8,
|
||||
12.5,
|
||||
12.6,
|
||||
12.8,
|
||||
1_220_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-10",
|
||||
"000003.SZ",
|
||||
7.5,
|
||||
7.6,
|
||||
7.4,
|
||||
7.5,
|
||||
7.4,
|
||||
1_000_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-10",
|
||||
"600001.SH",
|
||||
15.4,
|
||||
15.5,
|
||||
15.1,
|
||||
15.2,
|
||||
15.5,
|
||||
870_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-11",
|
||||
"000001.SZ",
|
||||
12.0,
|
||||
12.1,
|
||||
11.5,
|
||||
11.6,
|
||||
12.0,
|
||||
1_420_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-11",
|
||||
"000002.SZ",
|
||||
12.5,
|
||||
12.6,
|
||||
12.1,
|
||||
12.2,
|
||||
12.6,
|
||||
1_210_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-11",
|
||||
"000003.SZ",
|
||||
7.4,
|
||||
7.5,
|
||||
7.2,
|
||||
7.3,
|
||||
7.5,
|
||||
980_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-11",
|
||||
"600001.SH",
|
||||
15.2,
|
||||
15.2,
|
||||
15.2,
|
||||
15.2,
|
||||
15.2,
|
||||
0,
|
||||
true,
|
||||
),
|
||||
market(
|
||||
"2024-01-12",
|
||||
"000001.SZ",
|
||||
11.5,
|
||||
11.6,
|
||||
11.1,
|
||||
11.2,
|
||||
11.6,
|
||||
1_380_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-12",
|
||||
"000002.SZ",
|
||||
12.1,
|
||||
12.2,
|
||||
11.8,
|
||||
11.9,
|
||||
12.2,
|
||||
1_190_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-12",
|
||||
"000003.SZ",
|
||||
7.2,
|
||||
7.2,
|
||||
6.9,
|
||||
7.0,
|
||||
7.3,
|
||||
960_000,
|
||||
false,
|
||||
),
|
||||
market(
|
||||
"2024-01-12",
|
||||
"600001.SH",
|
||||
14.8,
|
||||
15.0,
|
||||
14.7,
|
||||
14.9,
|
||||
15.2,
|
||||
850_000,
|
||||
false,
|
||||
),
|
||||
];
|
||||
let factors = dates
|
||||
.iter()
|
||||
.enumerate()
|
||||
.flat_map(|(idx, date)| {
|
||||
let i = idx as f64;
|
||||
[
|
||||
factor(date, "000001.SZ", 38.0 + i, 24.0 + i * 0.5),
|
||||
factor(date, "000002.SZ", 45.0 + i, 30.0 + i * 0.5),
|
||||
factor(date, "000003.SZ", 65.0 - i, 40.0 - i * 0.5),
|
||||
factor(date, "600001.SH", 85.0 + i, 55.0 + i * 0.5),
|
||||
]
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let candidates = dates
|
||||
.iter()
|
||||
.flat_map(|date| {
|
||||
let first_two = *date == "2024-01-02" || *date == "2024-01-03";
|
||||
let paused_600001 = *date == "2024-01-11";
|
||||
[
|
||||
candidate(date, "000001.SZ", first_two, false, !first_two, true),
|
||||
candidate(date, "000002.SZ", false, false, true, true),
|
||||
candidate(date, "000003.SZ", false, false, true, true),
|
||||
candidate(
|
||||
date,
|
||||
"600001.SH",
|
||||
false,
|
||||
paused_600001,
|
||||
!paused_600001,
|
||||
!paused_600001,
|
||||
),
|
||||
]
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let benchmarks = vec![
|
||||
benchmark("2024-01-02", 2990.0, 3000.0, 2980.0, 100_000_000),
|
||||
benchmark("2024-01-03", 3005.0, 3020.0, 3000.0, 102_000_000),
|
||||
benchmark("2024-01-04", 3025.0, 3050.0, 3020.0, 105_000_000),
|
||||
benchmark("2024-01-05", 3055.0, 3080.0, 3050.0, 108_000_000),
|
||||
benchmark("2024-01-08", 3085.0, 3110.0, 3080.0, 109_000_000),
|
||||
benchmark("2024-01-09", 3100.0, 3090.0, 3110.0, 107_000_000),
|
||||
benchmark("2024-01-10", 3080.0, 3040.0, 3090.0, 111_000_000),
|
||||
benchmark("2024-01-11", 3030.0, 2990.0, 3040.0, 115_000_000),
|
||||
benchmark("2024-01-12", 2980.0, 2950.0, 2990.0, 118_000_000),
|
||||
];
|
||||
DataSet::from_components(instruments, market, factors, candidates, benchmarks)
|
||||
.expect("strategy test dataset")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn strategy_emits_target_weights_and_diagnostics() {
|
||||
let data_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../data/demo");
|
||||
let data = DataSet::from_csv_dir(&data_dir).expect("demo data");
|
||||
let data = strategy_test_dataset();
|
||||
let decision_date = NaiveDate::from_ymd_opt(2024, 1, 10).unwrap();
|
||||
let execution_date = NaiveDate::from_ymd_opt(2024, 1, 11).unwrap();
|
||||
let portfolio = PortfolioState::new(1_000_000.0);
|
||||
@@ -53,8 +620,7 @@ fn strategy_emits_target_weights_and_diagnostics() {
|
||||
|
||||
#[test]
|
||||
fn omni_strategy_emits_same_day_decision() {
|
||||
let data_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../data/demo");
|
||||
let data = DataSet::from_csv_dir(&data_dir).expect("demo data");
|
||||
let data = strategy_test_dataset();
|
||||
let execution_date = NaiveDate::from_ymd_opt(2024, 1, 10).unwrap();
|
||||
let portfolio = PortfolioState::new(1_000_000.0);
|
||||
let mut cfg = OmniMicroCapConfig::omni_microcap();
|
||||
|
||||
Reference in New Issue
Block a user