data-backtest-live-common 0.2.0__tar.gz → 0.3.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.
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/PKG-INFO +5 -4
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/README.md +4 -3
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/data_backtest_live_common.egg-info/PKG-INFO +5 -4
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/__init__.py +8 -6
- data_backtest_live_common-0.3.0/dbl_common/fees.py +362 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/pyproject.toml +1 -1
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/tests/test_trading_rules.py +92 -10
- data_backtest_live_common-0.2.0/dbl_common/fees.py +0 -171
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/LICENSE +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/data_backtest_live_common.egg-info/SOURCES.txt +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/data_backtest_live_common.egg-info/dependency_links.txt +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/data_backtest_live_common.egg-info/requires.txt +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/data_backtest_live_common.egg-info/top_level.txt +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/adjust.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/boards.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/circuit_breaker.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/corporate_actions.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/halts.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/io_utils.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/lots.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/price_limit.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/proc.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/settlement.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/ticks.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/trade_calendar.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/trading_calendar.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/trading_hours.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/vec.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/setup.cfg +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/tests/test_adjust.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/tests/test_io_utils.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/tests/test_price_limit.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/tests/test_proc.py +0 -0
- {data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/tests/test_trade_calendar.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: data-backtest-live-common
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: 数据(Data)/回测(Backtest)/实盘(Live)三系统公共库:复权、A股交易规则全集(涨跌幅/时段/费用/交收/熔断/除权)、交易日历、原子写、无黑窗子进程
|
|
5
5
|
Author: dbl_common maintainers
|
|
6
6
|
License: MIT License
|
|
@@ -56,7 +56,7 @@ Dynamic: license-file
|
|
|
56
56
|
|
|
57
57
|
- **发行名(pip 名)**:`data-backtest-live-common` —— 数据/回测/实盘三个英文单词 + common(用户 2026-09-26 指定口径)
|
|
58
58
|
- **导入名**:`dbl_common` —— 三词首字母 + common(对齐 `beautifulsoup4 → import bs4` 的短名惯例,免得每次 import 敲 24 个字符)
|
|
59
|
-
- **版本**:0.
|
|
59
|
+
- **版本**:0.3.0 —— 2026-09-26 抽出独立成库 → 2026-09-27 并入 market_common 两库合一(0.2.0 上架 PyPI)→ 同日 **0.3.0 费用模块重大勘误**(逐条对照财政部/中登/交易所公告修正佣金封顶、过户费双轨制、印花税历史档)
|
|
60
60
|
|
|
61
61
|
## 收录标准(硬规则)
|
|
62
62
|
|
|
@@ -77,7 +77,7 @@ Dynamic: license-file
|
|
|
77
77
|
| `trading_hours` | 交易时段(集合竞价/连续竞价/收盘集合竞价,`Phase` 枚举) | 实盘下单时段校验;回测撮合时点 |
|
|
78
78
|
| `settlement` | 交收制度(T+1/T+0/T+3,`STOCK_T1_START`) | 实盘可卖判断;回测成交约束 |
|
|
79
79
|
| `lots` / `ticks` | 申报单位(手数)/ 最小变动价位(含 snap/校验) | 实盘委托合法性;回测撮合精度 |
|
|
80
|
-
| `fees` |
|
|
80
|
+
| `fees` | 交易费用(印花税 1997 起全时间线 / 过户费 2015 前沪面值深金额双轨 / 佣金法定上限 3‰ / 经手+证管规费,**v0.3.0 逐条对照官方公告勘误**) | 回测净收益;实盘成本预估 |
|
|
81
81
|
| `circuit_breaker` | 2016 熔断制度(历史触发记录) | 回测跨 2016-01 必须剔除熔断时段 |
|
|
82
82
|
| `halts` | 盘中临时停牌(新股/转债临停规则与复牌时间) | 回测撮合跳过临停;实盘委托拦截 |
|
|
83
83
|
| `corporate_actions` | 除权除息参考价官方公式 + 理论因子跳变 + 数据中心核验入口(容差 0.5%;B股/转债拒答) | 数据:dividend 对账;回测:复权核验 |
|
|
@@ -94,7 +94,7 @@ Dynamic: license-file
|
|
|
94
94
|
|
|
95
95
|
# ② 正式(打 wheel 安装)
|
|
96
96
|
python -m pip wheel . --no-deps -w dist
|
|
97
|
-
python -m pip install dist/data_backtest_live_common-0.
|
|
97
|
+
python -m pip install dist/data_backtest_live_common-0.3.0-py3-none-any.whl
|
|
98
98
|
|
|
99
99
|
# ③ 未来发布 PyPI 后(像 akshare 一样)
|
|
100
100
|
pip install data-backtest-live-common
|
|
@@ -117,6 +117,7 @@ $env:PYTHONPATH = "F:\code\finance\quant_data_center\vendor"
|
|
|
117
117
|
- `price_limit` 的 ST 判定只有当前名单、没有逐日历史 → 5% 档用「恰好贴板」精确判定(详见模块 docstring 的血泪教训:用 `≥` 会把普通涨超 5% 的交易日成片误判);
|
|
118
118
|
- `adjust` 的 hfq 锚定上市日(历史行永不变,适合增量落盘),qfq 锚定最新(历史随分红改写,只适合展示);
|
|
119
119
|
- 1996-12-16 之前 A 股无涨跌停制度,`vec.flags_from_bars` 一律不判;
|
|
120
|
+
- `fees`(v0.3.0 勘误后口径):佣金法定上限 **3‰ 从未变过**(不存在「0.03% 封顶」政策,2002-05-01 前固定佣金时代拒答);过户费 **2015-08-01 前沪市按面值/深市按金额双轨**(沪 0.5‰→0.375‰→0.3‰ 按面值,深 0.0255‰ 按金额),之后统一按金额 0.02‰→0.01‰;印花税 A 股 1997-05-10 前拒答、B 股 2001-11-16 前拒答;B 股过户费/结算费体系未编码整体拒答;经手费/证管费通常**已含在佣金内**(helper 仅供净佣金分析,ETF/基金经手费未编码返回 None);
|
|
120
121
|
- `corporate_actions` 对 B 股(需当日汇率折算,属运行期数据非规则)与可转债(不除权)显式 raise 拒答,不猜;
|
|
121
122
|
- 新股「首 N 日不设涨跌幅」没有交易日序号时按自然日近似,`reason` 里如实标注「近似」。
|
|
122
123
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
- **发行名(pip 名)**:`data-backtest-live-common` —— 数据/回测/实盘三个英文单词 + common(用户 2026-09-26 指定口径)
|
|
7
7
|
- **导入名**:`dbl_common` —— 三词首字母 + common(对齐 `beautifulsoup4 → import bs4` 的短名惯例,免得每次 import 敲 24 个字符)
|
|
8
|
-
- **版本**:0.
|
|
8
|
+
- **版本**:0.3.0 —— 2026-09-26 抽出独立成库 → 2026-09-27 并入 market_common 两库合一(0.2.0 上架 PyPI)→ 同日 **0.3.0 费用模块重大勘误**(逐条对照财政部/中登/交易所公告修正佣金封顶、过户费双轨制、印花税历史档)
|
|
9
9
|
|
|
10
10
|
## 收录标准(硬规则)
|
|
11
11
|
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
| `trading_hours` | 交易时段(集合竞价/连续竞价/收盘集合竞价,`Phase` 枚举) | 实盘下单时段校验;回测撮合时点 |
|
|
27
27
|
| `settlement` | 交收制度(T+1/T+0/T+3,`STOCK_T1_START`) | 实盘可卖判断;回测成交约束 |
|
|
28
28
|
| `lots` / `ticks` | 申报单位(手数)/ 最小变动价位(含 snap/校验) | 实盘委托合法性;回测撮合精度 |
|
|
29
|
-
| `fees` |
|
|
29
|
+
| `fees` | 交易费用(印花税 1997 起全时间线 / 过户费 2015 前沪面值深金额双轨 / 佣金法定上限 3‰ / 经手+证管规费,**v0.3.0 逐条对照官方公告勘误**) | 回测净收益;实盘成本预估 |
|
|
30
30
|
| `circuit_breaker` | 2016 熔断制度(历史触发记录) | 回测跨 2016-01 必须剔除熔断时段 |
|
|
31
31
|
| `halts` | 盘中临时停牌(新股/转债临停规则与复牌时间) | 回测撮合跳过临停;实盘委托拦截 |
|
|
32
32
|
| `corporate_actions` | 除权除息参考价官方公式 + 理论因子跳变 + 数据中心核验入口(容差 0.5%;B股/转债拒答) | 数据:dividend 对账;回测:复权核验 |
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
|
|
44
44
|
# ② 正式(打 wheel 安装)
|
|
45
45
|
python -m pip wheel . --no-deps -w dist
|
|
46
|
-
python -m pip install dist/data_backtest_live_common-0.
|
|
46
|
+
python -m pip install dist/data_backtest_live_common-0.3.0-py3-none-any.whl
|
|
47
47
|
|
|
48
48
|
# ③ 未来发布 PyPI 后(像 akshare 一样)
|
|
49
49
|
pip install data-backtest-live-common
|
|
@@ -66,6 +66,7 @@ $env:PYTHONPATH = "F:\code\finance\quant_data_center\vendor"
|
|
|
66
66
|
- `price_limit` 的 ST 判定只有当前名单、没有逐日历史 → 5% 档用「恰好贴板」精确判定(详见模块 docstring 的血泪教训:用 `≥` 会把普通涨超 5% 的交易日成片误判);
|
|
67
67
|
- `adjust` 的 hfq 锚定上市日(历史行永不变,适合增量落盘),qfq 锚定最新(历史随分红改写,只适合展示);
|
|
68
68
|
- 1996-12-16 之前 A 股无涨跌停制度,`vec.flags_from_bars` 一律不判;
|
|
69
|
+
- `fees`(v0.3.0 勘误后口径):佣金法定上限 **3‰ 从未变过**(不存在「0.03% 封顶」政策,2002-05-01 前固定佣金时代拒答);过户费 **2015-08-01 前沪市按面值/深市按金额双轨**(沪 0.5‰→0.375‰→0.3‰ 按面值,深 0.0255‰ 按金额),之后统一按金额 0.02‰→0.01‰;印花税 A 股 1997-05-10 前拒答、B 股 2001-11-16 前拒答;B 股过户费/结算费体系未编码整体拒答;经手费/证管费通常**已含在佣金内**(helper 仅供净佣金分析,ETF/基金经手费未编码返回 None);
|
|
69
70
|
- `corporate_actions` 对 B 股(需当日汇率折算,属运行期数据非规则)与可转债(不除权)显式 raise 拒答,不猜;
|
|
70
71
|
- 新股「首 N 日不设涨跌幅」没有交易日序号时按自然日近似,`reason` 里如实标注「近似」。
|
|
71
72
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: data-backtest-live-common
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: 数据(Data)/回测(Backtest)/实盘(Live)三系统公共库:复权、A股交易规则全集(涨跌幅/时段/费用/交收/熔断/除权)、交易日历、原子写、无黑窗子进程
|
|
5
5
|
Author: dbl_common maintainers
|
|
6
6
|
License: MIT License
|
|
@@ -56,7 +56,7 @@ Dynamic: license-file
|
|
|
56
56
|
|
|
57
57
|
- **发行名(pip 名)**:`data-backtest-live-common` —— 数据/回测/实盘三个英文单词 + common(用户 2026-09-26 指定口径)
|
|
58
58
|
- **导入名**:`dbl_common` —— 三词首字母 + common(对齐 `beautifulsoup4 → import bs4` 的短名惯例,免得每次 import 敲 24 个字符)
|
|
59
|
-
- **版本**:0.
|
|
59
|
+
- **版本**:0.3.0 —— 2026-09-26 抽出独立成库 → 2026-09-27 并入 market_common 两库合一(0.2.0 上架 PyPI)→ 同日 **0.3.0 费用模块重大勘误**(逐条对照财政部/中登/交易所公告修正佣金封顶、过户费双轨制、印花税历史档)
|
|
60
60
|
|
|
61
61
|
## 收录标准(硬规则)
|
|
62
62
|
|
|
@@ -77,7 +77,7 @@ Dynamic: license-file
|
|
|
77
77
|
| `trading_hours` | 交易时段(集合竞价/连续竞价/收盘集合竞价,`Phase` 枚举) | 实盘下单时段校验;回测撮合时点 |
|
|
78
78
|
| `settlement` | 交收制度(T+1/T+0/T+3,`STOCK_T1_START`) | 实盘可卖判断;回测成交约束 |
|
|
79
79
|
| `lots` / `ticks` | 申报单位(手数)/ 最小变动价位(含 snap/校验) | 实盘委托合法性;回测撮合精度 |
|
|
80
|
-
| `fees` |
|
|
80
|
+
| `fees` | 交易费用(印花税 1997 起全时间线 / 过户费 2015 前沪面值深金额双轨 / 佣金法定上限 3‰ / 经手+证管规费,**v0.3.0 逐条对照官方公告勘误**) | 回测净收益;实盘成本预估 |
|
|
81
81
|
| `circuit_breaker` | 2016 熔断制度(历史触发记录) | 回测跨 2016-01 必须剔除熔断时段 |
|
|
82
82
|
| `halts` | 盘中临时停牌(新股/转债临停规则与复牌时间) | 回测撮合跳过临停;实盘委托拦截 |
|
|
83
83
|
| `corporate_actions` | 除权除息参考价官方公式 + 理论因子跳变 + 数据中心核验入口(容差 0.5%;B股/转债拒答) | 数据:dividend 对账;回测:复权核验 |
|
|
@@ -94,7 +94,7 @@ Dynamic: license-file
|
|
|
94
94
|
|
|
95
95
|
# ② 正式(打 wheel 安装)
|
|
96
96
|
python -m pip wheel . --no-deps -w dist
|
|
97
|
-
python -m pip install dist/data_backtest_live_common-0.
|
|
97
|
+
python -m pip install dist/data_backtest_live_common-0.3.0-py3-none-any.whl
|
|
98
98
|
|
|
99
99
|
# ③ 未来发布 PyPI 后(像 akshare 一样)
|
|
100
100
|
pip install data-backtest-live-common
|
|
@@ -117,6 +117,7 @@ $env:PYTHONPATH = "F:\code\finance\quant_data_center\vendor"
|
|
|
117
117
|
- `price_limit` 的 ST 判定只有当前名单、没有逐日历史 → 5% 档用「恰好贴板」精确判定(详见模块 docstring 的血泪教训:用 `≥` 会把普通涨超 5% 的交易日成片误判);
|
|
118
118
|
- `adjust` 的 hfq 锚定上市日(历史行永不变,适合增量落盘),qfq 锚定最新(历史随分红改写,只适合展示);
|
|
119
119
|
- 1996-12-16 之前 A 股无涨跌停制度,`vec.flags_from_bars` 一律不判;
|
|
120
|
+
- `fees`(v0.3.0 勘误后口径):佣金法定上限 **3‰ 从未变过**(不存在「0.03% 封顶」政策,2002-05-01 前固定佣金时代拒答);过户费 **2015-08-01 前沪市按面值/深市按金额双轨**(沪 0.5‰→0.375‰→0.3‰ 按面值,深 0.0255‰ 按金额),之后统一按金额 0.02‰→0.01‰;印花税 A 股 1997-05-10 前拒答、B 股 2001-11-16 前拒答;B 股过户费/结算费体系未编码整体拒答;经手费/证管费通常**已含在佣金内**(helper 仅供净佣金分析,ETF/基金经手费未编码返回 None);
|
|
120
121
|
- `corporate_actions` 对 B 股(需当日汇率折算,属运行期数据非规则)与可转债(不除权)显式 raise 拒答,不猜;
|
|
121
122
|
- 新股「首 N 日不设涨跌幅」没有交易日序号时按自然日近似,`reason` 里如实标注「近似」。
|
|
122
123
|
|
|
@@ -47,8 +47,9 @@ from .trading_hours import Phase, PHASE_LABEL, phase_at, is_auction, \
|
|
|
47
47
|
from .settlement import settle_rule, can_sell_today, STOCK_T1_START
|
|
48
48
|
from .lots import lot_rule, validate_qty
|
|
49
49
|
from .ticks import tick_size, snap_to_tick, is_valid_price
|
|
50
|
-
from .fees import FeeResult, calc_fees, stamp_tax,
|
|
51
|
-
commission_cap,
|
|
50
|
+
from .fees import FeeResult, TransferFeeRule, calc_fees, stamp_tax, \
|
|
51
|
+
transfer_fee_rate, transfer_fee_rule, commission_cap, handling_fee_rate, \
|
|
52
|
+
regulatory_fee_rate, stamp_tax_timeline
|
|
52
53
|
from .circuit_breaker import is_active as cb_is_active, market_state as cb_state, \
|
|
53
54
|
CB_START, CB_END, LEVEL1, LEVEL2, HISTORICAL_TRIGGERS
|
|
54
55
|
from .halts import HaltRule, intraday_halt_rule, resume_time, halt_price
|
|
@@ -58,7 +59,7 @@ from .trading_calendar import InjectedCalendar, from_baostock_csv, \
|
|
|
58
59
|
from .corporate_actions import CorporateAction, from_per_ten, \
|
|
59
60
|
ex_right_price, factor_jump, validate_against_factor, check_applicable
|
|
60
61
|
|
|
61
|
-
__version__ = "0.
|
|
62
|
+
__version__ = "0.3.0"
|
|
62
63
|
|
|
63
64
|
__all__ = [
|
|
64
65
|
# boards
|
|
@@ -75,9 +76,10 @@ __all__ = [
|
|
|
75
76
|
"settle_rule", "can_sell_today", "STOCK_T1_START",
|
|
76
77
|
# lots / ticks
|
|
77
78
|
"lot_rule", "validate_qty", "tick_size", "snap_to_tick", "is_valid_price",
|
|
78
|
-
# fees
|
|
79
|
-
"FeeResult", "calc_fees", "stamp_tax", "
|
|
80
|
-
"
|
|
79
|
+
# fees(v0.3.0 勘误:佣金上限 3‰ 从未变;过户费 2015 前沪面值/深金额双轨)
|
|
80
|
+
"FeeResult", "TransferFeeRule", "calc_fees", "stamp_tax", "stamp_tax_timeline",
|
|
81
|
+
"transfer_fee_rate", "transfer_fee_rule", "commission_cap",
|
|
82
|
+
"handling_fee_rate", "regulatory_fee_rate",
|
|
81
83
|
# circuit breaker
|
|
82
84
|
"cb_is_active", "cb_state", "CB_START", "CB_END", "LEVEL1", "LEVEL2",
|
|
83
85
|
"HISTORICAL_TRIGGERS",
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""fees.py — A 股交易费用:制度时间线 + 费用计算器(公共模块 · 纯函数)。
|
|
3
|
+
|
|
4
|
+
回测扣费与实盘对账必须同一套费率——各算各的会让「回测赚钱、实盘亏钱」
|
|
5
|
+
的缺口无法解释。本模块把**随政策变化的费率**做成时间线(date → rate),
|
|
6
|
+
把**随券商变化的佣金**做成显式参数(不藏在默认值里)。
|
|
7
|
+
|
|
8
|
+
⚠️ 2026-09-27 v0.3.0 重大勘误(逐条对照官方公告核验后修正,旧版口径作废):
|
|
9
|
+
① 佣金封顶**从来都是 3‰**(2002-05-01 浮动佣金制改革起,证监会/税务总局
|
|
10
|
+
通知原文),旧版「2015-08-01 起降至 0.03%」是**错误政策**(把市场常见的
|
|
11
|
+
万 3 费率误当成法定封顶)——旧版会错杀万 3 以上的合法历史佣金;
|
|
12
|
+
② 过户费 2015-08-01 之前是**沪市按成交面值 / 深市按成交金额的双轨制**
|
|
13
|
+
(中登 2015-07 通知原文:沪市按面值 0.3‰、深市按金额 0.0255‰,统一改
|
|
14
|
+
按金额 0.02‰),旧版对 2015 前一律按金额 0.002% 是**错的**;
|
|
15
|
+
③ 印花税时间线补齐 1997-05-10 起(0.5%)与 1998-06-12 起(0.4%)两档。
|
|
16
|
+
|
|
17
|
+
══════════════════════════════════════════════════════════════════════
|
|
18
|
+
制度时间线(逐条对照:财政部/税务总局公告、中登通知、沪深交易所通知、
|
|
19
|
+
发改委财政部监管费标准通知;每条都可在政府网站查到原文)
|
|
20
|
+
══════════════════════════════════════════════════════════════════════
|
|
21
|
+
|
|
22
|
+
一、印花税(财政部;对卖方征收——2008-09-19 起单边):
|
|
23
|
+
· 1997-05-10 起 0.5%(双边);1998-06-12 起 0.4%(双边);
|
|
24
|
+
· 2001-11-16 起 0.2%(双边,A/B 股同步);2005-01-24 起 0.1%(双边);
|
|
25
|
+
· 2007-05-30 起 0.3%(双边,"5·30");2008-04-24 起 0.1%(双边);
|
|
26
|
+
· 2008-09-19 起**改单边**(仅卖出)0.1%;2023-08-28 起 0.05%(卖出)。
|
|
27
|
+
· 1997-05-10 之前:沪深两市开征时间不同、双边/单边口径反复(1990-11 深市
|
|
28
|
+
双边 0.6%、1991-10 沪市开征 0.3% 等)→ **拒答**(返回 None,查公告再说)。
|
|
29
|
+
· B 股:2001-11-16 起与 A 股同步;之前与 A 股分叉(如 1999-06-01 B 股
|
|
30
|
+
单独由 0.4% 降至 0.3%)→ 之前拒答。
|
|
31
|
+
· 免征:基金(ETF/LOF)份额交易、债券(含可转债)、回购。
|
|
32
|
+
|
|
33
|
+
二、过户费(中国结算;双向收取,仅股票类):
|
|
34
|
+
· 2015-08-01 起:沪深统一按**成交金额** 0.02‰ 双向
|
|
35
|
+
(2022-04-29 起减半为 0.01‰ 双向;北京市场原 0.025‰ 同步降至 0.01‰);
|
|
36
|
+
· 2015-08-01 之前(双轨制,中登 2015-07 调整通知原文确认旧口径):
|
|
37
|
+
沪市:按**成交面值**——2012-09-01 起 0.3‰;2012-06-01 起 0.375‰;
|
|
38
|
+
更早 0.5‰(中置信,百度百科口径,精确日期以中登公告为准);
|
|
39
|
+
深市:按**成交金额** 0.0255‰ 双向(起始日不详,如实标注)。
|
|
40
|
+
· 面值默认 1 元/股(A 股绝大多数量级;优先股等特殊面值请传参)。
|
|
41
|
+
· B 股:过户费/结算费体系与 A 股不同且未编码 → **拒答**(不编数)。
|
|
42
|
+
· 基金、债券、回购:不收。
|
|
43
|
+
|
|
44
|
+
三、佣金(券商收,双向):
|
|
45
|
+
· 2002-05-01 起:最高上限向下浮动制——上限 3‰,下限为代收的证券交易
|
|
46
|
+
监管费和证券交易所手续费等(规费);A 股/基金每笔最低 5 元、
|
|
47
|
+
**B 股每笔最低 1 美元**(深 1 港元,税务总局通知原文);
|
|
48
|
+
· 2002-05-01 之前:固定佣金时代(约 3.5‰)→ **拒答**;
|
|
49
|
+
· 本模块不设「默认佣金」——调用方必须显式传:模拟盘/实盘按实际开户
|
|
50
|
+
费率,回测建议做敏感性区间(万1 / 万2.5 / 万3)。
|
|
51
|
+
|
|
52
|
+
四、规费(通常**已含在佣金内**,券商代收代缴——投资者总成本 = 佣金
|
|
53
|
+
(含规费)+ 印花税 + 过户费;下列 helper 供「券商净佣金/全佣金」分析):
|
|
54
|
+
· 经手费(交易所收,双向)——沪深 A/B 股:
|
|
55
|
+
2012-06-01 起 0.0696‰(2012 年下调后口径;更早深市 0.122‰ 未细分);
|
|
56
|
+
2015-08-01 起 0.0487‰(其中 0.00974‰ 转投资者保护基金);
|
|
57
|
+
2023-08-28 起 0.0341‰(降 30%,沪深交易所通知)。
|
|
58
|
+
北交所:2021-11-15 起 0.5‰;2022-12-01 起 0.25‰;2023-08-28 起 0.125‰。
|
|
59
|
+
· 证管费(证监会收,交易所代收,双向)——A/B 股 0.02‰
|
|
60
|
+
(发改委/财政部通知口径,长期未变)。
|
|
61
|
+
· ETF/基金/债券的经手费费率与股票不同(含阶段性减免)→ 未编码返回 None,
|
|
62
|
+
请查交易所现行通知后用 extra_rate 显式传。
|
|
63
|
+
"""
|
|
64
|
+
from __future__ import annotations
|
|
65
|
+
|
|
66
|
+
from dataclasses import dataclass
|
|
67
|
+
from typing import Optional, Sequence, Tuple
|
|
68
|
+
|
|
69
|
+
from .boards import Board, SecurityType, board_of, normalize_code, security_type
|
|
70
|
+
|
|
71
|
+
# ── 印花税时间线((生效日, 边, 税率);边 'both'/'sell')──────────────────
|
|
72
|
+
# A 股口径(B 股 2001-11-16 起同步,之前拒答);1997-05-10 前拒答。
|
|
73
|
+
_STAMP_TAX_TIMELINE: Tuple[Tuple[str, str, float], ...] = (
|
|
74
|
+
("1997-05-10", "both", 0.005),
|
|
75
|
+
("1998-06-12", "both", 0.004),
|
|
76
|
+
("2001-11-16", "both", 0.002),
|
|
77
|
+
("2005-01-24", "both", 0.001),
|
|
78
|
+
("2007-05-30", "both", 0.003),
|
|
79
|
+
("2008-04-24", "both", 0.001),
|
|
80
|
+
("2008-09-19", "sell", 0.001),
|
|
81
|
+
("2023-08-28", "sell", 0.0005),
|
|
82
|
+
)
|
|
83
|
+
_STAMP_TAX_START = "1997-05-10" # A 股编码起点(此前拒答)
|
|
84
|
+
_STAMP_TAX_B_SHARE_START = "2001-11-16" # B 股与 A 股同步起点(此前分叉拒答)
|
|
85
|
+
|
|
86
|
+
# ── 过户费时间线(2015-08-01 起统一「成交金额」口径,双向)────────────────
|
|
87
|
+
_TRANSFER_FEE_AMOUNT_TIMELINE: Tuple[Tuple[str, float], ...] = (
|
|
88
|
+
("2015-08-01", 0.00002),
|
|
89
|
+
("2022-04-29", 0.00001),
|
|
90
|
+
)
|
|
91
|
+
# 2015-08-01 之前双轨制(沪市按面值 / 深市按金额;精确日期以中登公告为准)
|
|
92
|
+
_SH_FACE_TIER_2012_09 = 0.0003 # 沪市 2012-09-01 起按面值 0.3‰
|
|
93
|
+
_SH_FACE_TIER_2012_06 = 0.000375 # 沪市 2012-06-01 起按面值 0.375‰
|
|
94
|
+
_SH_FACE_TIER_EARLY = 0.0005 # 沪市更早按面值 0.5‰(中置信)
|
|
95
|
+
_SZ_AMOUNT_LEGACY = 0.0000255 # 深市按金额 0.0255‰(起始日不详)
|
|
96
|
+
_TRANSFER_DUAL_TRACK_START = "2015-08-01"
|
|
97
|
+
|
|
98
|
+
# ── 佣金封顶(2002-05-01 浮动佣金制;此前固定佣金时代拒答)─────────────────
|
|
99
|
+
_COMMISSION_CAP = 0.003 # 3‰(上限,从未变过——不存在"0.03%封顶"政策)
|
|
100
|
+
_COMMISSION_CAP_START = "2002-05-01"
|
|
101
|
+
_COMMISSION_MIN_DEFAULT = 5.0 # A 股/基金每笔最低(法定口径 5 元;B 股 1 美元/1 港元)
|
|
102
|
+
|
|
103
|
+
# ── 经手费(交易所,双向)────────────────────────────────────────────────
|
|
104
|
+
_HANDLING_FEE_TIMELINE: Tuple[Tuple[str, float], ...] = ( # 沪深 A/B 股
|
|
105
|
+
("2012-06-01", 0.0000696),
|
|
106
|
+
("2015-08-01", 0.0000487),
|
|
107
|
+
("2023-08-28", 0.0000341),
|
|
108
|
+
)
|
|
109
|
+
_HANDLING_FEE_BSE_TIMELINE: Tuple[Tuple[str, float], ...] = ( # 北交所
|
|
110
|
+
("2021-11-15", 0.0005),
|
|
111
|
+
("2022-12-01", 0.00025),
|
|
112
|
+
("2023-08-28", 0.000125),
|
|
113
|
+
)
|
|
114
|
+
_REGULATORY_FEE_RATE = 0.02 / 1000 # 证管费 0.02‰ 双向(A/B 股,发改委口径)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _norm_date(date: Optional[str]) -> str:
|
|
118
|
+
return str(date)[:10] if date else "9999-12-31"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def stamp_tax(date: Optional[str], *,
|
|
122
|
+
b_share: bool = False) -> Optional[Tuple[str, float]]:
|
|
123
|
+
"""某日的印花税档位 → (征收边, 税率)。
|
|
124
|
+
|
|
125
|
+
A 股 1997-05-10 前返回 None(拒答,不猜);
|
|
126
|
+
B 股 2001-11-16 前返回 None(此前与 A 股税率分叉)。
|
|
127
|
+
date=None 按现行(单边卖出 0.05%)。
|
|
128
|
+
"""
|
|
129
|
+
d = _norm_date(date)
|
|
130
|
+
floor = _STAMP_TAX_B_SHARE_START if b_share else _STAMP_TAX_START
|
|
131
|
+
if d < floor:
|
|
132
|
+
return None
|
|
133
|
+
cur: Optional[Tuple[str, float]] = None
|
|
134
|
+
for start, side, rate in _STAMP_TAX_TIMELINE:
|
|
135
|
+
if d >= start:
|
|
136
|
+
cur = (side, rate)
|
|
137
|
+
return cur
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@dataclass(frozen=True)
|
|
141
|
+
class TransferFeeRule:
|
|
142
|
+
"""过户费规则(值对象):mode 决定计费基数。
|
|
143
|
+
|
|
144
|
+
mode='face' → 费用 = 数量 × 面值 × rate(沪市 2015-08-01 前)
|
|
145
|
+
mode='amount' → 费用 = 成交金额 × rate(2015-08-01 起统一)
|
|
146
|
+
note 带口径出处与置信度标注。
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
mode: str # 'face' / 'amount'
|
|
150
|
+
rate: float
|
|
151
|
+
note: str = ""
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def transfer_fee_rule(code: str, date: Optional[str]) -> TransferFeeRule:
|
|
155
|
+
"""某代码某日的过户费规则(**仅 A 股**;B 股 raise 拒答,基金/转债不适用)。
|
|
156
|
+
|
|
157
|
+
2015-08-01 前沪深双轨(沪按面值、深按金额);之后统一按金额。
|
|
158
|
+
"""
|
|
159
|
+
d = _norm_date(date)
|
|
160
|
+
if d >= _TRANSFER_DUAL_TRACK_START:
|
|
161
|
+
rate = _TRANSFER_FEE_AMOUNT_TIMELINE[0][1]
|
|
162
|
+
for start, r in _TRANSFER_FEE_AMOUNT_TIMELINE:
|
|
163
|
+
if d >= start:
|
|
164
|
+
rate = r
|
|
165
|
+
return TransferFeeRule("amount", rate,
|
|
166
|
+
"沪深统一按成交金额双向(中登口径)")
|
|
167
|
+
# ── 2015-08-01 之前:双轨制 ──
|
|
168
|
+
c = normalize_code(code)
|
|
169
|
+
if c[:2] in ("00", "30"):
|
|
170
|
+
# 深市主板/创业板:按成交金额 0.0255‰(起始日不详,如实标注)
|
|
171
|
+
return TransferFeeRule("amount", _SZ_AMOUNT_LEGACY,
|
|
172
|
+
"深市 2015-08-01 前按成交金额 0.0255‰ 双向"
|
|
173
|
+
"(中登 2015-07 通知确认的旧口径;起始日不详)")
|
|
174
|
+
if c[:2] in ("60", "68"):
|
|
175
|
+
if d >= "2012-09-01":
|
|
176
|
+
r, note = _SH_FACE_TIER_2012_09, "沪市 2012-09-01 起按成交面值 0.3‰"
|
|
177
|
+
elif d >= "2012-06-01":
|
|
178
|
+
r, note = _SH_FACE_TIER_2012_06, "沪市 2012-06-01 起按成交面值 0.375‰"
|
|
179
|
+
else:
|
|
180
|
+
r, note = _SH_FACE_TIER_EARLY, "沪市按成交面值 0.5‰(中置信口径," \
|
|
181
|
+
"精确档位以中登公告为准)"
|
|
182
|
+
return TransferFeeRule("face", r, note + " 双向")
|
|
183
|
+
# 北交所(2021-11-15 开市前为新三板,制度不同)与其他:无可靠口径 → 拒答
|
|
184
|
+
raise ValueError(
|
|
185
|
+
f"{code} 在 {d}(2015-08-01 之前)的过户费口径未编码:北交所/新三板"
|
|
186
|
+
"早期制度不同,沪市口径亦随年代变化,请查中国结算公告后显式计算(不猜)")
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def transfer_fee_rate(date: Optional[str]) -> float:
|
|
190
|
+
"""某日**统一口径**(2015-08-01 起沪深按成交金额)的过户费双边费率。
|
|
191
|
+
|
|
192
|
+
⚠️ 2015-08-01 之前是沪面值/深金额双轨制,本函数无法表达 → raise,
|
|
193
|
+
请改用 `transfer_fee_rule(code, date)`(v0.3.0 勘误,旧版此处返回错误口径)。
|
|
194
|
+
"""
|
|
195
|
+
d = _norm_date(date)
|
|
196
|
+
if d < _TRANSFER_DUAL_TRACK_START:
|
|
197
|
+
raise ValueError(
|
|
198
|
+
f"{d} 早于 2015-08-01:过户费为沪市按面值/深市按金额双轨制,"
|
|
199
|
+
"请用 transfer_fee_rule(code, date) 按代码判定(v0.3.0 勘误)")
|
|
200
|
+
rate = _TRANSFER_FEE_AMOUNT_TIMELINE[0][1]
|
|
201
|
+
for start, r in _TRANSFER_FEE_AMOUNT_TIMELINE:
|
|
202
|
+
if d >= start:
|
|
203
|
+
rate = r
|
|
204
|
+
return rate
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def commission_cap(date: Optional[str]) -> float:
|
|
208
|
+
"""佣金法定上限(3‰,2002-05-01 浮动佣金制起从未变过)。
|
|
209
|
+
|
|
210
|
+
2002-05-01 前为固定佣金时代(约 3.5‰)→ raise 拒答。
|
|
211
|
+
⚠️ 不存在「0.03% 封顶」政策(那是市场常见万 3 费率的误传,v0.3.0 勘误)。
|
|
212
|
+
"""
|
|
213
|
+
d = _norm_date(date)
|
|
214
|
+
if d < _COMMISSION_CAP_START:
|
|
215
|
+
raise ValueError(
|
|
216
|
+
f"{d} 早于 2002-05-01:固定佣金时代(约 3.5‰),"
|
|
217
|
+
"请查券商协议/历史公告后显式传费率(不猜)")
|
|
218
|
+
return _COMMISSION_CAP
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def handling_fee_rate(code: str, date: Optional[str]) -> Optional[float]:
|
|
222
|
+
"""经手费率(交易所收,双向;通常已含在佣金内——供净佣金分析)。
|
|
223
|
+
|
|
224
|
+
沪深 A/B 股:2012-06-01 起 0.0696‰ → 2015-08-01 起 0.0487‰ →
|
|
225
|
+
2023-08-28 起 0.0341‰;北交所:2021-11-15 起 0.5‰ → 2022-12-01 起
|
|
226
|
+
0.25‰ → 2023-08-28 起 0.125‰。
|
|
227
|
+
ETF/基金/债券费率不同且含阶段性减免 → 返回 None(未编码,不猜)。
|
|
228
|
+
"""
|
|
229
|
+
d = _norm_date(date)
|
|
230
|
+
st = security_type(code)
|
|
231
|
+
if st not in (SecurityType.STOCK, SecurityType.B_SHARE):
|
|
232
|
+
return None
|
|
233
|
+
board = board_of(code)
|
|
234
|
+
timeline = _HANDLING_FEE_BSE_TIMELINE if board == Board.BSE \
|
|
235
|
+
else _HANDLING_FEE_TIMELINE
|
|
236
|
+
cur: Optional[float] = None
|
|
237
|
+
for start, r in timeline:
|
|
238
|
+
if d >= start:
|
|
239
|
+
cur = r
|
|
240
|
+
return cur
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def regulatory_fee_rate(code: str, date: Optional[str]) -> Optional[float]:
|
|
244
|
+
"""证管费率(证监会收、交易所代收,双向;通常已含在佣金内)。
|
|
245
|
+
|
|
246
|
+
A/B 股 0.02‰(发改委/财政部通知口径,长期未变);其他品种 None。
|
|
247
|
+
"""
|
|
248
|
+
st = security_type(code)
|
|
249
|
+
if st not in (SecurityType.STOCK, SecurityType.B_SHARE):
|
|
250
|
+
return None
|
|
251
|
+
return _REGULATORY_FEE_RATE
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
@dataclass(frozen=True)
|
|
255
|
+
class FeeResult:
|
|
256
|
+
"""一笔成交的费用明细(金额单位:元;逐项拆开以便对账)。"""
|
|
257
|
+
|
|
258
|
+
amount: float # 成交金额(股数 × 价格)
|
|
259
|
+
commission: float # 佣金(双边各收一次——调用方按 buy/sell 各算一笔)
|
|
260
|
+
stamp_tax: float # 印花税(只对征收边非零)
|
|
261
|
+
transfer_fee: float # 过户费(2015-08-01 前沪市按面值=数量×面值×率)
|
|
262
|
+
extra_fee: float # 经手费/证管费等(调用方显式传比率才有)
|
|
263
|
+
total: float
|
|
264
|
+
breakdown: str # 人读得懂的分项(进留痕,不许只给总数)
|
|
265
|
+
|
|
266
|
+
@property
|
|
267
|
+
def total_rate(self) -> float:
|
|
268
|
+
return self.total / self.amount if self.amount else 0.0
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def calc_fees(code: str, qty: float, price: float, side: str, *,
|
|
272
|
+
date: Optional[str] = None,
|
|
273
|
+
commission_rate: Optional[float] = None,
|
|
274
|
+
commission_min: float = _COMMISSION_MIN_DEFAULT,
|
|
275
|
+
extra_rate: float = 0.0,
|
|
276
|
+
stype: Optional[SecurityType] = None,
|
|
277
|
+
face_value: float = 1.0) -> FeeResult:
|
|
278
|
+
"""计算一笔竞价成交的费用(投资者口径:佣金含规费 + 印花税 + 过户费)。
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
qty/price: 成交数量与单价(数量单位随品种:股/份/张)。
|
|
282
|
+
side: 'buy' / 'sell'。
|
|
283
|
+
date: 成交日(费率时间线判定;None = 现行)。
|
|
284
|
+
commission_rate: 佣金率(**必传**,如 0.00025=万2.5;None 抛错——
|
|
285
|
+
不设默认是故意的:回测/实盘费率不同,藏默认值就是埋雷。
|
|
286
|
+
上限 3‰,超上限抛错——回测里「夸张佣金」多半是单位写错)。
|
|
287
|
+
commission_min: 每笔最低佣金(A 股法定口径 5 元;B 股为 1 美元/1 港元,
|
|
288
|
+
以券商协议为准——调用方换算成人民币传参)。
|
|
289
|
+
extra_rate: 附加费率合计(不确定就传 0 并披露;经手/证管规费通常
|
|
290
|
+
已含在佣金里,不要在这里重复计——见 handling_fee_rate 的说明)。
|
|
291
|
+
stype: 品种显式覆盖(None = 前缀推断)。
|
|
292
|
+
face_value: 每股面值(默认 1 元——过户费 2015-08-01 前沪市按面值计)。
|
|
293
|
+
|
|
294
|
+
Returns:
|
|
295
|
+
FeeResult(逐项 + 总额 + 可读明细)。
|
|
296
|
+
"""
|
|
297
|
+
if commission_rate is None:
|
|
298
|
+
raise ValueError("commission_rate 必须显式传(万2.5 → 0.00025);"
|
|
299
|
+
"不设默认是防止回测/实盘费率混用")
|
|
300
|
+
cap = commission_cap(date) # 2002-05-01 前固定佣金时代在此 raise
|
|
301
|
+
if commission_rate > cap:
|
|
302
|
+
raise ValueError(f"佣金率 {commission_rate} 超过法定上限 {cap}(3‰,"
|
|
303
|
+
"2002-05-01 起从未变过——若你以为上限是万3,那是把"
|
|
304
|
+
"市场常见费率误当成了政策)")
|
|
305
|
+
st = security_type(code, stype)
|
|
306
|
+
amount = float(qty) * float(price)
|
|
307
|
+
if amount <= 0:
|
|
308
|
+
raise ValueError(f"成交金额必须为正(qty={qty}, price={price})")
|
|
309
|
+
|
|
310
|
+
commission = max(amount * commission_rate, commission_min)
|
|
311
|
+
|
|
312
|
+
# ── 印花税:股票/B 股收;基金/债券/回购免 ──
|
|
313
|
+
stamp = 0.0
|
|
314
|
+
if st in (SecurityType.STOCK, SecurityType.B_SHARE):
|
|
315
|
+
tier = stamp_tax(date, b_share=(st == SecurityType.B_SHARE))
|
|
316
|
+
if tier is None:
|
|
317
|
+
floor = _STAMP_TAX_B_SHARE_START if st == SecurityType.B_SHARE \
|
|
318
|
+
else _STAMP_TAX_START
|
|
319
|
+
raise ValueError(
|
|
320
|
+
f"{date} 早于 {floor}:印花税历史档位未编码"
|
|
321
|
+
"(此前沪深不同步/AB 股分叉),请查财政部公告后显式计算(不猜)")
|
|
322
|
+
tside, rate = tier
|
|
323
|
+
if (tside == "both") or (tside == "sell" and side == "sell"):
|
|
324
|
+
stamp = amount * rate
|
|
325
|
+
|
|
326
|
+
# ── 过户费:仅 A 股股票(B 股体系未编码拒答;基金/转债不收)──
|
|
327
|
+
transfer = 0.0
|
|
328
|
+
transfer_note = ""
|
|
329
|
+
if st == SecurityType.STOCK:
|
|
330
|
+
rule = transfer_fee_rule(code, date)
|
|
331
|
+
if rule.mode == "face":
|
|
332
|
+
transfer = float(qty) * float(face_value) * rule.rate
|
|
333
|
+
transfer_note = f"(按面值{face_value:g}元×{rule.rate:.5f})"
|
|
334
|
+
else:
|
|
335
|
+
transfer = amount * rule.rate
|
|
336
|
+
elif st == SecurityType.B_SHARE:
|
|
337
|
+
raise ValueError("B 股过户费/结算费体系与 A 股不同且未编码——"
|
|
338
|
+
"请查中国结算公告后显式计算(不猜;印花税部分本模块"
|
|
339
|
+
"2001-11-16 起可算,过户费整体拒答)")
|
|
340
|
+
extra = amount * extra_rate
|
|
341
|
+
|
|
342
|
+
total = commission + stamp + transfer + extra
|
|
343
|
+
parts = [f"佣金 {commission:.2f}(率{commission_rate:.5f},最低{commission_min:.0f})"]
|
|
344
|
+
if stamp:
|
|
345
|
+
parts.append(f"印花税 {stamp:.2f}({side}边)")
|
|
346
|
+
if transfer:
|
|
347
|
+
parts.append(f"过户费 {transfer:.2f}{transfer_note}")
|
|
348
|
+
if extra:
|
|
349
|
+
parts.append(f"附加 {extra:.2f}(率{extra_rate:.5f})")
|
|
350
|
+
return FeeResult(amount=amount, commission=commission, stamp_tax=stamp,
|
|
351
|
+
transfer_fee=transfer, extra_fee=extra, total=total,
|
|
352
|
+
breakdown=";".join(parts))
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
def stamp_tax_timeline() -> Sequence[Tuple[str, str, float]]:
|
|
356
|
+
"""公开印花税时间线(给报告/前端渲染,不许调用方各抄一份)。"""
|
|
357
|
+
return _STAMP_TAX_TIMELINE
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
__all__ = ["FeeResult", "calc_fees", "stamp_tax", "stamp_tax_timeline",
|
|
361
|
+
"TransferFeeRule", "transfer_fee_rule", "transfer_fee_rate",
|
|
362
|
+
"commission_cap", "handling_fee_rate", "regulatory_fee_rate"]
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "data-backtest-live-common"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "数据(Data)/回测(Backtest)/实盘(Live)三系统公共库:复权、A股交易规则全集(涨跌幅/时段/费用/交收/熔断/除权)、交易日历、原子写、无黑窗子进程"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
{data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/tests/test_trading_rules.py
RENAMED
|
@@ -260,20 +260,74 @@ def test_tick_sizes():
|
|
|
260
260
|
|
|
261
261
|
|
|
262
262
|
# ═══════════════════════════════════════════════════════════════════════
|
|
263
|
-
# fees:政策时间线 +
|
|
263
|
+
# fees:政策时间线 + 计算器(v0.3.0 勘误后锚点,逐条对照官方公告)
|
|
264
264
|
# ═══════════════════════════════════════════════════════════════════════
|
|
265
265
|
def test_stamp_tax_timeline():
|
|
266
266
|
assert stamp_tax("2023-08-28") == ("sell", 0.0005) # 减半日(关键锚点)
|
|
267
267
|
assert stamp_tax("2023-08-27") == ("sell", 0.001)
|
|
268
268
|
assert stamp_tax("2008-09-19") == ("sell", 0.001) # 改单边日
|
|
269
269
|
assert stamp_tax("2008-09-18") == ("both", 0.001)
|
|
270
|
-
assert stamp_tax("2007-06-01") == ("both", 0.003) # 上调至 3‰
|
|
271
|
-
assert stamp_tax("2001-11-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
270
|
+
assert stamp_tax("2007-06-01") == ("both", 0.003) # "5·30" 上调至 3‰
|
|
271
|
+
assert stamp_tax("2001-11-16") == ("both", 0.002) # 4‰→2‰
|
|
272
|
+
assert stamp_tax("2001-11-15") == ("both", 0.004) # v0.3.0 补的档
|
|
273
|
+
assert stamp_tax("1998-06-12") == ("both", 0.004) # 5‰→4‰
|
|
274
|
+
assert stamp_tax("1998-06-11") == ("both", 0.005) # v0.3.0 补的档
|
|
275
|
+
assert stamp_tax("1997-05-10") == ("both", 0.005) # 3‰→5‰
|
|
276
|
+
assert stamp_tax("1997-05-09") is None # 拒答区间(沪深不同步)
|
|
277
|
+
assert stamp_tax("1990-06-30", b_share=True) is None # B 股 2001-11-16 前分叉拒答
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def test_transfer_fee_rule_dual_track():
|
|
281
|
+
"""2015-08-01 前双轨:沪按面值、深按金额(中登 2015-07 通知原文口径)。"""
|
|
282
|
+
from dbl_common import TransferFeeRule, transfer_fee_rule
|
|
283
|
+
# 沪市 2014:按面值 0.3‰(2012-09-01 档)
|
|
284
|
+
r = transfer_fee_rule("600519", "2014-06-03")
|
|
285
|
+
assert (r.mode, r.rate) == ("face", 0.0003)
|
|
286
|
+
# 沪市 2012-07:0.375‰ 档
|
|
287
|
+
assert transfer_fee_rule("600519", "2012-07-02").rate == 0.000375
|
|
288
|
+
# 沪市 2011:0.5‰ 档(中置信)
|
|
289
|
+
assert transfer_fee_rule("600519", "2011-06-01").rate == 0.0005
|
|
290
|
+
# 深市 2014:按金额 0.0255‰
|
|
291
|
+
r = transfer_fee_rule("000001", "2014-06-03")
|
|
292
|
+
assert (r.mode, r.rate) == ("amount", 0.0000255)
|
|
293
|
+
# 2015-08-01 起沪深统一按金额 0.02‰ → 2022-04-29 减半 0.01‰
|
|
294
|
+
r = transfer_fee_rule("600519", "2015-08-01")
|
|
295
|
+
assert (r.mode, r.rate) == ("amount", 0.00002)
|
|
296
|
+
assert transfer_fee_rule("000001", "2022-04-29").rate == 0.00001
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def test_transfer_fee_rate_unified():
|
|
275
300
|
assert transfer_fee_rate("2022-04-28") == 0.00002
|
|
276
301
|
assert transfer_fee_rate("2022-04-29") == 0.00001 # 下调 50%
|
|
302
|
+
with pytest.raises(ValueError): # 2015 前双轨制 → 拒答(v0.3.0 勘误)
|
|
303
|
+
transfer_fee_rate("2014-06-03")
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def test_commission_cap_never_below_3pct():
|
|
307
|
+
"""佣金法定上限 3‰ 自 2002-05-01 起从未变过(不存在 0.03% 封顶政策)。"""
|
|
308
|
+
from dbl_common import commission_cap
|
|
309
|
+
assert commission_cap("2024-06-03") == 0.003
|
|
310
|
+
assert commission_cap("2002-05-01") == 0.003
|
|
311
|
+
with pytest.raises(ValueError): # 固定佣金时代拒答
|
|
312
|
+
commission_cap("2001-12-31")
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def test_handling_and_regulatory_fee():
|
|
316
|
+
"""规费(通常含在佣金内,供净佣金分析):经手费三档 + 证管费 0.02‰。"""
|
|
317
|
+
from dbl_common import handling_fee_rate, regulatory_fee_rate
|
|
318
|
+
# 沪深 A 股经手费:0.0696‰ → 0.0487‰(2015-08-01)→ 0.0341‰(2023-08-28)
|
|
319
|
+
assert handling_fee_rate("600519", "2014-06-03") == 0.0000696
|
|
320
|
+
assert handling_fee_rate("600519", "2015-08-01") == 0.0000487
|
|
321
|
+
assert handling_fee_rate("600519", "2023-08-28") == 0.0000341
|
|
322
|
+
# 北交所:0.5‰ → 0.25‰(2022-12)→ 0.125‰(2023-08-28)
|
|
323
|
+
assert handling_fee_rate("920002", "2022-01-04") == 0.0005
|
|
324
|
+
assert handling_fee_rate("920002", "2022-12-01") == 0.00025
|
|
325
|
+
assert handling_fee_rate("920002", "2023-08-28") == 0.000125
|
|
326
|
+
# ETF 经手费未编码 → None(不猜)
|
|
327
|
+
assert handling_fee_rate("510300", "2024-06-03") is None
|
|
328
|
+
# 证管费 A/B 股 0.02‰ 双向;ETF None
|
|
329
|
+
assert regulatory_fee_rate("600519", "2024-06-03") == 0.00002
|
|
330
|
+
assert regulatory_fee_rate("510300", "2024-06-03") is None
|
|
277
331
|
|
|
278
332
|
|
|
279
333
|
def test_calc_fees_sell_stock_2024():
|
|
@@ -287,6 +341,22 @@ def test_calc_fees_sell_stock_2024():
|
|
|
287
341
|
assert r.total == pytest.approx(76.0)
|
|
288
342
|
|
|
289
343
|
|
|
344
|
+
def test_calc_fees_sh_2014_face_value_transfer():
|
|
345
|
+
"""v0.3.0 勘误核心用例:2014 沪市过户费按面值 0.3‰ = 数量 × 1 × 0.0003。
|
|
346
|
+
|
|
347
|
+
卖 10000 股 × 10 元(2014-06-03):印花税双边 0.1% = 100 元;
|
|
348
|
+
过户费 = 10000 × 1 × 0.0003 = 3 元(旧版错误地按金额 0.002% 算 2 元)。
|
|
349
|
+
"""
|
|
350
|
+
r = calc_fees("600519", 10000, 10.0, "sell",
|
|
351
|
+
date="2014-06-03", commission_rate=0.00025)
|
|
352
|
+
assert r.stamp_tax == pytest.approx(100.0) # 2014 双边 0.1%(买卖都收)
|
|
353
|
+
assert r.transfer_fee == pytest.approx(3.0) # 按面值,不按金额
|
|
354
|
+
# 同日深市:按金额 0.0255‰ = 100000 × 0.0000255 = 2.55 元
|
|
355
|
+
r2 = calc_fees("000001", 10000, 10.0, "sell",
|
|
356
|
+
date="2014-06-03", commission_rate=0.00025)
|
|
357
|
+
assert r2.transfer_fee == pytest.approx(2.55)
|
|
358
|
+
|
|
359
|
+
|
|
290
360
|
def test_calc_fees_buy_no_stamp():
|
|
291
361
|
r = calc_fees("600519", 10000, 10.0, "buy",
|
|
292
362
|
date="2024-06-03", commission_rate=0.00025)
|
|
@@ -312,11 +382,23 @@ def test_calc_fees_etf_exempt():
|
|
|
312
382
|
def test_calc_fees_guards():
|
|
313
383
|
with pytest.raises(ValueError): # 佣金必须显式传
|
|
314
384
|
calc_fees("600519", 100, 10.0, "buy", commission_rate=None)
|
|
315
|
-
with pytest.raises(ValueError): #
|
|
316
|
-
calc_fees("600519", 100, 10.0, "buy", commission_rate=0.
|
|
317
|
-
with pytest.raises(ValueError): #
|
|
385
|
+
with pytest.raises(ValueError): # 超法定上限 3‰(万5 合法,5‰ 不合法)
|
|
386
|
+
calc_fees("600519", 100, 10.0, "buy", commission_rate=0.005)
|
|
387
|
+
with pytest.raises(ValueError): # 1997 前印花税未编码 → 拒答
|
|
318
388
|
calc_fees("600519", 100, 10.0, "sell",
|
|
319
|
-
date="
|
|
389
|
+
date="1996-12-31", commission_rate=0.00025)
|
|
390
|
+
with pytest.raises(ValueError): # 2002 前固定佣金时代 → 拒答
|
|
391
|
+
calc_fees("600519", 100, 10.0, "buy",
|
|
392
|
+
date="2001-12-31", commission_rate=0.0035)
|
|
393
|
+
with pytest.raises(ValueError): # B 股过户费体系未编码 → 拒答
|
|
394
|
+
calc_fees("900901", 100, 1.0, "buy", commission_rate=0.00025)
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
def test_calc_fees_high_commission_legal():
|
|
398
|
+
"""万 5 / 千 1 历史佣金合法(v0.3.0 勘误:旧版会错杀为「超封顶」)。"""
|
|
399
|
+
r = calc_fees("600519", 10000, 10.0, "buy",
|
|
400
|
+
date="2010-06-03", commission_rate=0.001) # 千1
|
|
401
|
+
assert r.commission == pytest.approx(100.0)
|
|
320
402
|
|
|
321
403
|
|
|
322
404
|
# ═══════════════════════════════════════════════════════════════════════
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
"""fees.py — A 股交易费用:制度时间线 + 费用计算器(公共模块 · 纯函数)。
|
|
3
|
-
|
|
4
|
-
回测扣费与实盘对账必须同一套费率——各算各的会让「回测赚钱、实盘亏钱」
|
|
5
|
-
的缺口无法解释。本模块把**随政策变化的费率**做成时间线(date → rate),
|
|
6
|
-
把**随券商变化的佣金**做成显式参数(不藏在默认值里)。
|
|
7
|
-
|
|
8
|
-
制度时间线(财政部/中登/交易所公告,锚点事件为高置信度)
|
|
9
|
-
--------------------------------------------------------
|
|
10
|
-
印花税(对卖方征收的证券交易印花税):
|
|
11
|
-
· 2001-11-16 起 0.2%(双边改单边? — 此前多次调整,**2001 年前历史请查公告**,
|
|
12
|
-
本模块 2001-11-16 之前的查询返回 None 拒答);
|
|
13
|
-
· 2005-01-24 起 0.1%;2007-05-30 起 0.3%;2008-04-24 起 0.1%;
|
|
14
|
-
· 2008-09-19 起 改**单边**(仅卖出)0.1%;
|
|
15
|
-
· 2023-08-28 起 减半为**单边** 0.05%。
|
|
16
|
-
免征:ETF/LOF 基金份额交易、债券(含可转债)、回购。
|
|
17
|
-
|
|
18
|
-
过户费(中国结算,双边):
|
|
19
|
-
· 0.002% → **2022-04-29 起下调 50% 至 0.001%**(中登公告口径);
|
|
20
|
-
· 历史上仅沪市股票收取、深市 2015 年前后纳入(精确日以中登公告为准——
|
|
21
|
-
回测 2015 年前后成本差异 < 万分之二,影响可忽略但如实标注);
|
|
22
|
-
· 仅股票/B 股收;基金、转债不收。
|
|
23
|
-
|
|
24
|
-
佣金(券商):双边、成交金额的 0.03% 封顶(2015 年 8 月起沪深统一从
|
|
25
|
-
0.3% 降至 0.03%——**注意封顶值本身也是政策变量**)、每笔最低 5 元
|
|
26
|
-
(各券商可下浮)。本模块不设「默认佣金」——调用方必须显式传,
|
|
27
|
-
模拟盘/实盘按实际开户费率,回测建议做敏感性区间(万1/万2.5/万3)。
|
|
28
|
-
|
|
29
|
-
经手费/证管费/风险金:合计约万分之几、随交易所公告微调,本模块不硬编码
|
|
30
|
-
(计算器留 `extra_rate` 参数),避免拿不确定的数冒充确定。
|
|
31
|
-
"""
|
|
32
|
-
from __future__ import annotations
|
|
33
|
-
|
|
34
|
-
from dataclasses import dataclass
|
|
35
|
-
from typing import Optional, Sequence, Tuple
|
|
36
|
-
|
|
37
|
-
from .boards import SecurityType, security_type
|
|
38
|
-
|
|
39
|
-
# ── 印花税时间线((生效日, 边, 税率);边 'both'/'sell';None=拒答区间)────
|
|
40
|
-
_STAMP_TAX_TIMELINE: Tuple[Tuple[str, str, float], ...] = (
|
|
41
|
-
("2001-11-16", "both", 0.002),
|
|
42
|
-
("2005-01-24", "both", 0.001),
|
|
43
|
-
("2007-05-30", "both", 0.003),
|
|
44
|
-
("2008-04-24", "both", 0.001),
|
|
45
|
-
("2008-09-19", "sell", 0.001),
|
|
46
|
-
("2023-08-28", "sell", 0.0005),
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
# ── 过户费时间线(双边费率)────────────────────────────────────────────
|
|
50
|
-
_TRANSFER_FEE_TIMELINE: Tuple[Tuple[str, float], ...] = (
|
|
51
|
-
("1990-01-01", 0.00002),
|
|
52
|
-
("2022-04-29", 0.00001),
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
_COMMISSION_CAP = 0.0003 # 2015-08-01 起佣金封顶 0.03%(此前 0.3%)
|
|
56
|
-
_COMMISSION_CAP_EARLY = 0.003 # 2015-08-01 前
|
|
57
|
-
_COMMISSION_CAP_START = "2015-08-01"
|
|
58
|
-
_COMMISSION_MIN_DEFAULT = 5.0 # 每笔最低佣金(常见 5 元,以券商协议为准)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def stamp_tax(date: Optional[str]) -> Optional[Tuple[str, float]]:
|
|
62
|
-
"""某日的印花税档位 → (征收边, 税率);2001-11-16 前返回 None(拒答,不猜)。
|
|
63
|
-
|
|
64
|
-
date=None 按现行(单边卖出 0.05%)。
|
|
65
|
-
"""
|
|
66
|
-
d = str(date)[:10] if date else "9999-12-31"
|
|
67
|
-
cur: Optional[Tuple[str, float]] = None
|
|
68
|
-
for start, side, rate in _STAMP_TAX_TIMELINE:
|
|
69
|
-
if d >= start:
|
|
70
|
-
cur = (side, rate)
|
|
71
|
-
return cur
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def transfer_fee_rate(date: Optional[str]) -> float:
|
|
75
|
-
"""某日过户费双边费率(股票/B股适用;基金转债不收——见 calc_fees)。"""
|
|
76
|
-
d = str(date)[:10] if date else "9999-12-31"
|
|
77
|
-
rate = _TRANSFER_FEE_TIMELINE[0][1]
|
|
78
|
-
for start, r in _TRANSFER_FEE_TIMELINE:
|
|
79
|
-
if d >= start:
|
|
80
|
-
rate = r
|
|
81
|
-
return rate
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def commission_cap(date: Optional[str]) -> float:
|
|
85
|
-
"""佣金法定封顶(回测里给「夸张佣金」做合法性钳制用)。"""
|
|
86
|
-
d = str(date)[:10] if date else "9999-12-31"
|
|
87
|
-
return _COMMISSION_CAP if d >= _COMMISSION_CAP_START else _COMMISSION_CAP_EARLY
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
@dataclass(frozen=True)
|
|
91
|
-
class FeeResult:
|
|
92
|
-
"""一笔成交的费用明细(金额单位:元;逐项拆开以便对账)。"""
|
|
93
|
-
|
|
94
|
-
amount: float # 成交金额(股数 × 价格)
|
|
95
|
-
commission: float # 佣金(双边各收一次——调用方按 buy/sell 各算一笔)
|
|
96
|
-
stamp_tax: float # 印花税(只对征收边非零)
|
|
97
|
-
transfer_fee: float # 过户费
|
|
98
|
-
extra_fee: float # 经手费/证管费等(调用方显式传比率才有)
|
|
99
|
-
total: float
|
|
100
|
-
breakdown: str # 人读得懂的分项(进留痕,不许只给总数)
|
|
101
|
-
|
|
102
|
-
@property
|
|
103
|
-
def total_rate(self) -> float:
|
|
104
|
-
return self.total / self.amount if self.amount else 0.0
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def calc_fees(code: str, qty: float, price: float, side: str, *,
|
|
108
|
-
date: Optional[str] = None,
|
|
109
|
-
commission_rate: Optional[float] = None,
|
|
110
|
-
commission_min: float = _COMMISSION_MIN_DEFAULT,
|
|
111
|
-
extra_rate: float = 0.0,
|
|
112
|
-
stype: Optional[SecurityType] = None) -> FeeResult:
|
|
113
|
-
"""计算一笔竞价成交的费用。
|
|
114
|
-
|
|
115
|
-
Args:
|
|
116
|
-
qty/price: 成交数量与单价(数量单位随品种:股/份/张)。
|
|
117
|
-
side: 'buy' / 'sell'。
|
|
118
|
-
date: 成交日(费率时间线判定;None = 现行)。
|
|
119
|
-
commission_rate: 佣金率(**必传**,如 0.00025=万2.5;None 抛错——
|
|
120
|
-
不设默认是故意的:回测/实盘费率不同,藏默认值就是埋雷)。
|
|
121
|
-
extra_rate: 经手+证管+风险金等附加费率合计(不确定就传 0 并披露)。
|
|
122
|
-
|
|
123
|
-
Returns:
|
|
124
|
-
FeeResult(逐项 + 总额 + 可读明细)。
|
|
125
|
-
"""
|
|
126
|
-
if commission_rate is None:
|
|
127
|
-
raise ValueError("commission_rate 必须显式传(万2.5 → 0.00025);"
|
|
128
|
-
"不设默认是防止回测/实盘费率混用")
|
|
129
|
-
if commission_rate > commission_cap(date):
|
|
130
|
-
raise ValueError(f"佣金率 {commission_rate} 超过封顶 {commission_cap(date)}")
|
|
131
|
-
st = security_type(code, stype)
|
|
132
|
-
amount = float(qty) * float(price)
|
|
133
|
-
if amount <= 0:
|
|
134
|
-
raise ValueError(f"成交金额必须为正(qty={qty}, price={price})")
|
|
135
|
-
|
|
136
|
-
commission = max(amount * commission_rate, commission_min)
|
|
137
|
-
# 基金/债券/回购免印花税
|
|
138
|
-
stamp = 0.0
|
|
139
|
-
if st in (SecurityType.STOCK, SecurityType.B_SHARE):
|
|
140
|
-
tier = stamp_tax(date)
|
|
141
|
-
if tier is None:
|
|
142
|
-
raise ValueError(f"{date} 早于 2001-11-16:印花税历史档位未编码,"
|
|
143
|
-
"请查财政部公告后显式计算(不猜)")
|
|
144
|
-
tside, rate = tier
|
|
145
|
-
if (tside == "both") or (tside == "sell" and side == "sell"):
|
|
146
|
-
stamp = amount * rate
|
|
147
|
-
# 过户费:股票/B股双边
|
|
148
|
-
transfer = amount * transfer_fee_rate(date) \
|
|
149
|
-
if st in (SecurityType.STOCK, SecurityType.B_SHARE) else 0.0
|
|
150
|
-
extra = amount * extra_rate
|
|
151
|
-
|
|
152
|
-
total = commission + stamp + transfer + extra
|
|
153
|
-
parts = [f"佣金 {commission:.2f}(率{commission_rate:.5f},最低{commission_min:.0f})"]
|
|
154
|
-
if stamp:
|
|
155
|
-
parts.append(f"印花税 {stamp:.2f}({side}边)")
|
|
156
|
-
if transfer:
|
|
157
|
-
parts.append(f"过户费 {transfer:.2f}")
|
|
158
|
-
if extra:
|
|
159
|
-
parts.append(f"附加 {extra:.2f}(率{extra_rate:.5f})")
|
|
160
|
-
return FeeResult(amount=amount, commission=commission, stamp_tax=stamp,
|
|
161
|
-
transfer_fee=transfer, extra_fee=extra, total=total,
|
|
162
|
-
breakdown=";".join(parts))
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
def stamp_tax_timeline() -> Sequence[Tuple[str, str, float]]:
|
|
166
|
-
"""公开时间线(给报告/前端渲染,不许调用方各抄一份)。"""
|
|
167
|
-
return _STAMP_TAX_TIMELINE
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
__all__ = ["FeeResult", "calc_fees", "stamp_tax", "transfer_fee_rate",
|
|
171
|
-
"commission_cap", "stamp_tax_timeline"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/circuit_breaker.py
RENAMED
|
File without changes
|
{data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/corporate_actions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/price_limit.py
RENAMED
|
File without changes
|
|
File without changes
|
{data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/settlement.py
RENAMED
|
File without changes
|
|
File without changes
|
{data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/trade_calendar.py
RENAMED
|
File without changes
|
{data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/trading_calendar.py
RENAMED
|
File without changes
|
{data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/dbl_common/trading_hours.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/tests/test_price_limit.py
RENAMED
|
File without changes
|
|
File without changes
|
{data_backtest_live_common-0.2.0 → data_backtest_live_common-0.3.0}/tests/test_trade_calendar.py
RENAMED
|
File without changes
|