未完成项目:股票分析系统MyFunction23_05_18.py

import datetime,os
import math
import time
import multiprocessing,threading # 导入多进程和多线程包

import numpy as np
import pandas as pd
import tushare as ts
from matplotlib import pyplot as plt


ts.set_token('c1fa5bbb1934cf23e053974c6eb58ffbf2713312c520a2e1074d5090')
pro = ts.pro_api()

'''
关于本函数库的说明:
        1.本函数库使用的是类方法属性,@classmethod。关于类以及此语法的用法,留待日期再认真研究。
    使用类的好处,方便使用时可以快速查找到对应的函数,可以大大减少记忆量。
        2.文件保存方面:
            a.文件保存的路径前缀在函数Basics.PandasSaveData、Basics.IsNewDataFile的参数path_prefix中设置
            b.文件保存后缀的设置格式:'/类名/函数名/文件名'
        3.暂定设置以下类:
            Basics          基础类
            BasicsData      基础数据类
            Financial       财务类
            Technology      技术分析类
            Chart           图表类
            Index           指标类
            Fund            资金类
            Price           价格类
            Volume          成交量类
            Industry        行业概念类
            WanWei          万维股票分析系统
            Upgrade         待升级的函数的类
            Immaturity      未成熟的函数
            
'''
def ShowFunc():
    # 技术类
    Technology.Hist_List()
    Technology.Day_Index_Hist()
    Technology.MA_Data_Func()
    Technology.MA_Figure()
    Technology.Judge_MA()
    Technology.MACD_Data_Func()
    Technology.MACD_Figure()
    Technology.Judge_MACD()
    Technology.MACD_FourCrossingAnalysis()
    Technology.MACD_FourCrossingAnalysisResult()
    # TODO 将成交量分析函数化为技术类中



def Today_Date_Count(Num=0): # 计算当前日期加减一个数字,向前或向后得出新的日期
    '''
    :param Num: 当前日期向前或向后加减的天数:正数为向后推算,负数为向前推算
    :return:
    '''
    now = datetime.datetime.today()
    result_time=now+datetime.timedelta(days=Num)
    year = result_time.year
    month = result_time.month
    day = result_time.day

    year_str = '{}'.format(year)
    month_str = '{}'.format(month).rjust(2, '0')
    day_str='{}'.format(day).rjust(2,'0')

    date_str='{}{}{}'.format(year_str,month_str,day_str)

    return date_str

# MACD_FourCrossingAnalysis(RecentTradeDayNum=2)
# MACD_FourCrossingAnalysisResult()

# TODO 1.均线作为支撑线,验证格南维尔法则的不同买卖时点的概率。2.分析多头排列股份持续上升的天数,并统计其分步规律。
# TODO 1.优化MA多头排列的判断方法,是否可以使用相邻MA5-MA10的变化差的波动百分比来判断.2。增加参数judge_num的天数来判断



def PAN(target='pb'):
    pb_df=pd.read_csv('./LoadFile/LongUpdateData/财务{}统计结果.csv'.format(target))
    pb_index=[i[0:6] for i in pb_df.loc[:,'ts_code'].values]
    pb_df.index=pb_index
    pb_df.drop(columns=['Unnamed: 0'],inplace=True)
    print(pb_df)


    # 获取每日指标:使用for循环,但是使用了for break语句

    for i in range(365):
        trade_date=Today_Date_Count(Num=-i)
        print(trade_date)
        df = pro.daily_basic(ts_code='', trade_date=trade_date,
                               fields='ts_code,trade_date,{}'.format(target))
        num=df['ts_code'].count()
        print(i,end='\t')
        print(num)
        if num>0:
            break
    df.index=[i[0:6] for i in df.loc[:,'ts_code']] # TODO 此处语法有点瑕疵,有待优化
    df.drop(columns=['ts_code'], inplace=True)
    print(df)
    # 合并数据
    result=pb_df.join(df)
    print(result)
    y=result.columns.values[2:9]
    print(y)
    def judge(t):
        bool_list=[]
        for i in y:
            if t[target]>t[i]:
                bool_list.append(t[i])

        len1=len(bool_list)
        return y[len1-1] # TODO 此语法有瑕疵,应为 return y[len1],但运行此语句时程序报错
    result['judge']=result.apply(judge,axis=1)
    print(result)
    result.to_csv('20230512临时数据.csv', encoding='utf_8_sig')








def ListDaysYears(): # 关于上市天数和年数的函数
    '''
    :return:返回一个元组。元组中包括两个变量:
            data:DataFrame数据,包含A股所有上市公司的上市年数数据,list_years列中数据为上市公司的自上市至今的上市年数
            running_time:函数的运行时间
    '''
    # 计算函数运行时间的辅助代码
    begin_time=datetime.datetime.now()
    # 获取A股所有股票的上市公司代码、名称、上市时间数据
    data = pro.stock_basic(exchange='', list_status='L', fields='ts_code,symbol,name,list_date')

    symbol_list=[i for i in data.loc[:,'symbol'].values]
    data.index=symbol_list
    # 使用循环获向上市天数和年数列表中添加数据
    list_days=[]
    list_years=[]
    for i in symbol_list:
        old_date_str = data.loc[i, 'list_date']  # 由上市日期构成的字符串
        new_date_str = old_date_str[0:4] + '-' + old_date_str[4:6] + '-' + old_date_str[6:]  # 将date_str1转化为YYYY-MM-DD格式
        List_Date = datetime.date.fromisoformat(new_date_str)  # 上市日期
        today = datetime.date.today()  # 今天的日期
        ListDaysNum = (today - List_Date).days  # 上市时间天数,该天数为自然日天数,不是交易日天数
        ListYearNums = round(ListDaysNum / 365, 2)  # 上市时间年数
        list_days.append(ListDaysNum)
        list_years.append(ListYearNums)
    else:
        data['list_days']=list_days # 向原data数据中添加上市日期天数,即list_days
        data['list_years']=list_years # 向原data数据中添加上市年数列,即list_years
        data.index=range(data['ts_code'].count()) # 按股票代码出现的顺序号设置行索引
    # 计算函数运行时间的辅助代码
    end_time=datetime.datetime.now()
    running_time=end_time-begin_time
    myresult=(data,running_time)
    return myresult



