Exemple #1
0
 def query(self, qname, tscode_str='', **kwargs):
     exchangeid = self.parseCode(tscode_str, seg='exch')
     cryptoSymbol = self.parseCode(tscode_str, seg='pair')
     if qname == 'ohlcv':
         return self.dct_exchanges[exchangeid].fetch_ohlcv(
             symbol=cryptoSymbol, limit=5000, timeframe='1d', **kwargs)
     elif qname == 'tickers':
         return self.dct_exchanges[exchangeid].fetch_tickers(
             symbols=cryptoSymbol)
     elif qname == 'load_alld':  # 读取本地已存储的csv格式历史信息
         fname = '{}{}.csv'.format(cfg.PATH_CPTFILE, tscode_str)
         if os.path.isfile(fname):
             df_result = pd.read_csv(fname,
                                     encoding=cfg.FILE_ENCODE).astype(
                                         dtype={'trade_date': 'int64'})
             df_result = df_result if kwargs[
                 'tpl_dateindex'] is None else df_result[
                     df_result['trade_date'].isin(kwargs['tpl_dateindex'])]
             return df_result
         else:
             libs.log_csv(
                 str_cat='WARNING',
                 str_op='query',
                 str_desc='WARNING! no csv file found for {}'.format(
                     tscode_str))
             return False
     else:
         return False
Exemple #2
0
    def __init__(self,ts_code,heartbeat=None,tags=[]):  
        self.ts_code = ts_code
        self.tags = tags # can label a sec with a chain of tags at run time so that they can be filtered
        self.cursorBar = None
        self.histBars = None
        self.allBars = None
        self.mchart = None
        self.tradeunit = 0 # 0代表最低可买一股,-2代表100(1手)-3代表1000
        self.commission = Decimal('0')
        self.basicCols = ['ts_code','timeAxis','unit_intdate','trade_date','open','high','low','close','vol',
            'sec_type','sec_market','candle_size','box_size','upper_stick','lower_stick','MA_S','MA_M','MA_L',
            'MA_Y','VolMA_S','VolMA_M','VolMA_L']

        self._dataagent = DataAgent_Factory.singleton() # expecting dataagent object to be a singleton
        self._heartbeat = heartbeat
        self._cursorTick = None # should be a str or a row in calendar table
        self.anchorObj = None # to hold underlying anchor security object

        targeted = self._dataagent.registry.loc[self._dataagent.registry['ts_code']==ts_code]
        if self.ts_code=='cash':
            self.exists = False
            self.sec_name = 'cash'
            self.sec_type = 'cash'
            self.ts_market = ''
        elif len(targeted)==0:
            self.exists = False
            libs.log_csv(str_cat='WARNING', str_op='Security initiation', str_desc='{} does not exist in registry'.format(self.ts_code))
            raise Exception('{} does not exist in registry'.format(self.ts_code))
        else:
            self.exists = True
            self.sec_name = targeted['name'].values[0]
            self.sec_type = targeted['sec_type'].values[0]
            self.ts_market = targeted['sec_market'].values[0]
            # used to, e.g. capture the underlying index of an ETF fund
            self.anchor_tscode = None if targeted['anchor'].isnull().values.any() else targeted['anchor'].values[0]
