Пример #1
0
 def get_stock_basic(self):
     """
     从ts_pro.stock_basic获取个股的基本信息列表
     return:<df> is success, None if fail
     """
     file_name = PurePath('stock_basic.csv')
     file_path = sub_path / file_name
     self.basic = ts_pro.stock_basic(
         fields=
         'ts_code,symbol,name,area,industry,fullname,enname,market,exchange,curr_type,list_status,list_date,delist_date,is_hs'
     )
     if isinstance(self.basic, pd.DataFrame):
         if len(self.basic) > 10:
             self.basic.set_index('ts_code', inplace=True)
             self.basic.to_csv(file_path, encoding='utf-8')
             log_args = [file_path]
             add_log(
                 40,
                 '[fn]:Stock_Basic.get_stock_basic() file "{0[0]}" saved',
                 log_args)
             return self.basic
     log_args = [file_path]
     add_log(
         20,
         '[fn]:Stock_Basic.get_stock_basic() failed to save file "{0[0]}"',
         log_args)
     return
Пример #2
0
 def que_list_date(self, ts_code):
     """查询上市时间list_date
     return:<str> e.g. '19930503'
     ts_code:<str> e.g. '000001.SH'
     """
     from st_board import valid_date_str_fmt
     try:
         result = self.basic.loc[ts_code]['list_date']
     except KeyError:
         log_args = [ts_code]
         add_log(
             20,
             '[fn]:Stock_Basic.que_list_date() ts_code: "{0[0]}" was not found in Stock.base. use DEFAULT_OPEN_DATE_STR instead',
             log_args)
         result = DEFAULT_OPEN_DATE_STR
         return result
     if valid_date_str_fmt(result):
         return result
     else:
         result = DEFAULT_OPEN_DATE_STR
         log_args = [ts_code, result]
         add_log(
             40,
             '[fn]:Stock_Basic.que_list_date() ts_code: "{0[0]}" used "DEFAULT_OPEN_DATE_STR" {0[1]} instead "list_date".',
             log_args)
         return result
Пример #3
0
 def que_list_date(self, ts_code):
     """
     查询上市时间
     ts_code:<str> e.g. "518880.SH"
     return:<str> e.g. "19930512"
     """
     from st_board import valid_date_str_fmt
     ts_code = ts_code.upper()
     try:
         result = self.basic_e.loc[ts_code]['list_date']
     except KeyError:
         try:
             result = self.basic_o.loc[ts_code]['list_date']
         except KeyError:
             log_args = [ts_code]
             add_log(
                 20,
                 '[fn]:Fund_Basic.que_list_date() ts_code:{0[0]} was not found in Fund.base_e/_o',
                 log_args)
             return
     if valid_date_str_fmt(result):
         return result
     else:
         log_args = [ts_code, result]
         add_log(
             20,
             '[fn]:Fund_Basic.que_list_date() ts_code:{0[0]} result:{0[1]} invalid',
             log_args)
         return
Пример #4
0
 def get_fund_basic(self, market='E'):
     """
     从ts_pro.fund_basic获取个股的基本信息列表
     market: <str> 'E'场内  'O'场外
     return: <df> is success, None if fail
     """
     if market == 'E':
         file_name = PurePath('fund_e_basic.csv')  # 场内基金
     elif market == 'O':
         file_name = PurePath('fund_o_basic.csv')  # 场外基金
     else:
         log_args = [market]
         add_log(
             20,
             '[fn]:Fund_Basic.get_fund_basic() unsupported market type:{0[0], aborted',
             log_args)
         return
     file_path = sub_path / file_name
     if market == 'E':
         self.basic_e = ts_pro.fund_basic(market=market)  # 场内基金
         if isinstance(self.basic_e, pd.DataFrame):
             if len(self.basic_e) > 10:
                 self.basic_e.set_index('ts_code', inplace=True)
                 self.basic_e.to_csv(file_path, encoding='utf-8')
                 log_args = [file_path, len(self.basic_e)]
                 add_log(
                     40,
                     '[fn]:Fund_Basic.get_fund_basic() file "{0[0]}" saved, items:{0[1]}',
                     log_args)
                 return self.basic_e
         log_args = [file_path]
         add_log(
             20,
             '[fn]:Fund_Basic.get_fund_basic() failed to save file "{0[0]}"',
             log_args)
         return
     elif market == 'O':
         self.basic_o = ts_pro.fund_basic(market=market)  # 场外基金
         if isinstance(self.basic_o, pd.DataFrame):
             if len(self.basic_o) > 10:
                 self.basic_o.set_index('ts_code', inplace=True)
                 self.basic_o.to_csv(file_path, encoding='utf-8')
                 log_args = [file_path, len(self.basic_o)]
                 add_log(
                     40,
                     '[fn]:Fund.get_fund_basic() file "{0[0]}" saved, items:{0[1]}',
                     log_args)
                 return self.basic_o
         log_args = [file_path]
         add_log(
             20,
             '[fn]:Fund_Basic.get_fund_basic() failed to save file "{0[0]}"',
             log_args)
         return
Пример #5
0
 def in_calendar(self, date_str):
     """
     查看日期是否在calendar中
     """
     try:
         self.trade_calendar.index.get_loc(int(date_str))
         return True
     except Exception as e:
         log_args = [type(e)]
         add_log(20, '[fn]Raw_Data.in_calendar() except type:{0[0]}',
                 log_args)
         return
Пример #6
0
 def next_trade_day(self, dt_str, next_n=1):
     """
     查询之后第n个交易日
     dt_str: <string> in 'YYYYMMDD' e.g.'20190721'
     next_n: <int>
     return: <string> in 'YYYYMMDD' e.g.'20190719'
     """
     SUSPENDED_DAYS_LIM = 100
     if self.valid_trade_calendar() is None:
         add_log(20, '[fn]Raw_Data.next_trade_day() trade_calendar invalid')
         return
     if next_n < 1:
         log_args = [next_n]
         add_log(
             20,
             '[fn]Raw_Data.next_trade_day() next_n:{0[0]} invalid'.format(
                 log_args))
         return
     if isinstance(dt_str, str) and (len(dt_str) == 8):
         tdf = self.trade_calendar
         try:
             pos = tdf.index.get_loc(int(dt_str))
             for _ in range(int(next_n)):
                 for i in range(1, SUSPENDED_DAYS_LIM):  # 估计最长休市天数不超过x天
                     if tdf.iloc[pos + i]['is_open'] == 1:
                         pos = pos + i
                         break
                 else:
                     add_log(
                         20,
                         '[fn]Raw_Data.next_trade_day() suspended days exceed limit'
                     )
                     return
         except KeyError:
             log_args = [dt_str]
             add_log(
                 10,
                 '[fn]Raw_Data.next_trade_day() dt_str "{0[0]}" not in stock_basic.csv. check date_str and pull Raw_Data',
                 log_args)
             return
         next_trade_date = tdf.iloc[
             pos].name  # tdf.iloc[pos]是Series,所以用.name
         # print('[L167] next_trade_date: {}'.format())
         return str(next_trade_date)
     else:
         log_args = [dt_str]
         add_log(
             20,
             '[fn]Raw_Data.next_trade_day() dt_str "{0[0]}" incorrect format',
             log_args)
         return