class Basics(): # 基础类
    @classmethod
    def RecentlyTradeDate(cls):
        # 获取A股股票数据
        data = pro.stock_basic(exchange='', list_status='L', fields='ts_code,symbol,name,list_date')
        # 获取股标ts_code构成的列表中第一个元素
        ts_code = data['ts_code'][0]
        # 获取变量ts_code的日线行情
        df = pro.daily(ts_code=ts_code, start_date='20180701')
        # 获取变量ts_code的最近一个交易日
        recently_trade_date = df['trade_date'][0]
        # 函数返回值
        return recently_trade_date
    @classmethod
    def PandasSaveData(cls,data, path_suffix, save_file_type='csv', path_prefix='D:\StockAnalysis',encoding='utf_8_sig', index=False, header=True):
        '''
        :param data: 需要导入的pandas数据
        :param path_suffix:保存文件路径的后缀。数据格式:'/张三/李四/王五/赵六/测试函数{}-{}.xlsx'.format(k1,k2)。
                           使用技巧:可以在使用SaveData函数前,定义一个路径变量,然后再使用SaveData函数。这个路径变量中可以包含生成该数据的函数中的参数
                                data=pd.DataFrame([[4, 9, 16], [25, 36, 49], [64, 81, 100]], columns=list('ABC'))
                                k1='财务'
                                k2='刘洋'
                                my_path_suffix= '/张三/李四/王五/赵六/测试函数{}-{}.xlsx'.format(k1, k2)
                                SaveData(data=data, path_suffix=my_path_suffix, save_file_type='excel')
        :param save_file_type:导出文件的格式,分为csv和excel两种,默认值为csv。参数值只有两个:csv和excel
        :param path_prefix:保存文件路径的前缀,即将文件统一保存至某个文件夹中。数据格式:'E:\小白课堂\证券投资\立讯精密'。路径名称的最后一个文件夹名称后面不许带有符号'\'
        :param encoding: 编码格式,设置的默认值为utf_8_sig,可以正常显示汉字
        :param index: 是否需要导入行索引,默认为Flase,即不导入行索引
        :param header: 是否需要导入列索引,默认为True,即导入行索引
        :return:1.将数据导出成csv或excel格式文件
                2.返回文件的保存路径
        :自我评价:1.从学习pthon以来,这是创建的参数最多的一个函数,这也是一个很漂亮的函数
                 2.该函数运行时间极短,大约为0.001秒
        '''
        start_time = datetime.datetime.now()
        # 1.将参数中的路径前缀转化为python格式的路径,并前缀电脑中不存在前缀路径,则程序创建一个前缀路径

        prefix = path_prefix.replace('\\', '/')
        prefix_list = prefix.split(sep='/')
        mypath_prefix = ''  # 使用循环创建前缀路径

        for i in prefix_list:
            if i == prefix_list[0]:
                mypath_prefix = mypath_prefix + i
                if os.path.exists(mypath_prefix):
                    pass
                else:
                    os.mkdir(mypath_prefix)
            else:
                mypath_prefix = mypath_prefix + '/' + i
                if os.path.exists(mypath_prefix):
                    pass
                else:
                    os.mkdir(mypath_prefix)

        # 2.创建路径后缀中的文件夹

        suffix_list1 = path_suffix.split(sep='/')  # 将路径后缀按'/'进行分析,并将分割结果返回成列表数据

        lenght = len(suffix_list1)
        suffix_list2 = suffix_list1[1:lenght - 1]  # 列表2中的元素,从前至后,依次为各级文件的名称

        mypath = prefix  # 为使用循环反复赋值定义的一个路径变量

        for i in suffix_list2:
            mypath = mypath + '/' + i

            if os.path.exists(mypath):  # 判断文件夹或文件是否存在的函数
                pass
            else:
                os.mkdir(mypath)  # 创建文件夹

        # 3.删除旧文件并创建新文件

        del_name = suffix_list1[-1]  # 旧文件名称中的相同文件
        del_name_list = del_name.split(sep='.')  # split将del分割为'.'前后两部分
        identifier=Basics.RecentlyTradeDate()
        '''
            20230623年新增功能,以交易日期作为文件是否更新标识符更合理
        '''
        file_name=del_name_list[0]+'(交易日期{})'.format(identifier)+'.'+del_name_list[1]
        final_save_path = mypath + '/' + file_name  # 创建文件的最终路径和名称
        if os.path.exists(final_save_path):  # 通过标识符变量判断,是否为最新文件。如果是最新文件,则不需要重复创建,否则,删除旧文件并创建新文件
            print('文件已存在,不需要重复创建')
        else:
            # 删除旧文件
            use_file_list = os.listdir(mypath)
            for j in use_file_list:
                if j.count(del_name_list[0]) != 0 and j.count(del_name_list[1]) !=0:
                    remove_file_name = mypath + '/' + j
                    os.remove(remove_file_name)
            # 创建新文件
            if save_file_type == 'csv':
                data.to_csv(final_save_path, encoding=encoding, index=index, header=header)
                print('文件创建完成')
            elif save_file_type == 'excel':
                data.to_excel(final_save_path, encoding=encoding, index=index, header=header)
                print('文件创建完成')
        end_time = datetime.datetime.now()
        print(end_time - start_time)
        # 4.函数返回值
        return final_save_path
    @classmethod
    def IsNewDataFile(cls,path_suffix, path_prefix='D:\StockAnalysis'):
        '''
        :param path_suffix: 文件的只在路径,不需要带本是否更新标识符,如file_path = '/Financial/FinancialItem/股票[{}-{}]所有季度数据.csv'.format(statement_type, item)
        :param path_prefix: 参考Basics.PandasSaveData()说明
        :return: 返回值是一个元组:1.返回True或False,如果是最新的文件,则返回True,否则返回False
                                2.返回文件的保存路径,路径返回值是同Basics.PandasSaveData()一致。
        '''
        # 1.将参数中的路径前缀转化为python格式的路径,并前缀电脑中不存在前缀路径,则程序创建一个前缀路径

        prefix = path_prefix.replace('\\', '/')
        prefix_list = prefix.split(sep='/')
        mypath_prefix = ''  # 使用循环创建前缀路径

        for i in prefix_list:
            if i == prefix_list[0]:
                mypath_prefix = mypath_prefix + i
                if os.path.exists(mypath_prefix):
                    pass
                else:
                    os.mkdir(mypath_prefix)
            else:
                mypath_prefix = mypath_prefix + '/' + i
                if os.path.exists(mypath_prefix):
                    pass
                else:
                    os.mkdir(mypath_prefix)

        # 2.创建路径后缀中的文件夹

        suffix_list1 = path_suffix.split(sep='/')  # 将路径后缀按'/'进行分析,并将分割结果返回成列表数据

        lenght = len(suffix_list1)
        suffix_list2 = suffix_list1[1:lenght - 1]  # 列表2中的元素,从前至后,依次为各级文件的名称

        mypath = prefix  # 为使用循环反复赋值定义的一个路径变量

        for i in suffix_list2:
            mypath = mypath + '/' + i

            if os.path.exists(mypath):  # 判断文件夹或文件是否存在的函数
                pass
            else:
                os.mkdir(mypath)  # 创建文件夹

        # 3.删除旧文件并创建新文件

        del_name = suffix_list1[-1]  # 旧文件名称中的相同文件
        del_name_list = del_name.split(sep='.')  # split将del分割为'.'前后两部分
        identifier=Basics.RecentlyTradeDate()
        '''
            20230623年新增功能,以交易日期作为文件是否更新标识符更合理
        '''
        file_name = del_name_list[0] + '(交易日期{})'.format(identifier) + '.' + del_name_list[1]
        final_save_path = mypath + '/' + file_name  # 创建文件的最终路径和名称
        if os.path.exists(final_save_path):  # 通过标识符变量判断,是否为最新文件。如果是最新文件,则不需要重复创建,否则,删除旧文件并创建新文件
            return (True,final_save_path)
        else:
            return (False,final_save_path)
    @classmethod
    def PandasMultipleBool(cls,data, col, mylist: list):  # 可以参考此函数写一个关于'&'符的多条件布尔索引
        '''
        :param data: 需要使用多个"或条件"索引的pandas数据
        :param col: 需要使用多个"或条件"索引的pandas殉索引
        :param mylist:需要使用多个"或条件"索引的多个条件
        :return: 返回多个"或条件"索引的pandas数据结果
        '''
        # 1.使用concat函数将多个"或"即"|"条件索引出来的数据拼接在一起,即实现了多个"或条件"即"|"条件下的pandas布尔索引
        result = pd.DataFrame()
        for i in mylist:
            bool = data[data[col] == i]
            result = pd.concat([result, bool])

        # 2.将获得的数据按'ts_code'列的值进行排列,并重新设置行索引
        mydf = result.sort_values(by=['ts_code'], ascending=True, inplace=False)
        num = result['ts_code'].count()
        mydf.index = [i for i in range(num)]
        # 3.函数返回值
        return mydf
    @classmethod
    def WholeFilePath(cls,path_suffix, path_prefix='D:\StockAnalysis'):
        '''
        : param path_suffix: 手工添加文件的路径前辍,格式:path_suffix='/ManualEntryFile(NoDelete)/HighQualityStock/优质股.xlsx'
        : param path_prefix: 参考Basics.PandasSaveData()说明
        : return: 返回一个完整的文件路径
        '''
        # 1.将参数中的路径前缀转化为python格式的路径,并前缀电脑中不存在前缀路径,则程序创建一个前缀路径

        prefix = path_prefix.replace('\\', '/')
        prefix_list = prefix.split(sep='/')
        mypath_prefix = ''  # 使用循环创建前缀路径

        for i in prefix_list:
            if i == prefix_list[0]:
                mypath_prefix = mypath_prefix + i
                if os.path.exists(mypath_prefix):
                    pass
                else:
                    os.mkdir(mypath_prefix)
            else:
                mypath_prefix = mypath_prefix + '/' + i
                if os.path.exists(mypath_prefix):
                    pass
                else:
                    os.mkdir(mypath_prefix)

        # 2.生成一个完成的文件路径
        whole_path = mypath_prefix + path_suffix

        # 3.函数返回值
        return whole_path
    @classmethod
    def ReadManualFileData(cls,path_suffix):
        '''
        :param path_suffix: 手写文件的路径后辍,含义参见Basics.PandasSaveData()中相同参数的解释
        :return: 返回一个由手写的文件数据生成的dataframe
        :应用价值:
            TODO
            1.可以将BasicData.Save_Manual_SW()和BasicData.Read_Manual_SW()两个函数优化掉,因
        为这两个函数中涉及到绝对路径问题,如果不优化掉,程序放在别的电脑上运行,会出现错误。
            2.BasicData.Save_Manual_SW()和BasicData.Read_Manual_SW()两个函数中的功能,可以由
        本函数更简洁的实现。
        '''
        # 1.获取完整路径
        path = Basics.WholeFilePath(path_suffix=path_suffix)

        # 2.读取文件数据

        if path_suffix[-4:] == 'xlsx':
            df = pd.read_excel(path)
            if 'Unnamed: 0' in df.columns.values:
                df.drop(labels='Unnamed: 0', axis=1, inplace=True)
            return df
        elif path_suffix[-3:] == 'csv':
            df = pd.read_csv(path)
            if 'Unnamed: 0' in df.columns.values:
                df.drop(labels='Unnamed: 0', axis=1, inplace=True)
            return df
        else:
            return '可能数据格式或路径后辍错误'
    @classmethod
    def MyTimer(cls,year, month, day, hour, minute, second,function,arguments_dict=None):
        '''
        编写本函数的参考资料:
            https://blog.csdn.net/u010701274/article/details/122958603
            https://www.jb51.net/article/277143.htm
        :param function: 函数名称,不带名称后面的括号
        :param arguments_dict: 用字典接收函数的参数,类似多进程kwargs参数
        :param year: 年数
        :param month: 月份
        :param day: 日期
        :param hour:小时
        :param minute:分钟
        :param second:妙
        :return: 定时启动某个函数
        '''
        # 当前时间
        now = datetime.datetime.now()
        # 开始时间
        start_time = datetime.datetime(year=year, month=month, day=day, hour=hour, minute=minute, second=second,
                                       microsecond=0)
        # 时间差
        time_interval = (start_time - now).total_seconds()
        # 多线程定时器
        pro = threading.Timer(interval=time_interval, function=function, kwargs=arguments_dict)
        pro.start()