Exemple #3
0
    def get_livebar(self, assign_timestamp, assign_unitdate=None):
        df_liveQuote = self._dataagent.query('quote_now', [
            self.ts_code,
        ])
        if len(df_liveQuote) > 0:
            df_liveQuote.rename(columns={
                'open': 'open',
                'high': 'high',
                'low': 'low',
                'price': 'close',
                'volume': 'vol',
                'amount': 'amount'
            },
                                inplace=True)
            df_liveQuote = df_liveQuote.astype(
                dtype={
                    'open': 'float',
                    'high': 'float',
                    'low': 'float',
                    'close': 'float',
                    'vol': 'float',
                    'amount': 'float'
                })
            # all self.basicCols need to be normalised here, extendCols to be normalised in child class
            df_liveQuote['timeAxis'] = assign_timestamp
            # unit_intdate 和timestamp有可能不是同一日,如周六时timeAxis是周六的某一时间而unit_intdate应是下一交易日即下周一日期,因此此处应对liveQuote设置之后再append allBar
            df_liveQuote['unit_intdate'] = int(
                datetime.strftime(
                    assign_timestamp,
                    '%Y%m%d')) if assign_unitdate is None else assign_unitdate
            df_liveQuote['trade_date'] = df_liveQuote['date'].str.replace(
                '-', '', regex=False).astype(int)
            df_liveQuote['ts_code'] = self.ts_code
            df_liveQuote['vol'] = df_liveQuote[
                'vol'] / 100 if self.sec_type == 'stk' or self.ts_code[:3] == '399' else df_liveQuote[
                    'vol']
            df_liveQuote['amount'] = df_liveQuote['amount'] / 1000

            df_liveQuote['sec_type'] = self.sec_type
            df_liveQuote['sec_market'] = self.ts_market
            # 凡是需要前一bar数据配合计算的此处不做处理
            df_liveQuote['candle_size'] = np.nan
            df_liveQuote['box_size'] = np.nan
            df_liveQuote['upper_stick'] = np.nan
            df_liveQuote['lower_stick'] = np.nan
            df_liveQuote['MA_S'] = np.nan
            df_liveQuote['MA_M'] = np.nan
            df_liveQuote['MA_L'] = np.nan
            df_liveQuote['MA_Y'] = np.nan
            df_liveQuote['VolMA_S'] = np.nan
            df_liveQuote['VolMA_M'] = np.nan
            df_liveQuote['VolMA_L'] = np.nan

            return df_liveQuote
        else:
            libs.log_csv(str_cat='WARNING',
                         str_op='get_livebar method',
                         str_desc='{} query returned none result'.format(
                             self.ts_code))
            return None
Exemple #4
0
    def __init__(self,ts_code,heartbeat=None,tags=[]):
        super().__init__(ts_code,heartbeat=heartbeat,tags=tags)
        self.kchart = None
        self.exists = False if self.sec_type != 'idx' else self.exists
        self.tradeunit = 0
        self.commission = Decimal('0')
        if self.exists == False:
            libs.log_csv(str_cat='WARNING', str_op='Security initiation', str_desc='{} does not exist in registry'.format(self.ts_code))
            raise Exception('{} no such index in registry'.format(self.ts_code))
        else:           
            self.extendCols = [*self.basicCols,'pre_close','amount']
            self.ts_market = self.ts_market

        self.allBars = self._get_all_bars()
Exemple #5
0
    def sync_repo(self):
        libs.log_csv(str_cat='INFO',
                     str_op='sync',
                     str_desc='Tsaisendo crypto data sync job started...')
        ''' 遍历给定code列表并同步本地存储数据 '''
        for str_tscrypto in self.symbol_list:
            str_paircode = self.parseCode(str_tscrypto, seg='pair')
            fname = '{}{}.csv'.format(cfg.PATH_CPTFILE, str_tscrypto)
            writeMode = 'a'
            if os.path.isfile(fname):
                int_lastRecDate = int(
                    pd.read_csv(
                        fname,
                        encoding=cfg.FILE_ENCODE)[-1:].iloc[0]['exch_timeid'])
                result = self.query(qname='ohlcv',
                                    tscode_str=str_tscrypto,
                                    since=int_lastRecDate + 1)
            else:
                result = self.query(qname='ohlcv',
                                    tscode_str=str_tscrypto,
                                    since=0)
                writeMode = 'w'

            if len(result) > 0:
                df_result = pd.DataFrame(result,
                                         columns=[
                                             'exch_timeid', 'open', 'high',
                                             'low', 'close', 'volume'
                                         ])
                df_result['ts_code'] = str_tscrypto
                # df_result['trade_date'] = (df_result['exch_timeid']/1000).astype('int').astype('datetime64[s]').dt.strftime("%Y-%m-%d %H:%M:%S")
                df_result['trade_date'] = (
                    df_result['exch_timeid'] / 1000).astype('int').astype(
                        'datetime64[s]').dt.strftime("%Y%m%d%H%M%S")

                libs.df_csv(fname, (df_result, ), writeMode)
                libs.log_csv(str_cat='INFO',
                             str_op='sync',
                             str_desc='{} crypto file syncronized...'.format(
                                 str_tscrypto))
            else:
                libs.log_csv(
                    str_cat='INFO',
                    str_op='sync',
                    str_desc='{} crypto file skipped...'.format(str_tscrypto))
        libs.log_csv(str_cat='INFO',
                     str_op='sync',
                     str_desc='Tsaisendo crypto data sync job ended...')