Пример #7
0
 def load_fund_basic(self, market='E'):
     """
     从fund_e_basic.csv或fund_o_basic.csv文件读入个股的基本信息列表
     return:<df> is success, None if fail
     """
     if market == 'E':
         file_name = PurePath('fund_e_basic.csv')  # 场内基金
     elif market == 'O':
         file_name = PurePath('fund_o_basic.csv')  # 场外基金
     else:
         log_args = [market]
         add_log(
             20,
             '[fn]:Fund_Basic.load_fund_basic() unsupported market type:{0[0], aborted',
             log_args)
         return
     file_path = sub_path / file_name
     try:
         if market == 'E':
             self.basic_e = pd.read_csv(file_path,
                                        dtype={
                                            'found_date': str,
                                            'due_date': str,
                                            'list_date': str,
                                            'delist_date': str,
                                            'issue_date': str,
                                            'purc_startdate': str,
                                            'redm_startdate': str
                                        },
                                        index_col='ts_code')
             return self.basic_e
         elif market == 'O':
             self.basic_o = pd.read_csv(file_path,
                                        dtype={
                                            'found_date': str,
                                            'due_date': str,
                                            'list_date': str,
                                            'delist_date': str,
                                            'issue_date': str,
                                            'purc_startdate': str,
                                            'redm_startdate': str
                                        },
                                        index_col='ts_code')
             return self.basic_o
     except FileNotFoundError:
         log_args = [file_name]
         add_log(
             20,
             '[fn]Fund_Basic.load_fund_basic()e. file "{0[0]}" not found',
             log_args)
         return
Пример #8
0
 def load_all_assets_list(self):
     """
     从all_assets_list.csv中读取全代码列表
     """
     file_name = PurePath("all_assets_list.csv")
     file_path = sub_path / sub_path_config / file_name
     try:
         df = pd.read_csv(file_path, index_col='ts_code')
     except FileNotFoundError:
         log_args = [file_path]
         add_log(10,
                 '[fn]Raw_Data.load_all_assets_list. "{0[0]}" not found',
                 log_args)
         df = None
     self.all_assets_list = df
Пример #9
0
 def query_name(self, ts_code):
     """
     查询asset的name
     return: <str> e.g. "上证指数"
     """
     try:
         name = self.all_assets_list.loc[ts_code]['name']
     except Exception as e:  # 具体except待细化
         log_args = [ts_code, type(e)]
         add_log(
             20,
             '[fn]Raw_Data.query_name(). ts_code:{0[0]} failed to get name, except:{0[1]}',
             log_args)
         return
     return name
Пример #10
0
    def len_trade_days(self, start_day, end_day=None):
        """
        查询两个日期间所包括的交易日数,start_day算第1天,end_day也算1天
        具体except处理待完善
        start_day: <str> e.g. '20191231'
        end_day: None = today_str() 今天的字符串
                 <str> e.g. '20191231'
        """
        from st_board import today_str
        if end_day is None:
            end_day = today_str()

        if self.in_calendar(start_day) is not True:
            log_args = [start_day]
            add_log(
                20,
                '[fn]Raw_Data.len_trade_days() start_day:{0[0]} not in calendar',
                log_args)
            return

        if self.in_calendar(end_day) is not True:
            log_args = [end_day]
            add_log(
                20,
                '[fn]Raw_Data.len_trade_days() end_day:{0[0]} not in calendar',
                log_args)
            return

        try:
            int_start = int(start_day)
            int_end = int(end_day)
        except ValueError:
            log_args = [start_day, end_day]
            add_log(
                20,
                '[fn]Raw_Data.len_trade_days() start_day:{0[0]} or end_day:{0[1]} invalid',
                log_args)
            return

        try:
            df = self.trade_calendar[
                self.trade_calendar.index.to_series().between(
                    int_start, int_end)]
            rslt = df['is_open'].value_counts()[1]
        except IndexError:
            log_args = [start_day, end_day]
            add_log(
                30,
                '[fn]Raw_Data.len_trade_days() start_day:{0[0]} or end_day:{0[1]} invalid or mis-order',
                log_args)
            return
        except KeyError:
            rslt = 0  # 之间无交易日
        return rslt
Пример #11
0
 def load_trade_calendar(self):
     """
     load trade_calendar.csv文件,读入self.trade_calendar
     """
     file_name = PurePath("trade_calendar.csv")
     file_path = sub_path / file_name
     try:
         self.trade_calendar = pd.read_csv(file_path,
                                           dtype={
                                               'cal_date': str,
                                               'pretrade_date': str
                                           },
                                           index_col='cal_date')
     except FileNotFoundError:
         log_args = [file_path]
         add_log(
             20,
             '[fn]Raw_Data.load_trade_calendar(). file "{0[0]}" not found',
             log_args)
         self.trade_calendar = None
Пример #12
0
 def valid_ts_code(self, ts_code):
     """验证在raw_data内ts_code是否有效,
     return: <bool> True=valid
     """
     if ts_code in SPC_TS_CODE:
         return True
     # --------------------Index---------------
     try:
         name = self.all_assets_list.loc[ts_code]['name']
         # print("[debug L249] name:{}".format(name))
     except KeyError:
         log_args = [ts_code]
         add_log(30,
                 '[fn]Raw_Data.valid_ts_code(). ts_code "{0[0]}" invalid',
                 log_args)
         return
     if isinstance(name, str):
         if len(name) > 0:
             return True
     return
Пример #13
0
 def load_stock_basic(self):
     """
     从stock_basic.csv文件读入个股的基本信息列表
     return:<df> is success, None if fail
     """
     file_name = PurePath("stock_basic.csv")
     file_path = sub_path / file_name
     try:
         self.basic = pd.read_csv(file_path,
                                  dtype={
                                      'symbol': str,
                                      'list_date': str,
                                      'delist_date': str
                                  },
                                  index_col='ts_code')
         return self.basic
     except FileNotFoundError:
         log_args = [file_path]
         add_log(
             20,
             '[fn]Stock_Basic.load_stock_basic()e. file "{0[0]}" not found',
             log_args)
         return
