msd-backtest 0.1.0__py3-none-any.whl
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.
- mbt/__init__.py +28 -0
- mbt/account.py +446 -0
- mbt/data_provider.py +134 -0
- mbt/run/__init__.py +5 -0
- mbt/run/backend.py +95 -0
- mbt/run/cli.py +192 -0
- mbt/run/msd.py +76 -0
- mbt/run/report.py +313 -0
- mbt/run/review.py +67 -0
- mbt/run/runner.py +85 -0
- mbt/run/server.py +103 -0
- mbt/select/__init__.py +0 -0
- mbt/strategy.py +85 -0
- msd_backtest-0.1.0.dist-info/METADATA +182 -0
- msd_backtest-0.1.0.dist-info/RECORD +17 -0
- msd_backtest-0.1.0.dist-info/WHEEL +5 -0
- msd_backtest-0.1.0.dist-info/top_level.txt +1 -0
mbt/run/runner.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from mbt.account import Operation, ACTION_BUY_PERCENT, ACTION_SELL_PERCENT
|
|
2
|
+
from mbt.strategy import Context
|
|
3
|
+
from mbt.account import Account
|
|
4
|
+
from mbt.strategy import Strategy
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RunnerContext(Context):
|
|
9
|
+
"""RunnerContext is a context for a strategy
|
|
10
|
+
|
|
11
|
+
It is used to pass data and operations to a strategy.
|
|
12
|
+
|
|
13
|
+
Data required internally are:
|
|
14
|
+
- ts: timestamp
|
|
15
|
+
- price: price of the stock
|
|
16
|
+
Data optional internally are:
|
|
17
|
+
- "dividend": dividend per share in dividend
|
|
18
|
+
- "transfer_shares": transfer shares per share in dividend
|
|
19
|
+
- "right_shares": right share per share in dividend
|
|
20
|
+
- "right_price": right price per share in dividend
|
|
21
|
+
Other data can be added by user for specific strategy
|
|
22
|
+
|
|
23
|
+
The strategy can use the following methods to operate the account:
|
|
24
|
+
- buy: buy a position
|
|
25
|
+
- sell: sell a position
|
|
26
|
+
and refer data by `ctx.data_name`
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, account: Account):
|
|
30
|
+
self.accounts = [account.clone(g) for g in range(account.dp.groups)]
|
|
31
|
+
self.dp = account.dp
|
|
32
|
+
self.actions = np.zeros(len(self.dp.dates), dtype=np.int32)
|
|
33
|
+
self.action_percents = np.zeros(len(self.dp.dates), dtype=np.float64)
|
|
34
|
+
|
|
35
|
+
def data(self, name: str, /, symbol: str | None = None) -> np.ndarray:
|
|
36
|
+
# user may use it like ctx.open, ctx.high, ctx.low, ctx.close, ctx.volume
|
|
37
|
+
if name in self.dp.data:
|
|
38
|
+
return self.dp.all(name, symbol=symbol)
|
|
39
|
+
raise ValueError(f"data '{name}' not found")
|
|
40
|
+
|
|
41
|
+
def buy(self, flags: np.ndarray, percent: float = 1.0):
|
|
42
|
+
for g in range(self.dp.groups):
|
|
43
|
+
j = g * self.dp.bars + self.dp.i
|
|
44
|
+
if flags[j]:
|
|
45
|
+
self.actions[j] = ACTION_BUY_PERCENT
|
|
46
|
+
self.action_percents[j] = percent
|
|
47
|
+
|
|
48
|
+
def sell(self, flags: np.ndarray, percent: float = 1.0):
|
|
49
|
+
for g in range(self.dp.groups):
|
|
50
|
+
j = g * self.dp.bars + self.dp.i
|
|
51
|
+
if flags[j]:
|
|
52
|
+
self.actions[j] = ACTION_SELL_PERCENT
|
|
53
|
+
self.action_percents[j] = percent
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class Runner:
|
|
57
|
+
"""Runner is a runner of a strategy"""
|
|
58
|
+
|
|
59
|
+
def __init__(self, account: Account):
|
|
60
|
+
self.ctx = RunnerContext(account)
|
|
61
|
+
|
|
62
|
+
def run(self, strategy: Strategy):
|
|
63
|
+
prices = self.ctx.dp.all("price")
|
|
64
|
+
for i in self.ctx.dp:
|
|
65
|
+
strategy.execute(self.ctx)
|
|
66
|
+
for g in range(self.ctx.dp.groups):
|
|
67
|
+
j = g * self.ctx.dp.bars + self.ctx.dp.i
|
|
68
|
+
action = self.ctx.actions[j]
|
|
69
|
+
percent = self.ctx.action_percents[j]
|
|
70
|
+
if action == ACTION_BUY_PERCENT:
|
|
71
|
+
self.ctx.accounts[g].do_operation(
|
|
72
|
+
self.ctx.dp.i,
|
|
73
|
+
Operation.buy_percent(
|
|
74
|
+
percent, prices[j] * (1 + self.ctx.accounts[g].slippage)
|
|
75
|
+
),
|
|
76
|
+
)
|
|
77
|
+
elif action == ACTION_SELL_PERCENT:
|
|
78
|
+
self.ctx.accounts[g].do_operation(
|
|
79
|
+
self.ctx.dp.i,
|
|
80
|
+
Operation.sell_percent(
|
|
81
|
+
percent, prices[j] * (1 - self.ctx.accounts[g].slippage)
|
|
82
|
+
),
|
|
83
|
+
)
|
|
84
|
+
else:
|
|
85
|
+
self.ctx.accounts[g].do_operation(self.ctx.dp.i, Operation.keep(prices[j]))
|
mbt/run/server.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from dotenv import load_dotenv
|
|
2
|
+
load_dotenv(override=True)
|
|
3
|
+
|
|
4
|
+
from mbt import Runner, Account, Fee
|
|
5
|
+
from mbt.run import Report, build_report, build_json_report, RunRequest
|
|
6
|
+
from mbt.run.msd import load_data
|
|
7
|
+
import logging
|
|
8
|
+
from typing import List, Optional
|
|
9
|
+
from fastapi import FastAPI, HTTPException
|
|
10
|
+
from pydantic import BaseModel
|
|
11
|
+
import os
|
|
12
|
+
|
|
13
|
+
# Configuration
|
|
14
|
+
logging.basicConfig(
|
|
15
|
+
format="%(asctime)s %(name)s %(levelname)s %(message)s", level=logging.INFO
|
|
16
|
+
)
|
|
17
|
+
logger = logging.getLogger("backtest-server")
|
|
18
|
+
|
|
19
|
+
DEFAULT_MSD_HOST = "http://localhost:50510"
|
|
20
|
+
|
|
21
|
+
DEFAULT_FEE = Fee()
|
|
22
|
+
|
|
23
|
+
app = FastAPI(title="MSD Backtest Server")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class RunRequestModel(BaseModel):
|
|
27
|
+
strategy: str
|
|
28
|
+
symbols: List[str]
|
|
29
|
+
start: str
|
|
30
|
+
end: str
|
|
31
|
+
args: Optional[List] = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@app.post("/backtest")
|
|
37
|
+
async def run_backtest(req_model: RunRequestModel):
|
|
38
|
+
try:
|
|
39
|
+
logger.info(f"Received backtest request for symbols: {req_model.symbols}")
|
|
40
|
+
|
|
41
|
+
# Use RunRequest to load the strategy (can be source code or file path)
|
|
42
|
+
# The RunRequest class in backend.py expects strategy, symbols, start, end, args
|
|
43
|
+
# We'll pass the strategy string directly to load_strategy logic if needed,
|
|
44
|
+
# but RunRequest handles it.
|
|
45
|
+
|
|
46
|
+
# We need to load data first as in cli.py
|
|
47
|
+
logger.info(f"Loading data from {DEFAULT_MSD_HOST} for {req_model.symbols}")
|
|
48
|
+
dp, symbols = load_data(
|
|
49
|
+
DEFAULT_MSD_HOST, req_model.symbols, req_model.start, req_model.end
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if "ts" not in dp.data:
|
|
53
|
+
raise ValueError(
|
|
54
|
+
"No data found for the given symbols and date range. Please check your MSD server and parameters."
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
logger.info("Data loaded successfully")
|
|
58
|
+
|
|
59
|
+
# Initialize Account and Runner
|
|
60
|
+
account = Account(10000.0, dp, fee=DEFAULT_FEE)
|
|
61
|
+
runner = Runner(account)
|
|
62
|
+
|
|
63
|
+
# Load the strategy using backend logic
|
|
64
|
+
# RunRequest constructor expects strategy as (str | IO | Strategy)
|
|
65
|
+
strategy_obj = RunRequest.load_strategy(req_model.strategy, args=req_model.args)
|
|
66
|
+
|
|
67
|
+
logger.info("Running strategy...")
|
|
68
|
+
runner.run(strategy_obj)
|
|
69
|
+
logger.info("Strategy run completed")
|
|
70
|
+
|
|
71
|
+
# Build report
|
|
72
|
+
reports = build_report(dp, runner.ctx.accounts)[1:]
|
|
73
|
+
report = build_json_report(reports)
|
|
74
|
+
return report
|
|
75
|
+
|
|
76
|
+
except Exception as e:
|
|
77
|
+
logger.exception("Error during backtest execution")
|
|
78
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
if __name__ == "__main__":
|
|
82
|
+
import uvicorn
|
|
83
|
+
import argparse
|
|
84
|
+
|
|
85
|
+
parser = argparse.ArgumentParser(description="MSD Backtest Server")
|
|
86
|
+
parser.add_argument("--host", default="0.0.0.0", help="Listen host")
|
|
87
|
+
parser.add_argument("--port", type=int, default=8000, help="Listen port")
|
|
88
|
+
parser.add_argument(
|
|
89
|
+
"--msd", default=os.getenv("MSD_HOST", DEFAULT_MSD_HOST), help="Default MSD host"
|
|
90
|
+
)
|
|
91
|
+
parser.add_argument(
|
|
92
|
+
"--fee",
|
|
93
|
+
default=os.environ.get("MSD_BT_FEE", ""),
|
|
94
|
+
help="fee config path, env $MSD_BT_FEE",
|
|
95
|
+
)
|
|
96
|
+
args = parser.parse_args()
|
|
97
|
+
|
|
98
|
+
if len(args.fee) > 0:
|
|
99
|
+
DEFAULT_FEE = Fee(args.fee)
|
|
100
|
+
|
|
101
|
+
DEFAULT_MSD_HOST = args.msd
|
|
102
|
+
|
|
103
|
+
uvicorn.run(app, host=args.host, port=args.port)
|
mbt/select/__init__.py
ADDED
|
File without changes
|
mbt/strategy.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from mbt.account import Operation
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Context:
|
|
6
|
+
"""Context of a strategy"""
|
|
7
|
+
|
|
8
|
+
def __init__(self):
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
def order(self, op: Operation) -> Operation:
|
|
12
|
+
"""
|
|
13
|
+
execute an operation and return the result
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
op: operation to be executed
|
|
17
|
+
"""
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
def data(self, name: str, /, symbol: str | None = None) -> np.ndarray:
|
|
21
|
+
"""
|
|
22
|
+
return the corresponding data
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
name: name of the data
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
numpy array of the data
|
|
29
|
+
"""
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
def __getattr__(self, name: str) -> np.ndarray:
|
|
33
|
+
"""
|
|
34
|
+
return the corresponding data
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
name: name of the data
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
numpy array of the data
|
|
41
|
+
"""
|
|
42
|
+
return self.data(name)
|
|
43
|
+
|
|
44
|
+
def symbols(self) -> list[str]:
|
|
45
|
+
"""
|
|
46
|
+
return the symbols of the account
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
list of symbols
|
|
50
|
+
"""
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
def buy(self, flags: np.ndarray, percent: float = 1.0):
|
|
54
|
+
"""
|
|
55
|
+
buy a position
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
flags: boolean array of flags, True means buy
|
|
59
|
+
percent: percent of cash to buy
|
|
60
|
+
"""
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
def sell(self, flags: np.ndarray, percent: float = 1.0):
|
|
64
|
+
"""
|
|
65
|
+
sell a position
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
flags: boolean array of flags, True means sell
|
|
69
|
+
percent: percent of position to sell
|
|
70
|
+
"""
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class Strategy:
|
|
75
|
+
"""Base class of a strategy"""
|
|
76
|
+
|
|
77
|
+
def execute(self, ctx: Context):
|
|
78
|
+
"""
|
|
79
|
+
execute the strategy, this method will be called for each bar.
|
|
80
|
+
use ctx.order() to order, ctx.data() to get data
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
ctx: context of the strategy
|
|
84
|
+
"""
|
|
85
|
+
pass
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: msd-backtest
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MSD backtest framework
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: numpy>=2.4.2
|
|
8
|
+
Provides-Extra: alpha
|
|
9
|
+
Requires-Dist: py-alpha-lib>=0.2; extra == "alpha"
|
|
10
|
+
Provides-Extra: msd
|
|
11
|
+
Requires-Dist: pymsd>=0.1; extra == "msd"
|
|
12
|
+
Requires-Dist: requests>=2.32; extra == "msd"
|
|
13
|
+
Requires-Dist: pandas>=3.0; extra == "msd"
|
|
14
|
+
Provides-Extra: server
|
|
15
|
+
Requires-Dist: fastapi[standard]>=0.135.1; extra == "server"
|
|
16
|
+
Requires-Dist: msd-backtest[cli]; extra == "server"
|
|
17
|
+
Provides-Extra: cli
|
|
18
|
+
Requires-Dist: orjson>=3.11.9; extra == "cli"
|
|
19
|
+
Requires-Dist: msd-backtest[alpha,msd]; extra == "cli"
|
|
20
|
+
Requires-Dist: python-dotenv>=1.2.2; extra == "cli"
|
|
21
|
+
Requires-Dist: tabulate>=0.10.0; extra == "cli"
|
|
22
|
+
|
|
23
|
+
# msd-backtest
|
|
24
|
+
|
|
25
|
+
`msd-backtest` 是一个基于 Python 的高性能、向量化股票策略回测框架。它旨在为量化开发者提供一个简单、高效且灵活的工具,用于开发、测试和优化交易策略。
|
|
26
|
+
|
|
27
|
+
## 🌟 核心特性
|
|
28
|
+
|
|
29
|
+
- **高性能向量化计算**:核心数据处理基于 NumPy,支持大规模数据的快速回测。
|
|
30
|
+
- **多标的支持**:原生支持同时对多个股票或指数进行回测。
|
|
31
|
+
- **模块化架构**:
|
|
32
|
+
- `Account`:模拟真实交易账户,处理资金、持仓、手续费和滑点。
|
|
33
|
+
- `Strategy`:解耦策略逻辑,通过继承 `Strategy` 基类快速实现自定义逻辑。
|
|
34
|
+
- `DataProvider`:灵活的数据提供接口,支持接入不同的行情数据源。
|
|
35
|
+
- **完善的报表输出**:支持生成 CSV、Excel (XLSX) 和 JSON 格式的回测结果报表。
|
|
36
|
+
- **内置 MSD 集成**:支持从 MSD (Market Strategy Data) 服务端直接拉取行情和财务数据。
|
|
37
|
+
- **远程回测支持**:内置 FastAPI 服务器,支持跨语言或远程调用回测引擎。
|
|
38
|
+
|
|
39
|
+
## 🚀 快速开始
|
|
40
|
+
|
|
41
|
+
### 安装
|
|
42
|
+
|
|
43
|
+
推荐使用 `uv` 进行依赖管理:
|
|
44
|
+
|
|
45
|
+
#### 普通用户
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
uv add "msd-backtest[cli]" # 仅cli
|
|
49
|
+
# or
|
|
50
|
+
uv add "msd-backtest[server]" # 支持作为服务运行
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
#### 开发者
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# 克隆仓库
|
|
57
|
+
git clone https://github.com/your-repo/msd-backtest.git
|
|
58
|
+
cd msd-backtest
|
|
59
|
+
|
|
60
|
+
# 安装依赖
|
|
61
|
+
uv sync --with cli
|
|
62
|
+
|
|
63
|
+
# 如果需要运行回测服务器
|
|
64
|
+
uv sync --with server
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 运行回测
|
|
68
|
+
|
|
69
|
+
你可以通过命令行工具直接运行已有的策略:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
uv run python -m mbt.run.cli strategy/double_avg.py -s 000001.SZ 600000.SH --begin 2023-01-01 --end 2023-12-31 -o report.xlsx
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**常用参数说明:**
|
|
76
|
+
- `strategy`: 策略文件路径(`.py` 或 `.json`)。
|
|
77
|
+
- `-s`, `--symbols`: 股票代码列表。
|
|
78
|
+
- `-b`, `--begin`: 开始日期 (YYYY-MM-DD)。
|
|
79
|
+
- `-e`, `--end`: 结束日期 (YYYY-MM-DD)。
|
|
80
|
+
- `-o`, `--output`: 输出文件路径(支持 `.csv`, `.xlsx`, `.json`)。
|
|
81
|
+
|
|
82
|
+
## 🛡️ 回测机制:杜绝未来数据
|
|
83
|
+
|
|
84
|
+
`msd-backtest` 采用**逐条数据迭代**(Bar-by-Bar Iteration)的执行机制,确保回测过程的严谨性和真实性。
|
|
85
|
+
|
|
86
|
+
- **单向时间线**:回测引擎(`mbt.Runner`)严格按照时间顺序,逐个时间步调用策略的 `execute` 方法。
|
|
87
|
+
- **数据隔离**:在任一时刻,策略仅能通过 `ctx` 访问当前及之前的数据,无法窥视未来的行情。
|
|
88
|
+
- **真实模拟**:所有的买卖指令都在当前 Bar 生成,并在当前或下一个 Bar 的价格基础上执行(取决于配置和滑点),完美模拟真实市场的环境。
|
|
89
|
+
|
|
90
|
+
## 💡 编写你的策略
|
|
91
|
+
|
|
92
|
+
编写策略非常简单,只需要继承 `mbt.Strategy` 并实现 `execute` 方法:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from mbt import Strategy, Context
|
|
96
|
+
|
|
97
|
+
class MyStrategy(Strategy):
|
|
98
|
+
def __init__(self, fast_period=5, slow_period=20):
|
|
99
|
+
self.fast_period = fast_period
|
|
100
|
+
self.slow_period = slow_period
|
|
101
|
+
|
|
102
|
+
def execute(self, ctx: Context):
|
|
103
|
+
# 获取当前收盘价序列
|
|
104
|
+
close = ctx.close
|
|
105
|
+
|
|
106
|
+
# 计算移动平均线
|
|
107
|
+
# 注意:ctx 提供的是 NumPy 数组,支持向量化操作
|
|
108
|
+
# 这里仅为示意,实际开发中建议预计算指标
|
|
109
|
+
|
|
110
|
+
# 买入逻辑示例
|
|
111
|
+
# ctx.buy(buy_flags, percent=1.0)
|
|
112
|
+
|
|
113
|
+
# 卖出逻辑示例
|
|
114
|
+
# ctx.sell(sell_flags, percent=1.0)
|
|
115
|
+
pass
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## 🧠 AI 辅助策略编写
|
|
119
|
+
|
|
120
|
+
本项目深度集成 AI 辅助开发流程。利用 [msd_strategy](.agents/skills/write-strategy/SKILL.md) 技能,AI 可以根据用户描述自动生成符合规范的策略代码。
|
|
121
|
+
|
|
122
|
+
### 核心方法与目标
|
|
123
|
+
- **目标:** 通过自然语言描述,由 AI 生成高效、可运行的 Python 策略类。
|
|
124
|
+
- **技术栈:** Python 3.11+, NumPy, `py-alpha-lib`。
|
|
125
|
+
- **编码规范:**
|
|
126
|
+
- 必须继承 `mbt.Strategy`。
|
|
127
|
+
- 实现 `execute(self, ctx: mbt.Context)` 方法。
|
|
128
|
+
- 使用 `ctx.buy()` 和 `ctx.sell()` 进行下单。
|
|
129
|
+
|
|
130
|
+
### 常用算子库 (alpha-lib)
|
|
131
|
+
为了支持 AI 高效构建因子,框架内置了丰富的 `alpha-lib` 算子,包括:
|
|
132
|
+
- **时间序列算子:** `MA`, `EMA`, `HHV`, `LLV`, `STDDEV`, `CORR`, `SLOPE` 等。
|
|
133
|
+
- **横截面算子:** `CC_RANK`, `CC_ZSCORE`, `GROUP_RANK`, `NEUTRALIZE` 等。
|
|
134
|
+
- **逻辑算子:** `CROSS`, `LONGCROSS`, `BARSLAST` 等。
|
|
135
|
+
|
|
136
|
+
AI 在编写策略时应优先使用这些向量化算子,以确保最佳性能。
|
|
137
|
+
|
|
138
|
+
## 📂 项目结构
|
|
139
|
+
|
|
140
|
+
```text
|
|
141
|
+
.
|
|
142
|
+
├── mbt/ # 核心回测包
|
|
143
|
+
│ ├── account.py # 账户、持仓、手续费管理
|
|
144
|
+
│ ├── strategy.py # 策略基类与上下文定义
|
|
145
|
+
│ ├── data_provider.py # 数据提供接口
|
|
146
|
+
│ └── run/ # 运行引擎
|
|
147
|
+
│ ├── runner.py # 回测执行核心
|
|
148
|
+
│ ├── cli.py # 命令行界面
|
|
149
|
+
│ ├── msd.py # MSD 数据源接入
|
|
150
|
+
│ └── server.py # REST API 服务
|
|
151
|
+
├── strategy/ # 示例策略目录
|
|
152
|
+
├── tests/ # 单元测试
|
|
153
|
+
└── pyproject.toml # 项目配置与依赖说明
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## 🔧 进阶配置
|
|
157
|
+
|
|
158
|
+
### 手续费配置 (Fee)
|
|
159
|
+
|
|
160
|
+
在 `mbt/account.py` 中支持自定义手续费。你可以通过 JSON 配置文件或代码中初始化 `Fee` 类来设置不同时间段的印花税、过户费及佣金。
|
|
161
|
+
|
|
162
|
+
### 复权处理
|
|
163
|
+
|
|
164
|
+
`msd-backtest` 默认在 `mbt/run/msd.py` 中实现了前/后复权的计算逻辑,确保回测收益计算的准确性。
|
|
165
|
+
|
|
166
|
+
## 🛠️ 开发与测试
|
|
167
|
+
|
|
168
|
+
运行单元测试:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
uv run pytest
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
运行性能基准测试:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
uv run pytest --benchmark-only
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
*更多详细文档请参考各模块代码注释。*
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
mbt/__init__.py,sha256=4OzOWR9DtXwwcprjeq9EyPAc_nD2GfRjka5_QH56To8,503
|
|
2
|
+
mbt/account.py,sha256=SIJdlolAcZVcf6ctvjXLR956KAG9fe35iMD1FhEa52M,13375
|
|
3
|
+
mbt/data_provider.py,sha256=ZoG-rT2K-EFbC4Mi5mSdc-OaQy0E0nSFTRi3il63F9A,4142
|
|
4
|
+
mbt/strategy.py,sha256=krDT_EBGCR_HEw_-QKejnLfQ2M0gvdJWZD4zPC1KxXI,1555
|
|
5
|
+
mbt/run/__init__.py,sha256=KVdmGXMB0CZulU3IlcLpgVM4e8utSlsg4on504Z3CHI,165
|
|
6
|
+
mbt/run/backend.py,sha256=sh2LjlSCe-KqGu2qlqn7EWhCkPZwYHuPlR3eGxrB4Hs,2973
|
|
7
|
+
mbt/run/cli.py,sha256=EfxlGRnkBsgQ5hXTS4sfCUckK0K8ENGdLXtW_0mfi2A,5843
|
|
8
|
+
mbt/run/msd.py,sha256=yWhxFOt0x3ATv6mCT4LrvkOe4klWDIgzZxJj0psCw4k,2774
|
|
9
|
+
mbt/run/report.py,sha256=SERAHZ6LHnPvDWdgoWi4KTEU3DNVgVvePabcmsH1Cks,9951
|
|
10
|
+
mbt/run/review.py,sha256=udkiOG8E2bwNhGcILfJgkt-63oVLXCdgRYNmbryjUao,2192
|
|
11
|
+
mbt/run/runner.py,sha256=9YHciHsZZSsSWl8CMIqwVFEIwb_2JKUtQW0eLNiL0w0,2959
|
|
12
|
+
mbt/run/server.py,sha256=Rwqioec8g_vM2qv5sek7VdOxGu1LLFyZu4iQYx1ZyNI,3023
|
|
13
|
+
mbt/select/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
msd_backtest-0.1.0.dist-info/METADATA,sha256=dd4_Lu4tNjClc3d2guoZww2Uyt-nADLcV3_8s_XBrGg,6449
|
|
15
|
+
msd_backtest-0.1.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
16
|
+
msd_backtest-0.1.0.dist-info/top_level.txt,sha256=GXOojMcn-hI0kcRSUPX73WOB_zhHW35goKON-Rxu_dg,4
|
|
17
|
+
msd_backtest-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mbt
|