Exemple #6
0
 def pollPulse(self):
     libs.log_csv(str_cat='INFO',
                  str_op='poll',
                  str_desc='Tsaisendo polling job started...')
     # 定义历史数据留多久
     str_oldestViewDateTime = str(
         self.da.int_findOffsetDate(self.int_pollPulseDate, -21)) + '000000'
     df_indexpoll = pd.DataFrame()
     df_stockpoll = pd.DataFrame()
     ''' 遍历所有时间点并请求最新数据'''
     for beat in self.pollPulseRange:
         while True:
             timecheck = datetime.now().astimezone(
                 timezone(cfg.STR_TIMEZONE)).replace(tzinfo=None)
             if timecheck.replace(second=0, microsecond=0) > beat:
                 libs.log_csv(
                     str_cat='INFO',
                     str_op='poll',
                     str_desc=
                     'WARNING! {}/{} - {}:{} heartbeat dropped at {} due to happening too late...'
                     .format(
                         beat.month, beat.day, beat.hour, beat.minute,
                         datetime.now().astimezone(
                             timezone(cfg.STR_TIMEZONE))))
                 break
             elif timecheck.replace(second=0, microsecond=0) == beat:
                 libs.log_csv(str_cat='INFO',
                              str_op='poll',
                              str_desc='poll time...{}'.format(timecheck))
                 df_index = self.da.query('allindex_now')
                 df_stock = self.da.query('allstock_now')
                 # data_store = libs.tryOpenH5(cfg.H5_FILE_POLL)
                 if len(df_index) > 0:
                     df_index['time_index'] = int(
                         datetime.strftime(beat, '%Y%m%d%H%M%S'))
                     df_index['candle_size'] = round(
                         (df_index['high'] - df_index['low']) /
                         df_index['pre_close'], 3)
                     df_index['box_size'] = round(
                         (df_index['close'] - df_index['open']) /
                         df_index['pre_close'], 3)
                     df_index['upper_stick'] = round(
                         (df_index['high'] -
                          df_index[['open', 'close']].max(axis=1)) /
                         df_index['pre_close'], 3)
                     df_index['lower_stick'] = round(
                         (df_index[['open', 'close']].min(axis=1) -
                          df_index['low']) / df_index['pre_close'], 3)
                     binRange0 = [0, 0.005, 0.010, 0.016,
                                  float('inf')]  # 指数类的尺寸划分标准
                     df_index['klineSML'] = ''
                     df_index.loc[df_index['sec_type'] == 0,
                                  ['klineSML']] = DataAgent.classifyKline(
                                      df_index, DataAgent.binRange0, 0)
                     df_index.to_sql('index_poll',
                                     DataAgent.dbsession.bind,
                                     if_exists='append',
                                     index=False)
                     # data_store.append('indexPoll', df_index,format='t')
                 if len(df_stock) > 0:
                     df_stock['time_index'] = int(
                         datetime.strftime(beat, '%Y%m%d%H%M%S'))
                     df_stock['candle_size'] = round(
                         (df_stock['high'] - df_stock['low']) /
                         df_stock['pre_close'], 3)
                     df_stock['box_size'] = round(
                         (df_stock['close'] - df_stock['open']) /
                         df_stock['pre_close'], 3)
                     df_stock['upper_stick'] = round(
                         (df_stock['high'] -
                          df_stock[['open', 'close']].max(axis=1)) /
                         df_stock['pre_close'], 3)
                     df_stock['lower_stick'] = round(
                         (df_stock[['open', 'close']].min(axis=1) -
                          df_stock['low']) / df_stock['pre_close'], 3)
                     binRange1 = [0, 0.01, 0.033, 0.066,
                                  float('inf')]  # 股票类的尺寸划分标准
                     df_stock['klineSML'] = ''
                     df_stock.loc[df_stock['sec_type'] == 1,
                                  ['klineSML']] = DataAgent.classifyKline(
                                      df_stock, DataAgent.binRange1, 1)
                     '''df_stock.to_sql('stock_poll', DataAgent.dbsession.bind, if_exists='append',index=False)'''
                     # data_store.append('stockPoll', df_stock,format='t')
                 # data_store.close()
                 libs.log_csv(
                     str_cat='INFO',
                     str_op='poll',
                     str_desc='[{}] index and [{}] stock data acquired'.
                     format(len(df_index), len(df_stock)))
                 break
             else:
                 libs.log_csv(
                     str_cat='INFO',
                     str_op='poll',
                     str_desc=
                     'waiting {} seconds until next poll heartbeat - {}'.
                     format(libs.datediff_insec(timecheck, beat), beat))
                 time.sleep(libs.datediff_insec(timecheck, beat) + 1)
     ''' 删除掉过旧的数据'''
     # 创建储存对象,将 DataFrame 放进对象中,并设置 key
     '''DataAgent.dbsession.query(Stock_poll).filter(Stock_poll.time_index<int(str_oldestViewDateTime)).delete()
     DataAgent.dbsession.query(Index_poll).filter(Index_poll.time_index<int(str_oldestViewDateTime)).delete()'''
     '''
     data_store = libs.tryOpenH5(cfg.H5_FILE_POLL,mode='a')
     try:
         df_toRemove = data_store['indexPoll'][data_store['indexPoll']['time_index']<=int(str_oldestViewDateTime)]
         if len(df_toRemove)>0:
             df_toKeep = data_store['indexPoll'][data_store['indexPoll']['time_index']>int(str_oldestViewDateTime)]
             data_store.put('indexPoll', df_toKeep,format='t')
             libs.log_csv(str_cat='INFO',str_op='poll',str_desc='{} rows of old index data removed from offline data'.format(len(df_toRemove)))
     except Exception as e:
         data_store.put('indexPoll', df_indexpoll,format='t')
         libs.log_csv(str_cat='INFO',str_op='poll',str_desc='{} ---- indexPoll dataset doesnot exist in datastore, new one created'.format(e.__class__.__name__))        
     try:
         df_toRemove = data_store['stockPoll'][data_store['stockPoll']['time_index']<=int(str_oldestViewDateTime)]
         if len(df_toRemove)>0:
             df_toKeep = data_store['stockPoll'][data_store['stockPoll']['time_index']>int(str_oldestViewDateTime)]
             data_store.put('stockPoll', df_toKeep,format='t')
             libs.log_csv(str_cat='INFO',str_op='poll',str_desc='{} rows of old stock ata removed from offline data'.format(len(df_toRemove))) 
     except Exception as e:
         data_store.put('stockPoll', df_indexpoll,format='t')
         libs.log_csv(str_cat='INFO',str_op='poll',str_desc='{} ---- stockPoll dataset doesnot exist in datastore, new one created'.format(e.__class__.__name__))   
     print(data_store.info())
     data_store.close()
     '''
     libs.log_csv(str_cat='INFO',
                  str_op='poll',
                  str_desc='Tsaisendo polling job ended...')
