lightbt


Namelightbt JSON
Version 0.1.2 PyPI version JSON
download
home_page
Summarylightweight backtester
upload_time2023-08-19 12:31:09
maintainer
docs_urlNone
author
requires_python>=3.7
licenseBSD-3-Clause
keywords backtest
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # LightBT
轻量级回测工具

## 注意
每种工具都有其适合的应用场景。遇到需要快速评测大批量参数或因子的场景,我们只要相对准确。所以使用对数收益累加更合适

## 现状
1. 收益率乘权重的向量计算极快,但在连续做空的场景下,收益不正确,仅仅是因为每天收益率变化不大,所以误差很难察觉。
2. 大部分回测库策略与绩效统计结合过于紧密,达不到策略与平台分离的设想
3. 大部分回测库都很慢,如:`zipline`、`rqalpha`、`backtrader`
4. 回测快的库,底层一般是用`C++`、`Rust`等语言实现。跨语言部署和二次开发对量化研究员而言比较困难
5. `vectorbt`计算准确,回测也快。但不支持保证金无法直接用在期货市场,输入宽表比较占内存
6. `bt`策略树设计很好,但也不支持保证金概念

## 目标
1. 正确处理保证金和做空
2. 架构简单易扩展
3. 回测速度快

## 技术选型
1. `C++/Cython`开发,模仿`TA-Lib`的技术方案,`Cython`版库部署麻烦,开发也复杂
2. `Rust`开发,模仿`polars`的技术方案,使用`pyo3`进行跨语言调用,但`Rust`入门困难
3. `Numba`支持`JIT`,安装部署方便,易于调试和二次开发

## 三层结构
1. 开仓成交回报产生的持仓导致持仓盈亏、平仓成交回报产生平仓盈亏。将两种盈亏累计便成盈亏曲线
    - 已经可以统计盈亏、胜率、最大回撤等指标
2. 叠加初始资金即可构成资金曲线和净值曲线,可计算收益率、最大回撤率等指标
    - 没有考虑资金不足、是否能成交等情况。已经是简化回测绩效统计工具。仅能按手数进行交易
3. 初始资金和保证金率决定了可开手数
    - 关注交易细节,考虑资金不足等情况。可以按比例进行资金分配下单

## 工作原理
1. 使用对象来维护每种资产的交易信息。其中的成员变量全是最新值
2. 根据时间的推进和交易指令,更新对应对象
3. 指定时间间隔获取对象成员变量的快照,将所有快照连起来便成总体绩效
    - 月频交易,但日频取快照
    - 周频交易,周频取快照
    - 分钟交易,日频取快照

## 安装
```commandline
pip install lightbt -U
```
## 使用
以下是代码片段。完整代码请参考[stocks.py](examples/stocks.py)
```python
# %%
import numpy as np
import pandas as pd

from lightbt import LightBT, warmup
from lightbt.enums import SizeType
from lightbt.stats import pnl_by_assets, total_equity, pnl_by_asset
from lightbt.utils import Timer

# 省略代码......

# %% 热身
with Timer():
    print('warmup:', warmup())

# %% 初始化
bt = LightBT(max_trades=_N * _K, max_performances=_N * _K)
# 入金。必需先入金,否则资金为0无法交易
bt.deposit(10000 * 100)

# %% 配置资产信息
with Timer():
    bt.setup(conf)

# %% 交易
with Timer():
    bt.run_bars(groupby(orders_daily(df), by='date', dtype=order_outside_dt))

# %% 查看最终持仓
positions = bt.positions()
print(positions)
# %% 查看所有交易记录
trades = bt.trades()
print(trades)
# %% 查看绩效
perf = bt.performances()
print(perf)
# %% 总体绩效
equity = total_equity(perf)
print(equity)
equity.plot()

```

## 输入格式
1. date: int64
    - 时间日期。需在外部提前转成数字。可用`astype(np.int64)`或`to_records(dtype)`等方法来实现