Пример #14
0
 def load_index_basic(self):
     """
     load index_basic.csv文件,读入self.index_basic_df
     """
     # 上交所指数
     file_name = PurePath("index_basic_sse.csv")
     try:
         self._sse = pd.read_csv(sub_path / file_name,
                                 dtype={
                                     'base_date': str,
                                     'list_date': str
                                 })
         self.valid['index_basic_sse'] = STATUS_WORD[1]
     except FileNotFoundError:
         log_args = [file_name]
         add_log(20,
                 '[fn]Index.load_index_basic(). file "{0[0]}" not found',
                 log_args)
         self._sse = None
     # 深交所指数
     file_name = PurePath("index_basic_szse.csv")
     try:
         self._szse = pd.read_csv(sub_path / file_name,
                                  dtype={
                                      'base_date': str,
                                      'list_date': str
                                  })
         self.valid['index_basic_szse'] = STATUS_WORD[1]
     except FileNotFoundError:
         log_args = [file_name]
         add_log(20,
                 '[fn]Index.load_index_basic(). file "{0[0]}" not found',
                 log_args)
         self._szse = None
     # 申万指数
     file_name = PurePath("index_basic_sw.csv")
     try:
         self._sw = pd.read_csv(sub_path / file_name,
                                dtype={
                                    'base_date': str,
                                    'list_date': str
                                })
         self.valid['index_basic_sw'] = STATUS_WORD[1]
     except FileNotFoundError:
         log_args = [file_name]
         add_log(20,
                 '[fn]Index.load_index_basic(). file "{0[0]}" not found',
                 log_args)
         self._sw = None
     self._update_index_basic_df()
     return
Пример #15
0
 def last_trade_day(self, dt_str=None):
     """
     查询指定日当日或之前最近的交易日,返回日期字符串
     dt_str: <string> in 'YYYYMMDD' e.g.'20190721'
             None 代表当日
     return: <string> in 'YYYYMMDD' e.g.'20190719'
     """
     if self.valid_trade_calendar() is None:
         add_log(20, '[fn]Raw_Data.last_trade_day() trade_calendar invalid')
         return
     if dt_str is None:
         dt = datetime.now()
         dt_str = dt.strftime("%Y%m%d")
     if isinstance(dt_str, str) and (len(dt_str) == 8):
         # tdf = self.trade_calendar.set_index(['cal_date'])
         tdf = self.trade_calendar
         try:
             is_open = tdf.loc[int(dt_str)]['is_open']
             if is_open == 1:
                 return dt_str
             elif is_open == 0:
                 pretrade_date = tdf.loc[int(dt_str)]['pretrade_date']
                 return str(pretrade_date)
             else:
                 return None
         except KeyError:
             log_args = [dt_str]
             add_log(
                 10,
                 '[fn]Raw_Data.last_trade_day() dt_str "{0[0]}" not in stock_basic.csv. check date_str and pull Raw_Data',
                 log_args)
             return
     else:
         log_args = [dt_str]
         add_log(
             20,
             '[fn]Raw_Data.last_trade_day() dt_str "{0[0]}" incorrect format',
             log_args)
         return None
