# zvt
**Repository Path**: sshling/zvt
## Basic Information
- **Project Name**: zvt
- **Description**: ZVT是对fooltrader重新思考后编写的量化项目,其包含可扩展的数据recorder,api,因子计算,选股,回测,交易,以及统一的可视化,定位为中低频 多级别 多因子 多标的 全市场分析和交易框架。
- **Primary Language**: Python
- **License**: MIT
- **Default Branch**: master
- **Homepage**: https://zvt.readthedocs.io/en/latest/
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 311
- **Created**: 2023-05-28
- **Last Updated**: 2023-05-28
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
[](https://github.com/zvtvz/zvt)
[](https://pypi.org/project/zvt/)
[](https://pypi.org/project/zvt/)
[](https://pypi.org/project/zvt/)
[](https://github.com/zvtvz/zvt/actions/workflows/build.yml)
[](https://github.com/zvtvz/zvt/actions/workflows/package.yaml)
[](https://zvt.readthedocs.io/en/latest/?badge=latest)
[](https://codecov.io/github/zvtvz/zvt)
[](https://pepy.tech/project/zvt)
**Read this in other languages: [English](README-cn.md).**  
**详细文档:[https://zvt.readthedocs.io/en/latest/](https://zvt.readthedocs.io/en/latest/)**
## 市场模型
ZVT 将市场抽象为如下的模型:

* TradableEntity (交易标的)
* ActorEntity (市场参与者)
* EntityEvent (交易标的 和 市场参与者 发生的事件)
## 快速开始
### 安装
```
python3 -m pip install -U zvt
```
### 使用展示
#### 主界面
安装完成后,在命令行下输入 zvt
```shell
zvt
```
打开 [http://127.0.0.1:8050/](http://127.0.0.1:8050/)
> 这里展示的例子依赖后面的下载历史数据,数据更新请参考后面文档


> 系统的核心概念是可视化的,界面的名称与其一一对应,因此也是统一可扩展的。
> 你可以在你喜欢的ide里编写和运行策略,然后运行界面查看其相关的标的,因子,信号和净值展示。
#### 见证奇迹的时刻
```
>>> from zvt.domain import Stock, Stock1dHfqKdata
>>> from zvt.ml import MaStockMLMachine
>>> Stock.record_data(provider="em")
>>> entity_ids = ["stock_sz_000001", "stock_sz_000338", "stock_sh_601318"]
>>> Stock1dHfqKdata.record_data(provider="em", entity_ids=entity_ids, sleeping_time=1)
>>> machine = MaStockMLMachine(entity_ids=["stock_sz_000001"], data_provider="em")
>>> machine.train()
>>> machine.predict()
>>> machine.draw_result(entity_id="stock_sz_000001")
```

> 以上几行代码实现了:数据的抓取,持久化,增量更新,机器学习,预测,展示结果。
> 熟悉系统的核心概念后,可以应用到市场中的任何标的。
### 核心概念
```
>>> from zvt.domain import *
```
### TradableEntity (交易标的)
#### A股交易标的
```
>>> Stock.record_data()
>>> df = Stock.query_data(index='code')
>>> print(df)
                     id        entity_id  timestamp entity_type exchange    code   name  list_date end_date
code
000001  stock_sz_000001  stock_sz_000001 1991-04-03       stock       sz  000001   平安银行 1991-04-03     None
000002  stock_sz_000002  stock_sz_000002 1991-01-29       stock       sz  000002  万  科A 1991-01-29     None
000004  stock_sz_000004  stock_sz_000004 1990-12-01       stock       sz  000004   国华网安 1990-12-01     None
000005  stock_sz_000005  stock_sz_000005 1990-12-10       stock       sz  000005   世纪星源 1990-12-10     None
000006  stock_sz_000006  stock_sz_000006 1992-04-27       stock       sz  000006   深振业A 1992-04-27     None
...                 ...              ...        ...         ...      ...     ...    ...        ...      ...
605507  stock_sh_605507  stock_sh_605507 2021-08-02       stock       sh  605507   国邦医药 2021-08-02     None
605577  stock_sh_605577  stock_sh_605577 2021-08-24       stock       sh  605577   龙版传媒 2021-08-24     None
605580  stock_sh_605580  stock_sh_605580 2021-08-19       stock       sh  605580   恒盛能源 2021-08-19     None
605588  stock_sh_605588  stock_sh_605588 2021-08-12       stock       sh  605588   冠石科技 2021-08-12     None
605589  stock_sh_605589  stock_sh_605589 2021-08-10       stock       sh  605589   圣泉集团 2021-08-10     None
[4136 rows x 9 columns]
```
#### 美股交易标的
```
>>> Stockus.record_data()
>>> df = Stockus.query_data(index='code')
>>> print(df)
                       id            entity_id timestamp entity_type exchange  code                         name list_date end_date
code
A          stockus_nyse_A       stockus_nyse_A       NaT     stockus     nyse     A                          安捷伦      None     None
AA        stockus_nyse_AA      stockus_nyse_AA       NaT     stockus     nyse    AA                         美国铝业      None     None
AAC      stockus_nyse_AAC     stockus_nyse_AAC       NaT     stockus     nyse   AAC      Ares Acquisition Corp-A      None     None
AACG  stockus_nasdaq_AACG  stockus_nasdaq_AACG       NaT     stockus   nasdaq  AACG    ATA Creativity Global ADR      None     None
AACG    stockus_nyse_AACG    stockus_nyse_AACG       NaT     stockus     nyse  AACG    ATA Creativity Global ADR      None     None
...                   ...                  ...       ...         ...      ...   ...                          ...       ...      ...
ZWRK  stockus_nasdaq_ZWRK  stockus_nasdaq_ZWRK       NaT     stockus   nasdaq  ZWRK    Z-Work Acquisition Corp-A      None     None
ZY      stockus_nasdaq_ZY    stockus_nasdaq_ZY       NaT     stockus   nasdaq    ZY                 Zymergen Inc      None     None
ZYME    stockus_nyse_ZYME    stockus_nyse_ZYME       NaT     stockus     nyse  ZYME                Zymeworks Inc      None     None
ZYNE  stockus_nasdaq_ZYNE  stockus_nasdaq_ZYNE       NaT     stockus   nasdaq  ZYNE  Zynerba Pharmaceuticals Inc      None     None
ZYXI  stockus_nasdaq_ZYXI  stockus_nasdaq_ZYXI       NaT     stockus   nasdaq  ZYXI                    Zynex Inc      None     None
[5826 rows x 9 columns]
>>> Stockus.query_data(code='AAPL')
                    id            entity_id timestamp entity_type exchange  code name list_date end_date
0  stockus_nasdaq_AAPL  stockus_nasdaq_AAPL      None     stockus   nasdaq  AAPL   苹果      None     None
```
#### 港股交易标的
```
>>> Stockhk.record_data()
>>> df = Stockhk.query_data(index='code')
>>> print(df)
                     id         entity_id timestamp entity_type exchange   code    name list_date end_date
code
00001  stockhk_hk_00001  stockhk_hk_00001       NaT     stockhk       hk  00001      长和      None     None
00002  stockhk_hk_00002  stockhk_hk_00002       NaT     stockhk       hk  00002    中电控股      None     None
00003  stockhk_hk_00003  stockhk_hk_00003       NaT     stockhk       hk  00003  香港中华煤气      None     None
00004  stockhk_hk_00004  stockhk_hk_00004       NaT     stockhk       hk  00004   九龙仓集团      None     None
00005  stockhk_hk_00005  stockhk_hk_00005       NaT     stockhk       hk  00005    汇丰控股      None     None
...                 ...               ...       ...         ...      ...    ...     ...       ...      ...
09996  stockhk_hk_09996  stockhk_hk_09996       NaT     stockhk       hk  09996  沛嘉医疗-B      None     None
09997  stockhk_hk_09997  stockhk_hk_09997       NaT     stockhk       hk  09997    康基医疗      None     None
09998  stockhk_hk_09998  stockhk_hk_09998       NaT     stockhk       hk  09998    光荣控股      None     None
09999  stockhk_hk_09999  stockhk_hk_09999       NaT     stockhk       hk  09999    网易-S      None     None
80737  stockhk_hk_80737  stockhk_hk_80737       NaT     stockhk       hk  80737  湾区发展-R      None     None
[2597 rows x 9 columns]
>>> df[df.code=='00700']
                    id         entity_id timestamp entity_type exchange   code  name list_date end_date
2112  stockhk_hk_00700  stockhk_hk_00700      None     stockhk       hk  00700  腾讯控股      None     None
```
#### 还有更多
```
>>> from zvt.contract import *
>>> zvt_context.tradable_schema_map
{'stockus': zvt.domain.meta.stockus_meta.Stockus,
 'stockhk': zvt.domain.meta.stockhk_meta.Stockhk,
 'index': zvt.domain.meta.index_meta.Index,
 'etf': zvt.domain.meta.etf_meta.Etf,
 'stock': zvt.domain.meta.stock_meta.Stock,
 'block': zvt.domain.meta.block_meta.Block,
 'fund': zvt.domain.meta.fund_meta.Fund}
```
其中key为交易标的的类型,value为其schema,系统为schema提供了统一的 **记录(record_data)** 和 **查询(query_data)** 方法。
```
>>> Index.record_data()
>>> df=Index.query_data(filters=[Index.category=='scope',Index.exchange='sh'])
>>> print(df)
                 id        entity_id  timestamp entity_type exchange    code    name  list_date end_date publisher category  base_point
0   index_sh_000001  index_sh_000001 1990-12-19       index       sh  000001    上证指数 1991-07-15     None   csindex    scope      100.00
1   index_sh_000002  index_sh_000002 1990-12-19       index       sh  000002    A股指数 1992-02-21     None   csindex    scope      100.00
2   index_sh_000003  index_sh_000003 1992-02-21       index       sh  000003    B股指数 1992-08-17     None   csindex    scope      100.00
3   index_sh_000010  index_sh_000010 2002-06-28       index       sh  000010   上证180 2002-07-01     None   csindex    scope     3299.06
4   index_sh_000016  index_sh_000016 2003-12-31       index       sh  000016    上证50 2004-01-02     None   csindex    scope     1000.00
..              ...              ...        ...         ...      ...     ...     ...        ...      ...       ...      ...         ...
25  index_sh_000020  index_sh_000020 2007-12-28       index       sh  000020    中型综指 2008-05-12     None   csindex    scope     1000.00
26  index_sh_000090  index_sh_000090 2009-12-31       index       sh  000090    上证流通 2010-12-02     None   csindex    scope     1000.00
27  index_sh_930903  index_sh_930903 2012-12-31       index       sh  930903    中证A股 2016-10-18     None   csindex    scope     1000.00
28  index_sh_000688  index_sh_000688 2019-12-31       index       sh  000688    科创50 2020-07-23     None   csindex    scope     1000.00
29  index_sh_931643  index_sh_931643 2019-12-31       index       sh  931643  科创创业50 2021-06-01     None   csindex    scope     1000.00
[30 rows x 12 columns]
```
### EntityEvent (交易标的 发生的事件)
有了交易标的,才有交易标的 发生的事。
#### 行情数据
交易标的 **行情schema** 遵从如下的规则:
```
{entity_shema}{level}{adjust_type}Kdata
```
* entity_schema
就是前面说的TradableEntity,比如Stock,Stockus等。
* level
```
>>> for level in IntervalLevel:
        print(level.value)
```
* adjust type
```
>>> for adjust_type in AdjustType:
        print(adjust_type.value)
```
> 注意: 为了兼容历史数据,前复权是个例外,{adjust_type}不填
前复权
```
>>> Stock1dKdata.record_data(code='000338', provider='em')
>>> df = Stock1dKdata.query_data(code='000338', provider='em')
>>> print(df)
                              id        entity_id  timestamp provider    code  name level   open  close   high    low     volume      turnover  change_pct  turnover_rate
0     stock_sz_000338_2007-04-30  stock_sz_000338 2007-04-30     None  000338  潍柴动力    1d   2.33   2.00   2.40   1.87   207375.0  1.365189e+09      3.2472         0.1182
1     stock_sz_000338_2007-05-08  stock_sz_000338 2007-05-08     None  000338  潍柴动力    1d   2.11   1.94   2.20   1.87    86299.0  5.563198e+08     -0.0300         0.0492
2     stock_sz_000338_2007-05-09  stock_sz_000338 2007-05-09     None  000338  潍柴动力    1d   1.90   1.81   1.94   1.66    93823.0  5.782065e+08     -0.0670         0.0535
3     stock_sz_000338_2007-05-10  stock_sz_000338 2007-05-10     None  000338  潍柴动力    1d   1.78   1.85   1.98   1.75    47720.0  2.999226e+08      0.0221         0.0272
4     stock_sz_000338_2007-05-11  stock_sz_000338 2007-05-11     None  000338  潍柴动力    1d   1.81   1.73   1.81   1.66    39273.0  2.373126e+08     -0.0649         0.0224
...                          ...              ...        ...      ...     ...   ...   ...    ...    ...    ...    ...        ...           ...         ...            ...
3426  stock_sz_000338_2021-08-27  stock_sz_000338 2021-08-27     None  000338  潍柴动力    1d  19.39  20.30  20.30  19.25  1688497.0  3.370241e+09      0.0601         0.0398
3427  stock_sz_000338_2021-08-30  stock_sz_000338 2021-08-30     None  000338  潍柴动力    1d  20.30  20.09  20.31  19.78  1187601.0  2.377957e+09     -0.0103         0.0280
3428  stock_sz_000338_2021-08-31  stock_sz_000338 2021-08-31     None  000338  潍柴动力    1d  20.20  20.07  20.63  19.70  1143985.0  2.295195e+09     -0.0010         0.0270
3429  stock_sz_000338_2021-09-01  stock_sz_000338 2021-09-01     None  000338  潍柴动力    1d  19.98  19.68  19.98  19.15  1218697.0  2.383841e+09     -0.0194         0.0287
3430  stock_sz_000338_2021-09-02  stock_sz_000338 2021-09-02     None  000338  潍柴动力    1d  19.71  19.85  19.97  19.24  1023545.0  2.012006e+09      0.0086         0.0241
[3431 rows x 15 columns]
>>> Stockus1dKdata.record_data(code='AAPL', provider='em')
>>> df = Stockus1dKdata.query_data(code='AAPL', provider='em')
>>> print(df)
                                  id            entity_id  timestamp provider  code name level    open   close    high     low      volume      turnover  change_pct  turnover_rate
0     stockus_nasdaq_AAPL_1984-09-07  stockus_nasdaq_AAPL 1984-09-07     None  AAPL   苹果    1d   -5.59   -5.59   -5.58   -5.59   2981600.0  0.000000e+00      0.0000         0.0002
1     stockus_nasdaq_AAPL_1984-09-10  stockus_nasdaq_AAPL 1984-09-10     None  AAPL   苹果    1d   -5.59   -5.59   -5.58   -5.59   2346400.0  0.000000e+00      0.0000         0.0001
2     stockus_nasdaq_AAPL_1984-09-11  stockus_nasdaq_AAPL 1984-09-11     None  AAPL   苹果    1d   -5.58   -5.58   -5.58   -5.58   5444000.0  0.000000e+00      0.0018         0.0003
3     stockus_nasdaq_AAPL_1984-09-12  stockus_nasdaq_AAPL 1984-09-12     None  AAPL   苹果    1d   -5.58   -5.59   -5.58   -5.59   4773600.0  0.000000e+00     -0.0018         0.0003
4     stockus_nasdaq_AAPL_1984-09-13  stockus_nasdaq_AAPL 1984-09-13     None  AAPL   苹果    1d   -5.58   -5.58   -5.58   -5.58   7429600.0  0.000000e+00      0.0018         0.0004
...                              ...                  ...        ...      ...   ...  ...   ...     ...     ...     ...     ...         ...           ...         ...            ...
8765  stockus_nasdaq_AAPL_2021-08-27  stockus_nasdaq_AAPL 2021-08-27     None  AAPL   苹果    1d  147.48  148.60  148.75  146.83  55802388.0  8.265452e+09      0.0072         0.0034
8766  stockus_nasdaq_AAPL_2021-08-30  stockus_nasdaq_AAPL 2021-08-30     None  AAPL   苹果    1d  149.00  153.12  153.49  148.61  90956723.0  1.383762e+10      0.0304         0.0055
8767  stockus_nasdaq_AAPL_2021-08-31  stockus_nasdaq_AAPL 2021-08-31     None  AAPL   苹果    1d  152.66  151.83  152.80  151.29  86453117.0  1.314255e+10     -0.0084         0.0052
8768  stockus_nasdaq_AAPL_2021-09-01  stockus_nasdaq_AAPL 2021-09-01     None  AAPL   苹果    1d  152.83  152.51  154.98  152.34  80313711.0  1.235321e+10      0.0045         0.0049
8769  stockus_nasdaq_AAPL_2021-09-02  stockus_nasdaq_AAPL 2021-09-02     None  AAPL   苹果    1d  153.87  153.65  154.72  152.40  71171317.0  1.093251e+10      0.0075         0.0043
[8770 rows x 15 columns]
```
后复权
```
>>> Stock1dHfqKdata.record_data(code='000338', provider='em')
>>> df = Stock1dHfqKdata.query_data(code='000338', provider='em')
>>> print(df)
                              id        entity_id  timestamp provider    code  name level    open   close    high     low     volume      turnover  change_pct  turnover_rate
0     stock_sz_000338_2007-04-30  stock_sz_000338 2007-04-30     None  000338  潍柴动力    1d   70.00   64.93   71.00   62.88   207375.0  1.365189e+09      2.1720         0.1182
1     stock_sz_000338_2007-05-08  stock_sz_000338 2007-05-08     None  000338  潍柴动力    1d   66.60   64.00   68.00   62.88    86299.0  5.563198e+08     -0.0143         0.0492
2     stock_sz_000338_2007-05-09  stock_sz_000338 2007-05-09     None  000338  潍柴动力    1d   63.32   62.00   63.88   59.60    93823.0  5.782065e+08     -0.0313         0.0535
3     stock_sz_000338_2007-05-10  stock_sz_000338 2007-05-10     None  000338  潍柴动力    1d   61.50   62.49   64.48   61.01    47720.0  2.999226e+08      0.0079         0.0272
4     stock_sz_000338_2007-05-11  stock_sz_000338 2007-05-11     None  000338  潍柴动力    1d   61.90   60.65   61.90   59.70    39273.0  2.373126e+08     -0.0294         0.0224
...                          ...              ...        ...      ...     ...   ...   ...     ...     ...     ...     ...        ...           ...         ...            ...
3426  stock_sz_000338_2021-08-27  stock_sz_000338 2021-08-27     None  000338  潍柴动力    1d  331.97  345.95  345.95  329.82  1688497.0  3.370241e+09      0.0540         0.0398
3427  stock_sz_000338_2021-08-30  stock_sz_000338 2021-08-30     None  000338  潍柴动力    1d  345.95  342.72  346.10  337.96  1187601.0  2.377957e+09     -0.0093         0.0280
3428  stock_sz_000338_2021-08-31  stock_sz_000338 2021-08-31     None  000338  潍柴动力    1d  344.41  342.41  351.02  336.73  1143985.0  2.295195e+09     -0.0009         0.0270
3429  stock_sz_000338_2021-09-01  stock_sz_000338 2021-09-01     None  000338  潍柴动力    1d  341.03  336.42  341.03  328.28  1218697.0  2.383841e+09     -0.0175         0.0287
3430  stock_sz_000338_2021-09-02  stock_sz_000338 2021-09-02     None  000338  潍柴动力    1d  336.88  339.03  340.88  329.67  1023545.0  2.012006e+09      0.0078         0.0241
[3431 rows x 15 columns]
```
#### 财务因子
```
>>> FinanceFactor.record_data(code='000338')
>>> FinanceFactor.query_data(code='000338',columns=FinanceFactor.important_cols(),index='timestamp')
            basic_eps  total_op_income    net_profit  op_income_growth_yoy  net_profit_growth_yoy     roe    rota  gross_profit_margin  net_margin  timestamp
timestamp
2002-12-31        NaN     1.962000e+07  2.471000e+06                   NaN                    NaN     NaN     NaN               0.2068      0.1259 2002-12-31
2003-12-31       1.27     3.574000e+09  2.739000e+08              181.2022               109.8778  0.7729  0.1783               0.2551      0.0766 2003-12-31
2004-12-31       1.75     6.188000e+09  5.369000e+08                0.7313                 0.9598  0.3245  0.1474               0.2489      0.0868 2004-12-31
2005-12-31       0.93     5.283000e+09  3.065000e+08               -0.1463                -0.4291  0.1327  0.0603               0.2252      0.0583 2005-12-31
2006-03-31       0.33     1.859000e+09  1.079000e+08                   NaN                    NaN     NaN     NaN                  NaN      0.0598 2006-03-31
...               ...              ...           ...                   ...                    ...     ...     ...                  ...         ...        ...
2020-08-28       0.59     9.449000e+10  4.680000e+09                0.0400                -0.1148  0.0983  0.0229               0.1958      0.0603 2020-08-28
2020-10-31       0.90     1.474000e+11  7.106000e+09                0.1632                 0.0067  0.1502  0.0347               0.1949      0.0590 2020-10-31
2021-03-31       1.16     1.975000e+11  9.207000e+09                0.1327                 0.0112  0.1919  0.0444               0.1931      0.0571 2021-03-31
2021-04-30       0.42     6.547000e+10  3.344000e+09                0.6788                 0.6197  0.0622  0.0158               0.1916      0.0667 2021-04-30
2021-08-31       0.80     1.264000e+11  6.432000e+09                0.3375                 0.3742  0.1125  0.0287               0.1884      0.0653 2021-08-31
[66 rows x 10 columns]
```
#### 财务三张表
```
#资产负债表
>>> BalanceSheet.record_data(code='000338')
#利润表
>>> IncomeStatement.record_data(code='000338')
#现金流量表
>>> CashFlowStatement.record_data(code='000338')
```
#### 还有更多
```
>>> zvt_context.schemas
[zvt.domain.dividend_financing.DividendFinancing,
 zvt.domain.dividend_financing.DividendDetail,
 zvt.domain.dividend_financing.SpoDetail...]
```
zvt_context.schemas为系统支持的schema,schema即表结构,即数据,其字段含义的查看方式如下:
* help
输入schema.按tab提示其包含的字段,或者.help()
```
>>> FinanceFactor.help()
```
* 源码
[domain](https://github.com/zvtvz/zvt/tree/master/zvt/domain)里的文件为schema的定义,查看相应字段的注释即可。
通过以上的例子,你应该掌握了统一的记录数据的方法:
> Schema.record_data(provider='your provider',codes='the codes')
注意可选参数provider,其代表数据提供商,一个schema可以有多个provider,这是系统稳定的基石。
查看**已实现**的provider
```
>>> Stock.provider_map_recorder
{'joinquant': zvt.recorders.joinquant.meta.jq_stock_meta_recorder.JqChinaStockRecorder,
 'exchange': zvt.recorders.exchange.exchange_stock_meta_recorder.ExchangeStockMetaRecorder,
 'em': zvt.recorders.em.meta.em_stock_meta_recorder.EMStockRecorder,
 'eastmoney': zvt.recorders.eastmoney.meta.eastmoney_stock_meta_recorder.EastmoneyChinaStockListRecorder}
```
你可以使用任意一个provider来获取数据,默认使用第一个。
再举个例子,股票板块数据获取:
```
>>> Block.provider_map_recorder
{'eastmoney': zvt.recorders.eastmoney.meta.eastmoney_block_meta_recorder.EastmoneyChinaBlockRecorder,
 'sina': zvt.recorders.sina.meta.sina_block_recorder.SinaBlockRecorder}
>>> Block.record_data(provider='sina')
Block registered recorders:{'eastmoney': , 'sina': }
2020-03-04 23:56:48,931  INFO  MainThread  finish record sina blocks:industry
2020-03-04 23:56:49,450  INFO  MainThread  finish record sina blocks:concept
```
再多了解一点record_data:
* 参数code[单个],codes[多个]代表需要抓取的股票代码
* 不传入code,codes则是全市场抓取
* 该方法会把数据存储到本地并只做增量更新
定时任务的方式更新可参考[定时更新](https://github.com/zvtvz/zvt/blob/master/examples/data_runner)
#### 全市场选股
查询数据使用的是query_data方法,把全市场的数据记录下来后,就可以在本地快速查询需要的数据了。
一个例子:2018年年报 roe>8% 营收增长>8% 的前20个股
```
>>> df=FinanceFactor.query_data(filters=[FinanceFactor.roe>0.08,FinanceFactor.report_period=='year',FinanceFactor.op_income_growth_yoy>0.08],start_timestamp='2019-01-01',order=FinanceFactor.roe.desc(),limit=20,columns=["code"]+FinanceFactor.important_cols(),index='code')
          code  basic_eps  total_op_income    net_profit  op_income_growth_yoy  net_profit_growth_yoy     roe    rota  gross_profit_margin  net_margin  timestamp
code
000048  000048     2.7350     4.919000e+09  1.101000e+09                0.4311                 1.5168  0.7035  0.1988               0.5243      0.2355 2020-04-30
000912  000912     0.3500     4.405000e+09  3.516000e+08                0.1796                 1.2363  4.7847  0.0539               0.2175      0.0795 2019-03-20
002207  002207     0.2200     3.021000e+08  5.189000e+07                0.1600                 1.1526  1.1175  0.1182               0.1565      0.1718 2020-04-27
002234  002234     5.3300     3.276000e+09  1.610000e+09                0.8023                 3.2295  0.8361  0.5469               0.5968      0.4913 2020-04-21
002458  002458     3.7900     3.584000e+09  2.176000e+09                1.4326                 4.9973  0.8318  0.6754               0.6537      0.6080 2020-02-20
...        ...        ...              ...           ...                   ...                    ...     ...     ...                  ...         ...        ...
600701  600701    -3.6858     7.830000e+08 -3.814000e+09                1.3579                -0.0325  1.9498 -0.7012               0.4173     -4.9293 2020-04-29
600747  600747    -1.5600     3.467000e+08 -2.290000e+09                2.1489                -0.4633  3.1922 -1.5886               0.0378     -6.6093 2020-06-30
600793  600793     1.6568     1.293000e+09  1.745000e+08                0.1164                 0.8868  0.7490  0.0486               0.1622      0.1350 2019-04-30
600870  600870     0.0087     3.096000e+07  4.554000e+06                0.7773                 1.3702  0.7458  0.0724               0.2688      0.1675 2019-03-30
688169  688169    15.6600     4.205000e+09  7.829000e+08                0.3781                 1.5452  0.7172  0.4832               0.3612      0.1862 2020-04-28
[20 rows x 11 columns]
```
以上,你应该会回答如下的三个问题了:
* 有什么数据?
* 如何记录数据?
* 如何查询数据?
更高级的用法以及扩展数据,可以参考详细文档里的数据部分。
### 写个策略
有了 **交易标的** 和 **交易标的发生的事**,就可以写策略了。
所谓策略回测,无非就是,重复以下过程:
#### 在某时间点,找到符合条件的标的,对其进行买卖,看其表现。
系统支持两种模式:
* solo (随意的)
在 某个时间 根据发生的事件 计算条件 并买卖
* formal (正式的)
系统设计的二维索引多标的计算模型
#### 一个很随便的人(solo)
嗯,这个策略真的很随便,就像我们大部分时间做的那样。
> 报表出来的时,我看一下报表,机构加仓超过5%我就买入,机构减仓超过50%我就卖出。
代码如下:
```
# -*- coding: utf-8 -*-
import pandas as pd
from zvt.api import get_recent_report_date
from zvt.contract import ActorType, AdjustType
from zvt.domain import StockActorSummary, Stock1dKdata
from zvt.trader import StockTrader
from zvt.utils import pd_is_not_null, is_same_date, to_pd_timestamp
class FollowIITrader(StockTrader):
    finish_date = None
    def on_time(self, timestamp: pd.Timestamp):
        recent_report_date = to_pd_timestamp(get_recent_report_date(timestamp))
        if self.finish_date and is_same_date(recent_report_date, self.finish_date):
            return
        filters = [StockActorSummary.actor_type == ActorType.raised_fund.value,
                   StockActorSummary.report_date == recent_report_date]
        if self.entity_ids:
            filters = filters + [StockActorSummary.entity_id.in_(self.entity_ids)]
        df = StockActorSummary.query_data(filters=filters)
        if pd_is_not_null(df):
            self.logger.info(f'{df}')
            self.finish_date = recent_report_date
        long_df = df[df['change_ratio'] > 0.05]
        short_df = df[df['change_ratio'] < -0.5]
        try:
            self.trade_the_targets(due_timestamp=timestamp, happen_timestamp=timestamp,
                                   long_selected=set(long_df['entity_id'].to_list()),
                                   short_selected=set(short_df['entity_id'].to_list()))
        except Exception as e:
            self.logger.error(e)
if __name__ == '__main__':
    entity_id = 'stock_sh_600519'
    Stock1dKdata.record_data(entity_id=entity_id, provider='em')
    StockActorSummary.record_data(entity_id=entity_id, provider='em')
    FollowIITrader(start_timestamp='2002-01-01', end_timestamp='2021-01-01', entity_ids=[entity_id],
                   provider='em', adjust_type=AdjustType.qfq, profit_threshold=None).run()
```
所以,写一个策略其实还是很简单的嘛。
你可以发挥想象力,社保重仓买买买,外资重仓买买买,董事长跟小姨子跑了卖卖卖......
然后,刷新一下[http://127.0.0.1:8050/](http://127.0.0.1:8050/),看你运行策略的performance
更多可参考[策略例子](https://github.com/zvtvz/zvt/tree/master/examples/trader)
#### 严肃一点(formal)
简单的计算可以通过query_data来完成,这里说的是系统设计的二维索引多标的计算模型。
下面以技术因子为例对**计算流程**进行说明:
```
In [7]: from zvt.factors.technical_factor import *
In [8]: factor = BullFactor(codes=['000338','601318'],start_timestamp='2019-01-01',end_timestamp='2019-06-10', transformer=MacdTransformer())
```
### data_df
data_df为factor的原始数据,即通过query_data从数据库读取到的数据,为一个**二维索引**DataFrame
```
In [11]: factor.data_df
Out[11]:
                           level   high                          id        entity_id   open    low  timestamp  close
entity_id       timestamp
stock_sh_601318 2019-01-02    1d  54.91  stock_sh_601318_2019-01-02  stock_sh_601318  54.78  53.70 2019-01-02  53.94
                2019-01-03    1d  55.06  stock_sh_601318_2019-01-03  stock_sh_601318  53.91  53.82 2019-01-03  54.42
                2019-01-04    1d  55.71  stock_sh_601318_2019-01-04  stock_sh_601318  54.03  53.98 2019-01-04  55.31
                2019-01-07    1d  55.88  stock_sh_601318_2019-01-07  stock_sh_601318  55.80  54.64 2019-01-07  55.03
                2019-01-08    1d  54.83  stock_sh_601318_2019-01-08  stock_sh_601318  54.79  53.96 2019-01-08  54.54
...                          ...    ...                         ...              ...    ...    ...        ...    ...
stock_sz_000338 2019-06-03    1d  11.04  stock_sz_000338_2019-06-03  stock_sz_000338  10.93  10.74 2019-06-03  10.81
                2019-06-04    1d  10.85  stock_sz_000338_2019-06-04  stock_sz_000338  10.84  10.57 2019-06-04  10.73
                2019-06-05    1d  10.92  stock_sz_000338_2019-06-05  stock_sz_000338  10.87  10.59 2019-06-05  10.59
                2019-06-06    1d  10.71  stock_sz_000338_2019-06-06  stock_sz_000338  10.59  10.49 2019-06-06  10.65
                2019-06-10    1d  11.05  stock_sz_000338_2019-06-10  stock_sz_000338  10.73  10.71 2019-06-10  11.02
[208 rows x 8 columns]
```
### factor_df
factor_df为transformer对data_df进行计算后得到的数据,设计因子即对[transformer](https://github.com/zvtvz/zvt/blob/master/zvt/factors/factor.py#L18)进行扩展,例子中用的是MacdTransformer()。
```
In [12]: factor.factor_df
Out[12]:
                           level   high                          id        entity_id   open    low  timestamp  close      diff       dea      macd
entity_id       timestamp
stock_sh_601318 2019-01-02    1d  54.91  stock_sh_601318_2019-01-02  stock_sh_601318  54.78  53.70 2019-01-02  53.94       NaN       NaN       NaN
                2019-01-03    1d  55.06  stock_sh_601318_2019-01-03  stock_sh_601318  53.91  53.82 2019-01-03  54.42       NaN       NaN       NaN
                2019-01-04    1d  55.71  stock_sh_601318_2019-01-04  stock_sh_601318  54.03  53.98 2019-01-04  55.31       NaN       NaN       NaN
                2019-01-07    1d  55.88  stock_sh_601318_2019-01-07  stock_sh_601318  55.80  54.64 2019-01-07  55.03       NaN       NaN       NaN
                2019-01-08    1d  54.83  stock_sh_601318_2019-01-08  stock_sh_601318  54.79  53.96 2019-01-08  54.54       NaN       NaN       NaN
...                          ...    ...                         ...              ...    ...    ...        ...    ...       ...       ...       ...
stock_sz_000338 2019-06-03    1d  11.04  stock_sz_000338_2019-06-03  stock_sz_000338  10.93  10.74 2019-06-03  10.81 -0.121336 -0.145444  0.048215
                2019-06-04    1d  10.85  stock_sz_000338_2019-06-04  stock_sz_000338  10.84  10.57 2019-06-04  10.73 -0.133829 -0.143121  0.018583
                2019-06-05    1d  10.92  stock_sz_000338_2019-06-05  stock_sz_000338  10.87  10.59 2019-06-05  10.59 -0.153260 -0.145149 -0.016223
                2019-06-06    1d  10.71  stock_sz_000338_2019-06-06  stock_sz_000338  10.59  10.49 2019-06-06  10.65 -0.161951 -0.148509 -0.026884
                2019-06-10    1d  11.05  stock_sz_000338_2019-06-10  stock_sz_000338  10.73  10.71 2019-06-10  11.02 -0.137399 -0.146287  0.017776
[208 rows x 11 columns]
```
### result_df
result_df为可用于选股器的**二维索引**DataFrame,通过对data_df或factor_df计算来实现。
该例子在计算macd之后,利用factor_df,黄白线在0轴上为True,否则为False,[具体代码](https://github.com/zvtvz/zvt/blob/master/zvt/factors/technical_factor.py#L56)
```
In [14]: factor.result_df
Out[14]:
                            score
entity_id       timestamp
stock_sh_601318 2019-01-02  False
                2019-01-03  False
                2019-01-04  False
                2019-01-07  False
                2019-01-08  False
...                           ...
stock_sz_000338 2019-06-03  False
                2019-06-04  False
                2019-06-05  False
                2019-06-06  False
                2019-06-10  False
[208 rows x 1 columns]
```
result_df的格式如下:

filter_result 为 True 或 False, score_result 取值为 0 到 1。
结合选股器和回测,整个流程如下:

## 环境设置(可选)
```
>>> from zvt import *
>>> zvt_env
{'zvt_home': '/Users/foolcage/zvt-home',
 'data_path': '/Users/foolcage/zvt-home/data',
 'tmp_path': '/Users/foolcage/zvt-home/tmp',
 'ui_path': '/Users/foolcage/zvt-home/ui',
 'log_path': '/Users/foolcage/zvt-home/logs'}
>>> zvt_config 
```
* jq_username 聚宽数据用户名
* jq_password 聚宽数据密码
* smtp_host 邮件服务器host
* smtp_port 邮件服务器端口
* email_username smtp邮箱账户
* email_password smtp邮箱密码
* wechat_app_id
* wechat_app_secrect
```
>>> init_config(current_config=zvt_config, jq_username='xxx', jq_password='yyy')
```
> 通用的配置方式为: init_config(current_config=zvt_config, **kv)
### 下载历史数据(可选)
百度网盘: https://pan.baidu.com/s/1kHAxGSxx8r5IBHe5I7MAmQ 提取码: yb6c
google drive: https://drive.google.com/drive/folders/17Bxijq-PHJYrLDpyvFAm5P6QyhKL-ahn?usp=sharing
里面包含joinquant的日/周线后复权数据,个股估值,基金及其持仓数据,eastmoney的财务等数据。
把下载的数据解压到正式环境的data_path(所有db文件放到该目录下,没有层级结构)
数据的更新是增量的,下载历史数据只是为了节省时间,全部自己更新也是可以的。
#### 注册聚宽(可选)
项目数据支持多provider,在数据schema一致性的基础上,可根据需要进行选择和扩展,目前支持新浪,东财,交易所等免费数据。
#### 数据的设计上是让provider来适配schema,而不是反过来,这样即使某provider不可用了,换一个即可,不会影响整个系统的使用。
但免费数据的缺点是显而易见的:不稳定,爬取清洗数据耗时耗力,维护代价巨大,且随时可能不可用。  
个人建议:如果只是学习研究,可以使用免费数据;如果是真正有意投身量化,还是选一家可靠的数据提供商。
项目支持聚宽的数据,可戳以下链接申请使用(目前可免费使用一年)  
https://www.joinquant.com/default/index/sdk?channelId=953cbf5d1b8683f81f0c40c9d4265c0d
> 项目中大部分的免费数据目前都是比较稳定的,且做过严格测试,特别是东财的数据,可放心使用
> 添加其他数据提供商, 请参考[数据扩展教程](https://zvtvz.github.io/zvt/#/data_extending)
## 开发
### clone代码
```
git clone https://github.com/zvtvz/zvt.git
```
设置项目的virtual env(python>=3.6),安装依赖
```
pip3 install -r requirements.txt
pip3 install pytest
```
### 测试案例
pycharm导入工程(推荐,你也可以使用其他ide),然后pytest跑测试案例

大部分功能使用都可以从tests里面参考
## 贡献
期待能有更多的开发者参与到 zvt 的开发中来,我会保证尽快 Reivew PR 并且及时回复。但提交 PR 请确保
先看一下[1分钟代码规范](https://github.com/zvtvz/zvt/blob/master/code_of_conduct.md)
1. 通过所有单元测试,如若是新功能,请为其新增单元测试
2. 遵守开发规范
3. 如若需要,请更新相对应的文档
也非常欢迎开发者能为 zvt 提供更多的示例,共同来完善文档。
## 请作者喝杯咖啡
如果你觉得项目对你有帮助,可以请作者喝杯咖啡  
 
     
 ## 联系方式  
加微信进群:foolcage 添加暗号:zvt
## 联系方式  
加微信进群:foolcage 添加暗号:zvt  
 ------
微信公众号:
------
微信公众号:  
 知乎专栏:  
https://zhuanlan.zhihu.com/automoney
## Thanks
知乎专栏:  
https://zhuanlan.zhihu.com/automoney
## Thanks
