iciv-predictor 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,181 @@
1
+ Metadata-Version: 2.4
2
+ Name: iciv-predictor
3
+ Version: 0.1.0
4
+ Summary: ICIV股票预测竞赛SDK - 用于开发和测试交易策略
5
+ Author-email: ICIV Lab <iciv@example.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://stock.w3drop.com
8
+ Project-URL: Documentation, https://stock.w3drop.com/docs
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Requires-Python: >=3.9
18
+ Description-Content-Type: text/markdown
19
+ Requires-Dist: pandas>=1.5.0
20
+ Requires-Dist: numpy>=1.21.0
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
23
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
24
+
25
+ # ICIV Stock Predictor SDK
26
+
27
+ 股票预测竞赛SDK,用于开发和测试交易策略。
28
+
29
+ ## 安装
30
+
31
+ ```bash
32
+ pip install iciv-predictor
33
+ ```
34
+
35
+ 或从源码安装:
36
+
37
+ ```bash
38
+ git clone https://github.com/your-repo/iciv-predictor-sdk.git
39
+ cd iciv-predictor-sdk
40
+ pip install -e .
41
+ ```
42
+
43
+ ## 快速开始
44
+
45
+ ### 1. 创建预测器
46
+
47
+ ```python
48
+ from iciv_predictor import BasePredictor, PredictionOutput
49
+ import numpy as np
50
+
51
+ class MyPredictor(BasePredictor):
52
+ def __init__(self, df, predict_steps=48):
53
+ super().__init__(df, predict_steps)
54
+ # 初始化你的参数
55
+ self.short_ma = 12
56
+ self.long_ma = 48
57
+
58
+ def predict_step(self, current_idx):
59
+ """
60
+ 预测当前时间点
61
+
62
+ Args:
63
+ current_idx: 当前索引,只能使用历史数据 df[:current_idx+1]
64
+
65
+ Returns:
66
+ PredictionOutput 或 None
67
+ """
68
+ if current_idx < self.long_ma:
69
+ return None
70
+
71
+ # 获取历史收盘价
72
+ closes = self.get_close_prices(current_idx)
73
+
74
+ # 计算均线
75
+ short_avg = closes[-self.short_ma:].mean()
76
+ long_avg = closes[-self.long_ma:].mean()
77
+
78
+ # 判断方向
79
+ if short_avg > long_avg:
80
+ direction = 1 # 看涨,买入
81
+ elif short_avg < long_avg:
82
+ direction = -1 # 看跌,卖出
83
+ else:
84
+ direction = 0 # 持有
85
+
86
+ return PredictionOutput(
87
+ predict_from_idx=current_idx,
88
+ predicted_prices=np.zeros(self.predict_steps),
89
+ predicted_returns=np.zeros(self.predict_steps),
90
+ confidence=0.6,
91
+ direction=direction
92
+ )
93
+ ```
94
+
95
+ ### 2. 本地测试
96
+
97
+ ```bash
98
+ iciv-test my_predictor.py --data 000021_SZ.csv
99
+ ```
100
+
101
+ 或使用Python:
102
+
103
+ ```python
104
+ from iciv_predictor import Backtester
105
+ import pandas as pd
106
+
107
+ # 加载数据
108
+ df = pd.read_csv('000021_SZ.csv')
109
+ df['trade_time'] = pd.to_datetime(df['datetime'])
110
+
111
+ # 创建预测器
112
+ predictor = MyPredictor(df)
113
+
114
+ # 运行回测
115
+ backtester = Backtester()
116
+ result = backtester.run(df, predictor)
117
+
118
+ print(f"收益率: {result.total_return:.2f}%")
119
+ print(f"最大回撤: {result.max_drawdown:.2f}%")
120
+ print(f"交易次数: {result.total_trades}")
121
+ ```
122
+
123
+ ### 3. 提交到平台
124
+
125
+ 测试通过后,将你的 `.py` 文件提交到 https://stock.w3drop.com
126
+
127
+ ## API 参考
128
+
129
+ ### BasePredictor
130
+
131
+ 基类,所有预测器必须继承此类。
132
+
133
+ **方法**:
134
+
135
+ | 方法 | 说明 |
136
+ |------|------|
137
+ | `__init__(df, predict_steps=48)` | 初始化,predict_steps为预测步长 |
138
+ | `predict_step(current_idx)` | **必须实现**,返回PredictionOutput |
139
+ | `get_historical_data(idx)` | 获取历史DataFrame |
140
+ | `get_close_prices(idx)` | 获取历史收盘价数组 |
141
+ | `get_returns(idx)` | 获取历史收益率数组 |
142
+
143
+ ### PredictionOutput
144
+
145
+ 预测输出结构。
146
+
147
+ **字段**:
148
+
149
+ | 字段 | 类型 | 说明 |
150
+ |------|------|------|
151
+ | `predict_from_idx` | int | 预测起始索引 |
152
+ | `predicted_prices` | np.ndarray | 预测价格序列 |
153
+ | `predicted_returns` | np.ndarray | 预测收益率序列 |
154
+ | `confidence` | float | 置信度 (0-1) |
155
+ | `direction` | int | **交易信号**: 1=买入, -1=卖出, 0=持有 |
156
+
157
+ ## 回测规则
158
+
159
+ 1. **预测频率**: 每48步(约4小时)预测一次
160
+ 2. **测试集**: 使用后20%数据
161
+ 3. **交易逻辑**:
162
+ - direction=1 且无持仓 → 买入
163
+ - direction=-1 且有持仓 → 卖出
164
+ 4. **手续费**: 买卖各万分之三
165
+ 5. **强制平仓**: 测试期结束时平仓
166
+
167
+ ## 注意事项
168
+
169
+ ⚠️ **禁止使用未来数据**!`predict_step(idx)` 只能访问 `idx` 及之前的数据。
170
+
171
+ ```python
172
+ # ✅ 正确
173
+ closes = self.get_close_prices(current_idx)
174
+
175
+ # ❌ 错误 - 访问了未来数据
176
+ future = self.df['close'].iloc[current_idx + 10]
177
+ ```
178
+
179
+ ## License
180
+
181
+ MIT
@@ -0,0 +1,157 @@
1
+ # ICIV Stock Predictor SDK
2
+
3
+ 股票预测竞赛SDK,用于开发和测试交易策略。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ pip install iciv-predictor
9
+ ```
10
+
11
+ 或从源码安装:
12
+
13
+ ```bash
14
+ git clone https://github.com/your-repo/iciv-predictor-sdk.git
15
+ cd iciv-predictor-sdk
16
+ pip install -e .
17
+ ```
18
+
19
+ ## 快速开始
20
+
21
+ ### 1. 创建预测器
22
+
23
+ ```python
24
+ from iciv_predictor import BasePredictor, PredictionOutput
25
+ import numpy as np
26
+
27
+ class MyPredictor(BasePredictor):
28
+ def __init__(self, df, predict_steps=48):
29
+ super().__init__(df, predict_steps)
30
+ # 初始化你的参数
31
+ self.short_ma = 12
32
+ self.long_ma = 48
33
+
34
+ def predict_step(self, current_idx):
35
+ """
36
+ 预测当前时间点
37
+
38
+ Args:
39
+ current_idx: 当前索引,只能使用历史数据 df[:current_idx+1]
40
+
41
+ Returns:
42
+ PredictionOutput 或 None
43
+ """
44
+ if current_idx < self.long_ma:
45
+ return None
46
+
47
+ # 获取历史收盘价
48
+ closes = self.get_close_prices(current_idx)
49
+
50
+ # 计算均线
51
+ short_avg = closes[-self.short_ma:].mean()
52
+ long_avg = closes[-self.long_ma:].mean()
53
+
54
+ # 判断方向
55
+ if short_avg > long_avg:
56
+ direction = 1 # 看涨,买入
57
+ elif short_avg < long_avg:
58
+ direction = -1 # 看跌,卖出
59
+ else:
60
+ direction = 0 # 持有
61
+
62
+ return PredictionOutput(
63
+ predict_from_idx=current_idx,
64
+ predicted_prices=np.zeros(self.predict_steps),
65
+ predicted_returns=np.zeros(self.predict_steps),
66
+ confidence=0.6,
67
+ direction=direction
68
+ )
69
+ ```
70
+
71
+ ### 2. 本地测试
72
+
73
+ ```bash
74
+ iciv-test my_predictor.py --data 000021_SZ.csv
75
+ ```
76
+
77
+ 或使用Python:
78
+
79
+ ```python
80
+ from iciv_predictor import Backtester
81
+ import pandas as pd
82
+
83
+ # 加载数据
84
+ df = pd.read_csv('000021_SZ.csv')
85
+ df['trade_time'] = pd.to_datetime(df['datetime'])
86
+
87
+ # 创建预测器
88
+ predictor = MyPredictor(df)
89
+
90
+ # 运行回测
91
+ backtester = Backtester()
92
+ result = backtester.run(df, predictor)
93
+
94
+ print(f"收益率: {result.total_return:.2f}%")
95
+ print(f"最大回撤: {result.max_drawdown:.2f}%")
96
+ print(f"交易次数: {result.total_trades}")
97
+ ```
98
+
99
+ ### 3. 提交到平台
100
+
101
+ 测试通过后,将你的 `.py` 文件提交到 https://stock.w3drop.com
102
+
103
+ ## API 参考
104
+
105
+ ### BasePredictor
106
+
107
+ 基类,所有预测器必须继承此类。
108
+
109
+ **方法**:
110
+
111
+ | 方法 | 说明 |
112
+ |------|------|
113
+ | `__init__(df, predict_steps=48)` | 初始化,predict_steps为预测步长 |
114
+ | `predict_step(current_idx)` | **必须实现**,返回PredictionOutput |
115
+ | `get_historical_data(idx)` | 获取历史DataFrame |
116
+ | `get_close_prices(idx)` | 获取历史收盘价数组 |
117
+ | `get_returns(idx)` | 获取历史收益率数组 |
118
+
119
+ ### PredictionOutput
120
+
121
+ 预测输出结构。
122
+
123
+ **字段**:
124
+
125
+ | 字段 | 类型 | 说明 |
126
+ |------|------|------|
127
+ | `predict_from_idx` | int | 预测起始索引 |
128
+ | `predicted_prices` | np.ndarray | 预测价格序列 |
129
+ | `predicted_returns` | np.ndarray | 预测收益率序列 |
130
+ | `confidence` | float | 置信度 (0-1) |
131
+ | `direction` | int | **交易信号**: 1=买入, -1=卖出, 0=持有 |
132
+
133
+ ## 回测规则
134
+
135
+ 1. **预测频率**: 每48步(约4小时)预测一次
136
+ 2. **测试集**: 使用后20%数据
137
+ 3. **交易逻辑**:
138
+ - direction=1 且无持仓 → 买入
139
+ - direction=-1 且有持仓 → 卖出
140
+ 4. **手续费**: 买卖各万分之三
141
+ 5. **强制平仓**: 测试期结束时平仓
142
+
143
+ ## 注意事项
144
+
145
+ ⚠️ **禁止使用未来数据**!`predict_step(idx)` 只能访问 `idx` 及之前的数据。
146
+
147
+ ```python
148
+ # ✅ 正确
149
+ closes = self.get_close_prices(current_idx)
150
+
151
+ # ❌ 错误 - 访问了未来数据
152
+ future = self.df['close'].iloc[current_idx + 10]
153
+ ```
154
+
155
+ ## License
156
+
157
+ MIT
@@ -0,0 +1,18 @@
1
+ """
2
+ ICIV Stock Predictor SDK
3
+ 股票预测竞赛SDK - 用于开发和测试交易策略
4
+ """
5
+
6
+ __version__ = "0.1.0"
7
+ __author__ = "ICIV Lab"
8
+
9
+ from .predictor import BasePredictor, PredictionOutput
10
+ from .backtest import Backtester, BacktestConfig, BacktestResult
11
+
12
+ __all__ = [
13
+ 'BasePredictor',
14
+ 'PredictionOutput',
15
+ 'Backtester',
16
+ 'BacktestConfig',
17
+ 'BacktestResult'
18
+ ]
@@ -0,0 +1,173 @@
1
+ """
2
+ 回测引擎 - 模拟服务器回测逻辑
3
+ """
4
+ from dataclasses import dataclass, field
5
+ from typing import List, Optional
6
+ from datetime import datetime
7
+ import numpy as np
8
+ import pandas as pd
9
+
10
+
11
+ @dataclass
12
+ class TradeRecord:
13
+ """交易记录"""
14
+ trade_time: datetime
15
+ trade_type: str # 'BUY' or 'SELL'
16
+ price: float
17
+ shares: int
18
+ amount: float
19
+ fee: float
20
+ capital_after: float
21
+
22
+
23
+ @dataclass
24
+ class BacktestResult:
25
+ """回测结果"""
26
+ initial_capital: float
27
+ final_capital: float
28
+ total_return: float # 收益率 %
29
+ max_drawdown: float # 最大回撤 %
30
+ win_rate: float # 胜率 %
31
+ total_trades: int
32
+ trade_records: List[TradeRecord]
33
+
34
+
35
+ @dataclass
36
+ class BacktestConfig:
37
+ """回测配置"""
38
+ initial_capital: float = 1000000.0 # 初始资金 100万
39
+ buy_fee_rate: float = 0.0003 # 买入费率 万三
40
+ sell_fee_rate: float = 0.0003 # 卖出费率 万三
41
+
42
+
43
+ class Backtester:
44
+ """
45
+ 回测引擎 - 完全匹配服务器逻辑
46
+
47
+ 特点:
48
+ - 每48步预测一次(约4小时)
49
+ - direction=1 买入, direction=-1 卖出
50
+ - 测试结束强制平仓
51
+ """
52
+
53
+ def __init__(self, config: BacktestConfig = None):
54
+ self.config = config or BacktestConfig()
55
+
56
+ def run(self, df: pd.DataFrame, predictor) -> BacktestResult:
57
+ """
58
+ 运行回测
59
+
60
+ Args:
61
+ df: K线数据 (需包含 trade_time, close 列)
62
+ predictor: 预测器实例
63
+
64
+ Returns:
65
+ BacktestResult
66
+ """
67
+ capital = self.config.initial_capital
68
+ position = 0
69
+ trades = []
70
+ equity_curve = [capital]
71
+
72
+ predict_steps = predictor.predict_steps
73
+ total_len = len(df)
74
+
75
+ # 每48步预测一次
76
+ for idx in range(0, total_len - predict_steps, predict_steps):
77
+ output = predictor.predict_step(idx)
78
+
79
+ if output is None:
80
+ continue
81
+
82
+ direction = output.direction
83
+ price = df['close'].iloc[idx]
84
+ trade_time = df['trade_time'].iloc[idx]
85
+
86
+ # 买入
87
+ if direction == 1 and position == 0:
88
+ shares = int(capital * 0.99 / price / 100) * 100
89
+ if shares >= 100:
90
+ amount = shares * price
91
+ fee = amount * self.config.buy_fee_rate
92
+ capital -= (amount + fee)
93
+ position = shares
94
+ trades.append(TradeRecord(
95
+ trade_time=trade_time,
96
+ trade_type='BUY',
97
+ price=price,
98
+ shares=shares,
99
+ amount=amount,
100
+ fee=fee,
101
+ capital_after=capital
102
+ ))
103
+
104
+ # 卖出
105
+ elif direction == -1 and position > 0:
106
+ amount = position * price
107
+ fee = amount * self.config.sell_fee_rate
108
+ capital += (amount - fee)
109
+ trades.append(TradeRecord(
110
+ trade_time=trade_time,
111
+ trade_type='SELL',
112
+ price=price,
113
+ shares=position,
114
+ amount=amount,
115
+ fee=fee,
116
+ capital_after=capital
117
+ ))
118
+ position = 0
119
+
120
+ # 记录权益
121
+ equity = capital + position * price
122
+ equity_curve.append(equity)
123
+
124
+ # 强制平仓
125
+ if position > 0:
126
+ price = df['close'].iloc[-1]
127
+ trade_time = df['trade_time'].iloc[-1]
128
+ amount = position * price
129
+ fee = amount * self.config.sell_fee_rate
130
+ capital += (amount - fee)
131
+ trades.append(TradeRecord(
132
+ trade_time=trade_time,
133
+ trade_type='SELL',
134
+ price=price,
135
+ shares=position,
136
+ amount=amount,
137
+ fee=fee,
138
+ capital_after=capital
139
+ ))
140
+
141
+ # 计算指标
142
+ initial = self.config.initial_capital
143
+ total_return = (capital - initial) / initial * 100
144
+
145
+ # 最大回撤
146
+ max_drawdown = 0.0
147
+ peak = equity_curve[0]
148
+ for eq in equity_curve:
149
+ if eq > peak:
150
+ peak = eq
151
+ dd = (peak - eq) / peak * 100
152
+ if dd > max_drawdown:
153
+ max_drawdown = dd
154
+
155
+ # 胜率
156
+ wins = 0
157
+ pairs = 0
158
+ for i in range(0, len(trades) - 1, 2):
159
+ if trades[i].trade_type == 'BUY' and trades[i+1].trade_type == 'SELL':
160
+ pairs += 1
161
+ if trades[i+1].price > trades[i].price:
162
+ wins += 1
163
+ win_rate = (wins / pairs * 100) if pairs > 0 else 0
164
+
165
+ return BacktestResult(
166
+ initial_capital=initial,
167
+ final_capital=capital,
168
+ total_return=total_return,
169
+ max_drawdown=max_drawdown,
170
+ win_rate=win_rate,
171
+ total_trades=len(trades),
172
+ trade_records=trades
173
+ )
@@ -0,0 +1,111 @@
1
+ """
2
+ 命令行工具 - 本地测试策略
3
+ """
4
+ import argparse
5
+ import sys
6
+ import os
7
+ import importlib.util
8
+ import pandas as pd
9
+
10
+ from .predictor import BasePredictor
11
+ from .backtest import Backtester, BacktestConfig
12
+
13
+
14
+ def load_predictor_class(filepath):
15
+ """从文件加载预测器类"""
16
+ spec = importlib.util.spec_from_file_location("strategy", filepath)
17
+ module = importlib.util.module_from_spec(spec)
18
+ spec.loader.exec_module(module)
19
+
20
+ # 查找继承BasePredictor的类
21
+ for name in dir(module):
22
+ obj = getattr(module, name)
23
+ if isinstance(obj, type) and issubclass(obj, BasePredictor) and obj is not BasePredictor:
24
+ return obj
25
+
26
+ raise ValueError("未找到继承BasePredictor的类")
27
+
28
+
29
+ def main():
30
+ parser = argparse.ArgumentParser(description='ICIV策略本地测试工具')
31
+ parser.add_argument('strategy', help='策略文件路径 (.py)')
32
+ parser.add_argument('--data', '-d', default='000021_SZ.csv', help='数据文件路径')
33
+ parser.add_argument('--capital', '-c', type=float, default=1000000, help='初始资金')
34
+ parser.add_argument('--test-ratio', '-t', type=float, default=0.2, help='测试集比例')
35
+
36
+ args = parser.parse_args()
37
+
38
+ # 检查文件
39
+ if not os.path.exists(args.strategy):
40
+ print(f"❌ 策略文件不存在: {args.strategy}")
41
+ sys.exit(1)
42
+
43
+ if not os.path.exists(args.data):
44
+ print(f"❌ 数据文件不存在: {args.data}")
45
+ sys.exit(1)
46
+
47
+ print(f"\n{'='*60}")
48
+ print(f"📊 ICIV 策略测试")
49
+ print(f"{'='*60}")
50
+ print(f"策略文件: {args.strategy}")
51
+ print(f"数据文件: {args.data}")
52
+ print(f"初始资金: ¥{args.capital:,.0f}")
53
+ print(f"{'='*60}\n")
54
+
55
+ # 加载数据
56
+ try:
57
+ df = pd.read_csv(args.data)
58
+ if 'datetime' in df.columns:
59
+ df = df.rename(columns={'datetime': 'trade_time'})
60
+ df['trade_time'] = pd.to_datetime(df['trade_time'])
61
+ print(f"✓ 数据加载: {len(df)} 条记录")
62
+ except Exception as e:
63
+ print(f"❌ 数据加载失败: {e}")
64
+ sys.exit(1)
65
+
66
+ # 加载策略
67
+ try:
68
+ predictor_class = load_predictor_class(args.strategy)
69
+ print(f"✓ 策略加载: {predictor_class.__name__}")
70
+ except Exception as e:
71
+ print(f"❌ 策略加载失败: {e}")
72
+ sys.exit(1)
73
+
74
+ # 分割数据
75
+ test_start = int(len(df) * (1 - args.test_ratio))
76
+ test_df = df.iloc[test_start:].reset_index(drop=True)
77
+ print(f"✓ 测试集: {len(test_df)} 条 (从索引 {test_start} 开始)")
78
+
79
+ # 创建预测器和回测器
80
+ try:
81
+ predictor = predictor_class(test_df)
82
+ config = BacktestConfig(initial_capital=args.capital)
83
+ backtester = Backtester(config)
84
+
85
+ print(f"\n🔄 运行回测...")
86
+ result = backtester.run(test_df, predictor)
87
+
88
+ print(f"\n{'='*60}")
89
+ print(f"📈 回测结果")
90
+ print(f"{'='*60}")
91
+ print(f" 初始资金: ¥{result.initial_capital:,.0f}")
92
+ print(f" 最终资金: ¥{result.final_capital:,.2f}")
93
+ print(f" 收益率: {result.total_return:+.2f}%")
94
+ print(f" 最大回撤: {result.max_drawdown:.2f}%")
95
+ print(f" 胜率: {result.win_rate:.1f}%")
96
+ print(f" 交易次数: {result.total_trades}")
97
+
98
+ if result.trade_records:
99
+ print(f"\n📋 交易记录:")
100
+ for t in result.trade_records[-6:]:
101
+ print(f" {t.trade_time} {t.trade_type:5s} ¥{t.price:.2f} x {t.shares}")
102
+
103
+ except Exception as e:
104
+ print(f"❌ 回测失败: {e}")
105
+ import traceback
106
+ traceback.print_exc()
107
+ sys.exit(1)
108
+
109
+
110
+ if __name__ == '__main__':
111
+ main()
@@ -0,0 +1,159 @@
1
+ """
2
+ ICIV Stock Predictor SDK
3
+ 用户需要继承 BasePredictor 类实现自己的预测算法
4
+ """
5
+ from abc import ABC, abstractmethod
6
+ from dataclasses import dataclass
7
+ from typing import Optional, List
8
+ import numpy as np
9
+ import pandas as pd
10
+
11
+
12
+ @dataclass
13
+ class PredictionOutput:
14
+ """预测输出结构"""
15
+ # 预测起始索引 (当前时间点)
16
+ predict_from_idx: int
17
+
18
+ # 预测的价格序列 (长度 = predict_steps)
19
+ predicted_prices: np.ndarray
20
+
21
+ # 预测的收益率序列 (百分比)
22
+ predicted_returns: np.ndarray
23
+
24
+ # 置信度 (0-1)
25
+ confidence: float = 0.5
26
+
27
+ # 方向判断: 1=看涨, -1=看跌, 0=中性
28
+ direction: int = 0
29
+
30
+
31
+ class BasePredictor(ABC):
32
+ """
33
+ 预测器基类 - 用户需要继承此类实现自己的预测算法
34
+
35
+ 使用示例:
36
+ ```python
37
+ class MyPredictor(BasePredictor):
38
+ def __init__(self, df: pd.DataFrame, predict_steps: int = 48):
39
+ super().__init__(df, predict_steps)
40
+ # 自定义初始化...
41
+
42
+ def predict_step(self, current_idx: int) -> Optional[PredictionOutput]:
43
+ # 实现预测逻辑...
44
+ return PredictionOutput(...)
45
+ ```
46
+ """
47
+
48
+ def __init__(self, df: pd.DataFrame, predict_steps: int = 48):
49
+ """
50
+ 初始化预测器
51
+
52
+ Args:
53
+ df: K线数据 DataFrame, 包含以下列:
54
+ - trade_time: 交易时间
55
+ - open: 开盘价
56
+ - high: 最高价
57
+ - low: 最低价
58
+ - close: 收盘价
59
+ - volume: 成交量
60
+ - amount: 成交额
61
+ predict_steps: 预测步数 (默认48步, 即4小时)
62
+ """
63
+ self.df = df.copy()
64
+ self.predict_steps = predict_steps
65
+
66
+ # 确保数据按时间排序
67
+ if 'trade_time' in self.df.columns:
68
+ self.df = self.df.sort_values('trade_time').reset_index(drop=True)
69
+
70
+ # 计算收益率
71
+ self.df['return'] = self.df['close'].pct_change() * 100
72
+
73
+ # 数据总长度
74
+ self.total_len = len(self.df)
75
+
76
+ @abstractmethod
77
+ def predict_step(self, current_idx: int) -> Optional[PredictionOutput]:
78
+ """
79
+ 对当前时间点进行预测
80
+
81
+ Args:
82
+ current_idx: 当前时间点索引 (只能使用 df[:current_idx+1] 的数据)
83
+
84
+ Returns:
85
+ PredictionOutput 或 None (如果无法预测)
86
+
87
+ 注意:
88
+ - 不要使用未来数据! 只能使用 current_idx 及之前的数据
89
+ - direction 字段用于生成交易信号
90
+ """
91
+ pass
92
+
93
+ def get_historical_data(self, current_idx: int) -> pd.DataFrame:
94
+ """获取历史数据 (截至 current_idx)"""
95
+ return self.df.iloc[:current_idx + 1].copy()
96
+
97
+ def get_close_prices(self, current_idx: int) -> np.ndarray:
98
+ """获取历史收盘价"""
99
+ return self.df['close'].iloc[:current_idx + 1].values
100
+
101
+ def get_returns(self, current_idx: int) -> np.ndarray:
102
+ """获取历史收益率"""
103
+ return self.df['return'].iloc[:current_idx + 1].values
104
+
105
+
106
+ # ==================== 示例预测器 ====================
107
+
108
+ class SimpleMovingAveragePredictor(BasePredictor):
109
+ """
110
+ 简单移动平均预测器 (示例)
111
+ """
112
+
113
+ def __init__(self, df: pd.DataFrame, predict_steps: int = 48,
114
+ short_window: int = 12, long_window: int = 48):
115
+ super().__init__(df, predict_steps)
116
+ self.short_window = short_window
117
+ self.long_window = long_window
118
+
119
+ def predict_step(self, current_idx: int) -> Optional[PredictionOutput]:
120
+ if current_idx < self.long_window:
121
+ return None
122
+
123
+ closes = self.get_close_prices(current_idx)
124
+ current_price = closes[-1]
125
+
126
+ # 计算移动平均
127
+ short_ma = closes[-self.short_window:].mean()
128
+ long_ma = closes[-self.long_window:].mean()
129
+
130
+ # 判断方向
131
+ if short_ma > long_ma * 1.01: # 短期均线高于长期均线 1%
132
+ direction = 1 # 看涨
133
+ elif short_ma < long_ma * 0.99:
134
+ direction = -1 # 看跌
135
+ else:
136
+ direction = 0
137
+
138
+ # 简单预测: 假设价格按趋势变化
139
+ avg_return = self.df['return'].iloc[current_idx - self.short_window:current_idx + 1].mean()
140
+ predicted_returns = np.full(self.predict_steps, avg_return)
141
+
142
+ # 计算预测价格
143
+ predicted_prices = np.zeros(self.predict_steps)
144
+ price = current_price
145
+ for i in range(self.predict_steps):
146
+ price = price * (1 + predicted_returns[i] / 100)
147
+ predicted_prices[i] = price
148
+
149
+ # 置信度基于均线差距
150
+ ma_diff = abs(short_ma - long_ma) / long_ma
151
+ confidence = min(0.9, 0.3 + ma_diff * 10)
152
+
153
+ return PredictionOutput(
154
+ predict_from_idx=current_idx,
155
+ predicted_prices=predicted_prices,
156
+ predicted_returns=predicted_returns,
157
+ confidence=confidence,
158
+ direction=direction
159
+ )
@@ -0,0 +1,181 @@
1
+ Metadata-Version: 2.4
2
+ Name: iciv-predictor
3
+ Version: 0.1.0
4
+ Summary: ICIV股票预测竞赛SDK - 用于开发和测试交易策略
5
+ Author-email: ICIV Lab <iciv@example.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://stock.w3drop.com
8
+ Project-URL: Documentation, https://stock.w3drop.com/docs
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Requires-Python: >=3.9
18
+ Description-Content-Type: text/markdown
19
+ Requires-Dist: pandas>=1.5.0
20
+ Requires-Dist: numpy>=1.21.0
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
23
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
24
+
25
+ # ICIV Stock Predictor SDK
26
+
27
+ 股票预测竞赛SDK,用于开发和测试交易策略。
28
+
29
+ ## 安装
30
+
31
+ ```bash
32
+ pip install iciv-predictor
33
+ ```
34
+
35
+ 或从源码安装:
36
+
37
+ ```bash
38
+ git clone https://github.com/your-repo/iciv-predictor-sdk.git
39
+ cd iciv-predictor-sdk
40
+ pip install -e .
41
+ ```
42
+
43
+ ## 快速开始
44
+
45
+ ### 1. 创建预测器
46
+
47
+ ```python
48
+ from iciv_predictor import BasePredictor, PredictionOutput
49
+ import numpy as np
50
+
51
+ class MyPredictor(BasePredictor):
52
+ def __init__(self, df, predict_steps=48):
53
+ super().__init__(df, predict_steps)
54
+ # 初始化你的参数
55
+ self.short_ma = 12
56
+ self.long_ma = 48
57
+
58
+ def predict_step(self, current_idx):
59
+ """
60
+ 预测当前时间点
61
+
62
+ Args:
63
+ current_idx: 当前索引,只能使用历史数据 df[:current_idx+1]
64
+
65
+ Returns:
66
+ PredictionOutput 或 None
67
+ """
68
+ if current_idx < self.long_ma:
69
+ return None
70
+
71
+ # 获取历史收盘价
72
+ closes = self.get_close_prices(current_idx)
73
+
74
+ # 计算均线
75
+ short_avg = closes[-self.short_ma:].mean()
76
+ long_avg = closes[-self.long_ma:].mean()
77
+
78
+ # 判断方向
79
+ if short_avg > long_avg:
80
+ direction = 1 # 看涨,买入
81
+ elif short_avg < long_avg:
82
+ direction = -1 # 看跌,卖出
83
+ else:
84
+ direction = 0 # 持有
85
+
86
+ return PredictionOutput(
87
+ predict_from_idx=current_idx,
88
+ predicted_prices=np.zeros(self.predict_steps),
89
+ predicted_returns=np.zeros(self.predict_steps),
90
+ confidence=0.6,
91
+ direction=direction
92
+ )
93
+ ```
94
+
95
+ ### 2. 本地测试
96
+
97
+ ```bash
98
+ iciv-test my_predictor.py --data 000021_SZ.csv
99
+ ```
100
+
101
+ 或使用Python:
102
+
103
+ ```python
104
+ from iciv_predictor import Backtester
105
+ import pandas as pd
106
+
107
+ # 加载数据
108
+ df = pd.read_csv('000021_SZ.csv')
109
+ df['trade_time'] = pd.to_datetime(df['datetime'])
110
+
111
+ # 创建预测器
112
+ predictor = MyPredictor(df)
113
+
114
+ # 运行回测
115
+ backtester = Backtester()
116
+ result = backtester.run(df, predictor)
117
+
118
+ print(f"收益率: {result.total_return:.2f}%")
119
+ print(f"最大回撤: {result.max_drawdown:.2f}%")
120
+ print(f"交易次数: {result.total_trades}")
121
+ ```
122
+
123
+ ### 3. 提交到平台
124
+
125
+ 测试通过后,将你的 `.py` 文件提交到 https://stock.w3drop.com
126
+
127
+ ## API 参考
128
+
129
+ ### BasePredictor
130
+
131
+ 基类,所有预测器必须继承此类。
132
+
133
+ **方法**:
134
+
135
+ | 方法 | 说明 |
136
+ |------|------|
137
+ | `__init__(df, predict_steps=48)` | 初始化,predict_steps为预测步长 |
138
+ | `predict_step(current_idx)` | **必须实现**,返回PredictionOutput |
139
+ | `get_historical_data(idx)` | 获取历史DataFrame |
140
+ | `get_close_prices(idx)` | 获取历史收盘价数组 |
141
+ | `get_returns(idx)` | 获取历史收益率数组 |
142
+
143
+ ### PredictionOutput
144
+
145
+ 预测输出结构。
146
+
147
+ **字段**:
148
+
149
+ | 字段 | 类型 | 说明 |
150
+ |------|------|------|
151
+ | `predict_from_idx` | int | 预测起始索引 |
152
+ | `predicted_prices` | np.ndarray | 预测价格序列 |
153
+ | `predicted_returns` | np.ndarray | 预测收益率序列 |
154
+ | `confidence` | float | 置信度 (0-1) |
155
+ | `direction` | int | **交易信号**: 1=买入, -1=卖出, 0=持有 |
156
+
157
+ ## 回测规则
158
+
159
+ 1. **预测频率**: 每48步(约4小时)预测一次
160
+ 2. **测试集**: 使用后20%数据
161
+ 3. **交易逻辑**:
162
+ - direction=1 且无持仓 → 买入
163
+ - direction=-1 且有持仓 → 卖出
164
+ 4. **手续费**: 买卖各万分之三
165
+ 5. **强制平仓**: 测试期结束时平仓
166
+
167
+ ## 注意事项
168
+
169
+ ⚠️ **禁止使用未来数据**!`predict_step(idx)` 只能访问 `idx` 及之前的数据。
170
+
171
+ ```python
172
+ # ✅ 正确
173
+ closes = self.get_close_prices(current_idx)
174
+
175
+ # ❌ 错误 - 访问了未来数据
176
+ future = self.df['close'].iloc[current_idx + 10]
177
+ ```
178
+
179
+ ## License
180
+
181
+ MIT
@@ -0,0 +1,12 @@
1
+ README.md
2
+ pyproject.toml
3
+ iciv_predictor/__init__.py
4
+ iciv_predictor/backtest.py
5
+ iciv_predictor/cli.py
6
+ iciv_predictor/predictor.py
7
+ iciv_predictor.egg-info/PKG-INFO
8
+ iciv_predictor.egg-info/SOURCES.txt
9
+ iciv_predictor.egg-info/dependency_links.txt
10
+ iciv_predictor.egg-info/entry_points.txt
11
+ iciv_predictor.egg-info/requires.txt
12
+ iciv_predictor.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ iciv-test = iciv_predictor.cli:main
@@ -0,0 +1,6 @@
1
+ pandas>=1.5.0
2
+ numpy>=1.21.0
3
+
4
+ [dev]
5
+ pytest>=7.0.0
6
+ pytest-cov>=4.0.0
@@ -0,0 +1 @@
1
+ iciv_predictor
@@ -0,0 +1,45 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "iciv-predictor"
7
+ version = "0.1.0"
8
+ description = "ICIV股票预测竞赛SDK - 用于开发和测试交易策略"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ authors = [
12
+ {name = "ICIV Lab", email = "iciv@example.com"}
13
+ ]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.9",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ ]
24
+ requires-python = ">=3.9"
25
+ dependencies = [
26
+ "pandas>=1.5.0",
27
+ "numpy>=1.21.0",
28
+ ]
29
+
30
+ [project.optional-dependencies]
31
+ dev = [
32
+ "pytest>=7.0.0",
33
+ "pytest-cov>=4.0.0",
34
+ ]
35
+
36
+ [project.urls]
37
+ Homepage = "https://stock.w3drop.com"
38
+ Documentation = "https://stock.w3drop.com/docs"
39
+
40
+ [project.scripts]
41
+ iciv-test = "iciv_predictor.cli:main"
42
+
43
+ [tool.setuptools.packages.find]
44
+ where = ["."]
45
+ include = ["iciv_predictor*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+