Exemple #7
0
    def candlechart(self,str_tscode=None,subset='masterCandle',dat_cursor=None,MA=[5,10,21], renderfile=False) -> Grid:
        str_tscode = DataAgent.formatCode(str_tscode)
        int_chartsize = 500
        if str_tscode == False or str_tscode is None:
            print('invalid sec code provided...')
            return False
        dat_cursor = datetime.now().astimezone(timezone(cfg.STR_TIMEZONE)) if dat_cursor is None else dat_cursor
        closestTradeDate = self.da.int_findClosestTradeDate(datetime.strftime(dat_cursor,'%Y%m%d') )
        tpl_dateindex = tuple(str(i) for i in self.da.df_calTbl.loc[self.da.df_calTbl['cal_date'] <= closestTradeDate]['cal_date'][-int_chartsize:] )

        # 连接储存对象
        if subset=='masterCandle': 
            data_store = libs.tryOpenH5(cfg.H5_FILE_PRE,mode='r')
        else:
            data_store = libs.tryOpenH5('{}{}.dat'.format(cfg.H5_FILE_PATH,subset),mode='r')
        
        # 初始化交易日表格,作为标准交易日序列join个股交易数据
        df_toPlot = data_store['masterCandle'].loc[data_store['masterCandle']['ts_code']==str_tscode]
        df_dateindex = pd.DataFrame({'trade_caldate': tpl_dateindex}).astype(int)
        data_store.close()
        try:
            str_secname = self.da.df_lookupTbl.loc[self.da.df_lookupTbl['ts_code']==str_tscode]['name'].values[0]
            str_sectype = self.da.df_lookupTbl.loc[self.da.df_lookupTbl['ts_code']==str_tscode]['sec_type'].values[0]
        except Exception as e:
            return libs.log_csv(str_cat='WARNING',str_op='candlechart',str_desc='security code {} does not exist in basic info table...'.format(str_tscode))
        str_plotname = '{} - {}'.format(str_tscode,str_secname)

        # 交易日时间轴标准化,补全停牌日,当日live数据等k线
        '''------ 获取实时交易数据部分--------------------'''
        int_liveDate = self.da.int_findClosestTradeDate(datetime.strftime(datetime.now().astimezone(timezone(cfg.STR_TIMEZONE)),'%Y%m%d') )
        if int_liveDate<=closestTradeDate and int_liveDate>df_toPlot['trade_date'].max():
            df_liveQuote = self.da.query('quote_now',[self.da.formatCode(str_tscode,False),])
            if len(df_liveQuote)>0:
                df_liveQuote.rename(columns={'open':'adj_open',
                                'high':'adj_high',
                                'low':'adj_low',
                                'price':'adj_close',
                                'volume':'vol',
                                'amount':'amount'}, inplace=True)
                df_liveQuote=df_liveQuote.astype(dtype= {'adj_open':'float','adj_high':'float','adj_low':'float','adj_close':'float','vol':'float','amount':'float'})                        
                df_liveQuote['trade_date'] = int_liveDate
                df_liveQuote['ts_code'] = str_tscode
                df_liveQuote['vol'] = df_liveQuote['vol']/100 if str_sectype==1 or str_tscode[:3]=='399' else  df_liveQuote['vol']
                df_liveQuote['amount'] = df_liveQuote['amount']/1000
            df_toPlot = df_toPlot.append(df_liveQuote[['ts_code','trade_date','adj_open','adj_high','adj_low','adj_close','vol','amount']],sort=False)
        '''------ 结束 获取实时交易数据部分--------------------'''

        df_toPlot = pd.merge(df_dateindex, df_toPlot, left_on='trade_caldate', right_on='trade_date', how='left')
        df_toPlot['close'].fillna(method='ffill',inplace=True)
        df_toPlot['ts_code'].fillna(method='ffill',inplace=True)
        df_toPlot['klineSML'].fillna('NNNN',inplace=True)
        df_toPlot['adj_close'].fillna(method='ffill',inplace=True)
        df_toPlot['vol'].fillna(value=0,inplace=True)
        df_toPlot['amount'].fillna(value=0,inplace=True)
        df_toPlot['open'].fillna(df_toPlot['close'],inplace=True)
        df_toPlot['high'].fillna(df_toPlot['close'],inplace=True)
        df_toPlot['low'].fillna(df_toPlot['close'],inplace=True)
        df_toPlot['adj_open'].fillna(df_toPlot['adj_close'],inplace=True)
        df_toPlot['adj_high'].fillna(df_toPlot['adj_close'],inplace=True)
        df_toPlot['adj_low'].fillna(df_toPlot['adj_close'],inplace=True)
        self.kchartdf = df_toPlot #输出至可访问对象属性中

        '''-----------------画图部分---------------------'''
        lst_ohlcv=df_toPlot.loc[:,['adj_open','adj_close','adj_low','adj_high']].values.tolist()
        lst_vol=list(df_toPlot['vol'].values)
        lst_amount=list(df_toPlot['amount'].values)
        lst_peaks=list(abs(df_toPlot['peaks'].values))
        # lst_pivotdown=[float('nan') if i<0 else i for i in list(df_toPlot['pivots'].values)]
        lst_pivotdown=[float('nan') if i<0 else i for i in list(df_toPlot['valid_pivots'].values)]
        # lst_pivotup=[float('nan') if i>0 else abs(i) for i in list(df_toPlot['pivots'].values)]
        lst_pivotup=[float('nan') if i>0 else abs(i) for i in list(df_toPlot['valid_pivots'].values)]
        lst_xaxis=list(df_toPlot['trade_caldate'].astype(str))

        def calculate_ma(day_count: int, d):
            result: List[Union[float, str]] = []
            for i in range(len(d)):
                if i < day_count:
                    result.append("-")
                    continue
                sum_total = 0.0
                for j in range(day_count):
                    sum_total += float(d[i - j][1])
                result.append(abs(float("%.3f" % (sum_total / day_count))))
            return result

        kline = (Kline()
            .add_xaxis(lst_xaxis)
            .add_yaxis(series_name=str_secname, y_axis=lst_ohlcv,
                        markpoint_opts=opts.MarkPointOpts(
                            data=[opts.MarkPointItem(type_="min",value_dim="close"),
                                opts.MarkPointItem(type_="max",value_dim="close")],
                            symbol_size = [20, 20], #表示标记宽为 20,高为 10
                        ),                           
                        itemstyle_opts=opts.ItemStyleOpts(
                            color="#ec0000",
                            color0="#00da3c",
                            border_color="#ec0000",
                            border_color0="#00da3c",
                        ),)
            .set_global_opts(
                title_opts=opts.TitleOpts(
                    title=str_plotname,
                    subtitle='MA='+str(MA),
                ),
                xaxis_opts=opts.AxisOpts(type_="category"),
                yaxis_opts=opts.AxisOpts(
                    is_scale=True,
                    splitarea_opts=opts.SplitAreaOpts(
                        is_show=True, areastyle_opts=opts.AreaStyleOpts(opacity=1)
                    ),
                ),
                legend_opts=opts.LegendOpts(is_show=True, pos_top='10%', pos_left="center"),
                datazoom_opts=[
                    opts.DataZoomOpts(
                        is_show=False,
                        type_="inside",
                        xaxis_index=[0,1,2],
                        range_start=75,
                        range_end=100,
                    ),
                    opts.DataZoomOpts(
                        is_show=True,
                        xaxis_index=[0,1,2],
                        type_="slider",
                        pos_top="90%",
                        range_start=75,
                        range_end=100,
                    ),
                ],
                tooltip_opts=opts.TooltipOpts(
                    trigger="axis",
                    axis_pointer_type="cross",
                    background_color="rgba(245, 245, 245, 0.8)",
                    border_width=1,
                    border_color="#ccc",
                    textstyle_opts=opts.TextStyleOpts(color="#000",font_size=10),
                ),
                # 阴量绿阳量红
                visualmap_opts=opts.VisualMapOpts(
                    is_show=False,
                    dimension=2,
                    series_index=list(map(lambda x: x+len(MA),[4,5])), #动态算出vol和amt柱状图的series index
                    is_piecewise=True,
                    pieces=[
                        {"value": 1, "color": "#ec0000"},
                        {"value": -1, "color": "#00da3c"},
                    ],
                ),  
                axispointer_opts=opts.AxisPointerOpts(
                    is_show=True,
                    link=[{"xAxisIndex": "all"}],
                    label=opts.LabelOpts(background_color="#777"),
                ),
                brush_opts=opts.BrushOpts(
                    x_axis_index="all",
                    brush_link="all",
                    out_of_brush={"colorAlpha": 0.1},
                    brush_type="lineX",
                ),
            )
        )
        trendline = (
            Line()
            .add_xaxis(lst_xaxis)
            .add_yaxis('高低点', lst_peaks,
                        itemstyle_opts=opts.ItemStyleOpts(color="green"))
        )
        for i in MA:
            if i is not None:
                trendline.add_yaxis(
                        series_name='MA'+str(i),
                        y_axis=calculate_ma(day_count=i, d=lst_ohlcv),
                        is_smooth=True,
                        is_hover_animation=False,
                        linestyle_opts=opts.LineStyleOpts(width=1, opacity=0.5),
                        label_opts=opts.LabelOpts(is_show=False),
                )
        trendline.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
        trendline.set_global_opts(legend_opts=opts.LegendOpts(is_show=False))
        
        keyPoints = (
            EffectScatter()
            .add_xaxis(lst_xaxis)
            .add_yaxis("末跌高", lst_pivotdown,symbol=SymbolType.ARROW,symbol_rotate=180,symbol_size=5,itemstyle_opts=opts.ItemStyleOpts(color="purple"))
            .add_yaxis("末升低", lst_pivotup,symbol=SymbolType.ARROW,symbol_size=5,itemstyle_opts=opts.ItemStyleOpts(color="blue"))
            .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
        )
        vol_bar = (
            Bar()
            .add_xaxis(lst_xaxis)
            .add_yaxis(
                series_name="交易量",
                yaxis_data=[
                [i, lst_vol[i], 1 if lst_ohlcv[i][0] < lst_ohlcv[i][1] else -1]
                for i in range(len(lst_vol))
                ],
                xaxis_index=1,
                yaxis_index=1,
                label_opts=opts.LabelOpts(is_show=False),
            )
            .set_global_opts(
                xaxis_opts=opts.AxisOpts(
                    type_="category",
                    is_scale=True,
                    grid_index=1,
                    boundary_gap=False,
                    axisline_opts=opts.AxisLineOpts(is_on_zero=False),
                    axistick_opts=opts.AxisTickOpts(is_show=False),
                    splitline_opts=opts.SplitLineOpts(is_show=False),
                    axislabel_opts=opts.LabelOpts(is_show=False),
                    split_number=20,
                    min_="最低",
                    max_="最高",
                ),
                yaxis_opts=opts.AxisOpts(
                    grid_index=1,
                    is_scale=True,
                    split_number=2,
                    axislabel_opts=opts.LabelOpts(is_show=False),
                    axisline_opts=opts.AxisLineOpts(is_show=False),
                    axistick_opts=opts.AxisTickOpts(is_show=False),
                    splitline_opts=opts.SplitLineOpts(is_show=False),
                ),
                legend_opts=opts.LegendOpts(is_show=False),
            )
            # .add_yaxis("交易量", lst_vol,itemstyle_opts=opts.ItemStyleOpts(color="#456A76"))
        )
        amnt_bar = (
            Bar()
            .add_xaxis(lst_xaxis)
            .add_yaxis(
                series_name="交易额",
                yaxis_data=[
                [i, lst_amount[i], 1 if lst_ohlcv[i][0] < lst_ohlcv[i][1] else -1]
                for i in range(len(lst_amount))
                ],
                xaxis_index=2,
                yaxis_index=2,
                label_opts=opts.LabelOpts(is_show=False),
            )
            .set_global_opts(
                xaxis_opts=opts.AxisOpts(
                    type_="category",
                    is_scale=True,
                    grid_index=2,
                    boundary_gap=False,
                    axisline_opts=opts.AxisLineOpts(is_on_zero=False),
                    axistick_opts=opts.AxisTickOpts(is_show=False),
                    splitline_opts=opts.SplitLineOpts(is_show=False),
                    axislabel_opts=opts.LabelOpts(is_show=False),
                    split_number=20,
                    min_="最低",
                    max_="最高",
                ),
                yaxis_opts=opts.AxisOpts(
                    grid_index=2,
                    is_scale=True,
                    split_number=2,
                    axislabel_opts=opts.LabelOpts(is_show=False),
                    axisline_opts=opts.AxisLineOpts(is_show=False),
                    axistick_opts=opts.AxisTickOpts(is_show=False),
                    splitline_opts=opts.SplitLineOpts(is_show=False),
                ),
                legend_opts=opts.LegendOpts(is_show=False),
            )
            # .add_yaxis("交易额", lst_amount,itemstyle_opts=opts.ItemStyleOpts(color="#456A76"))
        )
        priceChart = kline.overlap(trendline).overlap(keyPoints)
        gridChart = Grid()
        gridChart.add(
            priceChart,
            grid_opts=opts.GridOpts(pos_left="10%", pos_right="8%", pos_bottom='40%'),
        )
        gridChart.add(
            vol_bar,
            grid_opts=opts.GridOpts(pos_left="10%", pos_right="8%", pos_top="60%", height='15%'),
        )
        gridChart.add(
            amnt_bar,
            grid_opts=opts.GridOpts(pos_left="10%", pos_right="8%", pos_top="75%"),
        )

        fname = '{}{}.html'.format(cfg.PATH_ANAFILE,'kline')
        gridChart.render(fname) if renderfile else None
        self.kchart = gridChart # 将结果输出到analytics对象属性中用于function以外的调用
        return self