2. size_type: int
    - 数量类型。参考`lightbt.enums.SizeType`
3. asset: int
    - 资产ID。由`LightBT.setup`执行结果所确定。可通过`LightBT.asset_str2int`和`LightBT.asset_int2str`进行相互转换
4. size: float
    - 数量。具体含义需根据`size_type`决定。`nan`是一特殊值。用来表示当前一行不交易。在只更新最新价的需求中将频繁用到。
5. fill_price: float
    - 成交价。成交价不等于最新价也不等于收盘价。可以用成交均价等一些有意义的价格进行代替。
6. last_price: float
    - 最新价。可用收盘价、结算价等代替。它影响持仓的浮动盈亏。所以在对绩效快照前一定要更新一次
7. date_diff: bool
    - 是否换日。在换日的最后时刻需要更新最新价和记录绩效

## 配置格式
通过`LightBT.setup`进行设置
1. asset: str
    - 资产名。内部将使用对应的int进行各项处理
2. mult: float
    - 合约乘数。股票的合约乘数为1.0
3. margin_ratio: float
    - 保证金率。股票的保证金率为1.0
4. commission_ratio: float
    - 手续费率参数。具体含义参考`commission_fn`
5. commission_fn:
    - 手续费处理函数
    

## 二次开发
```commandline
git --clone https://github.com/wukan1986/LightBT.git
cd LightBT
pip install -e .
```

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "lightbt",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "",
    "keywords": "backtest",
    "author": "",
    "author_email": "wukan <wu-kan@163.com>",
    "download_url": "https://files.pythonhosted.org/packages/64/6f/2af833ac068cd5f6058f82cdac96530320f97952019cc22469c650c7a3aa/lightbt-0.1.2.tar.gz",
    "platform": null,
    "description": "# LightBT\r\n\u8f7b\u91cf\u7ea7\u56de\u6d4b\u5de5\u5177\r\n\r\n## \u6ce8\u610f\r\n\u6bcf\u79cd\u5de5\u5177\u90fd\u6709\u5176\u9002\u5408\u7684\u5e94\u7528\u573a\u666f\u3002\u9047\u5230\u9700\u8981\u5feb\u901f\u8bc4\u6d4b\u5927\u6279\u91cf\u53c2\u6570\u6216\u56e0\u5b50\u7684\u573a\u666f\uff0c\u6211\u4eec\u53ea\u8981\u76f8\u5bf9\u51c6\u786e\u3002\u6240\u4ee5\u4f7f\u7528\u5bf9\u6570\u6536\u76ca\u7d2f\u52a0\u66f4\u5408\u9002\r\n\r\n## \u73b0\u72b6\r\n1. \u6536\u76ca\u7387\u4e58\u6743\u91cd\u7684\u5411\u91cf\u8ba1\u7b97\u6781\u5feb\uff0c\u4f46\u5728\u8fde\u7eed\u505a\u7a7a\u7684\u573a\u666f\u4e0b\uff0c\u6536\u76ca\u4e0d\u6b63\u786e\uff0c\u4ec5\u4ec5\u662f\u56e0\u4e3a\u6bcf\u5929\u6536\u76ca\u7387\u53d8\u5316\u4e0d\u5927\uff0c\u6240\u4ee5\u8bef\u5dee\u5f88\u96be\u5bdf\u89c9\u3002\r\n2. \u5927\u90e8\u5206\u56de\u6d4b\u5e93\u7b56\u7565\u4e0e\u7ee9\u6548\u7edf\u8ba1\u7ed3\u5408\u8fc7\u4e8e\u7d27\u5bc6\uff0c\u8fbe\u4e0d\u5230\u7b56\u7565\u4e0e\u5e73\u53f0\u5206\u79bb\u7684\u8bbe\u60f3\r\n3. \u5927\u90e8\u5206\u56de\u6d4b\u5e93\u90fd\u5f88\u6162\uff0c\u5982\uff1a`zipline`\u3001`rqalpha`\u3001`backtrader`\r\n4. \u56de\u6d4b\u5feb\u7684\u5e93\uff0c\u5e95\u5c42\u4e00\u822c\u662f\u7528`C++`\u3001`Rust`\u7b49\u8bed\u8a00\u5b9e\u73b0\u3002\u8de8\u8bed\u8a00\u90e8\u7f72\u548c\u4e8c\u6b21\u5f00\u53d1\u5bf9\u91cf\u5316\u7814\u7a76\u5458\u800c\u8a00\u6bd4\u8f83\u56f0\u96be\r\n5. `vectorbt`\u8ba1\u7b97\u51c6\u786e\uff0c\u56de\u6d4b\u4e5f\u5feb\u3002\u4f46\u4e0d\u652f\u6301\u4fdd\u8bc1\u91d1\u65e0\u6cd5\u76f4\u63a5\u7528\u5728\u671f\u8d27\u5e02\u573a\uff0c\u8f93\u5165\u5bbd\u8868\u6bd4\u8f83\u5360\u5185\u5b58\r\n6. `bt`\u7b56\u7565\u6811\u8bbe\u8ba1\u5f88\u597d\uff0c\u4f46\u4e5f\u4e0d\u652f\u6301\u4fdd\u8bc1\u91d1\u6982\u5ff5\r\n\r\n## \u76ee\u6807\r\n1. \u6b63\u786e\u5904\u7406\u4fdd\u8bc1\u91d1\u548c\u505a\u7a7a\r\n2. \u67b6\u6784\u7b80\u5355\u6613\u6269\u5c55\r\n3. \u56de\u6d4b\u901f\u5ea6\u5feb\r\n\r\n## \u6280\u672f\u9009\u578b\r\n1. `C++/Cython`\u5f00\u53d1\uff0c\u6a21\u4eff`TA-Lib`\u7684\u6280\u672f\u65b9\u6848\uff0c`Cython`\u7248\u5e93\u90e8\u7f72\u9ebb\u70e6\uff0c\u5f00\u53d1\u4e5f\u590d\u6742\r\n2. `Rust`\u5f00\u53d1\uff0c\u6a21\u4eff`polars`\u7684\u6280\u672f\u65b9\u6848\uff0c\u4f7f\u7528`pyo3`\u8fdb\u884c\u8de8\u8bed\u8a00\u8c03\u7528\uff0c\u4f46`Rust`\u5165\u95e8\u56f0\u96be\r\n3. `Numba`\u652f\u6301`JIT`\uff0c\u5b89\u88c5\u90e8\u7f72\u65b9\u4fbf\uff0c\u6613\u4e8e\u8c03\u8bd5\u548c\u4e8c\u6b21\u5f00\u53d1\r\n\r\n## \u4e09\u5c42\u7ed3\u6784\r\n1. \u5f00\u4ed3\u6210\u4ea4\u56de\u62a5\u4ea7\u751f\u7684\u6301\u4ed3\u5bfc\u81f4\u6301\u4ed3\u76c8\u4e8f\u3001\u5e73\u4ed3\u6210\u4ea4\u56de\u62a5\u4ea7\u751f\u5e73\u4ed3\u76c8\u4e8f\u3002\u5c06\u4e24\u79cd\u76c8\u4e8f\u7d2f\u8ba1\u4fbf\u6210\u76c8\u4e8f\u66f2\u7ebf\r\n    - \u5df2\u7ecf\u53ef\u4ee5\u7edf\u8ba1\u76c8\u4e8f\u3001\u80dc\u7387\u3001\u6700\u5927\u56de\u64a4\u7b49\u6307\u6807\r\n2. \u53e0\u52a0\u521d\u59cb\u8d44\u91d1\u5373\u53ef\u6784\u6210\u8d44\u91d1\u66f2\u7ebf\u548c\u51c0\u503c\u66f2\u7ebf\uff0c\u53ef\u8ba1\u7b97\u6536\u76ca\u7387\u3001\u6700\u5927\u56de\u64a4\u7387\u7b49\u6307\u6807\r\n    - \u6ca1\u6709\u8003\u8651\u8d44\u91d1\u4e0d\u8db3\u3001\u662f\u5426\u80fd\u6210\u4ea4\u7b49\u60c5\u51b5\u3002\u5df2\u7ecf\u662f\u7b80\u5316\u56de\u6d4b\u7ee9\u6548\u7edf\u8ba1\u5de5\u5177\u3002\u4ec5\u80fd\u6309\u624b\u6570\u8fdb\u884c\u4ea4\u6613\r\n3. \u521d\u59cb\u8d44\u91d1\u548c\u4fdd\u8bc1\u91d1\u7387\u51b3\u5b9a\u4e86\u53ef\u5f00\u624b\u6570\r\n    - \u5173\u6ce8\u4ea4\u6613\u7ec6\u8282\uff0c\u8003\u8651\u8d44\u91d1\u4e0d\u8db3\u7b49\u60c5\u51b5\u3002\u53ef\u4ee5\u6309\u6bd4\u4f8b\u8fdb\u884c\u8d44\u91d1\u5206\u914d\u4e0b\u5355\r\n\r\n## \u5de5\u4f5c\u539f\u7406\r\n1. \u4f7f\u7528\u5bf9\u8c61\u6765\u7ef4\u62a4\u6bcf\u79cd\u8d44\u4ea7\u7684\u4ea4\u6613\u4fe1\u606f\u3002\u5176\u4e2d\u7684\u6210\u5458\u53d8\u91cf\u5168\u662f\u6700\u65b0\u503c\r\n2. \u6839\u636e\u65f6\u95f4\u7684\u63a8\u8fdb\u548c\u4ea4\u6613\u6307\u4ee4\uff0c\u66f4\u65b0\u5bf9\u5e94\u5bf9\u8c61\r\n3. \u6307\u5b9a\u65f6\u95f4\u95f4\u9694\u83b7\u53d6\u5bf9\u8c61\u6210\u5458\u53d8\u91cf\u7684\u5feb\u7167\uff0c\u5c06\u6240\u6709\u5feb\u7167\u8fde\u8d77\u6765\u4fbf\u6210\u603b\u4f53\u7ee9\u6548\r\n    - \u6708\u9891\u4ea4\u6613\uff0c\u4f46\u65e5\u9891\u53d6\u5feb\u7167\r\n    - \u5468\u9891\u4ea4\u6613\uff0c\u5468\u9891\u53d6\u5feb\u7167\r\n    - \u5206\u949f\u4ea4\u6613\uff0c\u65e5\u9891\u53d6\u5feb\u7167\r\n\r\n## \u5b89\u88c5\r\n```commandline\r\npip install lightbt -U\r\n```\r\n## \u4f7f\u7528\r\n\u4ee5\u4e0b\u662f\u4ee3\u7801\u7247\u6bb5\u3002\u5b8c\u6574\u4ee3\u7801\u8bf7\u53c2\u8003[stocks.py](examples/stocks.py)\r\n```python\r\n# %%\r\nimport numpy as np\r\nimport pandas as pd\r\n\r\nfrom lightbt import LightBT, warmup\r\nfrom lightbt.enums import SizeType\r\nfrom lightbt.stats import pnl_by_assets, total_equity, pnl_by_asset\r\nfrom lightbt.utils import Timer\r\n\r\n# \u7701\u7565\u4ee3\u7801......\r\n\r\n# %% \u70ed\u8eab\r\nwith Timer():\r\n    print('warmup:', warmup())\r\n\r\n# %% \u521d\u59cb\u5316\r\nbt = LightBT(max_trades=_N * _K, max_performances=_N * _K)\r\n# \u5165\u91d1\u3002\u5fc5\u9700\u5148\u5165\u91d1\uff0c\u5426\u5219\u8d44\u91d1\u4e3a0\u65e0\u6cd5\u4ea4\u6613\r\nbt.deposit(10000 * 100)\r\n\r\n# %% \u914d\u7f6e\u8d44\u4ea7\u4fe1\u606f\r\nwith Timer():\r\n    bt.setup(conf)\r\n\r\n# %% \u4ea4\u6613\r\nwith Timer():\r\n    bt.run_bars(groupby(orders_daily(df), by='date', dtype=order_outside_dt))\r\n\r\n# %% \u67e5\u770b\u6700\u7ec8\u6301\u4ed3\r\npositions = bt.positions()\r\nprint(positions)\r\n# %% \u67e5\u770b\u6240\u6709\u4ea4\u6613\u8bb0\u5f55\r\ntrades = bt.trades()\r\nprint(trades)\r\n# %% \u67e5\u770b\u7ee9\u6548\r\nperf = bt.performances()\r\nprint(perf)\r\n# %% \u603b\u4f53\u7ee9\u6548\r\nequity = total_equity(perf)\r\nprint(equity)\r\nequity.plot()\r\n\r\n```\r\n\r\n## \u8f93\u5165\u683c\u5f0f\r\n1. date: int64\r\n    - \u65f6\u95f4\u65e5\u671f\u3002\u9700\u5728\u5916\u90e8\u63d0\u524d\u8f6c\u6210\u6570\u5b57\u3002\u53ef\u7528`astype(np.int64)`\u6216`to_records(dtype)`\u7b49\u65b9\u6cd5\u6765\u5b9e\u73b0\r\n2. size_type: int\r\n    - \u6570\u91cf\u7c7b\u578b\u3002\u53c2\u8003`lightbt.enums.SizeType`\r\n3. asset: int\r\n    - \u8d44\u4ea7ID\u3002\u7531`LightBT.setup`\u6267\u884c\u7ed3\u679c\u6240\u786e\u5b9a\u3002\u53ef\u901a\u8fc7`LightBT.asset_str2int`\u548c`LightBT.asset_int2str`\u8fdb\u884c\u76f8\u4e92\u8f6c\u6362\r\n4. size: float\r\n    - \u6570\u91cf\u3002\u5177\u4f53\u542b\u4e49\u9700\u6839\u636e`size_type`\u51b3\u5b9a\u3002`nan`\u662f\u4e00\u7279\u6b8a\u503c\u3002\u7528\u6765\u8868\u793a\u5f53\u524d\u4e00\u884c\u4e0d\u4ea4\u6613\u3002\u5728\u53ea\u66f4\u65b0\u6700\u65b0\u4ef7\u7684\u9700\u6c42\u4e2d\u5c06\u9891\u7e41\u7528\u5230\u3002\r\n5. fill_price: float\r\n    - \u6210\u4ea4\u4ef7\u3002\u6210\u4ea4\u4ef7\u4e0d\u7b49\u4e8e\u6700\u65b0\u4ef7\u4e5f\u4e0d\u7b49\u4e8e\u6536\u76d8\u4ef7\u3002\u53ef\u4ee5\u7528\u6210\u4ea4\u5747\u4ef7\u7b49\u4e00\u4e9b\u6709\u610f\u4e49\u7684\u4ef7\u683c\u8fdb\u884c\u4ee3\u66ff\u3002\r\n6. last_price: float\r\n    - \u6700\u65b0\u4ef7\u3002\u53ef\u7528\u6536\u76d8\u4ef7\u3001\u7ed3\u7b97\u4ef7\u7b49\u4ee3\u66ff\u3002\u5b83\u5f71\u54cd\u6301\u4ed3\u7684\u6d6e\u52a8\u76c8\u4e8f\u3002\u6240\u4ee5\u5728\u5bf9\u7ee9\u6548\u5feb\u7167\u524d\u4e00\u5b9a\u8981\u66f4\u65b0\u4e00\u6b21\r\n7. date_diff: bool\r\n    - \u662f\u5426\u6362\u65e5\u3002\u5728\u6362\u65e5\u7684\u6700\u540e\u65f6\u523b\u9700\u8981\u66f4\u65b0\u6700\u65b0\u4ef7\u548c\u8bb0\u5f55\u7ee9\u6548\r\n\r\n## \u914d\u7f6e\u683c\u5f0f\r\n\u901a\u8fc7`LightBT.setup`\u8fdb\u884c\u8bbe\u7f6e\r\n1. asset: str\r\n    - \u8d44\u4ea7\u540d\u3002\u5185\u90e8\u5c06\u4f7f\u7528\u5bf9\u5e94\u7684int\u8fdb\u884c\u5404\u9879\u5904\u7406\r\n2. mult: float\r\n    - \u5408\u7ea6\u4e58\u6570\u3002\u80a1\u7968\u7684\u5408\u7ea6\u4e58\u6570\u4e3a1.0\r\n3. margin_ratio: float\r\n    - \u4fdd\u8bc1\u91d1\u7387\u3002\u80a1\u7968\u7684\u4fdd\u8bc1\u91d1\u7387\u4e3a1.0\r\n4. commission_ratio: float\r\n    - \u624b\u7eed\u8d39\u7387\u53c2\u6570\u3002\u5177\u4f53\u542b\u4e49\u53c2\u8003`commission_fn`\r\n5. commission_fn:\r\n    - \u624b\u7eed\u8d39\u5904\u7406\u51fd\u6570\r\n    \r\n\r\n## \u4e8c\u6b21\u5f00\u53d1\r\n```commandline\r\ngit --clone https://github.com/wukan1986/LightBT.git\r\ncd LightBT\r\npip install -e .\r\n```\r\n",
    "bugtrack_url": null,
    "license": "BSD-3-Clause",
    "summary": "lightweight backtester",
    "version": "0.1.2",
    "project_urls": null,
    "split_keywords": [
        "backtest"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "80d9a81edf679e76e835219e78442f28c2a6647ffe77e6061df131c1529aa5ff",
                "md5": "b719743666d813db93955b82e8ebcbff",
                "sha256": "f36397d47ba3cc270464a898491fb9b7781f55aef1cadaa597e3efad53d88c56"
            },
            "downloads": -1,
            "filename": "lightbt-0.1.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "b719743666d813db93955b82e8ebcbff",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 22378,
            "upload_time": "2023-08-19T12:31:07",
            "upload_time_iso_8601": "2023-08-19T12:31:07.812615Z",
            "url": "https://files.pythonhosted.org/packages/80/d9/a81edf679e76e835219e78442f28c2a6647ffe77e6061df131c1529aa5ff/lightbt-0.1.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "646f2af833ac068cd5f6058f82cdac96530320f97952019cc22469c650c7a3aa",
                "md5": "320d63d4ad3fc7b66e4b168bf36e5659",
                "sha256": "8dd17e2be6089594175bfd984b373fa9b0a3de667af47b5ddd57a1d9c41ff3a5"
            },
            "downloads": -1,
            "filename": "lightbt-0.1.2.tar.gz",
            "has_sig": false,
            "md5_digest": "320d63d4ad3fc7b66e4b168bf36e5659",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 20750,
            "upload_time": "2023-08-19T12:31:09",
            "upload_time_iso_8601": "2023-08-19T12:31:09.693118Z",
            "url": "https://files.pythonhosted.org/packages/64/6f/2af833ac068cd5f6058f82cdac96530320f97952019cc22469c650c7a3aa/lightbt-0.1.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-08-19 12:31:09",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "lightbt"
}
        
Elapsed time: 0.10150s