Пример #16
0
def report(al_file):
    """
    报告:每日资产概览
    al_file: <str> al_<al_file>.csv
    """
    from st_board import Strategy
    from st_board import today_str

    # global raw_data

    def head_across(row, column, text):
        """
        用于辅助打印标题栏0行的一组标题
        """
        nonlocal ws1
        cross = 4  # 单元格跨四格
        ws1.write(row, column, text, fmt_head0)
        for i in range(1, cross):
            ws1.write_blank(row, column + i, '', fmt_head0)

    # =================报告文件=================
    today_s = today_str()
    trade_day_str = raw_data.last_trade_day(today_s)
    file_name = PurePath('rpt_racing_' + al_file + '_' + trade_day_str +
                         '.xlsm')
    file_path = sub_path_rpt / file_name

    # =================初始化Strategy=================
    stg = Strategy('report_daily_basic')
    stg.add_pool(desc='p10',
                 al_file=al_file,
                 assets_daily_data='basic',
                 del_trsfed=None)
    p10 = stg.pools[10]

    # ------condition_0
    pre_args1 = {'idt_type': 'ma', 'period': 2}
    pre_args2 = {'idt_type': 'ma', 'period': 5}
    p10.add_condition(pre_args1, pre_args2, '>')

    # ------condition_1
    pre_args1 = {'idt_type': 'ma', 'period': 10}
    pre_args2 = {'idt_type': 'ma', 'period': 20}
    p10.add_condition(pre_args1, pre_args2, '>')

    # ------condition_2
    pre_args1 = {'idt_type': 'ma', 'period': 60}
    pre_args2 = {'idt_type': 'const', 'const_value': 0}
    p10.add_condition(pre_args1, pre_args2, '>')

    stg.init_pools_cnds_matrix()
    stg.init_ref_assets()
    end_date = trade_day_str
    start_date = raw_data.previous_trade_day(end_date, 2)
    stg.update_cycles(start_date=start_date, end_date=end_date)

    # ----当前周期的结束日期
    m1d = raw_data.previous_trade_day(end_date, 1)  # 前1交易日
    m2d = start_date  # 前2交易日
    m5d = raw_data.previous_trade_day(end_date, 5)  # 前5交易日
    m10d = raw_data.previous_trade_day(end_date, 10)  # 前10交易日
    m20d = raw_data.previous_trade_day(end_date, 20)  # 前20交易日
    m60d = raw_data.previous_trade_day(end_date, 60)  # 前60交易日

    # ----前一周期的开始结束日期
    p1d_end = m1d  # 前1周期结束日期
    p1d_start = raw_data.previous_trade_day(p1d_end, 1)  # 前1周期开始日期
    p2d_end = m2d  # 前1周期结束日期
    p2d_start = raw_data.previous_trade_day(p2d_end, 2)  # 前1周期开始日期
    p5d_end = m5d  # 前1周期结束日期
    p5d_start = raw_data.previous_trade_day(p5d_end, 5)  # 前1周期开始日期
    p10d_end = raw_data.previous_trade_day(m10d, 1)  # 前1周期结束日期
    p10d_start = m10d  # 前1周期开始日期
    p20d_end = raw_data.previous_trade_day(m20d, 1)  # 前1周期结束日期
    p20d_start = m20d  # 前1周期开始日期
    p60d_end = raw_data.previous_trade_day(m60d, 1)  # 前1周期结束日期
    p60d_start = m60d  # 前1周期开始日期

    # =================数据准备=================
    data = []  # [(数据1, 数据2, 数据3), (...)]存放用于报告显示的数据
    df = pd.DataFrame(columns=['ts_code', 'm1d_pct', 'close',
                               'p1d_pct'])  # 缓存<df>
    # df.set_index('ts_code', inplace=True)
    for asset in p10.assets.values():
        ts_code = asset.ts_code
        name = asset.name
        # ----最新的复权因子,当日收盘
        adj = 1  # 非Stock复权因子设为1
        if isinstance(asset, Stock):
            adj_sr = Stock.load_adj_factor(ts_code, nrows=1)
            if adj_sr is not None:
                adj, = adj_sr['adj_factor'].head(1)  # 最新的复权因子
        try:
            close, _ = asset.get_price(trade_date=end_date,
                                       seek_direction='backwards')  # 最新收盘
        except Exception as e:
            log_args = [asset.ts_code, e]
            add_log(
                20,
                '[fn]report_race.report() ts_code:{0[0]}; except type:{0[1]}, no valid close recently. skip asset',
                log_args)
            continue

        # ----1日
        try:
            close_m1d, _ = asset.get_price(trade_date=m1d,
                                           seek_direction='backwards')
            m1d_pct = (close - close_m1d) / close_m1d  # 本周期1日涨跌幅
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]report_race.report() ts_code:{0[0]}; m1d_pct TypeError, set value = -0.99',
                log_args)
            m1d_pct = -0.99

        try:
            close_p1d_end, _ = asset.get_price(trade_date=p1d_end,
                                               seek_direction='backwards')
            close_p1d_start, _ = asset.get_price(trade_date=p1d_start,
                                                 seek_direction='backwards')
            p1d_pct = (close_p1d_end -
                       close_p1d_start) / close_p1d_start  # 前周期1日涨跌幅
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]report_race.report() ts_code:{0[0]}; p1d_pct TypeError, set value = -0.99',
                log_args)
            p1d_pct = -0.99

        close_m = close / adj  # 本周期最新未除权价格

        # ----2日
        try:
            close_m2d, _ = asset.get_price(trade_date=m2d,
                                           seek_direction='backwards')
            m2d_pct = (close - close_m2d) / close_m2d  # 本周期2日涨跌幅
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]report_race.report() ts_code:{0[0]}; m2d_pct TypeError, set value = -0.99',
                log_args)
            m2d_pct = -0.99

        try:
            close_p2d_end, _ = asset.get_price(trade_date=p2d_end,
                                               seek_direction='backwards')
            close_p2d_start, _ = asset.get_price(trade_date=p2d_start,
                                                 seek_direction='backwards')
            p2d_pct = (close_p2d_end -
                       close_p2d_start) / close_p2d_start  # 前周期2日涨跌幅
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]report_race.report() ts_code:{0[0]}; p2d_pct TypeError, set value = -0.99',
                log_args)
            p2d_pct = -0.99

        try:
            close_ma2, = asset.ma_2.df_idt.head(1)['MA'].values
            close_ma2r = close_ma2 / adj  # 本周期ma2未除权价格
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]report_race.report() ts_code:{0[0]}; close_ma2r TypeError, set value = -99',
                log_args)
            close_ma2r = -99

        # ----5日
        try:
            close_m5d, _ = asset.get_price(trade_date=m5d,
                                           seek_direction='backwards')
            m5d_pct = (close - close_m5d) / close_m5d  # 本周期5日涨跌幅
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]report_race.report() ts_code:{0[0]}; m5d_pct TypeError, set value = -0.99',
                log_args)
            m5d_pct = -0.99

        try:
            close_p5d_end, _ = asset.get_price(trade_date=p5d_end,
                                               seek_direction='backwards')
            close_p5d_start, _ = asset.get_price(trade_date=p5d_start,
                                                 seek_direction='backwards')
            p5d_pct = (close_p5d_end -
                       close_p5d_start) / close_p5d_start  # 前周期5日涨跌幅
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]report_race.report() ts_code:{0[0]}; p5d_pct TypeError, set value = -0.99',
                log_args)
            p5d_pct = -0.99

        try:
            close_ma5, = asset.ma_5.df_idt.head(1)['MA'].values
            close_ma5r = close_ma5 / adj  # 本周期ma5未除权价格
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]report_race.report() ts_code:{0[0]}; close_ma5r TypeError, set value = -99',
                log_args)
            close_ma5r = -99

        # ----10日
        try:
            close_m10d, _ = asset.get_price(trade_date=m10d,
                                            seek_direction='backwards')
            m10d_pct = (close - close_m10d) / close_m10d  # 本周期10日涨跌幅
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]report_race.report() ts_code:{0[0]}; m10d_pct TypeError, set value = -0.99',
                log_args)
            m10d_pct = -0.99

        try:
            close_p10d_end, _ = asset.get_price(trade_date=p10d_end,
                                                seek_direction='backwards')
            close_p10d_start, _ = asset.get_price(trade_date=p10d_start,
                                                  seek_direction='backwards')
            p10d_pct = (close_p10d_end -
                        close_p10d_start) / close_p10d_start  # 前周期10日涨跌幅
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]report_race.report() ts_code:{0[0]}; p10d_pct TypeError, set value = -0.99',
                log_args)
            p10d_pct = -0.99

        try:
            close_ma10, = asset.ma_10.df_idt.head(1)['MA'].values
            close_ma10r = close_ma10 / adj  # 本周期ma10未除权价格
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]report_race.report() ts_code:{0[0]}; close_ma10r TypeError, set value = -99',
                log_args)
            close_ma10r = -99

        # ----20日
        try:
            close_m20d, _ = asset.get_price(trade_date=m20d,
                                            seek_direction='backwards')
            m20d_pct = (close - close_m20d) / close_m20d  # 本周期20日涨跌幅
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]report_race.report() ts_code:{0[0]}; m20d_pct TypeError, set value = -0.99',
                log_args)
            m20d_pct = -0.99

        try:
            close_p20d_end, _ = asset.get_price(trade_date=p20d_end,
                                                seek_direction='backwards')
            close_p20d_start, _ = asset.get_price(trade_date=p20d_start,
                                                  seek_direction='backwards')
            p20d_pct = (close_p20d_end -
                        close_p20d_start) / close_p20d_start  # 前周期20日涨跌幅
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]report_race.report() ts_code:{0[0]}; p20d_pct TypeError, set value = -0.99',
                log_args)
            p20d_pct = -0.99

        try:
            close_ma20, = asset.ma_20.df_idt.head(1)['MA'].values
            close_ma20r = close_ma20 / adj  # 本周期ma20未除权价格
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]report_race.report() ts_code:{0[0]}; close_ma20r TypeError, set value = -99',
                log_args)
            close_ma20r = -99

        # ----60日
        try:
            close_m60d, _ = asset.get_price(trade_date=m60d,
                                            seek_direction='backwards')
            m60d_pct = (close - close_m60d) / close_m60d  # 本周期60日涨跌幅
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]report_race.report() ts_code:{0[0]}; m60d_pct TypeError, set value = -0.99',
                log_args)
            m60d_pct = -0.99

        try:
            close_p60d_end, _ = asset.get_price(trade_date=p60d_end,
                                                seek_direction='backwards')
            close_p60d_start, _ = asset.get_price(trade_date=p60d_start,
                                                  seek_direction='backwards')
            p60d_pct = (close_p60d_end -
                        close_p60d_start) / close_p60d_start  # 前周期60日涨跌幅
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]report_race.report() ts_code:{0[0]}; p60d_pct TypeError, set value = -0.99',
                log_args)
            p60d_pct = -0.99

        try:
            close_ma60, = asset.ma_60.df_idt.head(1)['MA'].values
            close_ma60r = close_ma60 / adj  # 本周期ma60未除权价格
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]report_race.report() ts_code:{0[0]}; close_ma60r TypeError, set value = -99',
                log_args)
            close_ma60r = -99

        # ----asset加入<df>中
        data = {
            'ts_code': ts_code,
            'a_name': name,
            'm1d_pct': m1d_pct,
            'close': close_m,
            'p1d_pct': p1d_pct,
            'm2d_pct': m2d_pct,
            'ma2': close_ma2r,
            'p2d_pct': p2d_pct,
            'm5d_pct': m5d_pct,
            'ma5': close_ma5r,
            'p5d_pct': p5d_pct,
            'm10d_pct': m10d_pct,
            'ma10': close_ma10r,
            'p10d_pct': p10d_pct,
            'm20d_pct': m20d_pct,
            'ma20': close_ma20r,
            'p20d_pct': p20d_pct,
            'm60d_pct': m60d_pct,
            'ma60': close_ma60r,
            'p60d_pct': p60d_pct
        }
        df = df.append(data, ignore_index=True)

        # ----本周期、前周期排名及排位变化
        df.loc[:, 'm1d_rank'] = df['m1d_pct'].rank(ascending=False,
                                                   method='min')
        df.loc[:, 'p1d_rank'] = df['p1d_pct'].rank(ascending=False,
                                                   method='min')
        df.loc[:, 'chg_1d'] = df['p1d_rank'] - df['m1d_rank']

        df.loc[:, 'm2d_rank'] = df['m2d_pct'].rank(ascending=False,
                                                   method='min')
        df.loc[:, 'p2d_rank'] = df['p2d_pct'].rank(ascending=False,
                                                   method='min')
        df.loc[:, 'chg_2d'] = df['p2d_rank'] - df['m2d_rank']

        df.loc[:, 'm5d_rank'] = df['m5d_pct'].rank(ascending=False,
                                                   method='min')
        df.loc[:, 'p5d_rank'] = df['p5d_pct'].rank(ascending=False,
                                                   method='min')
        df.loc[:, 'chg_5d'] = df['p5d_rank'] - df['m5d_rank']

        df.loc[:, 'm10d_rank'] = df['m10d_pct'].rank(ascending=False,
                                                     method='min')
        df.loc[:, 'p10d_rank'] = df['p10d_pct'].rank(ascending=False,
                                                     method='min')
        df.loc[:, 'chg_10d'] = df['p10d_rank'] - df['m10d_rank']

        df.loc[:, 'm20d_rank'] = df['m20d_pct'].rank(ascending=False,
                                                     method='min')
        df.loc[:, 'p20d_rank'] = df['p20d_pct'].rank(ascending=False,
                                                     method='min')
        df.loc[:, 'chg_20d'] = df['p20d_rank'] - df['m20d_rank']

        df.loc[:, 'm60d_rank'] = df['m60d_pct'].rank(ascending=False,
                                                     method='min')
        df.loc[:, 'p60d_rank'] = df['p60d_pct'].rank(ascending=False,
                                                     method='min')
        df.loc[:, 'chg_60d'] = df['p60d_rank'] - df['m60d_rank']
    df.set_index('ts_code', inplace=True)

    # =================报告基础=================
    workbook = xlw.Workbook(file_path)
    ws1 = workbook.add_worksheet('日报')  # worksheet #1

    fmt_std = workbook.add_format(d_std)
    fmt_wrap = workbook.add_format(d_wrap)
    fmt_rpt_title = workbook.add_format(d_rpt_title)
    fmt_head0 = workbook.add_format(d_head0)
    fmt_head1 = workbook.add_format(d_head1)
    fmt_center = workbook.add_format(d_center)  # 居中
    fmt_int = workbook.add_format(d_int)  # 整数
    fmt_f1d = workbook.add_format(d_f1d)  # 1位小数
    fmt_f2d = workbook.add_format(d_f2d)  # 2位小数
    fmt_f3d = workbook.add_format(d_f3d)  # 3位小数
    fmt_pct = workbook.add_format(d_pct)  # 0%
    fmt_pct1d = workbook.add_format(d_pct1d)  # 1.1%
    fmt_pct2d = workbook.add_format(d_pct2d)  # 2.22%
    fmt_pct1d_g = workbook.add_format(d_pct1d_g)  # 1.1% 灰底

    # =================添加VBA=================
    file_bin = PurePath("rpt_racing.bin")
    path_bin = sub_path_rpt / 'bin' / file_bin
    workbook.add_vba_project(path_bin)

    # =================报告数据=================
    # ----标题栏
    ws1.write_string('A1', trade_day_str + '    ' + 'Report Assets Racing',
                     fmt_rpt_title)
    ws1.set_row(0, 19)  # 第一行,标题栏行高
    ws1.set_row(1, options={'hidden': True})  # 第二行,分隔行行高
    # ----表头第0行
    row_h0 = 2
    column_h0 = 2
    head_across(row_h0, column_h0, '1 Day')
    column_h0 = 6
    head_across(row_h0, column_h0, '2 Days')
    column_h0 = 10
    head_across(row_h0, column_h0, '5 Days')
    column_h0 = 14
    head_across(row_h0, column_h0, '10 Days')
    column_h0 = 18
    head_across(row_h0, column_h0, '20 Days')
    column_h0 = 22
    head_across(row_h0, column_h0, '60 Days')
    # ----表头第1行
    head2 = ('代码', '名称', 'chg%', 'C', 'rank', '+ -', 'chg%', 'ma', 'rank',
             '+ -', 'chg%', 'ma', 'rank', '+ -', 'chg%', 'ma', 'rank', '+ -',
             'chg%', 'ma', 'rank', '+ -', 'chg%', 'ma', 'rank', '+ -')
    ws1.write_row('A4', head2, fmt_head1)  # 标题栏第1行
    # ----ts_code列
    data = df.index.tolist()
    ws1.write_column(4, 0, data, fmt_center)
    # ----name列
    data = df.a_name.tolist()
    ws1.write_column(4, 1, data, fmt_center)
    # ----chg%列
    column_width = 8.38
    data = df.m1d_pct.tolist()
    ws1.write_column(4, 2, data, fmt_pct1d_g)  # 1 Day
    ws1.set_column(2, 2, width=column_width)
    data = df.m2d_pct.tolist()
    ws1.write_column(4, 6, data, fmt_pct1d_g)  # 2 Days
    ws1.set_column(6, 6, width=column_width)
    data = df.m5d_pct.tolist()
    ws1.write_column(4, 10, data, fmt_pct1d_g)  # 5 Days
    ws1.set_column(10, 10, width=column_width)
    data = df.m10d_pct.tolist()
    ws1.write_column(4, 14, data, fmt_pct1d_g)  # 10 Days
    ws1.set_column(14, 14, width=column_width)
    data = df.m20d_pct.tolist()
    ws1.write_column(4, 18, data, fmt_pct1d_g)  # 20 Days
    ws1.set_column(18, 18, width=column_width)
    data = df.m60d_pct.tolist()
    ws1.write_column(4, 22, data, fmt_pct1d_g)  # 60 Days
    ws1.set_column(22, 22, width=column_width)
    # ----close及ma列
    column_width = 8.38
    data = df.close.tolist()
    ws1.write_column(4, 3, data, fmt_f2d)  # 1 Day
    ws1.set_column(3, 3, width=column_width)
    data = df.ma2.tolist()
    ws1.write_column(4, 7, data, fmt_f2d)  # 2 Days
    ws1.set_column(7, 7, width=column_width)
    data = df.ma5.tolist()
    ws1.write_column(4, 11, data, fmt_f2d)  # 5 Days
    ws1.set_column(11, 11, width=column_width)
    data = df.ma10.tolist()
    ws1.write_column(4, 15, data, fmt_f2d)  # 10 Days
    ws1.set_column(15, 15, width=column_width)
    data = df.ma20.tolist()
    ws1.write_column(4, 19, data, fmt_f2d)  # 20 Days
    ws1.set_column(19, 19, width=column_width)
    data = df.ma60.tolist()
    ws1.write_column(4, 23, data, fmt_f2d)  # 60 Days
    ws1.set_column(23, 23, width=column_width)
    # ----rank列
    column_width = 5
    data = df.m1d_rank.tolist()
    ws1.write_column(4, 4, data, fmt_int)  # 1 Day
    ws1.set_column(4, 4, width=column_width)
    data = df.m2d_rank.tolist()
    ws1.write_column(4, 8, data, fmt_int)  # 2 Days
    ws1.set_column(8, 8, width=column_width)
    data = df.m5d_rank.tolist()
    ws1.write_column(4, 12, data, fmt_int)  # 5 Days
    ws1.set_column(12, 12, width=column_width)
    data = df.m10d_rank.tolist()
    ws1.write_column(4, 16, data, fmt_int)  # 10 Days
    ws1.set_column(16, 16, width=column_width)
    data = df.m20d_rank.tolist()
    ws1.write_column(4, 20, data, fmt_int)  # 20 Days
    ws1.set_column(20, 20, width=column_width)
    data = df.m60d_rank.tolist()
    ws1.write_column(4, 24, data, fmt_int)  # 60 Days
    ws1.set_column(24, 24, width=column_width)
    # ----change列
    column_width = 5
    data = df.chg_1d.tolist()
    ws1.write_column(4, 5, data, fmt_int)  # 1 Day
    ws1.set_column(5, 5, width=column_width)
    data = df.chg_2d.tolist()
    ws1.write_column(4, 9, data, fmt_int)  # 2 Days
    ws1.set_column(9, 9, width=column_width)
    data = df.chg_5d.tolist()
    ws1.write_column(4, 13, data, fmt_int)  # 5 Days
    ws1.set_column(13, 13, width=column_width)
    data = df.chg_10d.tolist()
    ws1.write_column(4, 17, data, fmt_int)  # 10 Days
    ws1.set_column(17, 17, width=column_width)
    data = df.chg_20d.tolist()
    ws1.write_column(4, 21, data, fmt_int)  # 20 Days
    ws1.set_column(21, 21, width=column_width)
    data = df.chg_60d.tolist()
    ws1.write_column(4, 25, data, fmt_int)  # 60 Days
    ws1.set_column(25, 25, width=column_width)

    # =================添加按钮=================
    ws1.insert_button(
        "C3", {
            'macro': 'sort_1D',
            'caption': '1D',
            'width': 40,
            'height': 15,
            'x_offset': 2,
            'y_offset': 2
        })
    ws1.insert_button(
        "G3", {
            'macro': 'sort_2D',
            'caption': '2D',
            'width': 40,
            'height': 15,
            'x_offset': 2,
            'y_offset': 2
        })
    ws1.insert_button(
        "K3", {
            'macro': 'sort_5D',
            'caption': '5D',
            'width': 40,
            'height': 15,
            'x_offset': 2,
            'y_offset': 2
        })
    ws1.insert_button(
        "O3", {
            'macro': 'sort_10D',
            'caption': '10D',
            'width': 40,
            'height': 15,
            'x_offset': 2,
            'y_offset': 2
        })
    ws1.insert_button(
        "S3", {
            'macro': 'sort_20D',
            'caption': '20D',
            'width': 40,
            'height': 15,
            'x_offset': 2,
            'y_offset': 2
        })
    ws1.insert_button(
        "W3", {
            'macro': 'sort_60D',
            'caption': '60D',
            'width': 40,
            'height': 15,
            'x_offset': 2,
            'y_offset': 2
        })

    # =================收尾格式=================
    ws1.set_column(0, 0, 9)  # 代码
    ws1.set_column(1, 1, 8)  # 名称
    ws1.set_landscape()  # 页面横向
    ws1.set_paper(9)  # 设置A4纸
    ws1.center_horizontally()  # 居中
    ws1.set_margins(0.1, 0.1, 0.1, 1)
    ws1.set_footer('&C&P of &N')  # 设置页脚
    ws1.repeat_rows(0, 3)  # 重复打印行
    ws1.repeat_columns(0, 1)  # 重复打印列
    ws1.freeze_panes(4, 2)  # freeze 4行2列
    ws1.fit_to_pages(1, 0)  # 宽度放在1页中,长度不限
    workbook.close()

    # print(df)
    # df.to_csv('临时report_race.csv', encoding='utf-8')
    pass
