├── 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 | ; --------------------------------------------------------------------------------