class Financial(): # 财务类

    @classmethod
    def PeriodFinancial(cls,statement_type, period, item):  # 一次获取A股某个报告期的某种财务报表的函数
        # TODO 1.删除不需要的以A开头的数据;2.股票代码的排序问题
        '''
        该函数运行时间大概5~13秒
        :param statement_type: 财务报表类型,
                     income 表示利润表
                     balancesheet 表示资产负债表
                     cashflow 表示现金流量表
        :param period:财务报表的季度报告期,比如,20181231,是2018年第4季度的报告期
        :param item:财务报表中的项目。切记,item参数必须对应财务报表类型中的项目,否则可能报错。
                    item的参数名称见以下三个接口的输出参数
                    利润表income:https://www.tushare.pro/document/2?doc_id=33
                    资产负债表balancesheet:https://www.tushare.pro/document/2?doc_id=36
                    现金流量表cashflow:https://www.tushare.pro/document/2?doc_id=44
        :return:返回数据类型是一个元组,包含Drop_Df2:某季度A股某个财务报表中对应项目中所有股票对应在数据,running_time:函数运行时间
        :应用价值:
                1.制作A股市场成立以来,股票某个财务报表项目对应项目自上市以来的所有报告期的数据,该数据包含A股所有股票。
                2.统计申万行业某季度财务报表的项目的均值,最大值,最小值等统计数据。
                3.计算申万行业某季度财务报表的项目的排名。
        '''
        begin_time = datetime.datetime.now()  # 测试函数运行时间的辅助代码
        # 1.设置一个条件判断,当type为不同值时,调用A股某季度不同的财务报表的相应报表项目的所有数据
        global period_financial_df
        if statement_type == 'income':
            period_financial_df = pro.income_vip(period=period,
                                                 fields='ts_code,ann_date,f_ann_date,end_date,{}'.format(item))
        elif statement_type == 'balancesheet':
            period_financial_df = pro.balancesheet_vip(period=period,
                                                       fields='ts_code,ann_date,f_ann_date,end_date,{}'.format(item))
        elif statement_type == 'cashflow':
            period_financial_df = pro.cashflow_vip(period=period,
                                                   fields='ts_code,ann_date,f_ann_date,end_date,{}'.format(item))
        num = period_financial_df['ts_code'].count()  # 获取的原始数据中的股票个数(该数据未去重)
        # 2.添加辅助列times,该列数值表示该ts_code出现的次数,即判断是否有重复的股票数据

        ts_code_list = [i for i in period_financial_df['ts_code'].values]  # 所有ts_code码构成的列表

        times_list = []  # 股票出现次数列表,用于添加辅助列,在导出的csv文件中方便查看哪里股票代码是重复的
        for i in range(num):  # 构造一个循环,向times_list中添加数据
            times_num = ts_code_list.count(ts_code_list[i])  # 股票Ts码出现的次数
            times_list.append(times_num)

        period_financial_df['times'] = times_list  # 在period_financial_df中增加times列

        # 3.测试另一种方法添加次数列,以及判断日期是否为最新标记列。事实证明两种判断是否重复的方法等效,因为times和times1两列数据完全一样
        time_list2 = []  # 另一种判断股票出次数的辅助列,含义同times_list
        is_new = []  # 判断实际公告日期f_ann_date中数据是否为最新日期的列表
        for i in range(num):  # 构造一个循环,生成time_list2和is_new两个中的数据
            Ts_Code = ts_code_list[i]  # ts_code_list中第i个股票TS码
            Bool_Df = period_financial_df[
                period_financial_df['ts_code'] == Ts_Code]  # 通过布尔索引,获取period_financial_df列索引为ts_code的列中数值等于i的所有数据
            count_num = Bool_Df['ts_code'].count()  # 切片后df获得数据的行数,等于某个股票出现的重复数
            time_list2.append(count_num)  # 向time_list2中添加数据

            f_list = [eval(i) for i in Bool_Df['f_ann_date'].values]  # 切片后df中f_ann_date列中的数据,并将其转化为int类型添加至f_list

            ts_f_date = eval(period_financial_df.loc[i, 'f_ann_date'])  # 某行股票ts_code码对应f_ann_date列交叉点位置的实际报告日期
            # 构造一个双重判断,判断实际公告日期是否为最新日期
            if count_num == 1:  # 如果不重复,判断为最新日期
                is_new.append('Y')
            else:
                if ts_f_date == max(f_list):  # 如果重复但f1是f_list中最大值,判断为最新日期
                    is_new.append('Y')
                else:  # # 如果重复但f1不是f_list中最大值,判断为非最新日期
                    is_new.append('N')

        period_financial_df['times1'] = time_list2  # period_financial_df中添加times1辅助列
        period_financial_df['is_new'] = is_new  # period_financial_df中添加is_new辅助列

        bool_df = period_financial_df[
            period_financial_df['is_new'] == 'Y']  # 通过布尔索引筛选period_financial_df为最新日期为数据,并赋值为了一个变量
        # 去掉bool_df中ts_code列中重复数据
        Drop_Df1 = bool_df.drop_duplicates(subset='ts_code', keep='last',
                                           inplace=False)  # 对ts_code去重,数据保最后出现的数据,并赋值给一个变量

        # 删除Drop_Df1不需要的列
        Drop_Df2 = Drop_Df1.drop(columns=['ann_date', 'f_ann_date', 'end_date', 'times', 'times1', 'is_new'],
                                 inplace=False)  # 删除不需要的列,并赋值给一个变量
        Drop_Df2.columns = ['ts_code', period]  # 重新设置列索引
        Drop_Df2.index = [i for i in Drop_Df2['ts_code'].values]  # 重新设置行索引

        # 测试函数运行时间的辅助代码
        end_time = datetime.datetime.now()
        running_time = end_time - begin_time
        # 4.函数返回值
        myresult = (Drop_Df2, running_time)
        return myresult

    @classmethod
    def FinancialItem(cls,statement_type, item):  # 一次性获取A股所有股票,自上市时间至今的某个财务报表项目全部数据
        '''
        该函数运行时间大概6分钟左右
        :param statement_type: 财务报表类型,
                     income 表示利润表
                     balancesheet 表示资产负债表
                     cashflow 表示现金流量表
        :param item:财务报表中的项目。切记,item参数必须对应财务报表类型中的项目,否则可能报错。
                    item的参数名称见以下三个接口的输出参数
                    利润表income:https://www.tushare.pro/document/2?doc_id=33
                    资产负债表balancesheet:https://www.tushare.pro/document/2?doc_id=36
                    现金流量表cashflow:https://www.tushare.pro/document/2?doc_id=44
        :return:1.返回值:函数运行时间
                2.生成文件:获取A股自上市以来所有季度某个财务数据的单个数据,并将这个数据导出成csv文件
        :应用价值:
                1.统计申万行业某季度财务报表的项目的均值,最大值,最小值等统计数据。
                2.计算申万行业某季度财务报表的项目的排名。
                3.制作股票某个指标不同季度不同年份变化的可视化图表
        '''
        start_time = datetime.datetime.now()  # 为计算函数运行时间而书写的辅助代码

        file_path = '/Financial/FinancialItem/股票[{}-{}]所有季度数据.csv'.format(statement_type, item)
        bool_value,final_save_path_str=Basics.IsNewDataFile(path_suffix=file_path)
        if bool_value: # 增加一个逻辑判断,如果是最新文件,则不需要重新生成文件
            print('已是最新文件,无需更新!')
        else:
            # 1.获取当年年份
            MYTODAY = datetime.date.today()
            year = MYTODAY.year

            # 2.创建报告日期列表
            report_date_list = []
            for i in range(1990, year):
                str1 = str(i) + '0331'
                str2 = str(i) + '0630'
                str3 = str(i) + '0930'
                str4 = str(i) + '1231'

                report_date_list.append(str1)
                report_date_list.append(str2)
                report_date_list.append(str3)
                report_date_list.append(str4)

            today_str = datetime.date.today().__format__('%Y%m%d')

            if eval(today_str) > eval(str(year) + '0331'):
                report_date_list.append(str(year) + '0331')
            if eval(today_str) > eval(str(year) + '0630'):
                report_date_list.append(str(year) + '0630')
            if eval(today_str) > eval(str(year) + '0930'):
                report_date_list.append(str(year) + '0930')
            if eval(today_str) > eval(str(year) + '1231'):
                report_date_list.append(str(year) + '1231')
            report_date_list.sort(reverse=True)  # 对列表数据进行排序,最近的日期排在最前面
            # print(report_date_list[:-3])
            # 3.获取当前上市的股票列表
            data = pro.query('stock_basic', exchange='', list_status='L', fields='ts_code,symbol,name')
            data.index = [i for i in data['ts_code'].values]  # 为使用join函数拼接数据,此处需要修改data的行索引。
            # 4.使用循环获取A股自上市以来所有报告的某个财务数据
            for i in report_date_list[:-3]:  # 使用循环方式获取所有报告期中财务数据,report_date_list[:-3]表示取report_date_list中自列表开头至倒数第4之间所有数据

                my_df, _ = Financial.PeriodFinancial(statement_type=statement_type, period=i,
                                           item=item)  # 调用PeriodFinancial获取某个季度的所有财务数据
                index_i = report_date_list.index(i)  # i所在列表中的位置
                print(f'获取财务报表{statement_type}_{item}:序号{index_i + 1}\t季度{i}')
                my_df.drop(columns=['ts_code'], inplace=True)  # 删除多余的列

                data = data.join(my_df)  # 使用join将获取的季度数据拼接同data进行接接,并将结果再次赋值给data变量

            else:
                # file_path = '/Financial/FinancialItem/股票[{}-{}]所有季度数据.csv'.format(statement_type, item)
                # final_save_path_str=Basics.PandasSaveData(data=data,path_suffix=file_path)
                Basics.PandasSaveData(data=data, path_suffix=file_path)

        # # 为计算函数运行时间而书写的辅助代码
        end_time = datetime.datetime.now()
        running_time = end_time - start_time
        # 函数返回值
        return (final_save_path_str,running_time)
    @classmethod
    def PeriodIndicator(cls,period, indicator):  # 获取某一期所有股票财务指标的函数
        '''

        :param period: 财务报表的季度报告期,比如,20181231,是2018年第4季度的报告期
        :param indicator: 参数及其含义如下:
                        profit_dedt 扣除非经常性损益后的净利润(扣非净利润)    对应同花顺中扣非净利润
                        netprofit_margin 销售净利率 对应同花顺相应名称
                        grossprofit_margin  销售毛利率 对应同花顺相应名称
                        roe_waa 加权平均净资产收益率 好像对应同花顺的净资产收益率
                        其他参数值解释见:https://www.tushare.pro/document/2?doc_id=79
        :return: 返回数据类型是一个元组,包含myresult:某季度A股所有股票财务指标数据接口中某个指标所有数据,running_time:函数运行时间
        :应用价值:
                1.制作A股市场成立以来,某个财务指标自上市以来的所有报告期的数据,该数据包含A股所有股票。
                2.统计申万行业某季度财务指标均值,最大值,最小值等统计数据。
                3.计算申万行业某季度财务指标的排名。
                4.关于该函数的应用价值理解参考函数PeriodFinancial
        '''

        start_time = datetime.datetime.now()  # 计算函数运行时间的辅助代码
        # 1.参数income的vip接口写法,书写获取单季度财务指标的写法。此写法网页没有直接给出来
        data = pro.fina_indicator_vip(period=period,
                                      fields='ts_code,ann_date,end_date,{},update_flag'.format(indicator))
        data['is_A'] = [True if i[0] == "A" else False for i in data['ts_code'].values]  # 使用三目运算符添加判断

        # 向data中添加times_num列,用于判断数据重复次数
        num = data['ts_code'].count()

        ts_code_list = [i for i in data['ts_code'].values]  # 所有ts_code码构成的列表
        times_list = []  # 股票出现次数列表,用于添加辅助列,在导出的csv文件中方便查看哪里股票代码是重复的
        for i in range(num):
            times_num = ts_code_list.count(ts_code_list[i])
            times_list.append(times_num)
        data['times_num'] = times_list

        # 3.增加判断是否保留数据的列,其值如果为Y,则切片时会保留,否则不保留
        if num != 0:  # 如果获取到的该季度数据不为空,则执行使用apply增加is_need列,否则直接赋值为空列
            def is_need_func(t):  # 判断数据是否保留的函数
                # global is_need_str
                if t['is_A'] == False:
                    if t['times_num'] == 1:
                        is_need_str = 'Y'
                    else:  # TODO 经验证,自上次所创建以来至2023年5月19日,所股票且所有报告期的重复次数最大为2.但是如果最大重复数超过3,则判断逻辑需要重新写。
                        if t['update_flag'] == '1':
                            is_need_str = 'Y'
                        else:
                            is_need_str = 'N'
                else:
                    is_need_str = 'N'
                return is_need_str

            data['is_need'] = data.apply(is_need_func, axis=1)
        else:
            data['is_need'] = []

        # 4.通过布尔索引对is_need数值等于Y的数据进行切片
        data_bool = data[data['is_need'] == 'Y']
        # 5.将data_bool中不需要的列删除,并重新设置行索引和列索引
        myresult = data_bool.drop(columns=['ann_date', 'end_date', 'update_flag', 'is_A', 'times_num', 'is_need'],
                                  inplace=False)  # 删除不需要的列
        myresult.index = range(myresult['ts_code'].count())  # 重新设置行索引
        myresult.columns = ['ts_code', period]  # 重新设置列索引
        # 6.计算函数运行时间的辅助代码
        end_time = datetime.datetime.now()
        running_time = end_time - start_time
        # 7.函数返回值
        return (myresult, running_time)
    @classmethod
    def FinaIndicator(csl,item):
        '''
        TODO 1.该函数可以指定季度列表,比如,不指定则默认获取所有季度,若指定季度,则可以按指定季度获取数据,这样可以方便统计
        TODO 2.可以设置一个参数,用来指定获取数据,是否以亿元为单位,并且结果保留2位小数。该功能同样适用于FinancialAll函数
        TODO 3.A股上市股票名称,在其他函数中使用时,需要对代码值进行排序。
        评价:增加参数可以使函数处理的问题更加具有通用性,更有普遍性。
        :param item:财务指标数据接口中的的某个输出参数,参数含义如下:
                    profit_dedt 扣除非经常性损益后的净利润(扣非净利润)    对应同花顺中扣非净利润
                    netprofit_margin 销售净利率 对应同花顺相应名称
                    grossprofit_margin  销售毛利率 对应同花顺相应名称
                    roe_waa 加权平均净资产收益率 好像对应同花顺的净资产收益率
                    其他参数值解释见:https://www.tushare.pro/document/2?doc_id=79
        :return:1.返回值:函数运行时间
                2.生成文件:获取A股自上市以来所有季度某个财务指标数据,并将这个数据导出成csv文件
        :应用价值:
                1.统计申万行业某季度财务指标的均值,最大值,最小值等统计数据。
                2.计算申万行业某季财务指标的排名。
                3.制作股票某个财务指标不同季度不同年份变化的可视化图表
                4.该函数的应用价值解释,可以参考函数QuantileDaily理解
        '''
        start_time = datetime.datetime.now()
        path_my_str16891 = '/Financial/FinaIndicator/财务指标{}.csv'.format(item)
        bool_value,final_save_path_str=Basics.IsNewDataFile(path_suffix=path_my_str16891)
        if bool_value: # 增加一个逻辑判断,如果是最新文件,则不需要重新生成文件
            print('已是最新文件,无需更新!')
        else:
            # 1.获取当年年份
            MYTODAY = datetime.date.today()
            year = MYTODAY.year

            # 2.创建报告日期列表
            report_date_list = []
            for i in range(1990, year):
                str1 = str(i) + '0331'
                str2 = str(i) + '0630'
                str3 = str(i) + '0930'
                str4 = str(i) + '1231'

                report_date_list.append(str1)
                report_date_list.append(str2)
                report_date_list.append(str3)
                report_date_list.append(str4)

            today_str = datetime.date.today().__format__('%Y%m%d')

            if eval(today_str) > eval(str(year) + '0331'):
                report_date_list.append(str(year) + '0331')
            if eval(today_str) > eval(str(year) + '0630'):
                report_date_list.append(str(year) + '0630')
            if eval(today_str) > eval(str(year) + '0930'):
                report_date_list.append(str(year) + '0930')
            if eval(today_str) > eval(str(year) + '1231'):
                report_date_list.append(str(year) + '1231')
            report_date_list.sort(reverse=True)  # 对列表数据进行排序,最近的日期排在最前面

            # 3.获取当前上市的股票列表
            data = pro.query('stock_basic', exchange='', list_status='L', fields='ts_code,symbol,name')
            data.sort_values(by=['symbol'], ascending=True, inplace=True)
            data.index = [i for i in data['ts_code'].values]  # 为使用join函数拼接数据,此处需要修改data的行索引。

            # 4.使用循环获取A股自上市以来所有报告的某个财务数据
            for i in report_date_list[:-3]:  # 使用循环方式获取所有报告期中财务数据,report_date_list[:-3]表示取report_date_list中自列表开头至倒数第4之间所有数据

                my_df, i_time = Financial.PeriodIndicator(period=i, indicator=item)  # 调用PeriodFinancial获取某个季度的所有财务数据
                my_df.index = [i for i in my_df['ts_code'].values]
                my_df.drop(columns=['ts_code'], inplace=True)  # 删除多余的列

                data = data.join(my_df)  # 使用join将获取的季度数据拼接同data进行接接,并将结果再次赋值给data变量
                print(i, '\t', i_time)

            else:
                # path_my_str16891='/Financial/FinaIndicator/财务指标{}.csv'.format(item)
                # final_save_path_str=Basics.PandasSaveData(data=data,path_suffix=path_my_str16891)
                Basics.PandasSaveData(data=data, path_suffix=path_my_str16891)

        # # 为计算函数运行时间而书写的辅助代码
        end_time = datetime.datetime.now()
        running_time = end_time - start_time
        # 函数返回值
        return (final_save_path_str,running_time)

    @classmethod
    def FinancialItemAnalysis(cls,statement_type, item, report_type,is_year_report=False):  # 这是一个优秀的函数
        '''
        :param statement_type: 财务报表或财务指标的类型,参数值的含义:
                                income  利润表
                                balancesheet    资产负债表
                                cashflow    现金流量表
                                fina_indicator  财务指标
        :param item: 利润表、资产负债表、现金流量表或财务指标数据接口中输出参数中对应的参数名称
        :param report_type: 参数值分别为一季报、中报,三季报或年报
        :param is_year_report: 是否为年报,默认参数为False,内置函数recent_report_data中的一个参数,该内只函数的作用是添加“YOY”列,即同比列
        :return: 1.生成一份csv格式分析数据。2.返回一个DataFrame,内容是财务项目的分析数据
        '''

        global period_date9988728  # 定义财务报表报告期的一个变量
        if report_type == '一季报':
            period_date9988728 = '0331'
        elif report_type == '中报':
            period_date9988728 = '0630'
        elif report_type == '三季报':
            period_date9988728 = '0930'
        elif report_type == '年报':
            period_date9988728 = '1231'

        start_time = datetime.datetime.now()
        # 1.读取数据
        MYTODAY = datetime.date.today()

        if statement_type == 'fina_indicator':
            # file_path789125698 = './LoadFile/FinancialTargetStatistics/FinaIndicator/{}财务指标{}.csv'.format(MYTODAY,
            #                                                                                                   item)
            file_path789125698,_=Financial.FinaIndicator(item=item)
        else:
            # file_path789125698 = './LoadFile/FinancialTargetStatistics/AllFinancialData/{}股票[{}-{}]所有季度数据.csv'.format(
            #     MYTODAY, statement_type, item)
            file_path789125698,_=Financial.FinancialItem(statement_type=statement_type,item=item)

        # file_path='./LoadFile/FinancialTargetStatistics/AllFinancialData/{}股票[{}-{}]所有季度数据.csv'.format(MYTODAY,statement_type,item)
        if os.path.exists(file_path789125698):  # 如果文件存在则直接读取,否则执行创建该文件的函数
            print('文件已存在,可以读取')
        else:
            print('数据文件不存在,正在创建......')
            if statement_type == 'fina_indicator':
                Financial.FinaIndicator(item=item)
            else:
                # FinancialAll(statement_type=statement_type, item=item) # TODO 整个财务类函数前的代码
                Financial.FinancialItem(statement_type=statement_type, item=item)
        FinancialData = pd.read_csv(file_path789125698)
        FinancialData.index = [i for i in FinancialData['ts_code'].values]

        # 2023年6月11日升级代码
        NoDropFinancialData = pd.read_csv(file_path789125698)
        NoDropFinancialData.index = [i for i in NoDropFinancialData['ts_code'].values]

        # print(FinancialData)
        # 2.获取当年年份
        year = datetime.date.today().year

        # 3.创建报告日期列表
        report_date_list = []
        for i in range(1990, year):
            str1 = str(i) + '0331'
            str2 = str(i) + '0630'
            str3 = str(i) + '0930'
            str4 = str(i) + '1231'

            report_date_list.append(str1)
            report_date_list.append(str2)
            report_date_list.append(str3)
            report_date_list.append(str4)

        today_str = datetime.date.today().__format__('%Y%m%d')

        if eval(today_str) > eval(str(year) + '0331'):
            report_date_list.append(str(year) + '0331')
        if eval(today_str) > eval(str(year) + '0630'):
            report_date_list.append(str(year) + '0630')
        if eval(today_str) > eval(str(year) + '0930'):
            report_date_list.append(str(year) + '0930')
        if eval(today_str) > eval(str(year) + '1231'):
            report_date_list.append(str(year) + '1231')

        report_date_list.sort(reverse=True)  # 对列表数据进行排序,最近的日期排在最前面
        ues_list = report_date_list[:-3]  # 切片去掉最后三个季度,原因是这三个季度没有数据

        # print(ues_list)

        # 4.获取最近三个报告期的标识符列表

        FistQuarter = []
        for i in ues_list:
            if i[4:8] == period_date9988728:
                FistQuarter.append(i)
        # print(FistQuarter)
        RecentYhreeQuarter = FistQuarter[0:3]
        RecentYhreeQuarter.sort(reverse=False)

        # print(RecentYhreeQuarter)

        # 5.从原数据中删除多余的列

        drop_columns = [i for i in FinancialData.columns.values]  # 不需要删除的列索引

        # print(drop_columns)

        for i in RecentYhreeQuarter:
            drop_columns.remove(i)

        # print(drop_columns)
        FinancialData.drop(columns=drop_columns, inplace=True)

        # 6.添加各种分析列

        def ThreeChange(t):  # 三年连续变化值列
            r1 = RecentYhreeQuarter[2]  # 最近第一个报告期的列索引
            r2 = RecentYhreeQuarter[1]  # 最近第二个报告期的列索引
            r3 = RecentYhreeQuarter[0]  # 最近第三个报告期的列索引

            if (t[r1] > 0 and t[r2] > 0 and t[r3] > 0) and (t[r3] < t[r2] and t[r2] < t[r1]):
                add1 = round((t[r1] - t[r2]) / t[r2], 3)
                add2 = round((t[r2] - t[r3]) / t[r3], 3)
                add = min(add1, add2)
                return '数值为正,但增长率为{}'.format(add)
            elif (t[r1] < 0 and t[r2] < 0 and t[r3] < 0) and (t[r3] < t[r2] and t[r2] < t[r1]):
                add1 = round((t[r1] - t[r2]) / t[r2], 3)
                add2 = round((t[r2] - t[r3]) / t[r3], 3)
                add = min(add1, add2)
                return '数值为负,但增长率为{}'.format(add)
            elif (t[r1] > 0 and t[r2] > 0 and t[r3] > 0) and (t[r3] > t[r2] and t[r2] > t[r1]):
                add1 = round((t[r1] - t[r2]) / t[r2], 3)
                add2 = round((t[r2] - t[r3]) / t[r3], 3)
                add = max(add1, add2)
                return '数值为正,但增长率为{}'.format(add)
            elif (t[r1] < 0 and t[r2] < 0 and t[r3] < 0) and (t[r3] > t[r2] and t[r2] > t[r1]):
                add1 = round((t[r1] - t[r2]) / t[r2], 3)
                add2 = round((t[r2] - t[r3]) / t[r3], 3)
                add = max(add1, add2)
                return '数值为负,但增长率为{}'.format(add)
            else:
                return 'NO'

        FinancialData['ThreeChange'] = FinancialData.apply(ThreeChange, axis=1)

        # 添加同比列:2023年6月11日升级部分的内容

        def recent_report_data(is_year_report=False):  # 内部函数
            '''
            :param is_year_report: 是否为年报,默认参数为False
            :return: 返回一个元组,变量的含义如下:
                        this_quarter816029  最近的报告日期
                        last_quarter816029  上一年的相同日期的报告日期
            '''
            year = datetime.date.today().year
            today_str = datetime.date.today().__format__('%Y%m%d')

            q1 = '0430'
            q2 = '0731'
            q3 = '1031'
            q4 = '0430'
            # TODO 是否将q1,q2,q3,q4设置为每个季度最后一在,在实际应用中根据需要调整
            '''
            上市公司的规定:
                季报包括半年报披露时间是季度结束后一个月内,也就是4月,7月,10月。即4月30前、7月31日、10月31日前。
                年报披露是会计年度结束后4个月内,也就是每年4月底之前,即4月30日前。

            '''
            global this_quarter816029, last_quarter816029
            if is_year_report == True:
                if eval(today_str) > eval(str(year) + q4) and eval(today_str) <= eval(str(year + 1) + q4):
                    this_quarter816029 = str(year) + '1231'
                    last_quarter816029 = str(year - 1) + '1231'
                elif eval(today_str) > eval(str(year - 1) + q4) and eval(today_str) <= eval(str(year) + q4):
                    this_quarter816029 = str(year - 1) + '1231'
                    last_quarter816029 = str(year - 2) + '1231'
            else:
                if eval(today_str) > eval(str(year) + q1) and eval(today_str) <= eval(str(year) + q2):
                    this_quarter816029 = str(year) + '0331'
                    last_quarter816029 = str(year - 1) + '0331'
                elif eval(today_str) > eval(str(year) + q2) and eval(today_str) <= eval(str(year) + q3):
                    this_quarter816029 = str(year) + '0630'
                    last_quarter816029 = str(year - 1) + '0630'
                elif eval(today_str) > eval(str(year) + q3) and eval(today_str) <= eval(str(year + 1) + q4):
                    this_quarter816029 = str(year) + '0930'
                    last_quarter816029 = str(year - 1) + '0930'
                elif eval(today_str) >= eval(str(year) + '0101') and eval(today_str) <= eval(str(year) + q1):
                    this_quarter816029 = str(year - 1) + '1231'
                    last_quarter816029 = str(year - 2) + '1231'
            # 函数返回值
            return (this_quarter816029, last_quarter816029)

        this_quarter816029,last_quarter816029=recent_report_data(is_year_report=is_year_report)


        ComparedWithTheSamePeriodList=[]
        this_quarter816029_item_list=[]
        last_quarter816029_item_list=[]

        # print('添加同比列'.center(100,'-'))
        # print(NoDropFinancialData)

        for i in NoDropFinancialData['ts_code'].values:
            v1=NoDropFinancialData.loc[i,this_quarter816029]
            v2=NoDropFinancialData.loc[i,last_quarter816029]
            growth=round((v1-v2)/v2,3)
            this_quarter816029_item_list.append(v1)
            last_quarter816029_item_list.append(v2)
            ComparedWithTheSamePeriodList.append(growth)
        # print(ComparedWithTheSamePeriodList)
        FinancialData[this_quarter816029]=this_quarter816029_item_list
        FinancialData[last_quarter816029]=last_quarter816029_item_list
        FinancialData['YoY']=ComparedWithTheSamePeriodList # 添加同比列


        # 较上一年变化情况
        def CompareLastYear(t):
            r1 = RecentYhreeQuarter[2]  # 最近第一个报告期的列索引
            r2 = RecentYhreeQuarter[1]  # 最近第二个报告期的列索引

            change = round((t[r1] - t[r2]) / t[r2], 3)

            return change

        FinancialData['CompareLastYear'] = FinancialData.apply(CompareLastYear, axis=1)

        def LittleChange(t, p):  # 是否基本持平列
            '''
            :param t: 好像表示DataFrame
            :param p: 三期数据是否在平均的正负浮动数值范围内,暂时将参数值设置为0.08
            :return: 返回布尔值,True 表示基本持平,NaN 表示否
            '''
            r1 = RecentYhreeQuarter[2]  # 最近第一个报告期的列索引
            r2 = RecentYhreeQuarter[1]  # 最近第二个报告期的列索引
            r3 = RecentYhreeQuarter[0]  # 最近第三个报告期的列索引
            average = (t[r1] + t[r2] + t[r3]) / 3

            if (t[r1] > 0 and t[r2] > 0 and t[r3] > 0) and \
                    ((t[r2] > t[r3] and t[r2] > t[r1]) or (t[r2] < t[r3] and t[r2] < t[r1])) and \
                    (t[r2] < (1 + p) * average and t[r2] > (1 - p) * average):
                return '基本持平[正]'
            elif (t[r1] < 0 and t[r2] < 0 and t[r3] < 0) and \
                    ((t[r2] > t[r3] and t[r2] > t[r1]) or (t[r2] < t[r3] and t[r2] < t[r1])) and \
                    (t[r2] > (1 + p) * average and t[r2] < (1 - p) * average):
                return '基本持平[负]'
            else:
                return np.NaN

        FinancialData['LittleChange'] = FinancialData.apply(LittleChange, p=0.08, axis=1)

        def Convex(t, p):  # 凸型变化
            r1 = RecentYhreeQuarter[2]  # 最近第一个报告期的列索引
            r2 = RecentYhreeQuarter[1]  # 最近第二个报告期的列索引
            r3 = RecentYhreeQuarter[0]  # 最近第三个报告期的列索引
            average = (t[r1] + t[r2] + t[r3]) / 3
            if (t[r1] > 0 and t[r2] > 0 and t[r3] > 0) and (
                    t[r2] > t[r1] and t[r2] > t[r3] and t[r2] > (1 + p) * average):
                return '正凸'
            elif (t[r1] < 0 and t[r2] < 0 and t[r3] < 0) and (
                    t[r2] < t[r1] and t[r2] < t[r3] and t[r2] < (1 + p) * average):
                return '负凸'
            else:
                return np.NaN

        FinancialData['Convex'] = FinancialData.apply(Convex, p=0.08, axis=1)

        def Concave(t, p):  # 凹型变化
            r1 = RecentYhreeQuarter[2]  # 最近第一个报告期的列索引
            r2 = RecentYhreeQuarter[1]  # 最近第二个报告期的列索引
            r3 = RecentYhreeQuarter[0]  # 最近第三个报告期的列索引
            average = (t[r1] + t[r2] + t[r3]) / 3
            if (t[r1] > 0 and t[r2] > 0 and t[r3] > 0) and (
                    t[r2] < t[r1] and t[r2] < t[r3] and t[r2] < (1 - p) * average):
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值