Пример #17
0
def rpt_d_basic(al_file):
    """
    报告:每日资产概览
    al_file: <str> al_<al_file>.csv
    """
    from st_board import Strategy
    from st_board import today_str
    # global raw_data

    # =================报告文件=================
    today_s = today_str()
    trade_day_str = raw_data.last_trade_day(today_s)
    file_name = PurePath('rpt_d_' + al_file + '_' + trade_day_str + '.xlsx')
    file_path = sub_path_rpt / file_name

    # =================初始化Strategy=================
    stg = Strategy('report_daily_basic')
    # dd = {'turnover_rate_f'}  # 成交额
    # stg.add_pool(desc='p10', al_file=al_file, assets_daily_data=dd, del_trsfed=None)
    stg.add_pool(desc='p10',
                 al_file=al_file,
                 assets_daily_data='basic',
                 del_trsfed=None)
    p10 = stg.pools[10]

    # ------condition_0
    pre_args1 = {'idt_type': 'ma', 'period': 20}
    pre_args2 = {'idt_type': 'maqs', 'period': 20}
    p10.add_condition(pre_args1, pre_args2, '>')

    # ------condition_1
    pre_args1 = {
        'idt_type': 'majh',
        'long_n3': 60,
        'medium_n2': 20,
        'short_n1': 5
    }
    pre_args2 = {'idt_type': 'maqs', 'period': 60}
    p10.add_condition(pre_args1, pre_args2, '>')

    # ------condition_2
    pre_args1 = {
        'idt_type': 'macd',  # 日线macd
        'long_n1': 26,
        'short_n2': 12,
        'dea_n3': 9
    }
    pre_args2 = {
        'idt_type': 'macd',  # 周线macd
        'long_n1': 130,
        'short_n2': 60,
        'dea_n3': 45
    }
    p10.add_condition(pre_args1, pre_args2, '>')

    # ------condition_3
    pre_args1 = {
        'idt_type': 'jdxz',  # 绝对吸资比例
        'period': 10
    }
    pre_args2 = {
        'idt_type': 'jdxz',  # 绝对吸资比例
        'period': 250
    }
    p10.add_condition(pre_args1, pre_args2, '>')

    # ------condition_4
    pre_args1 = {
        'idt_type': 'dktp',  # 多空头排列
        'short_n1': 5,
        'medium_n2': 10,
        'long_n3': 20
    }
    pre_args2 = {
        'idt_type': 'dktp',  # 多空头排列
        'source': 'vol',  # 成交量
        'short_n1': 5,
        'medium_n2': 10,
        'long_n3': 20
    }
    p10.add_condition(pre_args1, pre_args2, '>')

    # ------condition_5
    pre_args1 = {
        'idt_type': 'maqs',  # 量趋势变化
        'period': 10,
        'source': 'vol'
    }
    pre_args2 = {
        'idt_type': 'maqs',  # 量趋势变化
        'period': 20,
        'source': 'vol'
    }
    p10.add_condition(pre_args1, pre_args2, '>')

    stg.init_pools_cnds_matrix()
    stg.init_ref_assets()
    end_date = trade_day_str
    start_date = raw_data.previous_trade_day(end_date, 2)
    stg.update_cycles(start_date=start_date, end_date=end_date)

    # =================数据准备=================
    data = []  # [(数据1, 数据2, 数据3), (...)]存放用于报告显示的数据
    X = 2  # 聚合的程度%限值
    for asset in p10.assets.values():
        ts_code = asset.ts_code
        name = asset.name
        # ----从an_<ts_code>.xml读入comment
        tree = load_xml(ts_code)
        if isinstance(tree, ET.ElementTree):
            root = tree.getroot()
            comment1 = root.find('comment1').find('content').text
            comment2 = root.find('comment2').find('content').text
        else:
            comment1 = ''
            comment2 = ''

        # ----20日归%
        try:
            ma20_last, = asset.ma_20.df_idt.head(1)['MA'].values
            by_price = asset.by_price
            ma20_gl = (by_price / ma20_last - 1) * 100  # close与ma_20的归离率
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                20,
                '[fn]rpt_d_basic() ts_code:{0[0]}; ma20_gl AttributeError, set value = -99',
                log_args)
            ma20_gl = -99

        # ----20MA变化
        try:
            maqs20, = asset.maqs_20.df_idt.head(1)['MAQS'].values
            maqs20 = maqs20 * 1000
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                20,
                '[fn]rpt_d_basic() ts_code:{0[0]}; maqs20 AttributeError, set value = -99',
                log_args)
            maqs20 = -999

        # ----60MA变化
        try:
            maqs60, = asset.maqs_60.df_idt.head(1)['MAQS'].values
            maqs60 = maqs60 * 1000
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]rpt_d_basic() ts_code:{0[0]}; maqs60 AttributeError, set value = -99',
                log_args)
            maqs60 = -999

        # ----量20MA变化
        try:
            maqs_vol_20, = asset.maqs_vol_20.df_idt.head(1)['MAQS'].values
            maqs_vol_20 = maqs_vol_20 * 1000
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]rpt_d_basic() ts_code:{0[0]}; maqs_vol_20 AttributeError, set value = -99',
                log_args)
            maqs_vol_20 = -99

        # ----量10MA变化
        try:
            maqs_vol_10, = asset.maqs_vol_10.df_idt.head(1)['MAQS'].values
            maqs_vol_10 = maqs_vol_10 * 1000
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]rpt_d_basic() ts_code:{0[0]}; maqs_vol_10 AttributeError, set value = -99',
                log_args)
            maqs_vol_10 = -99

        # ----价聚合<x%天数的占比(最近20个交易日中)
        df = asset.majh_60_20_5.df_idt
        DAYS = 20  # 交易日窗口
        try:
            sr = df.head(DAYS)['MAJH']  # 如果数据少于20个,有几个取几个
            n = len(sr)
            if n > 0:
                n_meet = len(sr[sr < X])
                jh_pct = n_meet / n  # 聚合天数的占比
            else:
                jh_pct = 0
        except (AttributeError, TypeError):
            log_args = [asset.ts_code]
            add_log(
                30,
                '[fn]rpt_d_basic() ts_code:{0[0]}; jh_pct AttributeError, set value = -0.99',
                log_args)
            jh_pct = -0.99

        # ----吸资归离, 10D 与 250D
        try:
            jdxz10, = asset.jdxz_10.df_idt.head(1)['JDXZ'].values
            jdxz250, = asset.jdxz_250.df_idt.head(1)['JDXZ'].values
            xz_rate = jdxz10 / jdxz250 - 1
        except Exception as e:
            log_args = [asset.ts_code, e]
            add_log(
                20,
                '[fn]rpt_d_basic() ts_code:{0[0]}; xz_rate except type:{0[1]} to catch',
                log_args)
            xz_rate = -99

        # ----吸资10QS`   `````
        try:
            xz_current, xz_previous = asset.jdxz_10.df_idt.head(
                2)['JDXZ'].values
            xzqs = (xz_current / xz_previous - 1) * 100
        except Exception as e:
            log_args = [asset.ts_code, e]
            add_log(
                20,
                '[fn]rpt_d_basic() ts_code:{0[0]}; xzqs except type:{0[1]} to catch',
                log_args)
            xzqs = -99

        # ----价多空头排列天数
        try:
            p_dktp, = asset.dktp_5_10_20.df_idt.head(1)['DKTP'].values
        except Exception as e:
            log_args = [asset.ts_code, e]
            add_log(
                20,
                '[fn]rpt_d_basic() ts_code:{0[0]}; p_dktp except type:{0[1]} to catch',
                log_args)
            p_dktp = -99

        # ----量多空头排列天数
        try:
            v_dktp, = asset.dktp_vol_5_10_20.df_idt.head(1)['DKTP'].values
        except Exception as e:
            log_args = [asset.ts_code, e]
            add_log(
                20,
                '[fn]rpt_d_basic() ts_code:{0[0]}; v_dktp except type:{0[1]} to catch',
                log_args)
            v_dktp = -99

        # ----添加数据
        data.append(
            (ts_code, name, comment1, comment2, ma20_gl, maqs20, maqs60,
             maqs_vol_10, maqs_vol_20, jh_pct, xz_rate, xzqs, p_dktp, v_dktp))

    # =================报告基础=================
    workbook = xlw.Workbook(file_path)
    ws1 = workbook.add_worksheet('日报')  # worksheet #1

    fmt_std = workbook.add_format(d_std)
    fmt_wrap = workbook.add_format(d_wrap)
    fmt_rpt_title = workbook.add_format(d_rpt_title)
    fmt_center = workbook.add_format(d_center)  # 居中
    fmt_int = workbook.add_format(d_int)  # 整数
    fmt_f1d = workbook.add_format(d_f1d)  # 1位小数
    fmt_f2d = workbook.add_format(d_f2d)  # 2位小数
    fmt_f3d = workbook.add_format(d_f3d)  # 3位小数
    fmt_pct = workbook.add_format(d_pct)  # 0%
    fmt_pct1d = workbook.add_format(d_pct1d)  # 1.1%
    fmt_pct2d = workbook.add_format(d_pct2d)  # 2.22%

    # 与data对应的显示格式
    #           ts_code       名称      备注        备注    20日归    maqs20   maqs60
    formats = [
        fmt_center, fmt_center, fmt_wrap, fmt_wrap, fmt_f2d, fmt_f2d, fmt_f2d
    ]
    #                    量10QS   量20QS    聚合占比 吸资归离 吸资10QS 价多空排  量多空排
    formats = formats + [
        fmt_f2d, fmt_f2d, fmt_pct, fmt_f2d, fmt_f2d, fmt_int, fmt_int
    ]

    # =================报告数据=================
    # ----标题栏
    ws1.write_string('A1', trade_day_str + '    ' + 'Report Daily Basic',
                     fmt_rpt_title)
    ws1.set_row(0, 19)  # 第一行,标题栏行高
    ws1.set_row(1, options={'hidden': True})  # 第二行,分隔行行高
    # ----表头
    head = ('代码', '名称', '备注', '备注', '价20归%', '价20QS‰', '价60QS‰', '量10QS‰',
            '量20QS‰', '聚2%天比', '吸资归离', '吸资10QS', '价多空排', '量多空排')
    ws1.write_row('A3', head, fmt_center)
    ws1.write_comment('A1', '确保下载数据当日数据后再生成报表!')
    ws1.write_comment('E3', '(by_price / ma20_last - 1) * 100')
    ws1.write_comment('F3', 'maqs_20 * 1000')
    ws1.write_comment('G3', 'maqs_60 * 1000')
    ws1.write_comment('H3', 'maqs_vol_10 * 1000')
    ws1.write_comment('I3', 'maqs_vol_20 * 1000')
    ws1.write_comment('J3', '在20个交易日内,majh<' + str(X) + '%天数的占比 周期5, 10, 20')
    ws1.write_comment('K3', '10日吸资比 / 250日吸资比 -1')
    ws1.write_comment('L3', '10日吸资比变化率 * 100')
    ws1.write_comment('M3', '价多空头排列天数')
    ws1.write_comment('N3', '量多空头排列天数')
    # ----填充数据
    row = 3
    assert len(head) == len(formats)
    for item in data:
        for column in range(len(head)):
            ws1.write(row, column, item[column], formats[column])
        row += 1

    # =================收尾格式=================
    ws1.set_column(0, 0, 10.2)  # 代码
    ws1.set_column(1, 1, 8.2)  # 名称
    ws1.set_column(2, 3, 15)  # 备注
    max_column = len(head) - 1
    max_row = row - 1
    ws1.set_landscape()  # 页面横向
    ws1.set_paper(9)  # 设置A4纸
    ws1.center_horizontally()  # 居中
    ws1.set_margins(0.3, 0.3, 0.3, 1)
    ws1.set_footer('&C&P of &N')  # 设置页脚
    ws1.repeat_rows(0, 2)  # 重复打印行
    ws1.repeat_columns(0, 1)  # 重复打印列
    ws1.freeze_panes(3, 2)  # freeze 3行2列
    workbook.close()
    pass