获取申万各级指数的行情、估值数据
import finance from jqdatasdk
import jqdatasdk as jq
def get_sw_quote(index_code,startday,endday):
'''获取指定日期的申万指数列表--行情'''
q = jq.query(finance.SW1_DAILY_PRICE).filter(
finance.SW1_DAILY_PRICE.code==index_code,
finance.SW1_DAILY_PRICE.date >=startday,
finance.SW1_DAILY_PRICE.date < endday)
df = finance.run_query(q)
return df
#df = get_sw_quote('801010','2019-02-05','2019-08-09')
def get_sw_valuation_quote(index_code,startday,endday):
'''获取指定日期的申万指数列表---估值行情'''
q = jq.query(finance.SW1_DAILY_VALUATION).filter(
finance.SW1_DAILY_VALUATION.code==index_code,
finance.SW1_DAILY_VALUATION.date >=startday,
finance.SW1_DAILY_VALUATION.date < endday)
df = finance.run_query(q)
return df
#参数:
#query(finance.SW1_DAILY_PRICE):表示从finance.SW1_DAILY_PRICE这张表中查询申万一级行业指数的历史日行情数据,还可以指定所要查询的字段名,格式如下:query(库名.表名.字段名1,库名.表名.字段名2),多个字段用英文逗号分隔进行提取;如query(finance.SW1_DAILY_PRICE.code)。query函数的更多用法详见:query简易教程。
#finance.SW1_DAILY_PRICE:代表申万一级行业日行情数据表,收录了申万一级行业指数的历史日行情数据,表结构和字段信息如下:
#date 交易日 date N
#code 指数编码 varchar(12) N 对应申万一级行业指数编码
#name 指数名称 varchar(20) N
#open 开盘指数 decimal(20,4)
#high 最高指数 decimal(20,4)
#low 最低指数 decimal(20,4)
#close 收盘指数 decimal(20,4)
#pre_close 昨收盘指数 decimal(20,4) 昨收盘指数用昨日的收盘指数填充
#volume 成交量 decimal(20,4) 单位:股
#money 成交额 decimal(20,4) 单位:元
#change_pct 涨跌幅 decimal(10,4) 单位:%
#filter(finance.SW1_DAILY_PRICE.code==801010):指定筛选条件,通过finance.SW1_DAILY_PRICE.code==801010可以查询指定行业(如农林牧渔801010)的日行情数据;除此之外,还可以对表中其他字段指定筛选条件,如finance.SW1_DAILY_PRICE.date=='2019-03-01',指定获取2019年3月1日的申万一级行业日行情数据。
#limit(n):限制返回的数据条数,n指定返回条数。
#
#返回结果:
#返回一个 dataframe,每一行对应数据表中的一条数据, 列索引是您所查询的字段名称
#记录了申万一级行业指数的每日估值数据,每天18:00更新。
#参数:
#query(finance.SW1_DAILY_VALUATION):表示从finance.SW1_DAILY_VALUATION这张表中查询申万一级行业指数的估值数据,还可以指定所要查询的字段名,格式如下:query(库名.表名.字段名1,库名.表名.字段名2),多个字段用英文逗号分隔进行提取;如query(finance.SW1_DAILY_VALUATION.code)。query函数的更多用法详见:query简易教程。
#finance.SW1_DAILY_VALUATION:代表申万一级行业指数估值表,收录了申万一级行业指数的历史估值数据,表结构和字段信息如下:
#date 交易日 date N
#code 指数编码 varchar(12) N 对应申万一级行业指数编码
#name 指数名称 varchar(20) N
#turnover_ratio 换手率 decimal(10,4) 单位:%
#pe 市盈率 decimal(20,4) 单位:倍;PE = 流通市值/最近4个季度的净利润;最近 4 个季度的净利润按如下方法计算: 1-4 月,最近 4 个季度的净利润=上一年度前 3 季度累计净利润+上上一年度的四季度净利润;5-8 月,最近 4 个季度的净利润=当年 1 季度净利润+前 1 年净利润-前 1 年 1 季度净利润;9-10 月,最近 4 个季度的净利润=当年中期净利润+前 1 年净利润-前 1 年中期净利润;11-12 月,最近 4 个季度的净利润=当年前 3 季度累计净利润+上1年年度净利润-上 1 年前 3 季度累计净利润
#pb 市净率 decimal(20,4) 单位:倍;按照自由流通量加权的净资产倍率。 PB = 流通市值/按照流通市值计算的净资产;按照流通市值计算的净资产 = 最新净资产*流通股本/总股本
#average_price 均价 decimal(20,4) 单位:元。指数成份股在统计期最后交易日收盘的简单算术平均价
#money_ratio 成交额占比 decimal(10,4) 单位:%;成交额占比=某个行业成交额/所有行业成交额之和
#circulating_market_cap 流通市值 decimal(20,4) 单位:元
#average_circulating_market_cap 平均流通市值 decimal(20,4) 单位:元;平均流通市值=流通市值/所在行业股票数
#dividend_ratio 股息率 decimal(10,4) 单位:%;按照自由流通量加权的现金股息率;dividend_ratio=Df/Vf;Df: 所有股票在截止日的一 个自然年(365日)中所累积派发的税前现金红利之和按照流通股本对应的分红量;Vf: 该行业成分股股的流通市值之和
#filter(finance.SW1_DAILY_VALUATION.code==801010):指定筛选条件,通过finance.SW1_DAILY_VALUATION.code=='801010'可以查询指定行业(如农林牧渔801010)的估值数据;除此之外,还可以对表中其他字段指定筛选条件,如finance.SW1_DAILY_VALUATION.date=='2019-03-01',指定获取2019年3月1日的申万一级行业的估值数据。
#limit(n):限制返回的数据条数,n指定返回条数。
#
#返回结果:
#返回一个 dataframe,每一行对应数据表中的一条数据, 列索引是您所查询的字段名称
#
#注意:
#1.为了防止返回数据量过大, 我们每次最多返回3000行
#2.不能进行连表查询,即同时查询多张表的数据
from jqdata import finance
q = query(finance.STK_INCOME_STATEMENT).filter(
finance.STK_INCOME_STATEMENT.code=='000783.XSHE', #选定股票 000783.XSHE
finance.STK_INCOME_STATEMENT.end_date > '2005-01-01', #指定查询时间段大于2005年1月1日
finance.STK_INCOME_STATEMENT.end_date < '2018-01-01', #指定查询时间段小于2018年1月1日
finance.STK_INCOME_STATEMENT.net_profit <0, #指定查询到的数据中net_profit为负
finance.STK_INCOME_STATEMENT.report_type == 0, #指定报告期类型为本期
).order_by(finance.STK_INCOME_STATEMENT.end_date.desc() ).limit(5) #根据end_date降序排序,并返回前5条数据
finance.run_query(q)
q = query(
income.statDate,
income.code,
income.basic_eps,
cash_flow.goods_sale_and_service_render_cash
).filter(
income.code == '000001.XSHE',
)
ret = get_fundamentals(q, statDate='2014q2')
ret
q = query(
income.statDate,
income.code,
income.basic_eps,
cash_flow.goods_sale_and_service_render_cash
).filter(
income.code == '000001.XSHE',
)
ret = get_fundamentals(q, statDate='2014')
ret
# 查询平安银行2014年四个季度的季报, 放到数组中并拼接为dataframe
q = query(
income.statDate,
income.code,
income.basic_eps,
balance.cash_equivalents,
cash_flow.goods_sale_and_service_render_cash
).filter(
income.code == '000001.XSHE',
)
rets = [get_fundamentals(q, statDate='2014q'+str(i)) for i in range(1, 5)]
import pandas as pd
pd.concat(rets)
in_ 判断某个字段的值是否在列表之中(一般用于查询多个标的)¶
stocks = ['000001.XSHE','600741.XSHG','600507.XSHG']
q = query(balance.code,balance.pubDate,balance.statDate, # 指定返回的字段只包括code,pubDate,statDate,total_assets及total_sheet_owner_equities
balance.total_assets,balance.total_sheet_owner_equities).filter(
balance.code.in_(stocks) #指定查询到的数据只包括code在 stocks中的数据
)
get_fundamentals(q,date='2018-01-05') #查询单季度数据中在2018-01-05之前发布的数据,没有未来函数
distinct 去重,用于查看数据库中某个字段都存在哪些值¶
# 查看十大流通股东中都有哪些类别
from jqdata import finance
q = query(
finance.STK_SHAREHOLDER_FLOATING_TOP10.shareholder_class_id.distinct(), #提取ID不同的数据
finance.STK_SHAREHOLDER_FLOATING_TOP10.shareholder_class,
).order_by(finance.STK_SHAREHOLDER_FLOATING_TOP10.change_reason_id)
df = finance.run_query(q)
df.tail()
~ 反向查询符号
q = query(
finance.STK_SHAREHOLDER_FLOATING_TOP10.shareholder_class_id.distinct(),
finance.STK_SHAREHOLDER_FLOATING_TOP10.shareholder_class,
).filter(
~finance.STK_SHAREHOLDER_FLOATING_TOP10.shareholder_class_id.in_(['307007','307001']),#等同于notin_
)
finance.run_query(q)
运算和命名(label)
# label的作用是命名获得数据的标签,一般用于直接运算后的重命名
q = query(indicator.code.label('股票代码'),
indicator.operating_profit.label('get_operating_profit'),
(income.total_operating_revenue - income.total_operating_cost).label('my_operating_profit')
).filter(indicator.code=='600507.XSHG')
get_fundamentals(q)
or_ 或查询¶
from sqlalchemy.sql.expression import or_
get_fundamentals(query(
valuation.code
).filter(
or_(valuation.market_cap < 10,valuation.pe_ratio > 1000))).tail() # 查询当天总市值小于1000亿或pe大于10亿的所有股票
contains/like/ilike 数据库中的字符串模糊匹配
•% 百分号通配符: 表示任何字符出现任意次数(可以是0次).
•_ 下划线通配符:表示只能匹配单个字符,不能多也不能少,就是一个字符.
from jqdata import finance
# 获取000001.XSHG每一年的年报
df = finance.run_query(query(finance.FINANCE_INCOME_STATEMENT
).filter(finance.FINANCE_INCOME_STATEMENT.code.in_(['000001.XSHE']),
# finance.FINANCE_INCOME_STATEMENT.end_date.like('%-12-31%'), #sqlalchemy的版本,数据库的构建等问题可能导致查询报错,可以换以下两种方法尝试
# finance.FINANCE_INCOME_STATEMENT.end_date.contains('12-31') ,
finance.FINANCE_INCOME_STATEMENT.end_date.ilike('_____12-31'),
finance.FINANCE_INCOME_STATEMENT.report_type==0
))
df.tail()
简化计算的方法(sqlalchemy.sql.func) 和 group_by
func中的函数可以完成常用的一些计算,配合group_by完成简单的统计
下边以简单计算股票池/全市场每天的的等权重pe,pb为例
(当然,这个计算中一些细节并没有考虑到,实际还是以官方数据为准,可以通过聚源数据获取,具体下边会有演示)
from sqlalchemy.sql import func
from jqdata import finance
stocks = get_index_stocks('000016.XSHG')
q = query(valuation.day,
# func.count('*'), # 信息条数(也就是股票数量)
(func.count()/func.sum(1/valuation.pe_ratio)).label('avg_pe'), # 等权重pe
(func.count()/func.sum(1/valuation.pb_ratio)).label('avg_pb'), # 等权重pb
).group_by(valuation.day
).filter(
valuation.pe_ratio>0, #排除亏损的
valuation.pb_ratio>0,
valuation.day>'2009-12-01', #设置一个时间
valuation.code.in_(stocks) #设置股票池,注释即为全市场
)
df = finance.run_query(q)
df.set_index('day',inplace=True)
df.tail()
获取旧的申万指数列表和新的申万指数列表(14年有过改动)
from jqdata import *
def get_sw_quote(day=None):
'''获取指定日期的申万指数列表'''
day = get_trade_days(end_date=day,count=1)[-1]
df = jy.run_query(query(
jy.QT_SYWGIndexQuote.InnerCode.distinct().label('InnerCode')).filter(
jy.QT_SYWGIndexQuote.TradingDay==day,
))
code_df = jy.run_query(query(
jy.SecuMain.SecuCode,jy.SecuMain.ChiName
).filter(
jy.SecuMain.InnerCode.in_(df.InnerCode)))
return code_df
df = get_sw_quote('2013-02-05')
df.tail()
查询申万行情( 包含行业pe/pb)¶
from jqdata import jy
from jqdata import *
import pandas as pd
#注意申万指数在2014年有一次大改,聚源使用的是为改变之前的代码,官网包含更改前和更改后的代码,如果遇到找不到的标的可以根据需求自行查找
#如801124 >>801121食品加工II
def get_sw_quote(code,end_date=None,count=None,start_date=None):
'''获取申万指数行情,返回panel结构'''
if isinstance(code,str):
code=[code]
days = get_trade_days(start_date,end_date,count)
code_df = jy.run_query(query(
jy.SecuMain.InnerCode,jy.SecuMain.SecuCode,jy.SecuMain.ChiName
).filter(
jy.SecuMain.SecuCode.in_(code)))
df = jy.run_query(query(
jy.QT_SYWGIndexQuote).filter(
jy.QT_SYWGIndexQuote.InnerCode.in_(code_df.InnerCode),
jy.QT_SYWGIndexQuote.TradingDay.in_(days),
))
df2 = pd.merge(code_df, df, on='InnerCode').set_index(['TradingDay','SecuCode'])
df2.drop(['InnerCode','ID','UpdateTime','JSID'],axis=1,inplace=True)
return df2.to_panel()
code = get_industries(name='sw_l2').index[:5]
df = get_sw_quote(code,end_date='2018-01-01',count=10)
df.to_frame(False).tail()
def get_zz_quote(code,end_date=None,count=None,start_date=None):
'''获取中证指数行情,返回panel结构'''
if isinstance(code,str):
code=[code]
code.sort()
code = [x[:6] for x in code]
days = get_trade_days(start_date,end_date,count)
code_df = jy.run_query(query(
jy.SecuMain.InnerCode,jy.SecuMain.SecuCode,jy.SecuMain.ChiName
).filter(
jy.SecuMain.SecuCode.in_(code)).order_by(jy.SecuMain.SecuCode))
df = jy.run_query(query(
jy.QT_CSIIndexQuote).filter(
jy.QT_CSIIndexQuote.IndexCode.in_(code_df.InnerCode),
jy.QT_CSIIndexQuote.TradingDay.in_(days),
))
df2 = pd.merge(code_df, df, left_on='InnerCode',right_on='IndexCode').set_index(['TradingDay','SecuCode'])
df2.drop(['InnerCode','IndexCode','ID','UpdateTime','JSID','OpenInterest','SettleValue','IndexCSIType'],axis=1,inplace=True)
return df2.to_panel()
panel = get_zz_quote(['000016.XSHG','000001.XSHG'],end_date='2019-01-21',count=10)
panel.ClosePrice.tail()
查询股息率(近12个月)¶
from jqdata import *
def DividendRatio(security_list,end_date,count=1):
'''查询股息率(日更新)
输入:股票池,截止日期,获取数量
输出:panel结构,单位:1'''
trade_days = get_trade_days(end_date=end_date,count = count)
security_list.sort()
secu_list = [x[:6] for x in security_list]
code_df = jy.run_query(query(
jy.SecuMain.InnerCode,jy.SecuMain.SecuCode,
# jy.SecuMain.ChiName,jy.SecuMain.CompanyCode
).filter(
jy.SecuMain.SecuCode.in_(secu_list),jy.SecuMain.SecuCategory==1).order_by(jy.SecuMain.SecuCode))
code_df['code'] = security_list
df = jy.run_query(query(
# jy.LC_DIndicesForValuation #得到整表
jy.LC_DIndicesForValuation.InnerCode,
jy.LC_DIndicesForValuation.TradingDay,
jy.LC_DIndicesForValuation.DividendRatio,
).filter(jy.LC_DIndicesForValuation.InnerCode.in_(code_df.InnerCode),
jy.LC_DIndicesForValuation.TradingDay.in_(trade_days)
))
f_df = df.merge(code_df,on='InnerCode').set_index(['TradingDay','code']).drop(['InnerCode','SecuCode'],axis=1)
panel = f_df.to_panel()
return panel
securitys =get_index_stocks('399015.XSHE')
date='2018-01-01'
DividendRatio(securitys,date)
获取期货合约的基本信息(合约乘数、商品报价的计数单位、最小变动单位)¶
# lru缓存可以不要,加上后查询相同的合约可以避免重复数据库请求
from fastcache import clru_cache as lru_cache
@lru_cache(maxsize=128)
def future_basic_info(future):
from jqdata import jy
from numpy import nan
import re
if "9999" in future or "8888" in future:
match = re.match(r"(?P[A-Z]{1,})", future)
if not match:
raise ValueError("未知期货标的:{}".format(future))
else:
future = get_dominant_future(match.groupdict()["underlying_symbol"])
q = query(jy.Fut_ContractMain).filter(jy.Fut_ContractMain.ContractCode == future.split(".")[0])
result = jy.run_query(query_object=q).to_dict("record")
if result:
result = result.pop()
min_point = re.match("(?P^[0-9]+([.]{1}[0-9]+){0,1})", result["LittlestChangeUnit"]).groupdict(nan)["value"]
return {"ContractUnit": result["CMValue"],
"PriceScale": float(str(min_point)[:-1] + "1") if float(min_point) < 1 else 1,
"MinPoint": float(min_point)}
else:
return {"ContractUnit": nan,
"PriceScale": nan,
"MinPoint": nan}
future_basic_info('IF1801.CCFX')
多个dataframe的合并 (数据拼接) 获取多份财务报表¶
#获取多年的季度度数据
import pandas as pd
def get_more_state_fund(q_object,year_list):
df_list = []
for year in year_list:
rets = [get_fundamentals(q, statDate=str(year)+'q'+str(i)) for i in range(1, 5)]
df = pd.concat(rets).set_index('statDate') #个人习惯
df_list.append(df)
df_ = pd.concat(df_list,keys=year_list,axis=0) #axis=1或axis=0,依据个人习惯
return df_
q = query(
indicator.code,
indicator.statDate,
indicator.roe,
indicator.inc_return,
indicator.pubDate,
).filter(
income.code.in_(['000001.XSHE','600507.XSHG']))
df = get_more_state_fund(q,['2017','2018'])
# df.loc[('2014',slice(None))]
df
#h获取多个年度财务数据
import pandas as pd
stock_list=['000001.XSHE','000527.XSHE','600970.XSHG','600875.XSHG','600880.XSHG']
years = range(2005,2018)
df_list=[]
for year in years:
df_year= get_fundamentals(query(
indicator.code, indicator.inc_return,indicator.roe
).filter(
indicator.code.in_(stock_list)
),statDate=year).set_index('code')
df_list.append(df_year)
name = [str(x) for x in range(2005,2017)]
df=pd.concat(df_list,axis=1,keys=name)
df