获取股票列表的关键信息通常包括以下几个方面:
1. **股票代码**:股票的唯一标识符,通常由字母和数字组成,如"AAPL"代表苹果公司的股票。
2. **公司名称**:股票所代表的公司全称。
3. **行业板块**:股票所属的行业领域,如科技、金融、医疗等。
4. **市场类别**:股票上市的交易所,如纽约证券交易所(NYSE)、纳斯达克(NASDAQ)等。
5. **股价**:股票当前的交易价格。
6. **市值**:公司的总市值,通常由股价乘以发行的股票总数得出。
7. **成交量**:在一定时间内股票的交易数量。
8. **市盈率**:衡量股票价格相对于每股收益的指标,计算公式为股价除以每股收益。
9. **分红信息**:公司分配给股东的利润,通常以年度或季度进行。
10. **财务报表**:包括利润表、资产负债表和现金流量表等,反映公司的财务状况。
11. **公司新闻和公告**:公司发布的最新信息,可能影响股票价格。
12. **分析师评级**:专业分析师对股票的评价,包括买入、持有、卖出等建议。
如果你需要具体的帮助来获取或分析股票信息,请提供更多的细节或具体的问题。如果你有特定的股票列表或数据文件需要分析,请上传文件,我可以帮助你解读和分析这些数据。
# encoding:utf-8
import sys,os,copy,time,traceback,copy
from datetime import datetime
import pandas as pd
from loguru import logger
sys.path.append("..")
from QhSetting import QHJSPATH
from QhSpiderObj import QhDFSpider
from QhCsvMode import QHDFDBJSON
from QhSpiderTool import QhDbPathJieXiIsMkdir,QhJiSuanJinCheng,QhSouHuJiaoYiDate,QhReadStockCode,\
QhTimestamp,QhMultiProcessingMain,QhDorpFiled
from QhSpiderTool import QhStarEndTime
from QhSpiderTool import QhJoinPathLogCsv,QhGetXGDate
from QhInterFace import _QhDfMaiMAIDetails,_QhDBToCsv,_QhRequestDataFor,_QhDfCompayType,\
_QhGNBanKuaiUniqueN,QhDfZTGPool,QhDfStockQGQP,QhDfStockXuanGu
def QhDfMaiMAIDetailsForM(QhCodeDF,QhIsCsv=False,QhQueue=None):
"""
作者:阙辉
功能:获取每日买卖明细
"""
QhUniqueValue = QHDFDBJSON["_QhDfMaiMAIDetails"]["QhUniqueValue"]
QhJiaoYiDateD = QhSouHuJiaoYiDate()[2] # 获取交易日期('YYYY','YYYY-MM','YYYY-MM-DD')
QhCsvPathF0 = QHDFDBJSON["_QhDfMaiMAIDetails"]["QhCsvPathF"]
QhCsvNameF0 = QHDFDBJSON["_QhDfMaiMAIDetails"]["QhCsvNameF"]
QhI = 0
for index, row in QhCodeDF.iterrows():
try:
QhCode01 = row["股票代码"]
QhShiChang = row["市场代码"]
QhCsvPathF = copy.deepcopy(QhCsvPathF0)
QhCsvNameF = QhCsvNameF0.format(QhCode01)
QhCsvPathF = QhDbPathJieXiIsMkdir(QhCsvPathF,QHJSPATH)
QhCsvPathF = "{}\{}".format(QhCsvPathF,QhCsvNameF)
QhCode = QhCode01.replace("Q","")
QhCodes = QhShiChang
secid ="{}.{}".format(QhCodes,QhCode)
QhJieGuoRowDf = _QhDfMaiMAIDetails(QhSecid=secid)
QhJieGuoRowDf["交易日期01"] = QhJiaoYiDateD
if QhQueue != None: QhQueue.put(("QhData",QhJieGuoRowDf))
_QhDBToCsv(QhCsvPathF,QhUniqueValue,QhJieGuoRowDf,QhDateSort="",QhIsCsv=True)
if QhQueue != None: QhQueue.put(("QhMsg",["QhDfMaiMAIDetailsForM",QhTimestamp(),"2、批量请求买卖竞价数据成功*QueHui",QhCode01,"Success",""]))
QhI = QhI + 1
except:
QhErrMsg = traceback.print_exc()
if QhQueue != None: QhQueue.put(("QhMsg",["QhDfMaiMAIDetailsForM",QhTimestamp(),"2、批量请求买卖竞价数据失败*QueHui",QhCode01,"Error",QhErrMsg]))
logger.error("【买卖竞价数据】获取失败,报错消息\n{QhErrMsg}!QueHui!".format(QhErrMsg=QhErrMsg))
_QhDBToCsv(QhCsvPathF,QhUniqueValue,QhJieGuoRowDf,QhDateSort="",QhIsCsv=True)
QhI = QhI + 1
def QhDfMaiMAIDetailsForMuli(QhIsCsv=True):
"""
作者:阙辉
功能:获取每日买卖明细 多进程分发
"""
QhJiaoYiDateD = QhSouHuJiaoYiDate()[2] # 获取交易日期('YYYY','YYYY-MM','YYYY-MM-DD')
QhCsvPath = QHDFDBJSON["_QhDfMaiMAIDetails"]["QhCsvPath"]
QhUniqueValue = QHDFDBJSON["_QhDfMaiMAIDetails"]["QhUniqueValue"]
QhCsvName0 = QHDFDBJSON["_QhDfMaiMAIDetails"]["QhCsvName"]
QhCsvName = QhCsvName0.format(QhJiaoYiDateD)
QhCsvPath = QhDbPathJieXiIsMkdir(QhCsvPath,QHJSPATH)
QhCsvPath = "{}\{}".format(QhCsvPath,QhCsvName)
QhCodedf = QhReadStockCode(QHJSPATH,QHDFDBJSON,("交易板块",["上证A股","深证A股","北证A股","科创板","创业板"]))
QhLogdf,QhJieGuodf = QhMultiProcessingMain(QhCodedf,QhDfMaiMAIDetailsForM)
_QhDBToCsv(QhCsvPath,QhUniqueValue,QhJieGuoDf=QhJieGuodf,QhDateSort="",QhIsCsv=QhIsCsv)
return QhJieGuodf
def QhDfAllFenLeiBKDetailM(QhCodeDF,QhIsCsv=False,QhQueue=None):
"""
> 行情中心 > 沪深京板块 > 行业板块 明细
return:获取所有交易板块和股票代码的关系
"""
QhForCsvDf = QhCodeDF
QhPs=10000 # 请求数量
QhUrl = QHDFDBJSON["_QhDfAllFenLeiBKDetail"]["url"]
qh_params = QHDFDBJSON["_QhDfAllFenLeiBKDetail"]["params"]
qh_params["pz"] = QhPs
fielddic = QHDFDBJSON["_QhDfAllFenLeiBKDetail"]["fielddic"]
fielddic_keys = list(fielddic.keys()) # 原key
fielddic_values = list(fielddic.values()) # 中文字段名
QhI = 0
for index,QhRow0 in QhForCsvDf.iterrows():
try:
QhBankuai = QhRow0["交易板块"]
QhBankuaiName = QhRow0["股票名称"]
QhBankuaiCode = QhRow0["股票代码"].replace("Q","")
QhBankuaiCode0 = "b:{}+f:!50"
qh_params["fs"] = QhBankuaiCode0.format(QhBankuaiCode)
qh_params["pn"] = 1
QhJieGuoList = _QhRequestDataFor(QhUrl,qh_params,QhFielddicKeys=fielddic_keys,
QhPageC="pn",QhType="A2",QhType0="A0",QhPs=QhPs) # 请求获取数据 可分页
QhJieGuoDf = pd.DataFrame(QhJieGuoList,columns = fielddic_values)
QhJieGuoDf["分类板块"] = QhBankuai
QhJieGuoDf["板块代码"] = QhBankuaiCode
QhJieGuoDf["板块名称"] = QhBankuaiName
if QhQueue != None: QhQueue.put(("QhData",QhJieGuoDf)) # 结构数据传入消息队列
QhI += 1 # 标记作用
if QhQueue != None: QhQueue.put(("QhMsg",["QhDfAllFenLeiBKDetailM",QhTimestamp(),"2、【板块股票关系】批量请求板块与股票明细关系成功*QueHui",QhRow0["股票名称"],"Success",""]))
except:
QhErrMsg = traceback.print_exc()
logger.error("【板块股票关系】获取失败,报错消息\n{QhErrMsg}!QueHui!".format(QhErrMsg=QhErrMsg))
if QhQueue != None: QhQueue.put(("QhMsg",["QhDfAllFenLeiBKDetailM",QhTimestamp(),"2、【板块股票关系】批量请求板块与股票明细关系失败*QueHui",QhRow0["股票名称"],"Failure",QhErrMsg]))
def QhDfAllFenLeiBKDetailMuli(QhIsCsv=False):
"""
作者:阙辉
> 行情中心 > 沪深京板块 > 行业板块 明细 多进程获取
"""
QhUniqueValue = QHDFDBJSON["_QhDfAllFenLeiBKDetail"]["QhUniqueValue"]
QhCsvPath = QHDFDBJSON["_QhDfAllFenLeiBKDetail"]["QhCsvPath"]
QhCsvName = QHDFDBJSON["_QhDfAllFenLeiBKDetail"]["QhCsvName"]
QhCsvPath = QhDbPathJieXiIsMkdir(QhCsvPath,QHJSPATH)
QhCsvPath = "{}\{}".format(QhCsvPath,QhCsvName)
QhCodedf = QhReadStockCode(QHJSPATH,QHDFDBJSON,("交易板块",["概念板块","地域板块","行业板块"]))
QhLogdf,QhJieGuodf = QhMultiProcessingMain(QhCodedf,QhDfAllFenLeiBKDetailM)
print(QhJieGuodf)
_QhDBToCsv(QhCsvPath,QhUniqueValue,QhJieGuoDf=QhJieGuodf,QhDateSort="",QhIsCsv=QhIsCsv)
return QhJieGuodf
@QhStarEndTime
def QhDfAllStockM(QhPs=10000,QhIsCsv=False):
"""
> 行情中心 > 沪深京个股 > 沪深京A股
return:获取所有股票的行情数据
此方法只用于获取股票最新的基本信息
作者:阙辉
"""
QhLogListfiled = QHDFDBJSON["QhErrorDf"]["QhFiled"]
QhLogList = []
QhShiChangList = QHDFDBJSON["QhDfAllStock"]["QhShiChangList"] # 获取市场列表
QhUrl = QHDFDBJSON["QhDfAllStock"]["url"] # Url地址
qh_params = QHDFDBJSON["QhDfAllStock"]["params"] # 请求参数
QhUniqueValue = QHDFDBJSON["QhDfAllStock"]["QhUniqueValue"]
fielddic = QHDFDBJSON["QhDfAllStock"]["fielddic"]
QhCsvPath = QHDFDBJSON["QhDfAllStock"]["QhCsvPath"]
QhCsvName = QHDFDBJSON["QhDfAllStock"]["QhCsvName"]
QhCsvPath = QhDbPathJieXiIsMkdir(QhCsvPath,QHJSPATH)
QhCsvPath = "{}\{}".format(QhCsvPath,QhCsvName)
qh_params["pz"] = QhPs
QhJiaoYiDateD = QhSouHuJiaoYiDate()[2] # 获取交易日期('YYYY','YYYY-MM','YYYY-MM-DD')
QhLogList.append(["QhDfAllStockM",QhTimestamp(),
"1、【股票列表】获取运行时最近交易日期[{}]*QueHui".format(QhJiaoYiDateD),
"QhSouHuJiaoYiDate()[2]","Success",""])
fielddic_keys = list(fielddic.keys()) # 原key
fielddic_values = list(fielddic.values()) # 中文字段名
for QhI,QhRow0 in enumerate(QhShiChangList):
QhShiChang = QhRow0[0]
qh_params["fs"] = QhRow0[1]
qh_params["pn"] = 1
QhJieGuoList = _QhRequestDataFor(QhUrl,qh_params,QhFielddicKeys=fielddic_keys,
QhPageC="pn",QhType="A2",QhType0="A0",QhPs=QhPs) # 请求获取数据 可分页
QhJieGuoDf = pd.DataFrame(QhJieGuoList,columns = fielddic_values)
QhJieGuoDf["交易板块"] = QhShiChang
# 将数据添加后面
if QhI == 0:
QhJieGuoDfNew = QhJieGuoDf.copy(deep=True)
else:
try: # 兼容旧版本处理
QhJieGuoDfNew = QhJieGuoDfNew._append(QhJieGuoDf)
except:
QhJieGuoDfNew = QhJieGuoDfNew.append(QhJieGuoDf)
logger.info("2、【股票列表】{}市场数据获取成功!QueHui!".format(QhShiChang))
QhLogList.append(["QhDfAllStockM",QhTimestamp(),
"2、【股票列表】{}市场数据获取成功*QueHui".format(QhShiChang),
QhShiChang,"Success",""])
QhJieGuoDfNew["交易日期01"] = QhJiaoYiDateD # 添加交易日期
try:
"""股票池数据左连接 公司类型"""
QhDfCompayTypeDf = _QhDfCompayType(QhPs=20000,QhIsCsv=True) # 请求获取公司类型 并存储CSV 数据少 直接获取数据
QhDfCompayTypeDf = QhDorpFiled(QhDfCompayTypeDf,["唯一值"])
QhJieGuoDfNew = pd.merge(QhJieGuoDfNew, QhDfCompayTypeDf, how='left', left_on=["股票代码"],right_on=["股票代码"]) # 左连接公司报表类型
QhLogList.append(["_QhDfCompayType",QhTimestamp(),
"3、【股票列表】公司类型数据获取成功并连接*QueHui",
"公司类型","Success",""])
except:
QhErrMsg = traceback.print_exc()
logger.error("【财报类型拼接】拼接失败,报错消息\n{QhErrMsg}!QueHui!".format(QhErrMsg=QhErrMsg))
QhLogList.append(["_QhDfCompayType",QhTimestamp(),
"3、【股票列表】-公司类型数据获取失败*QueHui",
"公司类型","Error",QhErrMsg])
try:
"""股票池数据左连接 行业板块 地域板块"""
QhBanKuaiCsvDf = QhDfAllFenLeiBKDetailMuli(QhIsCsv=True) # 实时获取板块明细
start = time.time()
QhOldCsvDfHY = QhBanKuaiCsvDf[QhBanKuaiCsvDf["分类板块"]=="行业板块"].copy(deep=True) # 过滤行业板块明细
QhOldCsvDfHY =_QhGNBanKuaiUniqueN(QhOldCsvDfHY)
QhOldCsvDfHY.rename(columns={'板块名称':'行业板块名称','板块代码':'行业板块代码'},inplace=True) # 更改字段名称
QhOldCsvDfDY = QhBanKuaiCsvDf[QhBanKuaiCsvDf["分类板块"]=="地域板块"].copy(deep=True) # 过滤地域板块明细
QhOldCsvDfDY =_QhGNBanKuaiUniqueN(QhOldCsvDfDY)
QhOldCsvDfDY.rename(columns={'板块名称':'地域板块名称','板块代码':'地域板块代码'},inplace=True) # 更改字段名称
QhOldCsvDfGN = QhBanKuaiCsvDf[QhBanKuaiCsvDf["分类板块"]=="概念板块"].copy(deep=True) # 过滤地域板块明细
QhOldCsvDfGN =_QhGNBanKuaiUniqueN(QhOldCsvDfGN)
QhOldCsvDfGN.rename(columns={'板块名称':'概念板块名称','板块代码':'概念板块代码'},inplace=True) # 更改字段名称
QhJieGuoDfNew = pd.merge(QhJieGuoDfNew, QhOldCsvDfHY, how='left', left_on=["股票代码"],right_on=["股票代码"]) # 左连接行业板块明细
QhJieGuoDfNew = pd.merge(QhJieGuoDfNew, QhOldCsvDfDY, how='left', left_on=["股票代码"],right_on=["股票代码"]) # 左连接地域板块明细
QhJieGuoDfNew = pd.merge(QhJieGuoDfNew, QhOldCsvDfGN, how='left', left_on=["股票代码"],right_on=["股票代码"]) # 左连接地域板块
end = time.time()
print('程序运行时间为: %s Seconds'%(end-start))
QhLogList.append(["_QhDfAllFenLeiBKDetail",QhTimestamp(),
"4、【股票列表】获取公司板块成功,%s Seconds*QueHui"%(end-start),
"行业板块","Success",""])
except:
QhErrMsg = traceback.print_exc()
logger.error("【板块股票关系拼接】获取失败,报错消息\n{QhErrMsg}!QueHui!".format(QhErrMsg=QhErrMsg))
QhLogList.append(["_QhDfAllFenLeiBKDetail",QhTimestamp(),
"4、【股票列表】公司板块取失败*QueHui",
"行业板块","Error",QhErrMsg])
_QhDBToCsv(QhCsvPath,QhUniqueValue,QhJieGuoDfNew,QhDateSort="",QhIsCsv=QhIsCsv) # 第一次存储,如果不存后面买卖数据可能调用报错
try:
"""股票池数据左连接 涨跌池数据"""
QhDfZTGPoolDF = QhDfZTGPool(QhIsCsv=True) # 涨跌池数据
QhDfZTGPoolDF = QhDorpFiled(QhDfZTGPoolDF,["唯一值",'成交额','换手率','流通市值','股票名称','最新价','总市值','涨跌幅','动态市盈率','振幅','量比',])
QhJieGuoDfNew = pd.merge(QhJieGuoDfNew, QhDfZTGPoolDF, how='left', left_on=["股票代码","交易日期01"],right_on=["股票代码","ZDP交易日期"]) # 左连接买卖竞价数据S公司报表类型
QhLogList.append(["QhDfZTGPool",QhTimestamp(),
"5、【股票列表】获取公司涨跌池成功*QueHui",
"涨跌池","Success",""])
except:
QhErrMsg = traceback.print_exc()
logger.error("【涨跌池数据】拼接失败,报错消息\n{QhErrMsg}!QueHui!".format(QhErrMsg=QhErrMsg))
QhLogList.append(["QhDfZTGPool",QhTimestamp(),
"5、【股票列表】公司涨跌池取失败*QueHui",
"涨跌池","Error",QhErrMsg])
try:
"""股票池数据左连接 买卖竞价数据"""
QhJieGuodf = QhDfMaiMAIDetailsForMuli(QhIsCsv=True)
QhDfMaiMAIDf = QhDorpFiled(QhJieGuodf,["唯一值"])
QhJieGuoDfNew = pd.merge(QhJieGuoDfNew, QhDfMaiMAIDf, how='left', left_on=["股票代码","交易日期01"],right_on=["股票代码","交易日期01"]) # 左连接买卖竞价数据S公司报表类型
QhLogList.append(["QhDfMaiMAIDetailsForM",QhTimestamp(),
"6、【股票列表】获取买卖竞价数据成功*QueHui",
"买卖竞价","Success",""])
except:
QhErrMsg = traceback.print_exc()
logger.error("【买卖竞价数据】拼接失败,报错消息\n{QhErrMsg}!QueHui!".format(QhErrMsg=QhErrMsg))
QhLogList.append(["QhDfMaiMAIDetailsForM",QhTimestamp(),
"6、【股票列表】获取买卖竞价数据失败*QueHui",
"买卖竞价","Error",QhErrMsg])
try:
"""龙虎榜-当天 第一次合并"""
# QhJiaoYiDateD01 = "(TRADE_DATE<='{}')(TRADE_DATE>='{}')".format(QhJiaoYiDateD,QhJiaoYiDateD)
QhJiaoYiDateD = QhGetXGDate()[2] # 获取交易日期('YYYY','YYYY-MM','YYYY-MM-DD')
QhJiaoYiDateD01 = "(TRADE_DATE<='{}')(TRADE_DATE>='{}')".format(QhJiaoYiDateD,QhJiaoYiDateD)
QhLHBDdf = QhDfStockQGQP(QhreportName="RPT_DAILYBILLBOARD_DETAILSNEW",QhSECURITY_CODE = "",QhsortColumns="TRADE_DATE",
Qhcolumns="SECURITY_CODE,SECUCODE,SECURITY_NAME_ABBR,TRADE_DATE,EXPLAIN,CLOSE_PRICE,CHANGE_RATE,BILLBOARD_NET_AMT,BILLBOARD_BUY_AMT,BILLBOARD_SELL_AMT,BILLBOARD_DEAL_AMT,ACCUM_AMOUNT,DEAL_NET_RATIO,DEAL_AMOUNT_RATIO,TURNOVERRATE,FREE_MARKET_CAP,EXPLANATION,D1_CLOSE_ADJCHRATE,D2_CLOSE_ADJCHRATE,D5_CLOSE_ADJCHRATE,D10_CLOSE_ADJCHRATE,SECURITY_TYPE_CODE",
Qhfilter01=QhJiaoYiDateD01,QhIsCsv=True)
QhDropLie = ['唯一值','股票代码0','股票名称',"收盘价","涨跌幅","流通市值","换手率"] # 删除不需要的列
QhLHBDdf = QhDorpFiled(QhLHBDdf,QhDropLie)
QhLHBDdf.rename(columns={'交易日期':'LHB交易日期'},inplace=True)
# QhJieGuoDfNew = pd.merge(QhJieGuoDfNew,QhLHBDdf,how='left',left_on=["股票代码","交易日期01"],right_on=["股票代码","交易日期"]) # 交易数据左连接机构代码
QhJieGuoDfNew = pd.merge(QhJieGuoDfNew,QhLHBDdf,how='left',left_on=["股票代码"],right_on=["股票代码"]) # 交易数据左连接机构代码
logger.info("【龙虎榜-当天】数据请求成功!QueHui!")
QhLogList.append(["RPT_DAILYBILLBOARD_DETAILSNEW",QhTimestamp(),
"7、【股票列表】获取龙虎榜-当天数据成功*QueHui",
"龙虎榜","Success",""])
except:
QhErrMsg = traceback.print_exc()
logger.error("【龙虎榜-当天】获取失败,报错消息\n{QhErrMsg}!QueHui!".format(QhErrMsg=QhErrMsg))
QhLogList.append(["RPT_DAILYBILLBOARD_DETAILSNEW",QhTimestamp(),
"7、【股票列表】获取龙虎榜-当天数据失败*QueHui",
"龙虎榜","Error",QhErrMsg])
try:
"""股票池数据左连接 买卖选股数据"""
QhDfXuanGuDf = QhDfStockXuanGu(QhIsCsv=False,QhPs=1000)
QhDfXuanGuDf = QhDorpFiled(QhDfXuanGuDf,["唯一值"])
# QhJieGuoDfNew = pd.merge(QhJieGuoDfNew, QhDfXuanGuDf, how='left', left_on=["股票代码","交易日期01"],right_on=["XG股票代码","ZNXG交易日期"]) # 左连接买卖竞价数据S公司报表类型
# 智能选股数据更新是在收盘前(交易日16点30以后),收盘以后是当天的选股数据,智能选股数据会自己按月按日存储数据
QhJieGuoDfNew = pd.merge(QhJieGuoDfNew, QhDfXuanGuDf, how='left', left_on=["股票代码"],right_on=["XG股票代码"]) # 左连接买卖竞价数据S公司报表类型
QhLogList.append(["QhDfStockXuanGu",QhTimestamp(),
"8、【股票列表】获取选股数据数据成功*QueHui",
"智能选股","Success",""])
except:
QhErrMsg = traceback.print_exc()
logger.error("【买卖竞价数据】拼接失败,报错消息\n{QhErrMsg}!QueHui!".format(QhErrMsg=QhErrMsg))
QhLogList.append(["QhDfStockXuanGu",QhTimestamp(),
"8、【股票列表】获取选股数据数据失败*QueHui",
"智能选股","Error",QhErrMsg])
_QhDBToCsv(QhCsvPath,QhUniqueValue,QhJieGuoDfNew,QhDateSort="",QhIsCsv=QhIsCsv)
QhLogdf = pd.DataFrame(QhLogList,columns=QhLogListfiled)
QhCsvPath = QhJoinPathLogCsv("QhDfAllStockM")
QhLogdf.to_csv(QhCsvPath,index=False,encoding="gbk")
return QhJieGuoDfNew
if __name__ == '__main__':
# QhCodedf = QhReadStockCode(QHJSPATH,QHDFDBJSON,("交易板块",["上证A股","深证A股","北证A股","科创板","创业板"]))
# QhLogdf,QhJieGuodf = QhMultiProcessingMain(QhCodedf,QhDfMaiMAIDetailsForM)
# print(QhJieGuodf)
# print(QhLogdf)
aa = QhDfAllStockM(QhPs=10000,QhIsCsv=True)
# aa = _QhDfCompayType(QhPs=20000,QhIsCsv=True)
# QhDfAllFenLeiBKDetailMuli(QhIsCsv=True)
# aa = QhDfStockXuanGu(QhIsCsv=True,QhPs=1000)
print(aa)