├── tools
├── mydb
│ ├── __init__.py
│ ├── mydb_interface.py
│ └── mydb.py
├── __init__.py
└── util
│ ├── __init__.py
│ ├── config.py
│ ├── us.py
│ ├── zh.py
│ ├── date.py
│ └── analysis.py
├── other
├── alipay.jpg
└── wechatpay.jpg
├── data
├── Market-Breadth-US.jpg
└── Market-Breadth-ZH-SW.jpg
├── config
├── config.conf
└── sql
│ ├── zh_stocks_info.sql
│ ├── us_stocks_info.sql
│ ├── zh_stocks_d.sql
│ ├── us_stocks_d.sql
│ ├── us_stocks_sector_d.sql
│ ├── zh_stocks_sector_sw_d.sql
│ └── zh_stocks_industries_d.sql
├── requirements.txt
├── LICENSE
├── task
├── zh_get_info.py
├── us_get_info.py
├── zh_get_daily.py
└── us_get_daily.py
├── README.md
└── .gitignore
/tools/mydb/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | from .mydb_interface import *
4 |
--------------------------------------------------------------------------------
/other/alipay.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bankrollhunter/market-breadth/HEAD/other/alipay.jpg
--------------------------------------------------------------------------------
/tools/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | from .mydb import *
4 | from .util import *
5 |
--------------------------------------------------------------------------------
/other/wechatpay.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bankrollhunter/market-breadth/HEAD/other/wechatpay.jpg
--------------------------------------------------------------------------------
/data/Market-Breadth-US.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bankrollhunter/market-breadth/HEAD/data/Market-Breadth-US.jpg
--------------------------------------------------------------------------------
/data/Market-Breadth-ZH-SW.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bankrollhunter/market-breadth/HEAD/data/Market-Breadth-ZH-SW.jpg
--------------------------------------------------------------------------------
/tools/util/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | from .date import *
4 | from .analysis import *
5 | from .us import *
6 | from .zh import *
7 | from .config import *
8 |
--------------------------------------------------------------------------------
/config/config.conf:
--------------------------------------------------------------------------------
1 | [database]
2 | host=127.0.0.1
3 | port=3306
4 | db=stocks
5 | user=stocks
6 | password=123456
7 | charset=utf8mb4
8 |
9 | [tushare]
10 | token=xxxxx
11 |
--------------------------------------------------------------------------------
/tools/util/config.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | import os
4 | from configparser import RawConfigParser
5 |
6 | config = RawConfigParser()
7 | config_path = os.path.split(os.path.realpath(__file__))[0] + '/../../config/config.conf'
8 | config.read(config_path)
9 |
10 |
11 | if __name__ == '__main__':
12 | print(config.get('database', 'host'))
13 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | TA-Lib
2 | wkhtmltopdf
3 | pandas~=0.25.3
4 | sqlalchemy~=1.3.18
5 | requests~=2.24.0
6 | bs4~=0.0.1
7 | beautifulsoup4~=4.9.1
8 | yfinance~=0.1.54
9 | tushare~=1.2.60
10 | baostock~=0.8.8
11 | python-dateutil~=2.8.1
12 | configparser~=5.0.0
13 | numpy~=1.19.1
14 | seaborn~=0.10.0
15 | imgkit~=1.0.2
16 | matplotlib~=3.3.0
17 | git+git://github.com/hk-Lei/OpenData.git
--------------------------------------------------------------------------------
/tools/mydb/mydb_interface.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | from .mydb import MyDB
4 |
5 | mydb = MyDB()
6 |
7 |
8 | def upsert_table(table, columns, df):
9 | mydb.upsert_table(table_name=table, sql_columns=columns, sql_df=df)
10 |
11 |
12 | def read_data(table, columns):
13 | mydb.read_data(table_name=table, sql_columns=columns)
14 |
15 |
16 | def read_data_from_sql(sql):
17 | mydb.read_from_sql(sql=sql)
18 |
19 |
20 | def truncate_table(table):
21 | mydb.truncate_table(table_name=table)
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Bankroll Hunter
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.
22 |
--------------------------------------------------------------------------------
/task/zh_get_info.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | from opendatatools import swindex
4 | import os
5 | import sys
6 |
7 | path = os.path.dirname(__file__) + os.sep + '..' + os.sep
8 | sys.path.append(path)
9 |
10 | from ..tools.util import *
11 | from ..tools.mydb import *
12 |
13 | ts.set_token(config.get('tushare', 'token'))
14 | pro = ts.pro_api()
15 |
16 | df = pro.stock_basic()
17 | df.rename(columns={'symbol': 'code'}, inplace=True)
18 |
19 | table = 'zh_stocks_info'
20 | columns = ['code', 'ts_code', 'name', 'industry', 'area', 'market', 'list_date']
21 | df = df[columns]
22 | df = df[df['code'].str.isdigit()]
23 | mydb.upsert_table(table, columns, df)
24 |
25 | df, msg = swindex.get_index_list()
26 | df1 = df.loc[df['section_name'] == "一级行业"]
27 | ind1_list = df1.index_code
28 |
29 | sw_columns = ['code', 'name', 'sw_ind1', 'sw_ind1_weight']
30 | j = 0
31 | for i in ind1_list:
32 | j = j + 1
33 | print('processing [' + str(j) + '/' + str(ind1_list.size) + '] : ' + i)
34 | stock_data, msg = swindex.get_index_cons(i)
35 | stock_data.rename(columns={'stock_code': 'code', 'stock_name': 'name', 'weight': 'sw_ind1_weight'},
36 | inplace=True)
37 | stock_data.loc[:, 'sw_ind1'] = df1.query('index_code == "{}"'.format(i)).index_name.values[0]
38 | stock_data = stock_data[sw_columns]
39 | upsert_table(table, sw_columns, stock_data)
40 |
--------------------------------------------------------------------------------
/config/sql/zh_stocks_info.sql:
--------------------------------------------------------------------------------
1 |
2 | SET NAMES utf8mb4;
3 | SET FOREIGN_KEY_CHECKS = 0;
4 |
5 | -- ----------------------------
6 | -- Table structure for zh_stocks_info
7 | -- ----------------------------
8 | DROP TABLE IF EXISTS `zh_stocks_info`;
9 | CREATE TABLE `zh_stocks_info` (
10 | `code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '代码',
11 | `ts_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'tushare 股票代码',
12 | `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '股票名称',
13 | `sector` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '所在板块',
14 | `industry` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '所在行业',
15 | `sw_ind1` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '申万一级行业',
16 | `sw_ind1_weight` decimal(20,3) DEFAULT NULL COMMENT '申万一级行业权重',
17 | `area` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '地区',
18 | `market` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '市场',
19 | `list_date` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '上市时间',
20 | `total_cap` bigint DEFAULT NULL COMMENT '总市值',
21 | `pe` decimal(20,3) DEFAULT NULL COMMENT 'PE',
22 | `inst_percent` decimal(20,3) DEFAULT NULL,
23 | PRIMARY KEY (`code`) USING BTREE
24 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
25 |
26 | SET FOREIGN_KEY_CHECKS = 1;
27 |
--------------------------------------------------------------------------------
/config/sql/us_stocks_info.sql:
--------------------------------------------------------------------------------
1 |
2 | SET NAMES utf8mb4;
3 | SET FOREIGN_KEY_CHECKS = 0;
4 |
5 | -- ----------------------------
6 | -- Table structure for us_stocks_info
7 | -- ----------------------------
8 | DROP TABLE IF EXISTS `us_stocks_info`;
9 | CREATE TABLE `us_stocks_info` (
10 | `code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '代码',
11 | `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '名称',
12 | `sector` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '板块',
13 | `sp_sector` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '标普板块',
14 | `industry` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '行业',
15 | `country` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '国家',
16 | `total_cap` decimal(10,3) DEFAULT NULL COMMENT '总市值',
17 | `is_spx` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否标普500 成分股',
18 | `spx_weight` decimal(20,3) DEFAULT NULL COMMENT '标普500权重',
19 | `is_ndx` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否纳斯达克成分股',
20 | `ndx_weight` decimal(20,3) DEFAULT NULL COMMENT '纳斯达克权重',
21 | `is_dji` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否道琼斯成分股',
22 | `dji_weight` decimal(20,3) DEFAULT NULL COMMENT '道琼斯权重',
23 | PRIMARY KEY (`code`)
24 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
25 |
26 | SET FOREIGN_KEY_CHECKS = 1;
27 |
--------------------------------------------------------------------------------
/task/us_get_info.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | from opendatatools import usstock
4 | import os
5 | import sys
6 |
7 | path = os.path.dirname(__file__) + os.sep + '..' + os.sep
8 | sys.path.append(path)
9 |
10 | from ..tools.util import *
11 | from ..tools.mydb import *
12 |
13 | def us_total_cap(x):
14 | if isinstance(x, str) and x.endswith('B'):
15 | return float(x[1:-1]) * 10
16 | elif isinstance(x, str) and x.endswith('M'):
17 | return float(x[1:-1]) / 100
18 | else:
19 | return None
20 |
21 | start = datetime.now()
22 |
23 | info_table = 'us_stocks_info'
24 | # 更新 标普500 权重股
25 | spx_columns = ['code', 'name', 'is_spx', 'sp_sector']
26 | mydb.upsert_table(info_table, spx_columns, us.get_spx())
27 | spx2_columns = ['code', 'name', 'spx_weight']
28 | mydb.upsert_table(info_table, spx2_columns, us.get_spx2())
29 | # 更新 纳斯达克100 权重股
30 | ndx_columns = ['code', 'name', 'is_ndx', 'ndx_weight']
31 | mydb.upsert_table(info_table, ndx_columns, us.get_ndx())
32 | # 更新 道琼斯 权重股
33 | dji_columns = ['code', 'name', 'is_dji', 'dji_weight']
34 | mydb.upsert_table(info_table, dji_columns, us.get_dji())
35 |
36 | # 全美股市场股票
37 | symbols, msg = usstock.get_symbols()
38 | if symbols is not None:
39 | columns = ['code', 'name', 'sector', 'industry', 'total_cap']
40 | symbols.rename(columns={'Symbol': 'code', 'Name': 'name', 'Sector': 'sector', 'MarketCap': 'total_cap'},
41 | inplace=True)
42 | symbols = symbols[columns].set_index(['code']).drop_duplicates().reset_index()
43 | symbols.total_cap = symbols.total_cap.map(us_total_cap)
44 | mydb.upsert_table(info_table, columns, symbols)
45 |
46 | end = datetime.now()
47 | print('Download Data use {}'.format(end - start))
48 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Market-Breadth
2 |
3 | 计算美股、A股市场宽度
4 |
5 | ### 数据格式
6 | 使用 MySQL 存储数据,目前美股和A股各有两张表,具体表接口参加 config/sql/xxx.sql 文件,以A股为例:
7 | ```
8 | zh_stocks_info.sql 生成 zh_stocks_info 表: 股票基础数据
9 | zh_stocks_d.sql 生成 zh_stocks_d 表: 日线周期数据
10 | zh_stocks_sector_sw_d.sql 生成 计算市场宽度依赖的视图
11 | tmp_zh_stocks_sw_sector_d
12 | zh_stocks_sector_sw_d
13 | ```
14 |
15 | 安装好 mysql 并在 mysql 中运行 config/sql 目录下的文件可以创建好自己的底层表。
16 |
17 | 另外需要让创建用户并授权,这里密码采用 `123456` , 自行修改并修改配置文件 config/config.conf 中的配置项:
18 | ```SQL
19 | ALTER USER 'stocks'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
20 | grant all privileges on *.* to 'stocks'@'%';
21 | ```
22 |
23 | ### 数据获取
24 | A 股使用 Tushare 获取,欢迎使用 https://tushare.pro/register?reg=275414 注册邀请链接帮我加积分。
25 | ```python
26 | pip install tushare
27 | ```
28 | 申请之后记得替换 config.conf 中的 token 配置项。
29 |
30 | 美股使用 yfinance 获取:
31 | ```python
32 | pip install yfinance
33 | ```
34 | 其他库依赖:
35 | + opendatatools
36 | + requests
37 | + bs4
38 | + pandas
39 | + TA-Lib
40 |
41 | 遇到什么安装什么即可。。。
42 |
43 | ### 运行分析
44 | #### 1. 获取 A 股市场宽度
45 | + 1. 获取 A 股全市场股票基本信息:
46 | ```python
47 | python task/zh_get_info.py
48 | ```
49 | + 2. 计算 A 股市场宽度图表:
50 | ```python
51 | python task/zh_get_daily.py
52 | ```
53 | 获取数据时间比较久,请耐心等待,预计 1-2 个小时。
54 | + 3. 示例:
55 |
56 |

57 |
58 |
59 | #### 1. 获取 美股标普500 市场宽度
60 | 注意:美股数据获取最好使用科学上网。
61 | + 1. 获取美股全市场股票基本信息:
62 | ```python
63 | python task/us_get_info.py
64 | ```
65 | + 2. 计算 美股标普500 市场宽度图表:
66 | ```python
67 | python task/us_get_daily.py
68 | ```
69 | 获取数据时间比较久,请耐心等待,预计 1-2 个小时。
70 | + 3. 美股示例在 `data/Market-Breadth-US.jpg`
71 |
72 | #### 惊喜:
73 | 在计算过程中该程序已经计算了全市场股票的 破线、交叉、拐头 等数据,您可以用 sql 在 mysql 中自行分析。
74 |
75 | #### 如果觉得对您有帮助,欢迎请我喝杯咖啡:
76 |
77 | + 微信:
78 |
79 |

80 |
81 |
82 | + 支付宝:
83 |
84 |

85 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | .idea/
7 | # C extensions
8 | *.so
9 |
10 | # Distribution / packaging
11 | .Python
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | wheels/
24 | pip-wheel-metadata/
25 | share/python-wheels/
26 | *.egg-info/
27 | .installed.cfg
28 | *.egg
29 | MANIFEST
30 |
31 | # PyInstaller
32 | # Usually these files are written by a python script from a template
33 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
34 | *.manifest
35 | *.spec
36 |
37 | # Installer logs
38 | pip-log.txt
39 | pip-delete-this-directory.txt
40 |
41 | # Unit test / coverage reports
42 | htmlcov/
43 | .tox/
44 | .nox/
45 | .coverage
46 | .coverage.*
47 | .cache
48 | nosetests.xml
49 | coverage.xml
50 | *.cover
51 | *.py,cover
52 | .hypothesis/
53 | .pytest_cache/
54 |
55 | # Translations
56 | *.mo
57 | *.pot
58 |
59 | # Django stuff:
60 | *.log
61 | local_settings.py
62 | db.sqlite3
63 | db.sqlite3-journal
64 |
65 | # Flask stuff:
66 | instance/
67 | .webassets-cache
68 |
69 | # Scrapy stuff:
70 | .scrapy
71 |
72 | # Sphinx documentation
73 | docs/_build/
74 |
75 | # PyBuilder
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | .python-version
87 |
88 | # pipenv
89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
92 | # install all needed dependencies.
93 | #Pipfile.lock
94 |
95 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
96 | __pypackages__/
97 |
98 | # Celery stuff
99 | celerybeat-schedule
100 | celerybeat.pid
101 |
102 | # SageMath parsed files
103 | *.sage.py
104 |
105 | # Environments
106 | .env
107 | .venv
108 | env/
109 | venv/
110 | ENV/
111 | env.bak/
112 | venv.bak/
113 |
114 | # Spyder project settings
115 | .spyderproject
116 | .spyproject
117 |
118 | # Rope project settings
119 | .ropeproject
120 |
121 | # mkdocs documentation
122 | /site
123 |
124 | # mypy
125 | .mypy_cache/
126 | .dmypy.json
127 | dmypy.json
128 |
129 | # Pyre type checker
130 | .pyre/
131 |
--------------------------------------------------------------------------------
/tools/util/us.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | import requests
4 | import pandas as pd
5 | import bs4 as bs
6 | import yfinance as yf
7 | import time
8 |
9 |
10 | headers = {
11 | "User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
12 | + 'AppleWebKit/537.36 (KHTML, like Gecko) '
13 | + 'Chrome/83.0.4103.116 Safari/537.36'
14 | }
15 |
16 |
17 | def get_proxies():
18 | http_proxy = "http://127.0.0.1:10808"
19 | https_proxy = "https://127.0.0.1:10808"
20 | return {
21 | "http": http_proxy,
22 | "https": https_proxy
23 | }
24 |
25 |
26 | def get_spx():
27 | url = 'http://en.wikipedia.org/wiki/List_of_S%26P_500_companies'
28 | request = requests.get(url, headers=headers)
29 | soup = bs.BeautifulSoup(request.text, 'lxml')
30 | table = soup.find('table', {'class': 'wikitable sortable'})
31 |
32 | symbol_list = []
33 | name_list = []
34 | sector_list = []
35 | industry_list = []
36 | for i in table.findAll('tr')[1:]:
37 | symbol_list.append(i.find_all('td')[0].get_text().replace('\n', ''))
38 | name_list.append(i.find_all('td')[1].get_text().replace('\n', ''))
39 | sector_list.append(i.find_all('td')[3].get_text().replace('\n', ''))
40 | industry_list.append(i.find_all('td')[4].get_text().replace('\n', ''))
41 | return pd.DataFrame({'code': symbol_list, 'name': name_list, 'is_spx': 'Y', 'sp_sector': sector_list})
42 |
43 |
44 | def get_spx2():
45 | url = 'https://www.slickcharts.com/sp500'
46 | request = requests.get(url, headers=headers)
47 | data = pd.read_html(request.text)[0]
48 | # 『Symbol』就是股票代码
49 | return pd.DataFrame({'code': data.Symbol, 'name': data.Company, 'spx_weight': data.Weight})
50 |
51 |
52 | def get_ndx():
53 | url = 'https://www.slickcharts.com/nasdaq100'
54 | request = requests.get(url, headers=headers)
55 | data = pd.read_html(request.text)[0]
56 | # 『Symbol』就是股票代码
57 | return pd.DataFrame({'code': data.Symbol, 'name': data.Company, 'is_ndx': 'Y', 'ndx_weight': data.Weight})
58 |
59 |
60 | def get_dji():
61 | url = 'https://www.slickcharts.com/dowjones'
62 | request = requests.get(url, headers=headers)
63 | data = pd.read_html(request.text)[0]
64 | # 『Symbol』就是股票代码
65 | return pd.DataFrame({'code': data.Symbol, 'name': data.Company, 'is_dji': 'Y', 'dji_weight': data.Weight})
66 |
67 |
68 | def download(symbol_list, start, end, interval, retry=10, pause=2):
69 | for _ in range(retry):
70 | try:
71 | return yf.download(symbol_list, start=start, end=end,
72 | group_by="ticker", threads=True, auto_adjust=True,
73 | interval=interval)
74 | except:
75 | time.sleep(pause)
76 |
77 | return yf.download(symbol_list, start=start, end=end,
78 | group_by="ticker", threads=True, auto_adjust=True,
79 | interval=interval)
80 |
--------------------------------------------------------------------------------
/tools/mydb/mydb.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | import pandas as pd
4 | from sqlalchemy import create_engine
5 | import mysql.connector as mycon
6 | from ..util.config import config
7 |
8 |
9 | class MyDB(object):
10 | # 获取config配置文件
11 | def __init__(self):
12 | self.host = config.get('database', 'host')
13 | self.port = config.getint('database', 'port')
14 | self.db = config.get('database', 'db')
15 | self.user = config.get('database', 'user')
16 | self.password = config.get('database', 'password')
17 | self.charset = config.get('database', 'charset')
18 | self.url = 'mysql+pymysql://{}:{}@{}:{}/{}?charset={}'.format(self.user, self.password, self.host, self.port,
19 | self.db, self.charset)
20 |
21 | def create_mydb(self):
22 | self.mydb = mycon.connect(
23 | host=self.host, # 数据库主机地址
24 | port=self.port,
25 | user=self.user, # 数据库用户名
26 | password=self.password, # 数据库密码
27 | database=self.db,
28 | auth_plugin='mysql_native_password'
29 | )
30 |
31 | # 1. upsert_table 写入或者更新表
32 | # table_name : 写入的表明
33 | # sql_columns :写入的列
34 | # sql_df : dataframe 数据集
35 | def upsert_table(self, table_name, sql_columns, sql_df):
36 | self.create_mydb()
37 | mycursor = self.mydb.cursor()
38 | # `date` = VALUES(`date`)
39 | set_keys = map(lambda i: '`' + i + '` = VALUES(`' + i + '`)', sql_columns)
40 | # 记录在表中不存在则进行插入,如果存在则进行更新
41 | sql = '''
42 | INSERT INTO `{}` (`{}`) VALUES ({})
43 | ON DUPLICATE KEY UPDATE {};
44 | '''.format(table_name,
45 | '`,`'.join(sql_columns),
46 | ",".join('%s' for i in range(len(sql_columns))),
47 | ", ".join(set_keys)
48 | )
49 | sql_df = sql_df.reindex(columns=sql_columns)
50 | sql_df = sql_df.where(pd.notnull(sql_df), None)
51 | sql_values = sql_df.to_numpy().tolist()
52 | # 批量插入使用executement
53 | mycursor.executemany(sql, sql_values)
54 | self.mydb.commit()
55 |
56 | def read_data(self, table_name, sql_columns):
57 | db_engine = create_engine(self.url)
58 | # 记录在表中不存在则进行插入,如果存在则进行更新
59 | sql = '''
60 | SELECT `{}` FROM `{}`;
61 | '''.format('`,`'.join(sql_columns), table_name)
62 | return pd.read_sql(sql, db_engine)
63 |
64 | def read_from_sql(self, sql):
65 | db_engine = create_engine(self.url)
66 | return pd.read_sql(sql, db_engine)
67 |
68 | def truncate_table(self, table_name):
69 | self.create_mydb()
70 | mycursor = self.mydb.cursor()
71 | # 记录在表中不存在则进行插入,如果存在则进行更新
72 | sql = '''
73 | TRUNCATE TABLE {};
74 | '''.format(table_name)
75 |
76 | print('清空表数据:' + sql)
77 | # 批量插入使用executement
78 | mycursor.execute(sql)
79 | self.mydb.commit()
80 |
--------------------------------------------------------------------------------
/task/zh_get_daily.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | import os
4 | import sys
5 |
6 | path = os.path.dirname(__file__) + os.sep + '..' + os.sep
7 | sys.path.append(path)
8 |
9 | from ..tools.util import *
10 | from ..tools.mydb import *
11 |
12 | start_date = date.get_2year_ago('%Y%m%d')
13 | end_date = date.get_end_day('%Y%m%d')
14 |
15 | list_sql = '''
16 | select * from zh_stocks_info where ts_code is not null;
17 | '''
18 |
19 | start = datetime.now()
20 | stk_info = mydb.read_from_sql(list_sql)
21 | stk_codes = stk_info.ts_code.copy()
22 | stk_info = stk_info.set_index(['ts_code'])
23 |
24 | table = 'zh_stocks_d'
25 | mydb.truncate_table(table)
26 |
27 | columns = ['code', 'date', 'name', 'industry', 'sw_ind1', 'sw_ind1_weight', 'area', 'market',
28 | 'open', 'high', 'low', 'close', 'pre_close', 'is_gap',
29 | 'vol', 'ma_vol', 'vol_rate', 'amount', 'ma_amt', 'amt_rate',
30 | 's_ma', 'm_ma', 'l_ma', 's_ema', 'm_ema', 'l_ema',
31 | 'ecs', 'esm', 'pesm', 'is_esm_over',
32 | 'eml', 'peml', 'is_eml_over', 'ebais',
33 | 'cs', 'pcs', 'is_cs_over',
34 | 'sm', 'psm', 'is_sm_over',
35 | 'ml', 'pml', 'is_ml_over', 'bais',
36 | 's_close', 's_pre_close', 'is_s_up',
37 | 'm_close', 'm_pre_close', 'is_m_up',
38 | 'l_close', 'l_pre_close', 'is_l_up'
39 | ]
40 | # 获取日K线数据
41 | num = stk_codes.size
42 | j = 0
43 | for i in stk_codes:
44 | j = j + 1
45 | if i is None:
46 | print('processing [' + str(j) + '/' + str(num) + '] is None; Continue!')
47 | continue
48 | print('processing [' + str(j) + '/' + str(num) + '] : ' + i)
49 | df = zh.get_daily(ts_code=i, start_date=start_date, end_date=end_date)
50 | if df is None:
51 | continue
52 | df = df.tail(500)
53 | stock = stk_info.loc[i]
54 | df['ts_code'] = i
55 | df['code'] = stock.get('code')
56 | df.rename(columns={'trade_date': 'date'}, inplace=True)
57 | df.date = df.date.map(lambda x: date.date_convert(x, '%Y%m%d', '%Y-%m-%d'))
58 | df = df[~np.isnan(df['close'])]
59 | df = analysis.stock_zh_analysis(df, 20, 60, 120)
60 | if df is None:
61 | continue
62 | df['name'] = stock.get('name')
63 | df['sector'] = stock.get('sector')
64 | df['industry'] = stock.get('industry')
65 | df['sw_ind1'] = stock.get('sw_ind1')
66 | df['sw_ind1_weight'] = stock.get('sw_ind1_weight')
67 | df['area'] = stock.get('area')
68 | df['market'] = stock.get('market')
69 | df = df[~np.isnan(df['l_close'])]
70 | df = df[columns]
71 | mydb.upsert_table(table, columns, df)
72 |
73 | end = datetime.now()
74 | print('Download Data use {}'.format(end - start))
75 |
76 | # A 股市场宽度
77 | df = mydb.read_from_sql('SELECT * FROM zh_stocks_industries_d ORDER BY date desc;')
78 | a_mb_name = path + 'data/Market-Breadth-ZH.jpg'
79 | analysis.market_breadth(df, a_mb_name)
80 |
81 | # A 股市场宽度-申万
82 | df = mydb.read_from_sql('SELECT * FROM zh_stocks_sector_sw_d ORDER BY date desc;')
83 | a_sw_mb = path + './data/Market-Breadth-ZH-SW.jpg'
84 | analysis.market_breadth(df, a_sw_mb)
85 |
86 |
--------------------------------------------------------------------------------
/task/us_get_daily.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | import os
4 | import sys
5 |
6 | path = os.path.dirname(__file__) + os.sep + '..' + os.sep
7 | sys.path.append(path)
8 |
9 | from ..tools.util import *
10 | from ..tools.mydb import *
11 |
12 | list_sql = '''
13 | select * from us_stocks_info
14 | where total_cap > 10 or is_spx = 'Y' or is_ndx = 'Y' or is_dji = 'Y';
15 | '''
16 |
17 | start = datetime.now()
18 | stk_info = mydb.read_from_sql(list_sql)
19 | stk_codes = stk_info.code.copy()
20 | stk_info = stk_info.set_index(['code'])
21 |
22 | table = 'us_stocks_d'
23 | mydb.truncate_table(table)
24 |
25 | columns = ['code', 'date', 'name', 'sector', 'sp_sector', 'industry', 'total_cap',
26 | 'is_spx', 'spx_weight', 'is_ndx', 'ndx_weight', 'is_dji', 'dji_weight',
27 | 'open', 'high', 'low', 'close', 'pre_close', 'is_gap',
28 | 'vol', 'ma_vol', 'vol_rate',
29 | 's_ma', 'm_ma', 'l_ma', 's_ema', 'm_ema', 'l_ema',
30 | 'ecs', 'esm', 'pesm', 'is_esm_over',
31 | 'eml', 'peml', 'is_eml_over', 'ebais',
32 | 'cs', 'pcs', 'is_cs_over',
33 | 'sm', 'psm', 'is_sm_over',
34 | 'ml', 'pml', 'is_ml_over', 'bais',
35 | 's_close', 's_pre_close', 'is_s_up',
36 | 'm_close', 'm_pre_close', 'is_m_up',
37 | 'l_close', 'l_pre_close', 'is_l_up'
38 | ]
39 | # 获取日K线数据
40 | batch = 40
41 | num = 0
42 | for n in range(0, len(stk_codes), batch):
43 | num += 1
44 | print('Processing 第 {} 批 【{}~{}/{}】...'.format(num, n, n+batch, len(stk_codes)))
45 | sub_codes = stk_codes[n: n+batch]
46 | symbol_list = ' '.join(sub_codes)
47 | # data = yf.download(symbol_list, start=date.get_year_ago(), end=date.get_end_day(),
48 | # group_by="ticker", threads=True, auto_adjust=True,
49 | # interval='1d')
50 | data = us.download(symbol_list=symbol_list, start=date.get_year_ago(), end=date.get_end_day(),
51 | interval='1d')
52 | for i in sub_codes:
53 | if i in data.columns:
54 | stock = stk_info.loc[i]
55 | df = data[i]
56 | if df is None:
57 | continue
58 | df = df.tail(250)
59 | df = df.reset_index()
60 | df.rename(columns={'Date': 'date', 'Open': 'open', 'High': 'high', 'Low': 'low',
61 | 'Close': 'close', 'Volume': 'vol'},
62 | inplace=True)
63 | df = df[~np.isnan(df['close'])]
64 | df['code'] = i
65 | df = analysis.stock_analysis(df, 20, 60, 120)
66 | if df is None:
67 | continue
68 | df['name'] = stock.get('name')
69 | df['sector'] = stock.get('sector')
70 | df['sp_sector'] = stock.get('sp_sector')
71 | df['industry'] = stock.get('industry')
72 | df['total_cap'] = stock.get('total_cap')
73 | df['is_spx'] = stock.get('is_spx')
74 | df['spx_weight'] = stock.get('spx_weight')
75 | df['is_ndx'] = stock.get('is_ndx')
76 | df['ndx_weight'] = stock.get('ndx_weight')
77 | df['is_dji'] = stock.get('is_dji')
78 | df['dji_weight'] = stock.get('dji_weight')
79 | df = df[~np.isnan(df['l_close'])]
80 | df = df[columns]
81 | mydb.upsert_table(table, columns, df)
82 |
83 | end = datetime.now()
84 | print('Download Data use {}'.format(end - start))
85 |
86 |
87 | # US 股市场宽度
88 | df = mydb.read_from_sql('SELECT * FROM us_stocks_sector_d ORDER BY date desc;')
89 | mb_name = path + './data/Market-Breadth-US.jpg'
90 | analysis.market_breadth(df, mb_name)
91 |
--------------------------------------------------------------------------------
/tools/util/zh.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | import tushare as ts
4 | import time
5 | from ..util.config import config
6 | from ..util.date import *
7 | import baostock as bs
8 | import pandas as pd
9 |
10 | token = config.get('tushare', 'token')
11 | ts.set_token(token)
12 |
13 |
14 | def _baostock_get_kline(ts_code='', freq='d', start_date='', end_date='', adj='2'):
15 | # # 登陆系统
16 | # lg = bs.login()
17 | # # 显示登陆返回信息
18 | # if lg.error_code is not '0':
19 | # print('login respond error_code:' + lg.error_code)
20 | # print('login respond error_msg:' + lg.error_msg)
21 |
22 | bao_code = ts_code.split('.')[1] + '.' + ts_code.split('.')[0]
23 |
24 | fields = "date,code,open,high,low,close,volume,amount" \
25 | if freq in "d w m" \
26 | else "date,time,code,open,high,low,close,volume,amount"
27 | # 获取沪深A股历史K线数据
28 | # 详细指标参数,参见“历史行情指标参数”章节;“分钟线”参数与“日线”参数不同。
29 | # 分钟线指标:date,time,code,open,high,low,close,volume,amount,adjustflag
30 | # 周月线指标:date,code,open,high,low,close,volume,amount,adjustflag,turn,pctChg
31 | rs = bs.query_history_k_data_plus(bao_code,
32 | fields,
33 | start_date=start_date, end_date=end_date,
34 | frequency=freq, adjustflag=adj)
35 | if rs.error_code is not '0':
36 | print('query_history_k_data_plus respond error_code:' + rs.error_code)
37 | print('query_history_k_data_plus respond error_msg:' + rs.error_msg)
38 | #
39 | # # 登出系统
40 | # bs.logout()
41 | # 打印结果集
42 | data_list = []
43 | while (rs.error_code == '0') & rs.next():
44 | # 获取一条记录,将记录合并在一起
45 | data_list.append(rs.get_row_data())
46 | data = pd.DataFrame(data_list, columns=rs.fields)
47 | stk_columns = ['date', 'open', 'high', 'low', 'close', 'vol', 'amount']
48 | if 'time' in fields:
49 | data.rename(columns={'date': 'day', 'time': 'date', 'volume': 'vol'},
50 | inplace=True)
51 | data = data[stk_columns]
52 | data['date'] = data.date.apply(lambda x: date_convert(x, '%Y%m%d%H%M%S%f', '%Y-%m-%d %H:%M:%S'))
53 | else:
54 | data.rename(columns={'volume': 'vol'},
55 | inplace=True)
56 | data = data[stk_columns]
57 | data[["date"]] = data[["date"]].astype(str)
58 | data[["open"]] = data[["open"]].astype(float)
59 | data[["high"]] = data[["high"]].astype(float)
60 | data[["low"]] = data[["low"]].astype(float)
61 | data[["close"]] = data[["close"]].astype(float)
62 | data[["vol"]] = data[["vol"]].astype(int)
63 | data[["amount"]] = data[["amount"]].astype(float)
64 | return data
65 |
66 |
67 | def get_15min(ts_code='', start_date='', end_date='', retry=20, pause=0.1):
68 | return _baostock_get_kline(ts_code=ts_code, freq='15', start_date=start_date, end_date=end_date)
69 |
70 |
71 | def get_hour(ts_code='', start_date='', end_date='', retry=20, pause=0.1):
72 | return _baostock_get_kline(ts_code=ts_code, freq='60', start_date=start_date, end_date=end_date)
73 |
74 |
75 | def get_daily(ts_code='', start_date='', end_date='', retry=20, pause=0.1):
76 | for _ in range(retry):
77 | try:
78 | return ts.pro_bar(ts_code=ts_code, adj='qfq', start_date=start_date, end_date=end_date)
79 | except:
80 | time.sleep(pause)
81 |
82 |
83 | def get_week(ts_code='', start_date='', end_date='', retry=20, pause=0.1):
84 | for _ in range(retry):
85 | try:
86 | return ts.pro_bar(ts_code=ts_code, adj='qfq', freq='W', start_date=start_date, end_date=end_date)
87 | except:
88 | time.sleep(pause)
89 |
90 |
91 | if __name__ == '__main__':
92 | print(get_15min(ts_code='600000.SH', start_date='2020-01-01', end_date='2020-08-19'))
93 | print(get_hour(ts_code='600000.SH', start_date='2020-01-01', end_date='2020-08-19'))
94 | # print(get_daily(ts_code='600000.SH', start_date='2020-01-01', end_date='2020-08-19'))
95 |
--------------------------------------------------------------------------------
/config/sql/zh_stocks_d.sql:
--------------------------------------------------------------------------------
1 |
2 | SET NAMES utf8mb4;
3 | SET FOREIGN_KEY_CHECKS = 0;
4 |
5 | -- ----------------------------
6 | -- Table structure for zh_stocks_d
7 | -- ----------------------------
8 | DROP TABLE IF EXISTS `zh_stocks_d`;
9 | CREATE TABLE `zh_stocks_d` (
10 | `date` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '日期',
11 | `code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '代码',
12 | `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '名称',
13 | `industry` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '行业',
14 | `sw_ind1` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '申万一级行业',
15 | `sw_ind1_weight` decimal(20,3) DEFAULT NULL COMMENT '申万一级行业权重',
16 | `area` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '地区',
17 | `market` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '市场',
18 | `open` decimal(20,3) DEFAULT NULL COMMENT '开盘价',
19 | `high` decimal(20,3) DEFAULT NULL COMMENT '最高价',
20 | `low` decimal(20,3) DEFAULT NULL COMMENT '最低价',
21 | `close` decimal(20,3) DEFAULT NULL COMMENT '收盘价',
22 | `pre_close` decimal(20,3) DEFAULT NULL COMMENT '前一天收盘价',
23 | `is_gap` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否有缺口',
24 | `vol` bigint DEFAULT NULL COMMENT '成交量',
25 | `ma_vol` bigint DEFAULT NULL COMMENT '月均成交量',
26 | `vol_rate` decimal(20,3) DEFAULT NULL COMMENT '成交量/月均量',
27 | `amount` bigint DEFAULT NULL COMMENT '成交额',
28 | `ma_amt` bigint DEFAULT NULL COMMENT '月()均成交额',
29 | `amt_rate` decimal(20,3) DEFAULT NULL COMMENT '成交额/月均额',
30 | `s_ma` decimal(20,3) DEFAULT NULL COMMENT 'MA20',
31 | `m_ma` decimal(20,3) DEFAULT NULL COMMENT 'MA60',
32 | `l_ma` decimal(20,3) DEFAULT NULL COMMENT 'MA120',
33 | `s_ema` decimal(20,3) DEFAULT NULL COMMENT 'EMA20',
34 | `m_ema` decimal(20,3) DEFAULT NULL COMMENT 'EMA60',
35 | `l_ema` decimal(20,3) DEFAULT NULL COMMENT 'EMA120',
36 | `cs` decimal(20,3) DEFAULT NULL COMMENT 'C/S',
37 | `pcs` decimal(20,3) DEFAULT NULL COMMENT '前一日 C/S',
38 | `is_cs_over` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否破线(上穿)',
39 | `sm` decimal(20,3) DEFAULT NULL COMMENT 'S/M',
40 | `psm` decimal(20,3) DEFAULT NULL COMMENT '前一日 S/M',
41 | `is_sm_over` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否交叉(MA20上穿MA60)',
42 | `ml` decimal(20,3) DEFAULT NULL COMMENT 'M/L',
43 | `pml` decimal(20,3) DEFAULT NULL COMMENT '前一日 M/L',
44 | `is_ml_over` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否交叉(MA60上穿MA120)',
45 | `bais` decimal(20,3) DEFAULT NULL COMMENT 'C/S+S/M+M/L',
46 | `ecs` decimal(20,3) DEFAULT NULL COMMENT 'EMA C/S',
47 | `esm` decimal(20,3) DEFAULT NULL COMMENT 'EMA S/M',
48 | `pesm` decimal(20,3) DEFAULT NULL COMMENT '前一日 EMA S/M',
49 | `is_esm_over` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否交叉(EMA20上穿EMA60)',
50 | `eml` decimal(20,3) DEFAULT NULL COMMENT 'EMA M/L',
51 | `peml` decimal(20,3) DEFAULT NULL COMMENT '前一日 EMA M/L',
52 | `is_eml_over` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否交叉(EMA60上穿EMA120)',
53 | `ebais` decimal(20,3) DEFAULT NULL COMMENT 'EMA C/S+S/M+M/L',
54 | `s_close` decimal(20,3) DEFAULT NULL COMMENT 'MA20 抵扣价 ',
55 | `s_pre_close` decimal(20,3) DEFAULT NULL COMMENT 'MA21 抵扣价 ',
56 | `is_s_up` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'MA20 是否向上拐头',
57 | `m_close` decimal(20,3) DEFAULT NULL COMMENT 'MA60 抵扣价 ',
58 | `m_pre_close` decimal(20,3) DEFAULT NULL COMMENT 'MA61 抵扣价 ',
59 | `is_m_up` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'MA60 是否向上拐头',
60 | `l_close` decimal(20,3) DEFAULT NULL COMMENT 'MA120 抵扣价 ',
61 | `l_pre_close` decimal(20,3) DEFAULT NULL COMMENT 'MA121 抵扣价 ',
62 | `is_l_up` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'MA120 是否向上拐头',
63 | PRIMARY KEY (`date`,`code`) USING BTREE
64 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
65 |
66 | SET FOREIGN_KEY_CHECKS = 1;
67 |
--------------------------------------------------------------------------------
/tools/util/date.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | from datetime import datetime
4 | import calendar
5 | from dateutil.relativedelta import *
6 |
7 | lastday_map = {}
8 |
9 |
10 | def now(format="%Y-%m-%d %H:%M:%S"):
11 | curr_date = datetime.now()
12 | return datetime.strftime(curr_date, format)
13 |
14 |
15 | def get_current_day(format="%Y-%m-%d"):
16 | curr_date = datetime.now()
17 | return datetime.strftime(curr_date, format)
18 |
19 |
20 | def get_end_day(format="%Y-%m-%d"):
21 | today = datetime.today()
22 | end_day = today + relativedelta(days=+1)
23 | return datetime.strftime(end_day, format)
24 |
25 |
26 | def get_week_ago(format="%Y-%m-%d"):
27 | today = datetime.today()
28 | week_ago = today + relativedelta(days=-7)
29 | return datetime.strftime(week_ago, format)
30 |
31 |
32 | def get_2week_ago(format="%Y-%m-%d"):
33 | today = datetime.today()
34 | week_ago = today + relativedelta(days=-14)
35 | return datetime.strftime(week_ago, format)
36 |
37 |
38 | def get_month_ago(format="%Y-%m-%d"):
39 | today = datetime.today()
40 | month_ago = today + relativedelta(months=-1)
41 | return datetime.strftime(month_ago, format)
42 |
43 |
44 | def get_2month_ago(format="%Y-%m-%d"):
45 | today = datetime.today()
46 | month_ago = today + relativedelta(months=-2)
47 | return datetime.strftime(month_ago, format)
48 |
49 |
50 | def get_3month_ago(format="%Y-%m-%d"):
51 | today = datetime.today()
52 | month_ago = today + relativedelta(months=-3)
53 | return datetime.strftime(month_ago, format)
54 |
55 |
56 | def get_year_ago(format="%Y-%m-%d"):
57 | today = datetime.today()
58 | year_ago = today + relativedelta(years=-1)
59 | return datetime.strftime(year_ago, format)
60 |
61 | def get_2year_ago(format="%Y-%m-%d"):
62 | today = datetime.today()
63 | two_year_ago = today + relativedelta(years=-2)
64 | return datetime.strftime(two_year_ago, format)
65 |
66 | def get_3year_ago(format="%Y-%m-%d"):
67 | today = datetime.today()
68 | three_year_ago = today + relativedelta(years=-3)
69 | return datetime.strftime(three_year_ago, format)
70 |
71 |
72 | def get_current_day(format="%Y-%m-%d"):
73 | curr_date = datetime.now()
74 | return datetime.strftime(curr_date, format)
75 |
76 |
77 | def date_convert(date, format, target_format):
78 | return datetime.strftime(datetime.strptime(date, format), target_format)
79 |
80 |
81 | def get_month_firstday_and_lastday(year=None, month=None):
82 | """
83 | :param year: 年份,默认是本年,可传int或str类型
84 | :param month: 月份,默认是本月,可传int或str类型
85 | :return: firstDay: 当月的第一天,datetime.date类型
86 | lastDay: 当月的最后一天,datetime.date类型
87 | """
88 | if year:
89 | year = int(year)
90 | else:
91 | year = datetime.today().year
92 |
93 | if month:
94 | month = int(month)
95 | else:
96 | month = datetime.today().month
97 |
98 | # 获取当月第一天的星期和当月的总天数
99 | firstDayWeekDay, monthRange = calendar.monthrange(year, month)
100 |
101 | # 获取当月的第一天
102 | firstDay = datetime(year=year, month=month, day=1)
103 | lastDay = datetime(year=year, month=month, day=monthRange)
104 |
105 | return firstDay, lastDay
106 |
107 |
108 | def get_month_lastday(datestr, format="%Y-%m-%d"):
109 | if datestr in lastday_map:
110 | return lastday_map[datestr]
111 |
112 | date = datetime.strptime(datestr, format)
113 | year = date.year
114 | month = date.month
115 | firstDay, lastDay = get_month_firstday_and_lastday(year, month)
116 | result = datetime.strftime(lastDay, format)
117 | lastday_map[datestr] = result
118 | return result
119 |
120 |
121 | def get_target_date2(date, span, format="%Y-%m-%d"):
122 | curr_date = datetime.strptime(date, format)
123 | target = curr_date + relativedelta(days=span)
124 | return datetime.strftime(target, format)
125 |
126 |
127 | def get_target_date(span, format="%Y-%m-%d"):
128 | today = datetime.today()
129 | target = today + relativedelta(days=span)
130 | return datetime.strftime(target, format)
131 |
132 |
133 | def split_date(datestr, format="%Y-%m-%d"):
134 | date = datetime.strptime(datestr, format)
135 | return date.year, date.month, date.day
136 |
137 |
138 | if __name__ == '__main__':
139 | print(get_target_date(0))
140 | print(get_target_date(10))
141 | print(get_target_date(-1))
142 |
--------------------------------------------------------------------------------
/config/sql/us_stocks_d.sql:
--------------------------------------------------------------------------------
1 |
2 | SET NAMES utf8mb4;
3 | SET FOREIGN_KEY_CHECKS = 0;
4 |
5 | -- ----------------------------
6 | -- Table structure for us_stocks_d
7 | -- ----------------------------
8 | DROP TABLE IF EXISTS `us_stocks_d`;
9 | CREATE TABLE `us_stocks_d` (
10 | `date` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '日期',
11 | `code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '代码',
12 | `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '名称',
13 | `sector` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '板块',
14 | `sp_sector` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '标普板块',
15 | `industry` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '行业',
16 | `total_cap` decimal(10,3) DEFAULT NULL COMMENT '总市值',
17 | `is_spx` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否标普500 成分股',
18 | `spx_weight` decimal(20,3) DEFAULT NULL COMMENT '标普500权重',
19 | `is_ndx` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否纳斯达克成分股',
20 | `ndx_weight` decimal(20,3) DEFAULT NULL COMMENT '纳斯达克权重',
21 | `is_dji` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否道琼斯成分股',
22 | `dji_weight` decimal(20,3) DEFAULT NULL COMMENT '道琼斯权重',
23 | `open` decimal(20,3) DEFAULT NULL COMMENT '开盘价',
24 | `high` decimal(20,3) DEFAULT NULL COMMENT '最高价',
25 | `low` decimal(20,3) DEFAULT NULL COMMENT '最低价',
26 | `close` decimal(20,3) DEFAULT NULL COMMENT '收盘价',
27 | `pre_close` decimal(20,3) DEFAULT NULL COMMENT '前一天收盘价',
28 | `is_gap` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否有缺口',
29 | `vol` bigint DEFAULT NULL COMMENT '成交量',
30 | `ma_vol` bigint DEFAULT NULL COMMENT '月均成交量',
31 | `vol_rate` decimal(20,3) DEFAULT NULL COMMENT '成交量/月均量',
32 | `amount` bigint DEFAULT NULL COMMENT '成交额',
33 | `ma_amt` bigint DEFAULT NULL COMMENT '月()均成交额',
34 | `amt_rate` decimal(20,3) DEFAULT NULL COMMENT '成交额/月均额',
35 | `s_ma` decimal(20,3) DEFAULT NULL COMMENT 'MA20',
36 | `m_ma` decimal(20,3) DEFAULT NULL COMMENT 'MA60',
37 | `l_ma` decimal(20,3) DEFAULT NULL COMMENT 'MA120',
38 | `s_ema` decimal(20,3) DEFAULT NULL COMMENT 'EMA20',
39 | `m_ema` decimal(20,3) DEFAULT NULL COMMENT 'EMA60',
40 | `l_ema` decimal(20,3) DEFAULT NULL COMMENT 'EMA120',
41 | `cs` decimal(20,3) DEFAULT NULL COMMENT 'C/S',
42 | `pcs` decimal(20,3) DEFAULT NULL COMMENT '前一日 C/S',
43 | `is_cs_over` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否破线(上穿)',
44 | `sm` decimal(20,3) DEFAULT NULL COMMENT 'S/M',
45 | `psm` decimal(20,3) DEFAULT NULL COMMENT '前一日 S/M',
46 | `is_sm_over` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否交叉(MA20上穿MA60)',
47 | `ml` decimal(20,3) DEFAULT NULL COMMENT 'M/L',
48 | `pml` decimal(20,3) DEFAULT NULL COMMENT '前一日 M/L',
49 | `is_ml_over` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否交叉(MA60上穿MA120)',
50 | `bais` decimal(20,3) DEFAULT NULL COMMENT 'C/S+S/M+M/L',
51 | `ecs` decimal(20,3) DEFAULT NULL COMMENT 'EMA C/S',
52 | `esm` decimal(20,3) DEFAULT NULL COMMENT 'EMA S/M',
53 | `pesm` decimal(20,3) DEFAULT NULL COMMENT '前一日 EMA S/M',
54 | `is_esm_over` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否交叉(EMA20上穿EMA60)',
55 | `eml` decimal(20,3) DEFAULT NULL COMMENT 'EMA M/L',
56 | `peml` decimal(20,3) DEFAULT NULL COMMENT '前一日 EMA M/L',
57 | `is_eml_over` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '是否交叉(EMA60上穿EMA120)',
58 | `ebais` decimal(20,3) DEFAULT NULL COMMENT 'EMA C/S+S/M+M/L',
59 | `s_close` decimal(20,3) DEFAULT NULL COMMENT 'MA20 抵扣价 ',
60 | `s_pre_close` decimal(20,3) DEFAULT NULL COMMENT 'MA21 抵扣价 ',
61 | `is_s_up` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'MA20 是否向上拐头',
62 | `m_close` decimal(20,3) DEFAULT NULL COMMENT 'MA60 抵扣价 ',
63 | `m_pre_close` decimal(20,3) DEFAULT NULL COMMENT 'MA61 抵扣价 ',
64 | `is_m_up` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'MA60 是否向上拐头',
65 | `l_close` decimal(20,3) DEFAULT NULL COMMENT 'MA120 抵扣价 ',
66 | `l_pre_close` decimal(20,3) DEFAULT NULL COMMENT 'MA121 抵扣价 ',
67 | `is_l_up` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'MA120 是否向上拐头',
68 | PRIMARY KEY (`date`,`code`) USING BTREE
69 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
70 |
71 | SET FOREIGN_KEY_CHECKS = 1;
--------------------------------------------------------------------------------
/config/sql/us_stocks_sector_d.sql:
--------------------------------------------------------------------------------
1 | create view us_stocks_sector_d as
2 | SELECT
3 | `t`.`date` AS `date`,
4 | round(max(`t`.`MAT`), 0) AS `MAT`,
5 | round(max(`t`.`COM`), 0) AS `COM`,
6 | round(max(`t`.`CNS`), 0) AS `CNS`,
7 | round(max(`t`.`CND`), 0) AS `CND`,
8 | round(max(`t`.`ENE`), 0) AS `ENE`,
9 | round(max(`t`.`FIN`), 0) AS `FIN`,
10 | round(max(`t`.`HLT`), 0) AS `HLT`,
11 | round(max(`t`.`IND`), 0) AS `IND`,
12 | round(max(`t`.`REI`), 0) AS `REI`,
13 | round(max(`t`.`TEC`), 0) AS `TEC`,
14 | round(max(`t`.`UTL`), 0) AS `UTL`,
15 | round(
16 | (
17 | (
18 | (
19 | (
20 | (
21 | (
22 | (
23 | (
24 | (
25 | (
26 | (
27 | max(`t`.`MAT`) + max(`t`.`COM`)
28 | ) + max(`t`.`CNS`)
29 | ) + max(`t`.`CND`)
30 | ) + max(`t`.`ENE`)
31 | ) + max(`t`.`FIN`)
32 | ) + max(`t`.`HLT`)
33 | ) + max(`t`.`IND`)
34 | ) + max(`t`.`REI`)
35 | ) + max(`t`.`TEC`)
36 | ) + max(`t`.`UTL`)
37 | ) / 11
38 | ),
39 | 0
40 | ) AS `TOTAL`
41 | FROM
42 | (
43 | SELECT
44 | `t`.`date` AS `date`,
45 | (
46 | CASE
47 | WHEN (`t`.`sector` = 'Materials') THEN
48 | (
49 | (
50 | sum(`t`.`is_above_s_ma`) / count(DISTINCT `t`.`code`)
51 | ) * 100
52 | )
53 | END
54 | ) AS `MAT`,
55 | (
56 | CASE
57 | WHEN (
58 | `t`.`sector` = 'Communication Services'
59 | ) THEN
60 | (
61 | (
62 | sum(`t`.`is_above_s_ma`) / count(DISTINCT `t`.`code`)
63 | ) * 100
64 | )
65 | END
66 | ) AS `COM`,
67 | (
68 | CASE
69 | WHEN (
70 | `t`.`sector` = 'Consumer Staples'
71 | ) THEN
72 | (
73 | (
74 | sum(`t`.`is_above_s_ma`) / count(DISTINCT `t`.`code`)
75 | ) * 100
76 | )
77 | END
78 | ) AS `CNS`,
79 | (
80 | CASE
81 | WHEN (
82 | `t`.`sector` = 'Consumer Discretionary'
83 | ) THEN
84 | (
85 | (
86 | sum(`t`.`is_above_s_ma`) / count(DISTINCT `t`.`code`)
87 | ) * 100
88 | )
89 | END
90 | ) AS `CND`,
91 | (
92 | CASE
93 | WHEN (`t`.`sector` = 'Energy') THEN
94 | (
95 | (
96 | sum(`t`.`is_above_s_ma`) / count(DISTINCT `t`.`code`)
97 | ) * 100
98 | )
99 | END
100 | ) AS `ENE`,
101 | (
102 | CASE
103 | WHEN (`t`.`sector` = 'Financials') THEN
104 | (
105 | (
106 | sum(`t`.`is_above_s_ma`) / count(DISTINCT `t`.`code`)
107 | ) * 100
108 | )
109 | END
110 | ) AS `FIN`,
111 | (
112 | CASE
113 | WHEN (`t`.`sector` = 'Health Care') THEN
114 | (
115 | (
116 | sum(`t`.`is_above_s_ma`) / count(DISTINCT `t`.`code`)
117 | ) * 100
118 | )
119 | END
120 | ) AS `HLT`,
121 | (
122 | CASE
123 | WHEN (`t`.`sector` = 'Industrials') THEN
124 | (
125 | (
126 | sum(`t`.`is_above_s_ma`) / count(DISTINCT `t`.`code`)
127 | ) * 100
128 | )
129 | END
130 | ) AS `IND`,
131 | (
132 | CASE
133 | WHEN (`t`.`sector` = 'Real Estate') THEN
134 | (
135 | (
136 | sum(`t`.`is_above_s_ma`) / count(DISTINCT `t`.`code`)
137 | ) * 100
138 | )
139 | END
140 | ) AS `REI`,
141 | (
142 | CASE
143 | WHEN (
144 | `t`.`sector` = 'Information Technology'
145 | ) THEN
146 | (
147 | (
148 | sum(`t`.`is_above_s_ma`) / count(DISTINCT `t`.`code`)
149 | ) * 100
150 | )
151 | END
152 | ) AS `TEC`,
153 | (
154 | CASE
155 | WHEN (`t`.`sector` = 'Utilities') THEN
156 | (
157 | (
158 | sum(`t`.`is_above_s_ma`) / count(DISTINCT `t`.`code`)
159 | ) * 100
160 | )
161 | END
162 | ) AS `UTL`
163 | FROM
164 | (
165 | SELECT
166 | `t1`.`date` AS `date`,
167 | `t1`.`code` AS `code`,
168 | `t1`.`sp_sector` AS `sector`,
169 | `t1`.`is_above_s_ma` AS `is_above_s_ma`
170 | FROM
171 | (
172 | SELECT
173 | `us_stocks_d`.`date` AS `date`,
174 | `us_stocks_d`.`code` AS `code`,
175 | `us_stocks_d`.`name` AS `name`,
176 | `us_stocks_d`.`sector` AS `sector`,
177 | `us_stocks_d`.`sp_sector` AS `sp_sector`,
178 | `us_stocks_d`.`industry` AS `industry`,
179 | `us_stocks_d`.`total_cap` AS `total_cap`,
180 | `us_stocks_d`.`is_spx` AS `is_spx`,
181 | `us_stocks_d`.`spx_weight` AS `spx_weight`,
182 | `us_stocks_d`.`is_ndx` AS `is_ndx`,
183 | `us_stocks_d`.`ndx_weight` AS `ndx_weight`,
184 | `us_stocks_d`.`is_dji` AS `is_dji`,
185 | `us_stocks_d`.`dji_weight` AS `dji_weight`,
186 | `us_stocks_d`.`open` AS `open`,
187 | `us_stocks_d`.`high` AS `high`,
188 | `us_stocks_d`.`low` AS `low`,
189 | `us_stocks_d`.`close` AS `close`,
190 | `us_stocks_d`.`pre_close` AS `pre_close`,
191 | `us_stocks_d`.`is_gap` AS `is_gap`,
192 | `us_stocks_d`.`vol` AS `vol`,
193 | `us_stocks_d`.`ma_vol` AS `ma_vol`,
194 | `us_stocks_d`.`vol_rate` AS `vol_rate`,
195 | `us_stocks_d`.`s_ma` AS `s_ma`,
196 | `us_stocks_d`.`m_ma` AS `m_ma`,
197 | `us_stocks_d`.`l_ma` AS `l_ma`,
198 | `us_stocks_d`.`s_ema` AS `s_ema`,
199 | `us_stocks_d`.`m_ema` AS `m_ema`,
200 | `us_stocks_d`.`l_ema` AS `l_ema`,
201 | `us_stocks_d`.`cs` AS `cs`,
202 | `us_stocks_d`.`pcs` AS `pcs`,
203 | `us_stocks_d`.`is_cs_over` AS `is_cs_over`,
204 | `us_stocks_d`.`sm` AS `sm`,
205 | `us_stocks_d`.`psm` AS `psm`,
206 | `us_stocks_d`.`is_sm_over` AS `is_sm_over`,
207 | `us_stocks_d`.`ml` AS `ml`,
208 | `us_stocks_d`.`pml` AS `pml`,
209 | `us_stocks_d`.`is_ml_over` AS `is_ml_over`,
210 | `us_stocks_d`.`bais` AS `bais`,
211 | `us_stocks_d`.`ecs` AS `ecs`,
212 | `us_stocks_d`.`esm` AS `esm`,
213 | `us_stocks_d`.`pesm` AS `pesm`,
214 | `us_stocks_d`.`is_esm_over` AS `is_esm_over`,
215 | `us_stocks_d`.`eml` AS `eml`,
216 | `us_stocks_d`.`peml` AS `peml`,
217 | `us_stocks_d`.`is_eml_over` AS `is_eml_over`,
218 | `us_stocks_d`.`ebais` AS `ebais`,
219 | `us_stocks_d`.`s_close` AS `s_close`,
220 | `us_stocks_d`.`s_pre_close` AS `s_pre_close`,
221 | `us_stocks_d`.`is_s_up` AS `is_s_up`,
222 | `us_stocks_d`.`m_close` AS `m_close`,
223 | `us_stocks_d`.`m_pre_close` AS `m_pre_close`,
224 | `us_stocks_d`.`is_m_up` AS `is_m_up`,
225 | `us_stocks_d`.`l_close` AS `l_close`,
226 | `us_stocks_d`.`l_pre_close` AS `l_pre_close`,
227 | `us_stocks_d`.`is_l_up` AS `is_l_up`,
228 | (
229 | CASE
230 | WHEN (
231 | `us_stocks_d`.`close` > `us_stocks_d`.`s_ma`
232 | ) THEN
233 | 1
234 | ELSE
235 | 0
236 | END
237 | ) AS `is_above_s_ma`
238 | FROM
239 | `us_stocks_d`
240 | WHERE
241 | (
242 | `us_stocks_d`.`date` >= CONVERT (
243 | date_format(
244 | (now() - INTERVAL 6 MONTH),
245 | '%Y-%m-%d'
246 | ) USING utf8mb4
247 | )
248 | )
249 | ) `t1`
250 | ) `t`
251 | WHERE
252 | (`t`.`sector` IS NOT NULL)
253 | GROUP BY
254 | `t`.`date`,
255 | `t`.`sector`
256 | ) `t`
257 | GROUP BY
258 | `t`.`date`
259 | ORDER BY
260 | `t`.`date` DESC
261 | ;
--------------------------------------------------------------------------------
/tools/util/analysis.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | import talib as ta
4 | import numpy as np
5 | import pandas as pd
6 | from matplotlib import pyplot as plt
7 | from matplotlib import colors
8 | import seaborn as sns
9 | import imgkit
10 |
11 |
12 | def stock_ma(data, short, mid, long):
13 | data = data.set_index(['date']).sort_index()
14 | close = data.close.values
15 | data.loc[:, 's_ma'] = ta.SMA(close, timeperiod=short)
16 | data.loc[:, 'm_ma'] = ta.SMA(close, timeperiod=mid)
17 | data.loc[:, 'l_ma'] = ta.SMA(close, timeperiod=long)
18 |
19 | data.loc[:, 's_ema'] = ta.EMA(close, timeperiod=short)
20 | data.loc[:, 'm_ema'] = ta.EMA(close, timeperiod=mid)
21 | data.loc[:, 'l_ema'] = ta.EMA(close, timeperiod=long)
22 |
23 | data.loc[:, 'cs'] = (data['close'] - data['s_ma']) / data['s_ma'] * 100
24 | data.loc[:, 'sm'] = (data['s_ma'] - data['m_ma']) / data['m_ma'] * 100
25 | data.loc[:, 'ml'] = (data['m_ma'] - data['l_ma']) / data['l_ma'] * 100
26 | data.loc[:, 'bais'] = data['cs'] + data['sm'] + data['ml']
27 |
28 | data.loc[:, 'ecs'] = (data['close'] - data['s_ema']) / data['s_ema'] * 100
29 | data.loc[:, 'esm'] = (data['s_ema'] - data['m_ema']) / data['m_ema'] * 100
30 | data.loc[:, 'eml'] = (data['m_ema'] - data['l_ema']) / data['l_ema'] * 100
31 | data.loc[:, 'ebais'] = data['ecs'] + data['esm'] + data['eml']
32 | return data.reset_index()
33 |
34 |
35 | def stock_vol(data, short):
36 | data = data.set_index(['date']).sort_index()
37 | data['vol'] = data['vol'].replace(np.nan, 0)
38 | vol = data.vol.values
39 | vol = vol.astype(float)
40 | data.loc[:, 'ma_vol'] = ta.SMA(vol, timeperiod=short)
41 | data.loc[:, 'vol_rate'] = data['vol'] / data['ma_vol']
42 | return data.reset_index()
43 |
44 |
45 | def stock_amount(data, short):
46 | data = data.set_index(['date']).sort_index()
47 | data['amount'] = data['amount'].replace(np.nan, 0)
48 | amount = data.amount.values
49 | amount = amount.astype(float)
50 | data.loc[:, 'ma_amt'] = ta.SMA(amount, timeperiod=short)
51 | data.loc[:, 'amt_rate'] = data['amount'] / data['ma_amt']
52 | return data.reset_index()
53 |
54 |
55 | def is_gap(h, l, c, p_h, p_l, p_c):
56 | if c is None or p_c is None:
57 | return 'N'
58 | elif c > p_c:
59 | return "Y" if l > p_h else "N"
60 | else:
61 | return "Y" if h < p_l else "N"
62 |
63 |
64 | def is_over(x, px):
65 | if x is None or px is None:
66 | return 'N'
67 | elif x > 0 and px < 0:
68 | return 'Y'
69 | else:
70 | return 'N'
71 |
72 |
73 | def stock_gap_and_over(data):
74 | data[["date"]] = data[["date"]].astype(str)
75 | data['row_num'] = data.date.rank(method='min').astype(int)
76 | data_copy = data.copy()
77 | data_copy.row_num = data_copy.row_num.apply(lambda x: x + 1)
78 | data_copy.rename(columns={'open': 'pre_open', 'high': 'pre_high', 'low': 'pre_low', 'close': 'pre_close',
79 | 'cs': 'pcs', 'sm': 'psm', 'ml': 'pml', 'ecs': 'pecs', 'esm': 'pesm', 'eml': 'peml'
80 | },
81 | inplace=True)
82 | data_copy = data_copy[['code', 'row_num', 'pre_open', 'pre_high', 'pre_low', 'pre_close',
83 | 'pcs', 'psm', 'pml', 'pecs', 'pesm', 'peml'
84 | ]]
85 | data = data.set_index(['code', 'row_num'])
86 | data_copy = data_copy.set_index(['code', 'row_num'])
87 | data = pd.merge(data, data_copy, how='left', on=['code', 'row_num'])
88 |
89 | data['is_gap'] = data.apply(
90 | lambda row: is_gap(row['high'], row['low'], row['close'], row['pre_high'], row['pre_low'], row['pre_close']),
91 | axis=1, raw=True)
92 | data['is_esm_over'] = data.apply(
93 | lambda row: is_over(row['esm'], row['pesm']),
94 | axis=1, raw=True)
95 | data['is_eml_over'] = data.apply(
96 | lambda row: is_over(row['eml'], row['peml']),
97 | axis=1, raw=True)
98 | data['is_cs_over'] = data.apply(
99 | lambda row: is_over(row['cs'], row['pcs']),
100 | axis=1, raw=True)
101 | data['is_sm_over'] = data.apply(
102 | lambda row: is_over(row['sm'], row['psm']),
103 | axis=1, raw=True)
104 | data['is_ml_over'] = data.apply(
105 | lambda row: is_over(row['ml'], row['pml']),
106 | axis=1, raw=True)
107 | return data.reset_index()
108 |
109 |
110 | def is_turn_up(c, p_c, c_ago, p_c_ago):
111 | if p_c_ago is None or c_ago is None:
112 | return 'N'
113 | elif c > c_ago and p_c < p_c_ago:
114 | return "Y"
115 | else:
116 | return "N"
117 |
118 |
119 | def stock_turn_up(data, c, day):
120 | data[["date"]] = data[["date"]].astype(str)
121 | data['row_num'] = data.date.rank(method='min').astype(int)
122 | data_copy = data.copy()
123 | data_copy.row_num = data_copy.row_num.apply(lambda x: x + day)
124 | close_ago = '{}_close'.format(c)
125 | pre_close_ago = '{}_pre_close'.format(c)
126 | data_copy.rename(columns={'close': close_ago, 'pre_close': pre_close_ago},
127 | inplace=True)
128 | data_copy = data_copy[['code', 'row_num', close_ago, pre_close_ago]]
129 | data = data.set_index(['code', 'row_num'])
130 | data_copy = data_copy.set_index(['code', 'row_num'])
131 | data = pd.merge(data, data_copy, how='left', on=['code', 'row_num'])
132 |
133 | column = 'is_{}_up'.format(c)
134 | data[column] = data.apply(
135 | lambda row: is_turn_up(row['close'], row['pre_close'], row[close_ago], row[pre_close_ago]),
136 | axis=1, raw=True)
137 | return data.reset_index()
138 |
139 |
140 | def stock_analysis(data, short, mid, long):
141 | if data is None or data.empty or data.date.size < long + 1:
142 | return None
143 |
144 | stk_columns = ['date', 'code', 'open', 'high', 'low', 'close', 'vol']
145 | data = data[stk_columns]
146 | data = stock_vol(data, short)
147 | data = stock_ma(data, short, mid, long)
148 | data = stock_gap_and_over(data)
149 | data = stock_turn_up(data, 's', short)
150 | data = stock_turn_up(data, 'm', mid)
151 | data = stock_turn_up(data, 'l', long)
152 | return data
153 |
154 |
155 | def stock_zh_analysis(data, short, mid, long):
156 | if data is None or data.empty or data.date.size < long + 1:
157 | return None
158 |
159 | stk_columns = ['date', 'ts_code', 'code', 'open', 'high', 'low', 'close', 'vol', 'amount']
160 | data = data[stk_columns]
161 | data = stock_vol(data, short)
162 | data = stock_amount(data, short)
163 | data = stock_ma(data, short, mid, long)
164 | data = stock_gap_and_over(data)
165 | data = stock_turn_up(data, 's', short)
166 | data = stock_turn_up(data, 'm', mid)
167 | data = stock_turn_up(data, 'l', long)
168 | return data
169 |
170 |
171 | def _background_gradient(s, m, M, cmap='PuBu', low=0, high=0):
172 | rng = M - m
173 | norm = colors.Normalize(m - (rng * low),
174 | M + (rng * high))
175 | normed = norm(s.values)
176 | c = [colors.rgb2hex(x) for x in plt.cm.get_cmap(cmap)(normed)]
177 | return ['background-color: %s' % color for color in c]
178 |
179 |
180 | def market_breadth(data, file):
181 | if data is None or data.empty:
182 | return None
183 | cm = sns.diverging_palette(10, 130, as_cmap=True)
184 | options = {'encoding': "UTF-8"}
185 | data = data.set_index('date')
186 | data = data.astype(int)
187 | data.style.apply(_background_gradient, cmap=cm, m=0, M=100)
188 | html = data.style.apply(_background_gradient, cmap=cm, m=0, M=100).render()
189 | imgkit.from_string(html, file, options=options)
190 |
191 |
192 | def recommend(data, index_columns, file):
193 | if data is None or data.empty:
194 | return None
195 |
196 | options = {'encoding': "UTF-8"}
197 | data = data.set_index(index_columns).round(2)
198 | cm = sns.diverging_palette(10, 130, as_cmap=True)
199 | df_html = data.style.apply(_background_gradient, cmap=cm, m=-50, M=50).render()
200 | imgkit.from_string(df_html, file, options=options)
201 |
--------------------------------------------------------------------------------
/config/sql/zh_stocks_sector_sw_d.sql:
--------------------------------------------------------------------------------
1 | -- 创建 tmp_zh_stocks_sw_sector_d view
2 | create view tmp_zh_stocks_sw_sector_d as
3 | select
4 | date
5 | ,sector
6 | ,sum(is_above_s_ma) / COUNT(DISTINCT code) as above_rate
7 | from (
8 | select
9 | `t1`.`date` AS `date`
10 | ,`t1`.`code` AS `code`
11 | ,`t1`.`sw_ind1` AS `sector`
12 | ,`t1`.`is_above_s_ma` AS `is_above_s_ma`
13 | from (
14 | select
15 | *,case when (`close` > `s_ma`) then 1 else 0 end AS `is_above_s_ma`
16 | from `zh_stocks_d`
17 | where (`date` >= DATE_FORMAT(DATE_SUB(NOW(),INTERVAL 6 month), '%Y-%m-%d'))
18 | ) `t1`
19 | ) a
20 | where (`a`.`sector` is not null)
21 | group by
22 | date
23 | ,sector
24 | ;
25 |
26 | -- 创建 zh_stocks_sector_sw_d view
27 | create view zh_stocks_sector_sw_d as
28 | SELECT
29 | `tmp_zh_stocks_sw_sector_d`.`date` AS `date`,
30 | round(
31 | sum(
32 | (
33 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100 / 28
34 | )
35 | ),
36 | 0
37 | ) AS `TOTAL`,
38 | round(
39 | sum(
40 |
41 | IF (
42 | (
43 | `tmp_zh_stocks_sw_sector_d`.`sector` = '交通运输'
44 | ),
45 | (
46 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
47 | ),
48 | 0
49 | )
50 | ),
51 | 0
52 | ) AS `交通运输`,
53 | round(
54 | sum(
55 |
56 | IF (
57 | (
58 | `tmp_zh_stocks_sw_sector_d`.`sector` = '传媒'
59 | ),
60 | (
61 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
62 | ),
63 | 0
64 | )
65 | ),
66 | 0
67 | ) AS `传媒`,
68 | round(
69 | sum(
70 |
71 | IF (
72 | (
73 | `tmp_zh_stocks_sw_sector_d`.`sector` = '公用事业'
74 | ),
75 | (
76 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
77 | ),
78 | 0
79 | )
80 | ),
81 | 0
82 | ) AS `公用事业`,
83 | round(
84 | sum(
85 |
86 | IF (
87 | (
88 | `tmp_zh_stocks_sw_sector_d`.`sector` = '农林牧渔'
89 | ),
90 | (
91 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
92 | ),
93 | 0
94 | )
95 | ),
96 | 0
97 | ) AS `农林牧渔`,
98 | round(
99 | sum(
100 |
101 | IF (
102 | (
103 | `tmp_zh_stocks_sw_sector_d`.`sector` = '化工'
104 | ),
105 | (
106 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
107 | ),
108 | 0
109 | )
110 | ),
111 | 0
112 | ) AS `化工`,
113 | round(
114 | sum(
115 |
116 | IF (
117 | (
118 | `tmp_zh_stocks_sw_sector_d`.`sector` = '医药生物'
119 | ),
120 | (
121 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
122 | ),
123 | 0
124 | )
125 | ),
126 | 0
127 | ) AS `医药生物`,
128 | round(
129 | sum(
130 |
131 | IF (
132 | (
133 | `tmp_zh_stocks_sw_sector_d`.`sector` = '商业贸易'
134 | ),
135 | (
136 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
137 | ),
138 | 0
139 | )
140 | ),
141 | 0
142 | ) AS `商业贸易`,
143 | round(
144 | sum(
145 |
146 | IF (
147 | (
148 | `tmp_zh_stocks_sw_sector_d`.`sector` = '国防军工'
149 | ),
150 | (
151 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
152 | ),
153 | 0
154 | )
155 | ),
156 | 0
157 | ) AS `国防军工`,
158 | round(
159 | sum(
160 |
161 | IF (
162 | (
163 | `tmp_zh_stocks_sw_sector_d`.`sector` = '家用电器'
164 | ),
165 | (
166 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
167 | ),
168 | 0
169 | )
170 | ),
171 | 0
172 | ) AS `家用电器`,
173 | round(
174 | sum(
175 |
176 | IF (
177 | (
178 | `tmp_zh_stocks_sw_sector_d`.`sector` = '建筑材料'
179 | ),
180 | (
181 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
182 | ),
183 | 0
184 | )
185 | ),
186 | 0
187 | ) AS `建筑材料`,
188 | round(
189 | sum(
190 |
191 | IF (
192 | (
193 | `tmp_zh_stocks_sw_sector_d`.`sector` = '建筑装饰'
194 | ),
195 | (
196 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
197 | ),
198 | 0
199 | )
200 | ),
201 | 0
202 | ) AS `建筑装饰`,
203 | round(
204 | sum(
205 |
206 | IF (
207 | (
208 | `tmp_zh_stocks_sw_sector_d`.`sector` = '房地产'
209 | ),
210 | (
211 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
212 | ),
213 | 0
214 | )
215 | ),
216 | 0
217 | ) AS `房地产`,
218 | round(
219 | sum(
220 |
221 | IF (
222 | (
223 | `tmp_zh_stocks_sw_sector_d`.`sector` = '有色金属'
224 | ),
225 | (
226 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
227 | ),
228 | 0
229 | )
230 | ),
231 | 0
232 | ) AS `有色金属`,
233 | round(
234 | sum(
235 |
236 | IF (
237 | (
238 | `tmp_zh_stocks_sw_sector_d`.`sector` = '机械设备'
239 | ),
240 | (
241 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
242 | ),
243 | 0
244 | )
245 | ),
246 | 0
247 | ) AS `机械设备`,
248 | round(
249 | sum(
250 |
251 | IF (
252 | (
253 | `tmp_zh_stocks_sw_sector_d`.`sector` = '汽车'
254 | ),
255 | (
256 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
257 | ),
258 | 0
259 | )
260 | ),
261 | 0
262 | ) AS `汽车`,
263 | round(
264 | sum(
265 |
266 | IF (
267 | (
268 | `tmp_zh_stocks_sw_sector_d`.`sector` = '电子元器件'
269 | ),
270 | (
271 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
272 | ),
273 | 0
274 | )
275 | ),
276 | 0
277 | ) AS `电子元器件`,
278 | round(
279 | sum(
280 |
281 | IF (
282 | (
283 | `tmp_zh_stocks_sw_sector_d`.`sector` = '电气设备'
284 | ),
285 | (
286 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
287 | ),
288 | 0
289 | )
290 | ),
291 | 0
292 | ) AS `电气设备`,
293 | round(
294 | sum(
295 |
296 | IF (
297 | (
298 | `tmp_zh_stocks_sw_sector_d`.`sector` = '纺织服装'
299 | ),
300 | (
301 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
302 | ),
303 | 0
304 | )
305 | ),
306 | 0
307 | ) AS `纺织服装`,
308 | round(
309 | sum(
310 |
311 | IF (
312 | (
313 | `tmp_zh_stocks_sw_sector_d`.`sector` = '综合'
314 | ),
315 | (
316 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
317 | ),
318 | 0
319 | )
320 | ),
321 | 0
322 | ) AS `综合`,
323 | round(
324 | sum(
325 |
326 | IF (
327 | (
328 | `tmp_zh_stocks_sw_sector_d`.`sector` = '计算机'
329 | ),
330 | (
331 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
332 | ),
333 | 0
334 | )
335 | ),
336 | 0
337 | ) AS `计算机`,
338 | round(
339 | sum(
340 |
341 | IF (
342 | (
343 | `tmp_zh_stocks_sw_sector_d`.`sector` = '轻工制造'
344 | ),
345 | (
346 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
347 | ),
348 | 0
349 | )
350 | ),
351 | 0
352 | ) AS `轻工制造`,
353 | round(
354 | sum(
355 |
356 | IF (
357 | (
358 | `tmp_zh_stocks_sw_sector_d`.`sector` = '通信'
359 | ),
360 | (
361 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
362 | ),
363 | 0
364 | )
365 | ),
366 | 0
367 | ) AS `通信`,
368 | round(
369 | sum(
370 |
371 | IF (
372 | (
373 | `tmp_zh_stocks_sw_sector_d`.`sector` = '采掘'
374 | ),
375 | (
376 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
377 | ),
378 | 0
379 | )
380 | ),
381 | 0
382 | ) AS `采掘`,
383 | round(
384 | sum(
385 |
386 | IF (
387 | (
388 | `tmp_zh_stocks_sw_sector_d`.`sector` = '钢铁'
389 | ),
390 | (
391 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
392 | ),
393 | 0
394 | )
395 | ),
396 | 0
397 | ) AS `钢铁`,
398 | round(
399 | sum(
400 |
401 | IF (
402 | (
403 | `tmp_zh_stocks_sw_sector_d`.`sector` = '银行'
404 | ),
405 | (
406 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
407 | ),
408 | 0
409 | )
410 | ),
411 | 0
412 | ) AS `银行`,
413 | round(
414 | sum(
415 |
416 | IF (
417 | (
418 | `tmp_zh_stocks_sw_sector_d`.`sector` = '非银金融'
419 | ),
420 | (
421 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
422 | ),
423 | 0
424 | )
425 | ),
426 | 0
427 | ) AS `非银金融`,
428 | round(
429 | sum(
430 |
431 | IF (
432 | (
433 | `tmp_zh_stocks_sw_sector_d`.`sector` = '食品饮料'
434 | ),
435 | (
436 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
437 | ),
438 | 0
439 | )
440 | ),
441 | 0
442 | ) AS `食品饮料`,
443 | round(
444 | sum(
445 |
446 | IF (
447 | (
448 | `tmp_zh_stocks_sw_sector_d`.`sector` = '餐饮旅游'
449 | ),
450 | (
451 | `tmp_zh_stocks_sw_sector_d`.`above_rate` * 100
452 | ),
453 | 0
454 | )
455 | ),
456 | 0
457 | ) AS `餐饮旅游`
458 | FROM
459 | `tmp_zh_stocks_sw_sector_d`
460 | GROUP BY
461 | `tmp_zh_stocks_sw_sector_d`.`date`
462 | ORDER BY
463 | `tmp_zh_stocks_sw_sector_d`.`date` DESC
--------------------------------------------------------------------------------
/config/sql/zh_stocks_industries_d.sql:
--------------------------------------------------------------------------------
1 | create view tmp_zh_stocks_sector_d as
2 | select
3 | date
4 | ,sector
5 | ,sum(is_above_s_ma) / COUNT(DISTINCT code) as above_rate
6 | from (
7 | select
8 | `t1`.`date` AS `date`
9 | ,`t1`.`code` AS `code`
10 | ,`t1`.`industry` AS `sector`
11 | ,`t1`.`is_above_s_ma` AS `is_above_s_ma`
12 | from (
13 | select
14 | *,case when (`close` > `s_ma`) then 1 else 0 end AS `is_above_s_ma`
15 | from `zh_stocks_d`
16 | where (`date` >= DATE_FORMAT(DATE_SUB(NOW(),INTERVAL 6 month), '%Y-%m-%d'))
17 | ) `t1`
18 | ) a
19 | where (`a`.`sector` is not null)
20 | group by
21 | date
22 | ,sector
23 | ;
24 |
25 | create view zh_stocks_industries_d as
26 | SELECT
27 | `tmp_zh_stocks_sector_d`.`date` AS `date`,
28 | round(
29 | sum(
30 | (
31 | `tmp_zh_stocks_sector_d`.`above_rate` * 100 / 110
32 | )
33 | ),
34 | 0
35 | ) AS `TOTAL`,
36 | round(
37 | sum(
38 |
39 | IF (
40 | (
41 | `tmp_zh_stocks_sector_d`.`sector` = 'IT设备'
42 | ),
43 | (
44 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
45 | ),
46 | 0
47 | )
48 | ),
49 | 0
50 | ) AS `IT设备`,
51 | round(
52 | sum(
53 |
54 | IF (
55 | (
56 | `tmp_zh_stocks_sector_d`.`sector` = '专用机械'
57 | ),
58 | (
59 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
60 | ),
61 | 0
62 | )
63 | ),
64 | 0
65 | ) AS `专用机械`,
66 | round(
67 | sum(
68 |
69 | IF (
70 | (
71 | `tmp_zh_stocks_sector_d`.`sector` = '中成药'
72 | ),
73 | (
74 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
75 | ),
76 | 0
77 | )
78 | ),
79 | 0
80 | ) AS `中成药`,
81 | round(
82 | sum(
83 |
84 | IF (
85 | (
86 | `tmp_zh_stocks_sector_d`.`sector` = '乳制品'
87 | ),
88 | (
89 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
90 | ),
91 | 0
92 | )
93 | ),
94 | 0
95 | ) AS `乳制品`,
96 | round(
97 | sum(
98 |
99 | IF (
100 | (
101 | `tmp_zh_stocks_sector_d`.`sector` = '互联网'
102 | ),
103 | (
104 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
105 | ),
106 | 0
107 | )
108 | ),
109 | 0
110 | ) AS `互联网`,
111 | round(
112 | sum(
113 |
114 | IF (
115 | (
116 | `tmp_zh_stocks_sector_d`.`sector` = '仓储物流'
117 | ),
118 | (
119 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
120 | ),
121 | 0
122 | )
123 | ),
124 | 0
125 | ) AS `仓储物流`,
126 | round(
127 | sum(
128 |
129 | IF (
130 | (
131 | `tmp_zh_stocks_sector_d`.`sector` = '供气供热'
132 | ),
133 | (
134 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
135 | ),
136 | 0
137 | )
138 | ),
139 | 0
140 | ) AS `供气供热`,
141 | round(
142 | sum(
143 |
144 | IF (
145 | (
146 | `tmp_zh_stocks_sector_d`.`sector` = '保险'
147 | ),
148 | (
149 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
150 | ),
151 | 0
152 | )
153 | ),
154 | 0
155 | ) AS `保险`,
156 | round(
157 | sum(
158 |
159 | IF (
160 | (
161 | `tmp_zh_stocks_sector_d`.`sector` = '元器件'
162 | ),
163 | (
164 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
165 | ),
166 | 0
167 | )
168 | ),
169 | 0
170 | ) AS `元器件`,
171 | round(
172 | sum(
173 |
174 | IF (
175 | (
176 | `tmp_zh_stocks_sector_d`.`sector` = '全国地产'
177 | ),
178 | (
179 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
180 | ),
181 | 0
182 | )
183 | ),
184 | 0
185 | ) AS `全国地产`,
186 | round(
187 | sum(
188 |
189 | IF (
190 | (
191 | `tmp_zh_stocks_sector_d`.`sector` = '公共交通'
192 | ),
193 | (
194 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
195 | ),
196 | 0
197 | )
198 | ),
199 | 0
200 | ) AS `公共交通`,
201 | round(
202 | sum(
203 |
204 | IF (
205 | (
206 | `tmp_zh_stocks_sector_d`.`sector` = '公路'
207 | ),
208 | (
209 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
210 | ),
211 | 0
212 | )
213 | ),
214 | 0
215 | ) AS `公路`,
216 | round(
217 | sum(
218 |
219 | IF (
220 | (
221 | `tmp_zh_stocks_sector_d`.`sector` = '其他商业'
222 | ),
223 | (
224 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
225 | ),
226 | 0
227 | )
228 | ),
229 | 0
230 | ) AS `其他商业`,
231 | round(
232 | sum(
233 |
234 | IF (
235 | (
236 | `tmp_zh_stocks_sector_d`.`sector` = '其他建材'
237 | ),
238 | (
239 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
240 | ),
241 | 0
242 | )
243 | ),
244 | 0
245 | ) AS `其他建材`,
246 | round(
247 | sum(
248 |
249 | IF (
250 | (
251 | `tmp_zh_stocks_sector_d`.`sector` = '农业综合'
252 | ),
253 | (
254 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
255 | ),
256 | 0
257 | )
258 | ),
259 | 0
260 | ) AS `农业综合`,
261 | round(
262 | sum(
263 |
264 | IF (
265 | (
266 | `tmp_zh_stocks_sector_d`.`sector` = '农用机械'
267 | ),
268 | (
269 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
270 | ),
271 | 0
272 | )
273 | ),
274 | 0
275 | ) AS `农用机械`,
276 | round(
277 | sum(
278 |
279 | IF (
280 | (
281 | `tmp_zh_stocks_sector_d`.`sector` = '农药化肥'
282 | ),
283 | (
284 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
285 | ),
286 | 0
287 | )
288 | ),
289 | 0
290 | ) AS `农药化肥`,
291 | round(
292 | sum(
293 |
294 | IF (
295 | (
296 | `tmp_zh_stocks_sector_d`.`sector` = '出版业'
297 | ),
298 | (
299 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
300 | ),
301 | 0
302 | )
303 | ),
304 | 0
305 | ) AS `出版业`,
306 | round(
307 | sum(
308 |
309 | IF (
310 | (
311 | `tmp_zh_stocks_sector_d`.`sector` = '化学制药'
312 | ),
313 | (
314 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
315 | ),
316 | 0
317 | )
318 | ),
319 | 0
320 | ) AS `化学制药`,
321 | round(
322 | sum(
323 |
324 | IF (
325 | (
326 | `tmp_zh_stocks_sector_d`.`sector` = '化工原料'
327 | ),
328 | (
329 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
330 | ),
331 | 0
332 | )
333 | ),
334 | 0
335 | ) AS `化工原料`,
336 | round(
337 | sum(
338 |
339 | IF (
340 | (
341 | `tmp_zh_stocks_sector_d`.`sector` = '化工机械'
342 | ),
343 | (
344 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
345 | ),
346 | 0
347 | )
348 | ),
349 | 0
350 | ) AS `化工机械`,
351 | round(
352 | sum(
353 |
354 | IF (
355 | (
356 | `tmp_zh_stocks_sector_d`.`sector` = '化纤'
357 | ),
358 | (
359 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
360 | ),
361 | 0
362 | )
363 | ),
364 | 0
365 | ) AS `化纤`,
366 | round(
367 | sum(
368 |
369 | IF (
370 | (
371 | `tmp_zh_stocks_sector_d`.`sector` = '区域地产'
372 | ),
373 | (
374 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
375 | ),
376 | 0
377 | )
378 | ),
379 | 0
380 | ) AS `区域地产`,
381 | round(
382 | sum(
383 |
384 | IF (
385 | (
386 | `tmp_zh_stocks_sector_d`.`sector` = '医疗保健'
387 | ),
388 | (
389 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
390 | ),
391 | 0
392 | )
393 | ),
394 | 0
395 | ) AS `医疗保健`,
396 | round(
397 | sum(
398 |
399 | IF (
400 | (
401 | `tmp_zh_stocks_sector_d`.`sector` = '医药商业'
402 | ),
403 | (
404 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
405 | ),
406 | 0
407 | )
408 | ),
409 | 0
410 | ) AS `医药商业`,
411 | round(
412 | sum(
413 |
414 | IF (
415 | (
416 | `tmp_zh_stocks_sector_d`.`sector` = '半导体'
417 | ),
418 | (
419 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
420 | ),
421 | 0
422 | )
423 | ),
424 | 0
425 | ) AS `半导体`,
426 | round(
427 | sum(
428 |
429 | IF (
430 | (
431 | `tmp_zh_stocks_sector_d`.`sector` = '商品城'
432 | ),
433 | (
434 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
435 | ),
436 | 0
437 | )
438 | ),
439 | 0
440 | ) AS `商品城`,
441 | round(
442 | sum(
443 |
444 | IF (
445 | (
446 | `tmp_zh_stocks_sector_d`.`sector` = '商贸代理'
447 | ),
448 | (
449 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
450 | ),
451 | 0
452 | )
453 | ),
454 | 0
455 | ) AS `商贸代理`,
456 | round(
457 | sum(
458 |
459 | IF (
460 | (
461 | `tmp_zh_stocks_sector_d`.`sector` = '啤酒'
462 | ),
463 | (
464 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
465 | ),
466 | 0
467 | )
468 | ),
469 | 0
470 | ) AS `啤酒`,
471 | round(
472 | sum(
473 |
474 | IF (
475 | (
476 | `tmp_zh_stocks_sector_d`.`sector` = '园区开发'
477 | ),
478 | (
479 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
480 | ),
481 | 0
482 | )
483 | ),
484 | 0
485 | ) AS `园区开发`,
486 | round(
487 | sum(
488 |
489 | IF (
490 | (
491 | `tmp_zh_stocks_sector_d`.`sector` = '塑料'
492 | ),
493 | (
494 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
495 | ),
496 | 0
497 | )
498 | ),
499 | 0
500 | ) AS `塑料`,
501 | round(
502 | sum(
503 |
504 | IF (
505 | (
506 | `tmp_zh_stocks_sector_d`.`sector` = '多元金融'
507 | ),
508 | (
509 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
510 | ),
511 | 0
512 | )
513 | ),
514 | 0
515 | ) AS `多元金融`,
516 | round(
517 | sum(
518 |
519 | IF (
520 | (
521 | `tmp_zh_stocks_sector_d`.`sector` = '家居用品'
522 | ),
523 | (
524 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
525 | ),
526 | 0
527 | )
528 | ),
529 | 0
530 | ) AS `家居用品`,
531 | round(
532 | sum(
533 |
534 | IF (
535 | (
536 | `tmp_zh_stocks_sector_d`.`sector` = '家用电器'
537 | ),
538 | (
539 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
540 | ),
541 | 0
542 | )
543 | ),
544 | 0
545 | ) AS `家用电器`,
546 | round(
547 | sum(
548 |
549 | IF (
550 | (
551 | `tmp_zh_stocks_sector_d`.`sector` = '小金属'
552 | ),
553 | (
554 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
555 | ),
556 | 0
557 | )
558 | ),
559 | 0
560 | ) AS `小金属`,
561 | round(
562 | sum(
563 |
564 | IF (
565 | (
566 | `tmp_zh_stocks_sector_d`.`sector` = '工程机械'
567 | ),
568 | (
569 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
570 | ),
571 | 0
572 | )
573 | ),
574 | 0
575 | ) AS `工程机械`,
576 | round(
577 | sum(
578 |
579 | IF (
580 | (
581 | `tmp_zh_stocks_sector_d`.`sector` = '广告包装'
582 | ),
583 | (
584 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
585 | ),
586 | 0
587 | )
588 | ),
589 | 0
590 | ) AS `广告包装`,
591 | round(
592 | sum(
593 |
594 | IF (
595 | (
596 | `tmp_zh_stocks_sector_d`.`sector` = '建筑工程'
597 | ),
598 | (
599 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
600 | ),
601 | 0
602 | )
603 | ),
604 | 0
605 | ) AS `建筑工程`,
606 | round(
607 | sum(
608 |
609 | IF (
610 | (
611 | `tmp_zh_stocks_sector_d`.`sector` = '影视音像'
612 | ),
613 | (
614 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
615 | ),
616 | 0
617 | )
618 | ),
619 | 0
620 | ) AS `影视音像`,
621 | round(
622 | sum(
623 |
624 | IF (
625 | (
626 | `tmp_zh_stocks_sector_d`.`sector` = '房产服务'
627 | ),
628 | (
629 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
630 | ),
631 | 0
632 | )
633 | ),
634 | 0
635 | ) AS `房产服务`,
636 | round(
637 | sum(
638 |
639 | IF (
640 | (
641 | `tmp_zh_stocks_sector_d`.`sector` = '批发业'
642 | ),
643 | (
644 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
645 | ),
646 | 0
647 | )
648 | ),
649 | 0
650 | ) AS `批发业`,
651 | round(
652 | sum(
653 |
654 | IF (
655 | (
656 | `tmp_zh_stocks_sector_d`.`sector` = '摩托车'
657 | ),
658 | (
659 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
660 | ),
661 | 0
662 | )
663 | ),
664 | 0
665 | ) AS `摩托车`,
666 | round(
667 | sum(
668 |
669 | IF (
670 | (
671 | `tmp_zh_stocks_sector_d`.`sector` = '文教休闲'
672 | ),
673 | (
674 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
675 | ),
676 | 0
677 | )
678 | ),
679 | 0
680 | ) AS `文教休闲`,
681 | round(
682 | sum(
683 |
684 | IF (
685 | (
686 | `tmp_zh_stocks_sector_d`.`sector` = '新型电力'
687 | ),
688 | (
689 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
690 | ),
691 | 0
692 | )
693 | ),
694 | 0
695 | ) AS `新型电力`,
696 | round(
697 | sum(
698 |
699 | IF (
700 | (
701 | `tmp_zh_stocks_sector_d`.`sector` = '旅游景点'
702 | ),
703 | (
704 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
705 | ),
706 | 0
707 | )
708 | ),
709 | 0
710 | ) AS `旅游景点`,
711 | round(
712 | sum(
713 |
714 | IF (
715 | (
716 | `tmp_zh_stocks_sector_d`.`sector` = '旅游服务'
717 | ),
718 | (
719 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
720 | ),
721 | 0
722 | )
723 | ),
724 | 0
725 | ) AS `旅游服务`,
726 | round(
727 | sum(
728 |
729 | IF (
730 | (
731 | `tmp_zh_stocks_sector_d`.`sector` = '日用化工'
732 | ),
733 | (
734 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
735 | ),
736 | 0
737 | )
738 | ),
739 | 0
740 | ) AS `日用化工`,
741 | round(
742 | sum(
743 |
744 | IF (
745 | (
746 | `tmp_zh_stocks_sector_d`.`sector` = '普钢'
747 | ),
748 | (
749 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
750 | ),
751 | 0
752 | )
753 | ),
754 | 0
755 | ) AS `普钢`,
756 | round(
757 | sum(
758 |
759 | IF (
760 | (
761 | `tmp_zh_stocks_sector_d`.`sector` = '服饰'
762 | ),
763 | (
764 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
765 | ),
766 | 0
767 | )
768 | ),
769 | 0
770 | ) AS `服饰`,
771 | round(
772 | sum(
773 |
774 | IF (
775 | (
776 | `tmp_zh_stocks_sector_d`.`sector` = '机场'
777 | ),
778 | (
779 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
780 | ),
781 | 0
782 | )
783 | ),
784 | 0
785 | ) AS `机场`,
786 | round(
787 | sum(
788 |
789 | IF (
790 | (
791 | `tmp_zh_stocks_sector_d`.`sector` = '机床制造'
792 | ),
793 | (
794 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
795 | ),
796 | 0
797 | )
798 | ),
799 | 0
800 | ) AS `机床制造`,
801 | round(
802 | sum(
803 |
804 | IF (
805 | (
806 | `tmp_zh_stocks_sector_d`.`sector` = '机械基件'
807 | ),
808 | (
809 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
810 | ),
811 | 0
812 | )
813 | ),
814 | 0
815 | ) AS `机械基件`,
816 | round(
817 | sum(
818 |
819 | IF (
820 | (
821 | `tmp_zh_stocks_sector_d`.`sector` = '林业'
822 | ),
823 | (
824 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
825 | ),
826 | 0
827 | )
828 | ),
829 | 0
830 | ) AS `林业`,
831 | round(
832 | sum(
833 |
834 | IF (
835 | (
836 | `tmp_zh_stocks_sector_d`.`sector` = '染料涂料'
837 | ),
838 | (
839 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
840 | ),
841 | 0
842 | )
843 | ),
844 | 0
845 | ) AS `染料涂料`,
846 | round(
847 | sum(
848 |
849 | IF (
850 | (
851 | `tmp_zh_stocks_sector_d`.`sector` = '橡胶'
852 | ),
853 | (
854 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
855 | ),
856 | 0
857 | )
858 | ),
859 | 0
860 | ) AS `橡胶`,
861 | round(
862 | sum(
863 |
864 | IF (
865 | (
866 | `tmp_zh_stocks_sector_d`.`sector` = '水力发电'
867 | ),
868 | (
869 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
870 | ),
871 | 0
872 | )
873 | ),
874 | 0
875 | ) AS `水力发电`,
876 | round(
877 | sum(
878 |
879 | IF (
880 | (
881 | `tmp_zh_stocks_sector_d`.`sector` = '水务'
882 | ),
883 | (
884 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
885 | ),
886 | 0
887 | )
888 | ),
889 | 0
890 | ) AS `水务`,
891 | round(
892 | sum(
893 |
894 | IF (
895 | (
896 | `tmp_zh_stocks_sector_d`.`sector` = '水泥'
897 | ),
898 | (
899 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
900 | ),
901 | 0
902 | )
903 | ),
904 | 0
905 | ) AS `水泥`,
906 | round(
907 | sum(
908 |
909 | IF (
910 | (
911 | `tmp_zh_stocks_sector_d`.`sector` = '水运'
912 | ),
913 | (
914 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
915 | ),
916 | 0
917 | )
918 | ),
919 | 0
920 | ) AS `水运`,
921 | round(
922 | sum(
923 |
924 | IF (
925 | (
926 | `tmp_zh_stocks_sector_d`.`sector` = '汽车整车'
927 | ),
928 | (
929 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
930 | ),
931 | 0
932 | )
933 | ),
934 | 0
935 | ) AS `汽车整车`,
936 | round(
937 | sum(
938 |
939 | IF (
940 | (
941 | `tmp_zh_stocks_sector_d`.`sector` = '汽车服务'
942 | ),
943 | (
944 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
945 | ),
946 | 0
947 | )
948 | ),
949 | 0
950 | ) AS `汽车服务`,
951 | round(
952 | sum(
953 |
954 | IF (
955 | (
956 | `tmp_zh_stocks_sector_d`.`sector` = '汽车配件'
957 | ),
958 | (
959 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
960 | ),
961 | 0
962 | )
963 | ),
964 | 0
965 | ) AS `汽车配件`,
966 | round(
967 | sum(
968 |
969 | IF (
970 | (
971 | `tmp_zh_stocks_sector_d`.`sector` = '渔业'
972 | ),
973 | (
974 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
975 | ),
976 | 0
977 | )
978 | ),
979 | 0
980 | ) AS `渔业`,
981 | round(
982 | sum(
983 |
984 | IF (
985 | (
986 | `tmp_zh_stocks_sector_d`.`sector` = '港口'
987 | ),
988 | (
989 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
990 | ),
991 | 0
992 | )
993 | ),
994 | 0
995 | ) AS `港口`,
996 | round(
997 | sum(
998 |
999 | IF (
1000 | (
1001 | `tmp_zh_stocks_sector_d`.`sector` = '火力发电'
1002 | ),
1003 | (
1004 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1005 | ),
1006 | 0
1007 | )
1008 | ),
1009 | 0
1010 | ) AS `火力发电`,
1011 | round(
1012 | sum(
1013 |
1014 | IF (
1015 | (
1016 | `tmp_zh_stocks_sector_d`.`sector` = '焦炭加工'
1017 | ),
1018 | (
1019 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1020 | ),
1021 | 0
1022 | )
1023 | ),
1024 | 0
1025 | ) AS `焦炭加工`,
1026 | round(
1027 | sum(
1028 |
1029 | IF (
1030 | (
1031 | `tmp_zh_stocks_sector_d`.`sector` = '煤炭开采'
1032 | ),
1033 | (
1034 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1035 | ),
1036 | 0
1037 | )
1038 | ),
1039 | 0
1040 | ) AS `煤炭开采`,
1041 | round(
1042 | sum(
1043 |
1044 | IF (
1045 | (
1046 | `tmp_zh_stocks_sector_d`.`sector` = '特种钢'
1047 | ),
1048 | (
1049 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1050 | ),
1051 | 0
1052 | )
1053 | ),
1054 | 0
1055 | ) AS `特种钢`,
1056 | round(
1057 | sum(
1058 |
1059 | IF (
1060 | (
1061 | `tmp_zh_stocks_sector_d`.`sector` = '环境保护'
1062 | ),
1063 | (
1064 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1065 | ),
1066 | 0
1067 | )
1068 | ),
1069 | 0
1070 | ) AS `环境保护`,
1071 | round(
1072 | sum(
1073 |
1074 | IF (
1075 | (
1076 | `tmp_zh_stocks_sector_d`.`sector` = '玻璃'
1077 | ),
1078 | (
1079 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1080 | ),
1081 | 0
1082 | )
1083 | ),
1084 | 0
1085 | ) AS `玻璃`,
1086 | round(
1087 | sum(
1088 |
1089 | IF (
1090 | (
1091 | `tmp_zh_stocks_sector_d`.`sector` = '生物制药'
1092 | ),
1093 | (
1094 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1095 | ),
1096 | 0
1097 | )
1098 | ),
1099 | 0
1100 | ) AS `生物制药`,
1101 | round(
1102 | sum(
1103 |
1104 | IF (
1105 | (
1106 | `tmp_zh_stocks_sector_d`.`sector` = '电信运营'
1107 | ),
1108 | (
1109 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1110 | ),
1111 | 0
1112 | )
1113 | ),
1114 | 0
1115 | ) AS `电信运营`,
1116 | round(
1117 | sum(
1118 |
1119 | IF (
1120 | (
1121 | `tmp_zh_stocks_sector_d`.`sector` = '电器仪表'
1122 | ),
1123 | (
1124 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1125 | ),
1126 | 0
1127 | )
1128 | ),
1129 | 0
1130 | ) AS `电器仪表`,
1131 | round(
1132 | sum(
1133 |
1134 | IF (
1135 | (
1136 | `tmp_zh_stocks_sector_d`.`sector` = '电器连锁'
1137 | ),
1138 | (
1139 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1140 | ),
1141 | 0
1142 | )
1143 | ),
1144 | 0
1145 | ) AS `电器连锁`,
1146 | round(
1147 | sum(
1148 |
1149 | IF (
1150 | (
1151 | `tmp_zh_stocks_sector_d`.`sector` = '电气设备'
1152 | ),
1153 | (
1154 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1155 | ),
1156 | 0
1157 | )
1158 | ),
1159 | 0
1160 | ) AS `电气设备`,
1161 | round(
1162 | sum(
1163 |
1164 | IF (
1165 | (
1166 | `tmp_zh_stocks_sector_d`.`sector` = '白酒'
1167 | ),
1168 | (
1169 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1170 | ),
1171 | 0
1172 | )
1173 | ),
1174 | 0
1175 | ) AS `白酒`,
1176 | round(
1177 | sum(
1178 |
1179 | IF (
1180 | (
1181 | `tmp_zh_stocks_sector_d`.`sector` = '百货'
1182 | ),
1183 | (
1184 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1185 | ),
1186 | 0
1187 | )
1188 | ),
1189 | 0
1190 | ) AS `百货`,
1191 | round(
1192 | sum(
1193 |
1194 | IF (
1195 | (
1196 | `tmp_zh_stocks_sector_d`.`sector` = '石油加工'
1197 | ),
1198 | (
1199 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1200 | ),
1201 | 0
1202 | )
1203 | ),
1204 | 0
1205 | ) AS `石油加工`,
1206 | round(
1207 | sum(
1208 |
1209 | IF (
1210 | (
1211 | `tmp_zh_stocks_sector_d`.`sector` = '石油开采'
1212 | ),
1213 | (
1214 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1215 | ),
1216 | 0
1217 | )
1218 | ),
1219 | 0
1220 | ) AS `石油开采`,
1221 | round(
1222 | sum(
1223 |
1224 | IF (
1225 | (
1226 | `tmp_zh_stocks_sector_d`.`sector` = '石油贸易'
1227 | ),
1228 | (
1229 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1230 | ),
1231 | 0
1232 | )
1233 | ),
1234 | 0
1235 | ) AS `石油贸易`,
1236 | round(
1237 | sum(
1238 |
1239 | IF (
1240 | (
1241 | `tmp_zh_stocks_sector_d`.`sector` = '矿物制品'
1242 | ),
1243 | (
1244 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1245 | ),
1246 | 0
1247 | )
1248 | ),
1249 | 0
1250 | ) AS `矿物制品`,
1251 | round(
1252 | sum(
1253 |
1254 | IF (
1255 | (
1256 | `tmp_zh_stocks_sector_d`.`sector` = '种植业'
1257 | ),
1258 | (
1259 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1260 | ),
1261 | 0
1262 | )
1263 | ),
1264 | 0
1265 | ) AS `种植业`,
1266 | round(
1267 | sum(
1268 |
1269 | IF (
1270 | (
1271 | `tmp_zh_stocks_sector_d`.`sector` = '空运'
1272 | ),
1273 | (
1274 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1275 | ),
1276 | 0
1277 | )
1278 | ),
1279 | 0
1280 | ) AS `空运`,
1281 | round(
1282 | sum(
1283 |
1284 | IF (
1285 | (
1286 | `tmp_zh_stocks_sector_d`.`sector` = '红黄酒'
1287 | ),
1288 | (
1289 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1290 | ),
1291 | 0
1292 | )
1293 | ),
1294 | 0
1295 | ) AS `红黄酒`,
1296 | round(
1297 | sum(
1298 |
1299 | IF (
1300 | (
1301 | `tmp_zh_stocks_sector_d`.`sector` = '纺织'
1302 | ),
1303 | (
1304 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1305 | ),
1306 | 0
1307 | )
1308 | ),
1309 | 0
1310 | ) AS `纺织`,
1311 | round(
1312 | sum(
1313 |
1314 | IF (
1315 | (
1316 | `tmp_zh_stocks_sector_d`.`sector` = '纺织机械'
1317 | ),
1318 | (
1319 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1320 | ),
1321 | 0
1322 | )
1323 | ),
1324 | 0
1325 | ) AS `纺织机械`,
1326 | round(
1327 | sum(
1328 |
1329 | IF (
1330 | (
1331 | `tmp_zh_stocks_sector_d`.`sector` = '综合类'
1332 | ),
1333 | (
1334 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1335 | ),
1336 | 0
1337 | )
1338 | ),
1339 | 0
1340 | ) AS `综合类`,
1341 | round(
1342 | sum(
1343 |
1344 | IF (
1345 | (
1346 | `tmp_zh_stocks_sector_d`.`sector` = '航空'
1347 | ),
1348 | (
1349 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1350 | ),
1351 | 0
1352 | )
1353 | ),
1354 | 0
1355 | ) AS `航空`,
1356 | round(
1357 | sum(
1358 |
1359 | IF (
1360 | (
1361 | `tmp_zh_stocks_sector_d`.`sector` = '船舶'
1362 | ),
1363 | (
1364 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1365 | ),
1366 | 0
1367 | )
1368 | ),
1369 | 0
1370 | ) AS `船舶`,
1371 | round(
1372 | sum(
1373 |
1374 | IF (
1375 | (
1376 | `tmp_zh_stocks_sector_d`.`sector` = '装修装饰'
1377 | ),
1378 | (
1379 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1380 | ),
1381 | 0
1382 | )
1383 | ),
1384 | 0
1385 | ) AS `装修装饰`,
1386 | round(
1387 | sum(
1388 |
1389 | IF (
1390 | (
1391 | `tmp_zh_stocks_sector_d`.`sector` = '证券'
1392 | ),
1393 | (
1394 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1395 | ),
1396 | 0
1397 | )
1398 | ),
1399 | 0
1400 | ) AS `证券`,
1401 | round(
1402 | sum(
1403 |
1404 | IF (
1405 | (
1406 | `tmp_zh_stocks_sector_d`.`sector` = '超市连锁'
1407 | ),
1408 | (
1409 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1410 | ),
1411 | 0
1412 | )
1413 | ),
1414 | 0
1415 | ) AS `超市连锁`,
1416 | round(
1417 | sum(
1418 |
1419 | IF (
1420 | (
1421 | `tmp_zh_stocks_sector_d`.`sector` = '路桥'
1422 | ),
1423 | (
1424 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1425 | ),
1426 | 0
1427 | )
1428 | ),
1429 | 0
1430 | ) AS `路桥`,
1431 | round(
1432 | sum(
1433 |
1434 | IF (
1435 | (
1436 | `tmp_zh_stocks_sector_d`.`sector` = '软件服务'
1437 | ),
1438 | (
1439 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1440 | ),
1441 | 0
1442 | )
1443 | ),
1444 | 0
1445 | ) AS `软件服务`,
1446 | round(
1447 | sum(
1448 |
1449 | IF (
1450 | (
1451 | `tmp_zh_stocks_sector_d`.`sector` = '软饮料'
1452 | ),
1453 | (
1454 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1455 | ),
1456 | 0
1457 | )
1458 | ),
1459 | 0
1460 | ) AS `软饮料`,
1461 | round(
1462 | sum(
1463 |
1464 | IF (
1465 | (
1466 | `tmp_zh_stocks_sector_d`.`sector` = '轻工机械'
1467 | ),
1468 | (
1469 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1470 | ),
1471 | 0
1472 | )
1473 | ),
1474 | 0
1475 | ) AS `轻工机械`,
1476 | round(
1477 | sum(
1478 |
1479 | IF (
1480 | (
1481 | `tmp_zh_stocks_sector_d`.`sector` = '运输设备'
1482 | ),
1483 | (
1484 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1485 | ),
1486 | 0
1487 | )
1488 | ),
1489 | 0
1490 | ) AS `运输设备`,
1491 | round(
1492 | sum(
1493 |
1494 | IF (
1495 | (
1496 | `tmp_zh_stocks_sector_d`.`sector` = '通信设备'
1497 | ),
1498 | (
1499 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1500 | ),
1501 | 0
1502 | )
1503 | ),
1504 | 0
1505 | ) AS `通信设备`,
1506 | round(
1507 | sum(
1508 |
1509 | IF (
1510 | (
1511 | `tmp_zh_stocks_sector_d`.`sector` = '造纸'
1512 | ),
1513 | (
1514 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1515 | ),
1516 | 0
1517 | )
1518 | ),
1519 | 0
1520 | ) AS `造纸`,
1521 | round(
1522 | sum(
1523 |
1524 | IF (
1525 | (
1526 | `tmp_zh_stocks_sector_d`.`sector` = '酒店餐饮'
1527 | ),
1528 | (
1529 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1530 | ),
1531 | 0
1532 | )
1533 | ),
1534 | 0
1535 | ) AS `酒店餐饮`,
1536 | round(
1537 | sum(
1538 |
1539 | IF (
1540 | (
1541 | `tmp_zh_stocks_sector_d`.`sector` = '钢加工'
1542 | ),
1543 | (
1544 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1545 | ),
1546 | 0
1547 | )
1548 | ),
1549 | 0
1550 | ) AS `钢加工`,
1551 | round(
1552 | sum(
1553 |
1554 | IF (
1555 | (
1556 | `tmp_zh_stocks_sector_d`.`sector` = '铁路'
1557 | ),
1558 | (
1559 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1560 | ),
1561 | 0
1562 | )
1563 | ),
1564 | 0
1565 | ) AS `铁路`,
1566 | round(
1567 | sum(
1568 |
1569 | IF (
1570 | (
1571 | `tmp_zh_stocks_sector_d`.`sector` = '铅锌'
1572 | ),
1573 | (
1574 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1575 | ),
1576 | 0
1577 | )
1578 | ),
1579 | 0
1580 | ) AS `铅锌`,
1581 | round(
1582 | sum(
1583 |
1584 | IF (
1585 | (
1586 | `tmp_zh_stocks_sector_d`.`sector` = '铜'
1587 | ),
1588 | (
1589 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1590 | ),
1591 | 0
1592 | )
1593 | ),
1594 | 0
1595 | ) AS `铜`,
1596 | round(
1597 | sum(
1598 |
1599 | IF (
1600 | (
1601 | `tmp_zh_stocks_sector_d`.`sector` = '铝'
1602 | ),
1603 | (
1604 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1605 | ),
1606 | 0
1607 | )
1608 | ),
1609 | 0
1610 | ) AS `铝`,
1611 | round(
1612 | sum(
1613 |
1614 | IF (
1615 | (
1616 | `tmp_zh_stocks_sector_d`.`sector` = '银行'
1617 | ),
1618 | (
1619 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1620 | ),
1621 | 0
1622 | )
1623 | ),
1624 | 0
1625 | ) AS `银行`,
1626 | round(
1627 | sum(
1628 |
1629 | IF (
1630 | (
1631 | `tmp_zh_stocks_sector_d`.`sector` = '陶瓷'
1632 | ),
1633 | (
1634 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1635 | ),
1636 | 0
1637 | )
1638 | ),
1639 | 0
1640 | ) AS `陶瓷`,
1641 | round(
1642 | sum(
1643 |
1644 | IF (
1645 | (
1646 | `tmp_zh_stocks_sector_d`.`sector` = '食品'
1647 | ),
1648 | (
1649 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1650 | ),
1651 | 0
1652 | )
1653 | ),
1654 | 0
1655 | ) AS `食品`,
1656 | round(
1657 | sum(
1658 |
1659 | IF (
1660 | (
1661 | `tmp_zh_stocks_sector_d`.`sector` = '饲料'
1662 | ),
1663 | (
1664 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1665 | ),
1666 | 0
1667 | )
1668 | ),
1669 | 0
1670 | ) AS `饲料`,
1671 | round(
1672 | sum(
1673 |
1674 | IF (
1675 | (
1676 | `tmp_zh_stocks_sector_d`.`sector` = '黄金'
1677 | ),
1678 | (
1679 | `tmp_zh_stocks_sector_d`.`above_rate` * 100
1680 | ),
1681 | 0
1682 | )
1683 | ),
1684 | 0
1685 | ) AS `黄金`
1686 | FROM
1687 | `tmp_zh_stocks_sector_d`
1688 | GROUP BY
1689 | `tmp_zh_stocks_sector_d`.`date`
1690 | ORDER BY
1691 | `tmp_zh_stocks_sector_d`.`date` DESC
1692 | ;
--------------------------------------------------------------------------------