fintie.stock.fundamentals 源代码

# -*- coding: utf-8 -*-
# This file is part of fintie.

# Copyright (C) 2018-present qytz <hhhhhf@foxmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
""" 本模块负责获取上市公司财务数据,包含利润、资产负债、现金流量三大表及摘要和主要财务指标。

信息获取通道包括:

    * http://quotes.money.163.com/service/zcfzb_000333.html
    * http://quotes.money.163.com/service/lrb_000333.html
    * http://quotes.money.163.com/service/xjllb_000333.html
    * http://quotes.money.163.com/service/cwbbzy_000333.html
    * http://quotes.money.163.com/service/zycwzb_000333.html?type=report

加载已保存数据::

    import pandas as pd
    from pathlib import Path
    df = pd.read_csv(Path("xxx.json"), index_col=0)
"""
import os
import logging
import asyncio
from pathlib import Path

import click
import aiohttp
import pandas as pd

from .cli import stock_cli_group, MODULE_DATA_DIR
from ..utils import fetch_http_data, add_doc


logger = logging.getLogger(__file__)
__all__ = [
    "get_funda_tab",
    "async_get_funda_tab",
    "get_fundamentals",
    "async_get_fundamentals",
]


async def _init(session):
    return True


[文档]async def async_get_funda_tab(session, symbol, tab_name, return_df=True): """获取某表的财务数据 :param session: `aiohttp.ClientSession` 对象,同步接口不需要传 :param symbol: 股票代码 :param tab_name: lrb/zcfzb/xjllb/cwbbzy/zycwzb :param data_path: 数据保存路径 :param return_df: 是否返回 `pandas.DataFrame` 对象,False 返回原始数据 :returns: 原始财务数数据或带有财务数据的 `pandas.DataFrame` 对象,见 return_df 参数 """ assert tab_name in ("lrb", "zcfzb", "xjllb", "cwbbzy", "zycwzb") await _init(session) symbol_163 = symbol if symbol_163.startswith("SZ") or symbol_163.startswith("SH"): symbol_163 = symbol[2:] url = f"http://quotes.money.163.com/service/{tab_name}_{symbol_163}.html" try: async with await session.get(url) as resp: if resp.status != 200: logger.warning( "Download funda for %s.%s from url failed: http %s", symbol, tab_name, url, resp.status, ) return None data = await resp.text() encoding = resp.get_encoding() except (aiohttp.ServerTimeoutError, asyncio.TimerHandle): logger.warning("get %s for %s failed: timeout", tab_name, symbol) if not return_df: return data return pd.read_csv(data, encoding=encoding, index_col=0)
[文档]async def async_get_fundamentals(session, symbols, data_path): """获取财务数据 :param session: `aiohttp.ClientSession` 对象,同步接口不需要传 :param symbol: 股票代码 :param data_path: 数据保存路径 :returns: Nothing """ async def get_one_funda(symbol, tab_name, path): data = await async_get_funda_tab(session, symbol, tab_name, return_df=False) save_file = path / (tab_name + ".csv") with save_file.open("w", encoding="utf-8") as f: f.write(data) await _init(session) aws = [] logger.info("Getting fundamental from 163") for symbol in symbols: symbol_data_dir = Path(data_path) / MODULE_DATA_DIR / symbol / "fundamental" os.makedirs(symbol_data_dir, exist_ok=True) for tab_name in ("lrb", "zcfzb", "xjllb", "cwbbzy", "zycwzb"): aws.append(get_one_funda(symbol, tab_name, symbol_data_dir)) rets = await asyncio.gather(*aws, return_exceptions=True) for ret in rets: if isinstance(ret, Exception): raise ret return True
[文档]@add_doc(async_get_funda_tab.__doc__) def get_funda_tab(*args, **kwargs): ret = fetch_http_data(async_get_funda_tab, *args, **kwargs) if isinstance(ret, Exception): raise ret return ret
[文档]@add_doc(async_get_fundamentals.__doc__) def get_fundamentals(*args, **kwargs): ret = fetch_http_data(async_get_fundamentals, *args, **kwargs) if isinstance(ret, Exception): raise ret return ret
@click.option( "-f", "--save-path", type=click.Path(exists=False) ) @click.argument("symbols", nargs=-1, required=True) @stock_cli_group.command("funda") @click.pass_context def fundamental_cli(ctx, symbols, save_path): """从163获取财务报表及财务指标信息""" if not save_path: save_path = ctx.obj["data_path"] get_fundamentals(symbols, save_path) if __name__ == "__main__": fundamental_cli()