arithmion-core 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.
- arithmion_core-0.1.0/LICENSE +21 -0
- arithmion_core-0.1.0/PKG-INFO +172 -0
- arithmion_core-0.1.0/README.md +148 -0
- arithmion_core-0.1.0/pyproject.toml +40 -0
- arithmion_core-0.1.0/setup.cfg +4 -0
- arithmion_core-0.1.0/src/apexquant/core/__init__.py +6 -0
- arithmion_core-0.1.0/src/apexquant/core/backtest/__init__.py +17 -0
- arithmion_core-0.1.0/src/apexquant/core/backtest/result.py +192 -0
- arithmion_core-0.1.0/src/apexquant/core/backtest/serialize.py +108 -0
- arithmion_core-0.1.0/src/apexquant/core/bar.py +186 -0
- arithmion_core-0.1.0/src/apexquant/core/broker.py +613 -0
- arithmion_core-0.1.0/src/apexquant/core/calendar.py +54 -0
- arithmion_core-0.1.0/src/apexquant/core/config_schema.py +126 -0
- arithmion_core-0.1.0/src/apexquant/core/datasource.py +471 -0
- arithmion_core-0.1.0/src/apexquant/core/engine.py +212 -0
- arithmion_core-0.1.0/src/apexquant/core/metric.py +234 -0
- arithmion_core-0.1.0/src/apexquant/core/model_meta.py +149 -0
- arithmion_core-0.1.0/src/apexquant/core/panel.py +196 -0
- arithmion_core-0.1.0/src/apexquant/core/plugins.py +192 -0
- arithmion_core-0.1.0/src/apexquant/core/portfolio_strategy.py +106 -0
- arithmion_core-0.1.0/src/apexquant/core/predictor.py +348 -0
- arithmion_core-0.1.0/src/apexquant/core/py.typed +0 -0
- arithmion_core-0.1.0/src/apexquant/core/registry.py +110 -0
- arithmion_core-0.1.0/src/apexquant/core/result.py +271 -0
- arithmion_core-0.1.0/src/apexquant/core/risk/__init__.py +56 -0
- arithmion_core-0.1.0/src/apexquant/core/risk/manager.py +114 -0
- arithmion_core-0.1.0/src/apexquant/core/risk/sizing.py +101 -0
- arithmion_core-0.1.0/src/apexquant/core/risk/stops.py +129 -0
- arithmion_core-0.1.0/src/apexquant/core/signals.py +162 -0
- arithmion_core-0.1.0/src/apexquant/core/strategy.py +770 -0
- arithmion_core-0.1.0/src/apexquant/core/streaming.py +196 -0
- arithmion_core-0.1.0/src/apexquant/core/trade_plan.py +53 -0
- arithmion_core-0.1.0/src/apexquant/core/training/__init__.py +40 -0
- arithmion_core-0.1.0/src/apexquant/core/training/rolling.py +121 -0
- arithmion_core-0.1.0/src/apexquant/core/training/trainer.py +163 -0
- arithmion_core-0.1.0/src/apexquant/core/universe.py +94 -0
- arithmion_core-0.1.0/src/apexquant/core/validation.py +249 -0
- arithmion_core-0.1.0/src/arithmion_core.egg-info/PKG-INFO +172 -0
- arithmion_core-0.1.0/src/arithmion_core.egg-info/SOURCES.txt +40 -0
- arithmion_core-0.1.0/src/arithmion_core.egg-info/dependency_links.txt +1 -0
- arithmion_core-0.1.0/src/arithmion_core.egg-info/requires.txt +5 -0
- arithmion_core-0.1.0/src/arithmion_core.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Arithmion-git
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: arithmion-core
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Interface tier of the Arithmion agent-native quant platform: contracts, typed data carriers, and the plugin registry.
|
|
5
|
+
Author: Arithmion-git
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://arithmion.com
|
|
8
|
+
Project-URL: Repository, https://github.com/Arithmion-git/arithmion-core
|
|
9
|
+
Keywords: quant,trading,backtesting,framework,plugins,agent
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
15
|
+
Classifier: Typing :: Typed
|
|
16
|
+
Requires-Python: >=3.11
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: pandas>=2.0
|
|
20
|
+
Requires-Dist: loguru>=0.7
|
|
21
|
+
Provides-Extra: test
|
|
22
|
+
Requires-Dist: pytest; extra == "test"
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
# arithmion-core
|
|
26
|
+
|
|
27
|
+
The interface tier of [Arithmion](https://arithmion.com), an AI-native
|
|
28
|
+
quantitative research and trading platform. This package contains the
|
|
29
|
+
contracts the platform is built on: abstract base classes, typed data
|
|
30
|
+
carriers, and the entry-point plugin registry. It contains no engine, no
|
|
31
|
+
providers, and no agent runtime — those live in the Arithmion product, which
|
|
32
|
+
implements these contracts.
|
|
33
|
+
|
|
34
|
+
**Links** — [arithmion.com](https://arithmion.com) for the product;
|
|
35
|
+
[arithmion.com/learn](https://arithmion.com/learn/) for the learning center, a
|
|
36
|
+
free bilingual (English / 中文) quant curriculum covering market structure,
|
|
37
|
+
statistics, machine learning, and a validation track on multiple testing, PBO
|
|
38
|
+
and the deflated Sharpe ratio — also available as markdown in
|
|
39
|
+
[quant-learning-path](https://github.com/Arithmion-git/quant-learning-path).
|
|
40
|
+
|
|
41
|
+
The package installs into the `apexquant` namespace (`import apexquant.core`),
|
|
42
|
+
which is the platform's historical package name; the import path is shared
|
|
43
|
+
with the full product so that code written against these contracts runs
|
|
44
|
+
unchanged in both.
|
|
45
|
+
|
|
46
|
+
## What is in here
|
|
47
|
+
|
|
48
|
+
**Data contracts** — the shapes that cross every boundary:
|
|
49
|
+
|
|
50
|
+
- `bar` / `signals` / `result` / `trade_plan` — OHLCV bars, signal proxies,
|
|
51
|
+
prediction results, trade plans
|
|
52
|
+
- `backtest.result` / `backtest.serialize` — the backtest result carrier and
|
|
53
|
+
its canonical JSON wire shape
|
|
54
|
+
- `panel` — the cross-sectional factor-panel shape and its OHLCV converters
|
|
55
|
+
- `config_schema` — the typed schema plugins use to declare their
|
|
56
|
+
configuration surface
|
|
57
|
+
- `model_meta` — the `meta.json` schema describing trained-model artifacts
|
|
58
|
+
|
|
59
|
+
**Plugin contracts** — subclass one of these, register it via an entry
|
|
60
|
+
point, and the platform discovers it:
|
|
61
|
+
|
|
62
|
+
- `strategy` / `portfolio_strategy` — bar-driven and rebalance-driven
|
|
63
|
+
strategies
|
|
64
|
+
- `predictor` — per-bar inference
|
|
65
|
+
- `datasource` / `streaming` — bounded (batch) and unbounded (live) data
|
|
66
|
+
- `broker` — order routing
|
|
67
|
+
- `engine` — the backtest-engine protocol and factory
|
|
68
|
+
- `metric` / `validation` — result metrics and trustworthiness validators
|
|
69
|
+
- `risk` — risk manager, position sizer, stop policy
|
|
70
|
+
- `training` — the trainer contract and the walk-forward window partitioner
|
|
71
|
+
- `universe` / `calendar` — point-in-time stock pools and trading calendars
|
|
72
|
+
|
|
73
|
+
**Mechanism**:
|
|
74
|
+
|
|
75
|
+
- `registry` / `plugins` — the domain registry and the entry-point scanner
|
|
76
|
+
that performs discovery
|
|
77
|
+
|
|
78
|
+
## Install
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pip install -e .
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Requires Python ≥ 3.11. Runtime dependencies are `pandas` and `loguru` only.
|
|
85
|
+
|
|
86
|
+
## A minimal strategy
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from apexquant.core.bar import Bar
|
|
90
|
+
from apexquant.core.strategy import BaseStrategy, Signal
|
|
91
|
+
|
|
92
|
+
class Momentum(BaseStrategy):
|
|
93
|
+
name = "momentum"
|
|
94
|
+
freq = "daily"
|
|
95
|
+
|
|
96
|
+
def on_bar(self, bar: Bar) -> Signal:
|
|
97
|
+
if bar.close > bar.open:
|
|
98
|
+
return Signal.BUY
|
|
99
|
+
return Signal.HOLD
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Third-party packages expose implementations through entry-point groups
|
|
103
|
+
(`apexquant.strategies`, `apexquant.datasources`, `apexquant.metrics`, …);
|
|
104
|
+
see `plugins.py` for the group inventory and `registry.py` for the domain
|
|
105
|
+
registry the scanner populates.
|
|
106
|
+
|
|
107
|
+
## Stability
|
|
108
|
+
|
|
109
|
+
Interface versioning follows the platform's roadmap: during v0.x no
|
|
110
|
+
interface is frozen, and breaking changes are recorded in `CHANGELOG.md`.
|
|
111
|
+
Contracts carry an `__apexquant_api_version__` tuple where versioned.
|
|
112
|
+
|
|
113
|
+
## Relationship to the main repository
|
|
114
|
+
|
|
115
|
+
The Arithmion product repository is the source of truth; this repository is
|
|
116
|
+
a curated export of its `src/apexquant/core` interface tier
|
|
117
|
+
(`scripts/sync_from_apexquant.py` performs the sync and enforces the scope).
|
|
118
|
+
Issues and contributions against the contracts are welcome here.
|
|
119
|
+
|
|
120
|
+
## Why `apexquant` (and `aq`)?
|
|
121
|
+
|
|
122
|
+
Arithmion grew out of **ApexQuant**, a graduate thesis project on applying
|
|
123
|
+
deep time-series learning to stock forecasting and quantitative trading:
|
|
124
|
+
|
|
125
|
+
- [Applying Deep Time-Series Learning to Stock Forecasting and Quant
|
|
126
|
+
Trading](https://github.com/Heeeeeeliang/Applying-Deep-Time-Series-Learning-to-Stock-Forecasting-and-Quant-Trading)
|
|
127
|
+
— the thesis
|
|
128
|
+
- [Apexquant](https://github.com/Heeeeeeliang/Apexquant) — the thesis-era
|
|
129
|
+
codebase this platform descends from
|
|
130
|
+
|
|
131
|
+
When the project became the Arithmion platform, the brand changed but the
|
|
132
|
+
Python package kept its original `apexquant` name — frankly, because
|
|
133
|
+
renaming it was not worth the churn: imports, entry-point groups
|
|
134
|
+
(`apexquant.strategies`, …), and the `__apexquant_api_version__` markers
|
|
135
|
+
would all have had to move for zero functional gain. A convenient side
|
|
136
|
+
effect is that thesis-era and current code interoperate as-is. The same
|
|
137
|
+
applies to the `aq` shorthand you may see elsewhere in the platform (CSS
|
|
138
|
+
tokens, UI prefixes). Wherever you read `apexquant` or `aq`, it means
|
|
139
|
+
Arithmion.
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
MIT — see [LICENSE](LICENSE).
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## 中文说明
|
|
148
|
+
|
|
149
|
+
arithmion-core 是 Arithmion(AI 原生量化平台)的接口层:平台赖以构建的
|
|
150
|
+
契约——抽象基类、类型化数据载体、以及基于 entry-point 的插件注册机制。
|
|
151
|
+
本仓库不包含引擎实现、数据/券商 provider 或 agent 运行时;它们属于实现了
|
|
152
|
+
这些契约的 Arithmion 产品本体。
|
|
153
|
+
|
|
154
|
+
**相关链接**——产品在 [arithmion.com](https://arithmion.com);学习中心在
|
|
155
|
+
[arithmion.com/learn](https://arithmion.com/learn/):免费的中英双语量化课程,
|
|
156
|
+
覆盖市场结构、数理统计、机器学习,以及围绕多重检验、PBO 与 Deflated Sharpe
|
|
157
|
+
的验证专线,markdown 版在 [quant-learning-path](https://github.com/Arithmion-git/quant-learning-path)。
|
|
158
|
+
|
|
159
|
+
包安装在 `apexquant` 命名空间下(`import apexquant.core`),与完整产品共享
|
|
160
|
+
导入路径:针对这些契约编写的代码在两侧无需修改即可运行。
|
|
161
|
+
|
|
162
|
+
安装:`pip install -e .`,要求 Python ≥ 3.11,运行时依赖仅 pandas 与 loguru。
|
|
163
|
+
|
|
164
|
+
**关于 `apexquant` 与 `aq` 命名**:Arithmion 的前身是毕业设计项目
|
|
165
|
+
**ApexQuant**([论文](https://github.com/Heeeeeeliang/Applying-Deep-Time-Series-Learning-to-Stock-Forecasting-and-Quant-Trading)、
|
|
166
|
+
[当时的代码库](https://github.com/Heeeeeeliang/Apexquant))。品牌更名后
|
|
167
|
+
Python 包沿用了原名 `apexquant`——说白了是改名不值得折腾:导入路径、
|
|
168
|
+
entry-point 组名、`__apexquant_api_version__` 标记全都得跟着动,却没有
|
|
169
|
+
任何功能收益。顺带的好处是论文时期与当前的代码无需迁移即可互通;平台
|
|
170
|
+
其它位置的 `aq` 简写同理。代码中的 `apexquant` 与 `aq` 均指 Arithmion。
|
|
171
|
+
|
|
172
|
+
v0.x 期间接口均不冻结,破坏性变更记录于 `CHANGELOG.md`。许可证为 MIT。
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# arithmion-core
|
|
2
|
+
|
|
3
|
+
The interface tier of [Arithmion](https://arithmion.com), an AI-native
|
|
4
|
+
quantitative research and trading platform. This package contains the
|
|
5
|
+
contracts the platform is built on: abstract base classes, typed data
|
|
6
|
+
carriers, and the entry-point plugin registry. It contains no engine, no
|
|
7
|
+
providers, and no agent runtime — those live in the Arithmion product, which
|
|
8
|
+
implements these contracts.
|
|
9
|
+
|
|
10
|
+
**Links** — [arithmion.com](https://arithmion.com) for the product;
|
|
11
|
+
[arithmion.com/learn](https://arithmion.com/learn/) for the learning center, a
|
|
12
|
+
free bilingual (English / 中文) quant curriculum covering market structure,
|
|
13
|
+
statistics, machine learning, and a validation track on multiple testing, PBO
|
|
14
|
+
and the deflated Sharpe ratio — also available as markdown in
|
|
15
|
+
[quant-learning-path](https://github.com/Arithmion-git/quant-learning-path).
|
|
16
|
+
|
|
17
|
+
The package installs into the `apexquant` namespace (`import apexquant.core`),
|
|
18
|
+
which is the platform's historical package name; the import path is shared
|
|
19
|
+
with the full product so that code written against these contracts runs
|
|
20
|
+
unchanged in both.
|
|
21
|
+
|
|
22
|
+
## What is in here
|
|
23
|
+
|
|
24
|
+
**Data contracts** — the shapes that cross every boundary:
|
|
25
|
+
|
|
26
|
+
- `bar` / `signals` / `result` / `trade_plan` — OHLCV bars, signal proxies,
|
|
27
|
+
prediction results, trade plans
|
|
28
|
+
- `backtest.result` / `backtest.serialize` — the backtest result carrier and
|
|
29
|
+
its canonical JSON wire shape
|
|
30
|
+
- `panel` — the cross-sectional factor-panel shape and its OHLCV converters
|
|
31
|
+
- `config_schema` — the typed schema plugins use to declare their
|
|
32
|
+
configuration surface
|
|
33
|
+
- `model_meta` — the `meta.json` schema describing trained-model artifacts
|
|
34
|
+
|
|
35
|
+
**Plugin contracts** — subclass one of these, register it via an entry
|
|
36
|
+
point, and the platform discovers it:
|
|
37
|
+
|
|
38
|
+
- `strategy` / `portfolio_strategy` — bar-driven and rebalance-driven
|
|
39
|
+
strategies
|
|
40
|
+
- `predictor` — per-bar inference
|
|
41
|
+
- `datasource` / `streaming` — bounded (batch) and unbounded (live) data
|
|
42
|
+
- `broker` — order routing
|
|
43
|
+
- `engine` — the backtest-engine protocol and factory
|
|
44
|
+
- `metric` / `validation` — result metrics and trustworthiness validators
|
|
45
|
+
- `risk` — risk manager, position sizer, stop policy
|
|
46
|
+
- `training` — the trainer contract and the walk-forward window partitioner
|
|
47
|
+
- `universe` / `calendar` — point-in-time stock pools and trading calendars
|
|
48
|
+
|
|
49
|
+
**Mechanism**:
|
|
50
|
+
|
|
51
|
+
- `registry` / `plugins` — the domain registry and the entry-point scanner
|
|
52
|
+
that performs discovery
|
|
53
|
+
|
|
54
|
+
## Install
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install -e .
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Requires Python ≥ 3.11. Runtime dependencies are `pandas` and `loguru` only.
|
|
61
|
+
|
|
62
|
+
## A minimal strategy
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from apexquant.core.bar import Bar
|
|
66
|
+
from apexquant.core.strategy import BaseStrategy, Signal
|
|
67
|
+
|
|
68
|
+
class Momentum(BaseStrategy):
|
|
69
|
+
name = "momentum"
|
|
70
|
+
freq = "daily"
|
|
71
|
+
|
|
72
|
+
def on_bar(self, bar: Bar) -> Signal:
|
|
73
|
+
if bar.close > bar.open:
|
|
74
|
+
return Signal.BUY
|
|
75
|
+
return Signal.HOLD
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Third-party packages expose implementations through entry-point groups
|
|
79
|
+
(`apexquant.strategies`, `apexquant.datasources`, `apexquant.metrics`, …);
|
|
80
|
+
see `plugins.py` for the group inventory and `registry.py` for the domain
|
|
81
|
+
registry the scanner populates.
|
|
82
|
+
|
|
83
|
+
## Stability
|
|
84
|
+
|
|
85
|
+
Interface versioning follows the platform's roadmap: during v0.x no
|
|
86
|
+
interface is frozen, and breaking changes are recorded in `CHANGELOG.md`.
|
|
87
|
+
Contracts carry an `__apexquant_api_version__` tuple where versioned.
|
|
88
|
+
|
|
89
|
+
## Relationship to the main repository
|
|
90
|
+
|
|
91
|
+
The Arithmion product repository is the source of truth; this repository is
|
|
92
|
+
a curated export of its `src/apexquant/core` interface tier
|
|
93
|
+
(`scripts/sync_from_apexquant.py` performs the sync and enforces the scope).
|
|
94
|
+
Issues and contributions against the contracts are welcome here.
|
|
95
|
+
|
|
96
|
+
## Why `apexquant` (and `aq`)?
|
|
97
|
+
|
|
98
|
+
Arithmion grew out of **ApexQuant**, a graduate thesis project on applying
|
|
99
|
+
deep time-series learning to stock forecasting and quantitative trading:
|
|
100
|
+
|
|
101
|
+
- [Applying Deep Time-Series Learning to Stock Forecasting and Quant
|
|
102
|
+
Trading](https://github.com/Heeeeeeliang/Applying-Deep-Time-Series-Learning-to-Stock-Forecasting-and-Quant-Trading)
|
|
103
|
+
— the thesis
|
|
104
|
+
- [Apexquant](https://github.com/Heeeeeeliang/Apexquant) — the thesis-era
|
|
105
|
+
codebase this platform descends from
|
|
106
|
+
|
|
107
|
+
When the project became the Arithmion platform, the brand changed but the
|
|
108
|
+
Python package kept its original `apexquant` name — frankly, because
|
|
109
|
+
renaming it was not worth the churn: imports, entry-point groups
|
|
110
|
+
(`apexquant.strategies`, …), and the `__apexquant_api_version__` markers
|
|
111
|
+
would all have had to move for zero functional gain. A convenient side
|
|
112
|
+
effect is that thesis-era and current code interoperate as-is. The same
|
|
113
|
+
applies to the `aq` shorthand you may see elsewhere in the platform (CSS
|
|
114
|
+
tokens, UI prefixes). Wherever you read `apexquant` or `aq`, it means
|
|
115
|
+
Arithmion.
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
MIT — see [LICENSE](LICENSE).
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 中文说明
|
|
124
|
+
|
|
125
|
+
arithmion-core 是 Arithmion(AI 原生量化平台)的接口层:平台赖以构建的
|
|
126
|
+
契约——抽象基类、类型化数据载体、以及基于 entry-point 的插件注册机制。
|
|
127
|
+
本仓库不包含引擎实现、数据/券商 provider 或 agent 运行时;它们属于实现了
|
|
128
|
+
这些契约的 Arithmion 产品本体。
|
|
129
|
+
|
|
130
|
+
**相关链接**——产品在 [arithmion.com](https://arithmion.com);学习中心在
|
|
131
|
+
[arithmion.com/learn](https://arithmion.com/learn/):免费的中英双语量化课程,
|
|
132
|
+
覆盖市场结构、数理统计、机器学习,以及围绕多重检验、PBO 与 Deflated Sharpe
|
|
133
|
+
的验证专线,markdown 版在 [quant-learning-path](https://github.com/Arithmion-git/quant-learning-path)。
|
|
134
|
+
|
|
135
|
+
包安装在 `apexquant` 命名空间下(`import apexquant.core`),与完整产品共享
|
|
136
|
+
导入路径:针对这些契约编写的代码在两侧无需修改即可运行。
|
|
137
|
+
|
|
138
|
+
安装:`pip install -e .`,要求 Python ≥ 3.11,运行时依赖仅 pandas 与 loguru。
|
|
139
|
+
|
|
140
|
+
**关于 `apexquant` 与 `aq` 命名**:Arithmion 的前身是毕业设计项目
|
|
141
|
+
**ApexQuant**([论文](https://github.com/Heeeeeeliang/Applying-Deep-Time-Series-Learning-to-Stock-Forecasting-and-Quant-Trading)、
|
|
142
|
+
[当时的代码库](https://github.com/Heeeeeeliang/Apexquant))。品牌更名后
|
|
143
|
+
Python 包沿用了原名 `apexquant`——说白了是改名不值得折腾:导入路径、
|
|
144
|
+
entry-point 组名、`__apexquant_api_version__` 标记全都得跟着动,却没有
|
|
145
|
+
任何功能收益。顺带的好处是论文时期与当前的代码无需迁移即可互通;平台
|
|
146
|
+
其它位置的 `aq` 简写同理。代码中的 `apexquant` 与 `aq` 均指 Arithmion。
|
|
147
|
+
|
|
148
|
+
v0.x 期间接口均不冻结,破坏性变更记录于 `CHANGELOG.md`。许可证为 MIT。
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=69"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "arithmion-core"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Interface tier of the Arithmion agent-native quant platform: contracts, typed data carriers, and the plugin registry."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
authors = [{ name = "Arithmion-git" }]
|
|
12
|
+
requires-python = ">=3.11"
|
|
13
|
+
dependencies = [
|
|
14
|
+
"pandas>=2.0",
|
|
15
|
+
"loguru>=0.7",
|
|
16
|
+
]
|
|
17
|
+
keywords = ["quant", "trading", "backtesting", "framework", "plugins", "agent"]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Development Status :: 3 - Alpha",
|
|
20
|
+
"Intended Audience :: Financial and Insurance Industry",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Topic :: Office/Business :: Financial :: Investment",
|
|
24
|
+
"Typing :: Typed",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
Homepage = "https://arithmion.com"
|
|
29
|
+
Repository = "https://github.com/Arithmion-git/arithmion-core"
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
test = ["pytest"]
|
|
33
|
+
|
|
34
|
+
[tool.setuptools.packages.find]
|
|
35
|
+
where = ["src"]
|
|
36
|
+
include = ["apexquant*"]
|
|
37
|
+
namespaces = true
|
|
38
|
+
|
|
39
|
+
[tool.setuptools.package-data]
|
|
40
|
+
"apexquant.core" = ["py.typed"]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""apexquant.core.backtest — backtest RESULT contracts (contracts-only export).
|
|
2
|
+
|
|
3
|
+
This repo ships the result carrier and its canonical JSON wire shape only.
|
|
4
|
+
The engine implementations (``BacktestEngine``, the portfolio engine) live in
|
|
5
|
+
the full Arithmion product, which satisfies these contracts; any engine that
|
|
6
|
+
produces a :class:`BacktestResult` interoperates with tooling built on them.
|
|
7
|
+
|
|
8
|
+
NOTE (sync): this ``__init__`` is OWNED BY THIS REPO — the main repo's
|
|
9
|
+
counterpart also re-exports the engine implementation. See
|
|
10
|
+
``scripts/sync_from_apexquant.py`` OVERRIDES.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
__all__ = ["CASH_TICKER", "BacktestResult", "CashFlowEvent"]
|
|
16
|
+
|
|
17
|
+
from apexquant.core.backtest.result import CASH_TICKER, BacktestResult, CashFlowEvent
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"""Backtest result carrier (Phase E1 — relocated from ``backtest/engine.py``).
|
|
2
|
+
|
|
3
|
+
``BacktestResult`` is the structurally-identical successor to the
|
|
4
|
+
``BacktestResult`` defined in both legacy engines (``backtest/engine.py`` and
|
|
5
|
+
``backtest/_legacy.py``). It carries trades, the equity curve, headline
|
|
6
|
+
metrics (populated by :func:`backtest.metrics.compute_metrics`), and run
|
|
7
|
+
metadata.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
__all__ = ["CASH_TICKER", "BacktestResult", "CashFlowEvent"]
|
|
13
|
+
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
from typing import TYPE_CHECKING, Any
|
|
17
|
+
|
|
18
|
+
import pandas as pd
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from apexquant.core.strategy import Trade
|
|
22
|
+
|
|
23
|
+
#: Reserved pseudo-ticker for the uninvested cash sleeve in ``weights_curve``.
|
|
24
|
+
#: Cash is carried EXPLICITLY rather than derived as ``1 - sum(weights)`` so an
|
|
25
|
+
#: all-cash date survives serialization: a date whose weights dict is empty
|
|
26
|
+
#: would otherwise vanish from the long-table CSV entirely, and the consumer
|
|
27
|
+
#: could not tell "flat that day" from "no data that day". The ``$`` prefix
|
|
28
|
+
#: keeps it out of any real ticker namespace.
|
|
29
|
+
CASH_TICKER = "$CASH"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class CashFlowEvent:
|
|
34
|
+
"""One external cash injection/withdrawal during a backtest.
|
|
35
|
+
|
|
36
|
+
Distinct from trading P&L -- this is money that entered or left the
|
|
37
|
+
account from OUTSIDE the strategy's own decisions (a deposit, a
|
|
38
|
+
withdrawal, a scheduled contribution). ``metrics.compute_metrics``
|
|
39
|
+
reads a list of these to compute TWR/MWR without ever needing to know
|
|
40
|
+
WHY the flow happened.
|
|
41
|
+
|
|
42
|
+
Attributes:
|
|
43
|
+
timestamp: When the cash flow occurred (the bar timestamp it was
|
|
44
|
+
applied on).
|
|
45
|
+
amount: Positive = contribution/deposit, negative = withdrawal.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
timestamp: datetime
|
|
49
|
+
amount: float # positive = contribution/deposit, negative = withdrawal
|
|
50
|
+
|
|
51
|
+
def to_dict(self) -> dict[str, Any]:
|
|
52
|
+
"""JSON-native projection (round-trips via :meth:`from_dict`).
|
|
53
|
+
|
|
54
|
+
Follows the same ISO-timestamp convention as :meth:`Trade.to_dict`.
|
|
55
|
+
"""
|
|
56
|
+
return {
|
|
57
|
+
"timestamp": self.timestamp.isoformat() if self.timestamp else None,
|
|
58
|
+
"amount": self.amount,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@classmethod
|
|
62
|
+
def from_dict(cls, d: dict[str, Any]) -> CashFlowEvent:
|
|
63
|
+
"""Reconstruct a :class:`CashFlowEvent` from :meth:`to_dict` output."""
|
|
64
|
+
return cls(
|
|
65
|
+
timestamp=datetime.fromisoformat(d["timestamp"]),
|
|
66
|
+
amount=d.get("amount", 0.0),
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass
|
|
71
|
+
class BacktestResult:
|
|
72
|
+
"""Container for backtest output.
|
|
73
|
+
|
|
74
|
+
Attributes:
|
|
75
|
+
trades: All closed trades.
|
|
76
|
+
equity_curve: Portfolio value over time.
|
|
77
|
+
metrics: Performance metrics (populated by
|
|
78
|
+
:func:`backtest.metrics.compute_metrics`).
|
|
79
|
+
strategy_name: Name of the strategy that was tested — comes from the
|
|
80
|
+
strategy's own ``Strategy.name`` class attribute, so it need NOT
|
|
81
|
+
match the id the caller submitted (e.g. a user-authored workspace
|
|
82
|
+
strategy can set any ``name`` it likes). Kept for display/grouping;
|
|
83
|
+
do not use it to look the run back up in the strategy workspace.
|
|
84
|
+
start_date: First bar timestamp.
|
|
85
|
+
end_date: Last bar timestamp.
|
|
86
|
+
config_snapshot: Frozen copy of the config used.
|
|
87
|
+
strategy_id: The strategy-workspace id (or built-in type name, e.g.
|
|
88
|
+
``"ai"``/``"technical"``) the caller actually submitted, captured
|
|
89
|
+
*before* ``_resolve_strategy`` rewrites it to an on-disk path.
|
|
90
|
+
``None`` when the run has no such association (e.g. produced by a
|
|
91
|
+
legacy run predating this field, or a CLI/script invocation that
|
|
92
|
+
never went through the workspace-aware submission routes). Unlike
|
|
93
|
+
``strategy_name``, this is reliable for looking the run back up in
|
|
94
|
+
the strategy workspace.
|
|
95
|
+
weights_curve: Per-date portfolio composition as
|
|
96
|
+
``[(timestamp, {ticker: weight})]``, weights being **signed**
|
|
97
|
+
fractions of total equity (short exposure is negative) that sum to
|
|
98
|
+
1 including the :data:`CASH_TICKER` sleeve. **Experimental.**
|
|
99
|
+
Populated by portfolio mode (per rebalance mark) and by the
|
|
100
|
+
default event engine in mark-to-market mode (sampled once per
|
|
101
|
+
calendar day); left empty in stepped equity mode, which has no
|
|
102
|
+
marks to compose from. Every consumer must treat "empty" as a
|
|
103
|
+
normal case and degrade rather than assume composition data exists.
|
|
104
|
+
cash_flow_events: External cash injections/withdrawals applied during
|
|
105
|
+
the run, e.g. scheduled contributions or a one-off
|
|
106
|
+
deposit/withdrawal. Empty for every run that didn't configure
|
|
107
|
+
``backtest.contributions`` -- additive field, default ``[]``, so
|
|
108
|
+
existing callers that don't know about it are unaffected.
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
trades: list[Trade] = field(default_factory=list)
|
|
112
|
+
equity_curve: pd.Series = field(default_factory=lambda: pd.Series(dtype=float))
|
|
113
|
+
metrics: dict[str, Any] = field(default_factory=dict)
|
|
114
|
+
strategy_name: str = ""
|
|
115
|
+
start_date: datetime | None = None
|
|
116
|
+
end_date: datetime | None = None
|
|
117
|
+
config_snapshot: dict[str, Any] = field(default_factory=dict)
|
|
118
|
+
strategy_id: str | None = None
|
|
119
|
+
weights_curve: list[tuple[Any, dict[str, float]]] = field(default_factory=list)
|
|
120
|
+
cash_flow_events: list[CashFlowEvent] = field(default_factory=list)
|
|
121
|
+
|
|
122
|
+
def summary(self) -> dict[str, Any]:
|
|
123
|
+
"""Return a summary dict of key fields.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
Dict with strategy name, trade count, date range, and metrics.
|
|
127
|
+
"""
|
|
128
|
+
return {
|
|
129
|
+
"strategy": self.strategy_name,
|
|
130
|
+
"trades": len(self.trades),
|
|
131
|
+
"start": self.start_date,
|
|
132
|
+
"end": self.end_date,
|
|
133
|
+
**self.metrics,
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
def to_dict(self) -> dict[str, Any]:
|
|
137
|
+
"""JSON-native projection (round-trips via :meth:`from_dict`).
|
|
138
|
+
|
|
139
|
+
Trades use :meth:`Trade.to_dict`; the equity curve becomes a list of
|
|
140
|
+
``[iso_timestamp, value]`` pairs; datetimes become ISO strings. Makes the
|
|
141
|
+
backtest-output contract serializable end to end (agent / API / SaaS).
|
|
142
|
+
"""
|
|
143
|
+
eq: list[list[Any]] = []
|
|
144
|
+
for ts, val in self.equity_curve.items():
|
|
145
|
+
key = ts.isoformat() if hasattr(ts, "isoformat") else str(ts)
|
|
146
|
+
eq.append([key, float(val)])
|
|
147
|
+
wt: list[list[Any]] = []
|
|
148
|
+
for ts, weights in self.weights_curve:
|
|
149
|
+
key = ts.isoformat() if hasattr(ts, "isoformat") else str(ts)
|
|
150
|
+
wt.append([key, {t: float(w) for t, w in weights.items()}])
|
|
151
|
+
return {
|
|
152
|
+
"trades": [t.to_dict() for t in self.trades],
|
|
153
|
+
"equity_curve": eq,
|
|
154
|
+
"weights_curve": wt,
|
|
155
|
+
"metrics": self.metrics,
|
|
156
|
+
"strategy_name": self.strategy_name,
|
|
157
|
+
"start_date": self.start_date.isoformat() if self.start_date else None,
|
|
158
|
+
"end_date": self.end_date.isoformat() if self.end_date else None,
|
|
159
|
+
"config_snapshot": self.config_snapshot,
|
|
160
|
+
"strategy_id": self.strategy_id,
|
|
161
|
+
"cash_flow_events": [cfe.to_dict() for cfe in self.cash_flow_events],
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
@classmethod
|
|
165
|
+
def from_dict(cls, d: dict[str, Any]) -> BacktestResult:
|
|
166
|
+
"""Reconstruct a :class:`BacktestResult` from :meth:`to_dict` output."""
|
|
167
|
+
from apexquant.core.strategy import Trade
|
|
168
|
+
|
|
169
|
+
pairs = d.get("equity_curve") or []
|
|
170
|
+
index = pd.DatetimeIndex([pd.Timestamp(p[0]) for p in pairs]) if pairs else None
|
|
171
|
+
values = [float(p[1]) for p in pairs]
|
|
172
|
+
equity = pd.Series(values, index=index, dtype=float)
|
|
173
|
+
weights_curve = [
|
|
174
|
+
(pd.Timestamp(p[0]), {str(t): float(w) for t, w in (p[1] or {}).items()})
|
|
175
|
+
for p in (d.get("weights_curve") or [])
|
|
176
|
+
]
|
|
177
|
+
start = d.get("start_date")
|
|
178
|
+
end = d.get("end_date")
|
|
179
|
+
return cls(
|
|
180
|
+
trades=[Trade.from_dict(t) for t in d.get("trades", [])],
|
|
181
|
+
equity_curve=equity,
|
|
182
|
+
metrics=dict(d.get("metrics") or {}),
|
|
183
|
+
strategy_name=d.get("strategy_name", ""),
|
|
184
|
+
start_date=datetime.fromisoformat(start) if start else None,
|
|
185
|
+
end_date=datetime.fromisoformat(end) if end else None,
|
|
186
|
+
config_snapshot=dict(d.get("config_snapshot") or {}),
|
|
187
|
+
strategy_id=d.get("strategy_id"),
|
|
188
|
+
weights_curve=weights_curve,
|
|
189
|
+
cash_flow_events=[
|
|
190
|
+
CashFlowEvent.from_dict(cfe) for cfe in d.get("cash_flow_events") or []
|
|
191
|
+
],
|
|
192
|
+
)
|