if 1:
    from   oneclass.onedb   import Onedb
    from   oneclass.onedata import Onedata
    import os,math,sys,time,re,json,datetime,requests,warnings,logging,xlrd,traceback
    import numpy as np
    import pandas as pd
    import tushare as ts
    from   sqlalchemy import create_engine
    import sqlalchemy  #初始化数据库连接，使用pymysql模块
    import pymysql
    import multiprocessing as mp
if 1:
    ts.set_token('8f6e67ec8a48922bbb531b95687625d99ee263940a07561ae95f4648')  # Tushare Pro
    pd.set_option('mode.chained_assignment', None)
    warnings.filterwarnings("ignore")
    durtime,durting1,FocusPeriod,uihandle,plock,showtype,havelistseq=0.001,0.5,0,0,0,1,1
    stockcode,mysqlhost="300027.SS","119.45.95.223"
    xgresult,qsresult,allstocklist=pd.DataFrame(),pd.DataFrame(),pd.DataFrame()
class Kdata():
    '''K线类 技术分析评分机制'''
    def __init__(self,stockcode,showtype,havelistseq,parent=None):
        super().__init__()                  #没有父类,是否需要
        self.allstocklist=pd.DataFrame()    #不需要被重复更新的数据
        self.init_parameter()               #需要被重复更新的数据
        self.onedb=Onedb()
        self.onedata=Onedata(1)
        '''自动运行'''
    def init_parameter(self):
        '''定义参数'''
        self.hp=0.0
        self.ttlup=0.0
        self.ttldown=0.0
        self.mstatus=0
        self.period  = ['month', 'week', 'day', 'm30', 'm5', 'm1']
        self.periodab  = ['m', 'w', 'd', 't', 'f', 'o']
        self.p2ab={'month':'m','week':'w','day':'d','m30':'t','m5':'f','m1':'o'}
        self.QSKJ    = [100, 50, 20, 10, 5, 2]  # 可以从config.ini设置
        self.diffbyp ={"month":0.08,"week":  0.04,"day":0.02   ,"m30":0.01   ,"m5":0.005   ,"m1":0.0025 }
        self.space   ={"month": 1,"week":0.2,"day":0.08,"m30":0.04,"m5":0.02,"m1":0.01}
        self.QS      ={"month":"","week":"","day":"","m30":"","m5":"","m1":""}
        self.JG      ={"month":"","week":"","day":"","m30":"","m5":"","m1":""}
        self.keypoint={"QS":0,"NDG":0,"NKL":0,"DD":0,"Kai":0,"GG":0,"Luo":0,"CHL1":0,"DDCGorGGCD1":0,"CHL":0,"DDCGorGGCD":0,"DDCGorGGCD1ma30":0,"DDCGorGGCDma30":0,"GGday":0,"DDday":0}
        self.kdata_m = pd.DataFrame()  # K线数据库 
        self.kdata_w = pd.DataFrame()
        self.kdata_d = pd.DataFrame()
        self.kdata_t = pd.DataFrame()
        self.kdata_f = pd.DataFrame()
        self.kdata_o = pd.DataFrame()
        #趋势结果 - to Mysql
        self.QS_m = {}
        self.QS_w = {}
        self.QS_d = {}
        self.QS_t = {}
        self.QS_f = {}
        self.QS_o = {}
        #结构结果 - to Mysql
        self.JG_m = {}
        self.JG_w = {}
        self.JG_d = {}
        self.JG_t = {}
        self.JG_f = {}
        self.JG_o = {}
        #???
        self.all_YLZC = {}
        self.PnS = {} 
        #???
        self.pns=pd.DataFrame()
        self.pnsttl=pd.DataFrame()
        self.newpnsttl=pd.DataFrame()
        self.refreshK_timeinter=10000
        self.stockcode = stockcode  # 股票代码 300027.S
        self.showtype=showtype      # 显示什么内容
        self.havelistseq=havelistseq
        self.sig=1                  # 信号
        self.havelist=pd.DataFrame()
        self.xgresult=pd.DataFrame()
        self.qsresult=pd.DataFrame() 
    def run(self):
        self.whole_process()
    def whole_process(self):
        self.get_div()          #取除权数据
        self.get_K_all()        #下载所有周期K线数据
        self.cal_ma_all()       #计算所有周期ma
        self.cal_qs_all()       #计算所有周期的趋势和结构数据
    def thread_it(self, func, *args):  # '''将函数放入线程中执行''' #有两个参数 1，函数名称 func 2,函数变量 **args
        task = threading.Thread(target=func, args=args)  # 创建线程
        task.setDaemon(True)  # 守护线程
        task.start()

    def xg_all_mp(self):
        #计算所有股票
        starttime=time.time()
        self.xgresult=pd.DataFrame()
        self.qsresult=pd.DataFrame()
        corelist=[0]
        
        pro = ts.pro_api()
        stocklist = pro.query('stock_basic', exchange='', list_status='L')
        stocklist = pd.concat([stocklist, pd.DataFrame([{'ts_code': "000001.SH", 'name': "上证综指"}])], ignore_index=True)                        
        stocklist = pd.concat([stocklist, pd.DataFrame([{'ts_code': "399006.SZ", 'name': "创业板指"}])], ignore_index=True)
        stocklist = pd.concat([stocklist, pd.DataFrame([{'ts_code': "399001.SZ", 'name': "深圳成指"}])], ignore_index=True)
        self.allstocklist=stocklist#[-1600:]
        print(self.allstocklist)

        #stocklist = pd.read_csv(r"./csv/2022.csv")
        stockqty=self.allstocklist.shape[0]
        qtyperjob=100
        coreqty=math.ceil(stockqty/qtyperjob)
        for i in range(1,coreqty):
            corelist.append(i*100)
        print("XXXX corelist",corelist)
        threadqty=16
        pool=mp.Pool(threadqty)
        qtyperthread=math.ceil(stockqty/threadqty)
        print("qtyperthread",qtyperthread)
        #corelist=[0,400,800,1200,1600,2000,2400,2800,3200,3600,4000,4400]
        result=pool.map(self.xg_all_for_mp,corelist)
        a,b=zip(*result)
        for i in range(len(a)):
            self.xgresult=pd.concat([self.xgresult, a[i]], ignore_index=True)
            self.qsresult=pd.concat([self.qsresult, b[i]], ignore_index=True)
        self.xgresult = self.xgresult.replace([np.inf, -np.inf], 0)
        self.qsresult = self.qsresult.replace([np.inf, -np.inf], 0)
        onedb=Onedb()
        onedb.del_table("xgall")
        onedb.del_table("qsall")
        onedb.into_table(self.xgresult,"xgall","stockcode",9)
        onedb.into_table(self.qsresult,"qsall","stockcode",9)
        print("TTL time:", time.time()-starttime)
    def xg_all_for_mp(self,n):
        xgresult=pd.DataFrame()
        qsresult=pd.DataFrame()
        stocklist = self.allstocklist
        stocklist=stocklist[n:n+100]
        print("stock qty =", stocklist.shape[0])
        i=1
        for index,row in stocklist.iterrows():
            self.stockcode=row['ts_code']
            print(i,self.stockcode)
            if self.stockcode[-3:]==".BJ":
                self.onedata=Onedata(0)
            else:
                self.onedata=Onedata(1)
            '''
            self.get_div()
            try:
                self.get_K_D()
                #self.get_K_D_csv()
            except:
                continue
            if self.kdata_d.shape[0]==0: continue
            #self.kdata_d=self.wash_K_div(self.kdata_d)
            #self.get_K_MW()
            self.get_K_w()
            self.get_K_m()
            self.kdata_d=self.kdata_d[-300:]            #缩减日K线数量以加速计算
            try:
                self.kdata_t=self.get_K_TFO('m30')          #得到30分钟数据
                #self.get_K_T_csv()
                self.kdata_t=self.wash_K_div(self.kdata_t)
            except:
                continue
            try:
                self.kdata_f=self.get_K_TFO('m5')           #得到5分钟数据
                #self.get_K_F_csv()
                self.kdata_f=self.wash_K_div(self.kdata_f)
            except:
                continue
            try:
                self.kdata_o=self.get_K_TFO('m1')           #得到1分钟数据
                #self.get_K_O_csv()
                self.kdata_o=self.wash_K_div(self.kdata_o)
            except:
                continue
            '''
            try:
                self.kdata_o,self.kdata_f,self.kdata_t,self.kdata_d,self.kdata_w,self.kdata_m=self.onedata.k(self.stockcode,"all")
            except:
                continue
            #only cal ma
            self.cal_ma_all()
            '''
            self.kdata_m = self.cal_ma_K(self.kdata_m)
            self.kdata_w = self.cal_ma_K(self.kdata_w)
            self.kdata_d = self.cal_ma_K(self.kdata_d)
            self.kdata_t = self.cal_ma_K(self.kdata_t)
            self.kdata_f = self.cal_ma_K(self.kdata_f)
            self.kdata_o = self.cal_ma_K(self.kdata_o)
            '''
            #only cal QS
            self.kdata_m,self.QS_m,self.JG_m = self.cal_qs(self.kdata_m, self.stockcode, 'month')
            self.kdata_w,self.QS_w,self.JG_w = self.cal_qs(self.kdata_w, self.stockcode, 'week')
            self.kdata_d,self.QS_d,self.JG_d = self.cal_qs(self.kdata_d, self.stockcode, 'day')
            self.kdata_t,self.QS_t,self.JG_t = self.cal_qs(self.kdata_t, self.stockcode, 'm30')
            self.kdata_f,self.QS_f,self.JG_f = self.cal_qs(self.kdata_f, self.stockcode, 'm5')
            self.kdata_o,self.QS_o,self.JG_o = self.cal_qs(self.kdata_o, self.stockcode, 'm1')

            print(self.QS['month'],self.QS['week'],self.QS['day'],self.QS['m30'],self.QS['m5'],self.QS['m1'])
            if 1: #try:
                tmp={'scode':self.stockcode[0:6],'stockcode':self.stockcode,'stockname':row['name'],'time':self.QS_t['reviseTime'],'c':self.QS_t['C'],\
                     'QSm':self.QS['month'],'QSw':self.QS['week'],'QSd':self.QS['day'],'QSt':self.QS['m30'],'QSf':self.QS['m5'],'QSo':self.QS['m1'],\
                     'ma30m':self.QS_m['ma30'],'ma30w':self.QS_w['ma30'],'ma30d':self.QS_d['ma30'],'ma30t':self.QS_t['ma30'],'ma30f':self.QS_f['ma30'],'ma30o':self.QS_o['ma30'],\
                     'ma10m':self.QS_m['ma10'],'ma10w':self.QS_w['ma10'],'ma10d':self.QS_d['ma10'],'ma10t':self.QS_t['ma10'],'ma10f':self.QS_f['ma10'],'ma10o':self.QS_o['ma10'],\
                     'spacePm':self.QS_m['spaceP'],'profitPm':self.QS_m['profitP'],'riskPm':self.QS_m['riskP'],\
                     'NDGm':self.QS_m['NDG'],'NKLm':self.QS_m['NKL'],'DDm':self.QS_m['DD'],'Kaim':self.QS_m['Kai'],'GGm':self.QS_m['GG'],'Luom':self.QS_m['Luo'],\
                     'CHL1m':self.QS_m['CHL1'],'DDCGorGGCD1m':self.QS_m['DDCGorGGCD1'], 'CHLm':self.QS_m['CHL'],'DDCGorGGCDm':self.QS_m['DDCGorGGCD'],
                     'spacePw':self.QS_w['spaceP'],'profitPw':self.QS_w['profitP'],'riskPw':self.QS_w['riskP'],\
                     'NDGw':self.QS_w['NDG'],'NKLw':self.QS_w['NKL'],'DDw':self.QS_w['DD'],'Kaiw':self.QS_w['Kai'],'GGw':self.QS_w['GG'],'Luow':self.QS_w['Luo'],\
                     'CHL1w':self.QS_w['CHL1'],'DDCGorGGCD1w':self.QS_w['DDCGorGGCD1'], 'CHLw':self.QS_w['CHL'],'DDCGorGGCDw':self.QS_m['DDCGorGGCD'],
                     'spacePd':self.QS_d['spaceP'],'profitPd':self.QS_d['profitP'],'riskPd':self.QS_d['riskP'],\
                     'NDGd':self.QS_d['NDG'],'NKLd':self.QS_d['NKL'],'DDd':self.QS_d['DD'],'Kaid':self.QS_d['Kai'],'GGd':self.QS_d['GG'],'Luod':self.QS_d['Luo'],\
                     'CHL1d':self.QS_d['CHL1'],'DDCGorGGCD1d':self.QS_d['DDCGorGGCD1'], 'CHLd':self.QS_d['CHL'],'DDCGorGGCDd':self.QS_d['DDCGorGGCD'],
                     'spacePt':self.QS_t['spaceP'],'profitPt':self.QS_t['profitP'],'riskPt':self.QS_t['riskP'],\
                     'NDGt':self.QS_t['NDG'],'NKLt':self.QS_t['NKL'],'DDt':self.QS_t['DD'],'Kait':self.QS_t['Kai'],'GGt':self.QS_t['GG'],'Luot':self.QS_t['Luo'],\
                     'CHL1t':self.QS_t['CHL1'],'DDCGorGGCD1t':self.QS_t['DDCGorGGCD1'], 'CHLt':self.QS_t['CHL'],'DDCGorGGCDt':self.QS_t['DDCGorGGCD'],
                     'spacePf':self.QS_f['spaceP'],'profitPf':self.QS_f['profitP'],'riskPf':self.QS_f['riskP'],\
                     'NDGf':self.QS_f['NDG'],'NKLf':self.QS_f['NKL'],'DDf':self.QS_f['DD'],'Kaif':self.QS_f['Kai'],'GGf':self.QS_f['GG'],'Luof':self.QS_f['Luo'],\
                     'CHL1f':self.QS_f['CHL1'],'DDCGorGGCD1f':self.QS_f['DDCGorGGCD1'], 'CHLf':self.QS_f['CHL'],'DDCGorGGCDf':self.QS_f['DDCGorGGCD'],
                     'spacePo':self.QS_o['spaceP'],'profitPo':self.QS_o['profitP'],'riskPo':self.QS_o['riskP'],\
                     'NDGo':self.QS_o['NDG'],'NKLo':self.QS_o['NKL'],'DDo':self.QS_o['DD'],'Kaio':self.QS_o['Kai'],'GGo':self.QS_o['GG'],'Luoo':self.QS_o['Luo'],\
                     'CHL1o':self.QS_o['CHL1'],'DDCGorGGCD1o':self.QS_o['DDCGorGGCD1'], 'CHLo':self.QS_o['CHL'],'DDCGorGGCDo':self.QS_o['DDCGorGGCD'],\
                     'ConfirmedJGm':self.JG_m['ConfirmedJG'],'CurrentJGm':self.JG_m['CurrentJG'],'JGdonem':self.JG_m['JGdone'],'QXm':self.JG_m['QX'],'JGQRm':self.JG_m['JGQR'],\
                     'ConfirmedJGw':self.JG_w['ConfirmedJG'],'CurrentJGw':self.JG_w['CurrentJG'],'JGdonew':self.JG_w['JGdone'],'QXw':self.JG_w['QX'],'JGQRw':self.JG_w['JGQR'],\
                     'ConfirmedJGd':self.JG_d['ConfirmedJG'],'CurrentJGd':self.JG_d['CurrentJG'],'JGdoned':self.JG_d['JGdone'],'QXd':self.JG_d['QX'],'JGQRd':self.JG_d['JGQR'],\
                     'ConfirmedJGt':self.JG_t['ConfirmedJG'],'CurrentJGt':self.JG_t['CurrentJG'],'JGdonet':self.JG_t['JGdone'],'QXt':self.JG_t['QX'],'JGQRt':self.JG_t['JGQR'],\
                     'ConfirmedJGf':self.JG_f['ConfirmedJG'],'CurrentJGf':self.JG_f['CurrentJG'],'JGdonef':self.JG_f['JGdone'],'QXf':self.JG_f['QX'],'JGQRf':self.JG_f['JGQR'],\
                     'ConfirmedJGo':self.JG_o['ConfirmedJG'],'CurrentJGo':self.JG_o['CurrentJG'],'JGdoneo':self.JG_o['JGdone'],'QXo':self.JG_o['QX'],'JGQRo':self.JG_o['JGQR'],\
                     'hp':self.hp,'ttlup':self.ttlup,'ttldown':self.ttldown,'mstatus':self.mstatus
                    }
                #for key,value in tmp.items():
                #    if 1: #try:
                #        if value>1000:
                #            value=round(value)
                #            tmp[key]=value
                    #except:
                    #    print("error stockcode",self.stockcode)
                    #    pass
                xgresult=pd.concat([xgresult, tmp], ignore_index=True)
            #except:
            #    pass
            qsresult=pd.concat([qsresult, self.QS_m], ignore_index=True)
            qsresult=pd.concat([qsresult, self.QS_w], ignore_index=True)
            qsresult=pd.concat([qsresult, self.QS_d], ignore_index=True)
            qsresult=pd.concat([qsresult, self.QS_t], ignore_index=True)
            qsresult=pd.concat([qsresult, self.QS_f], ignore_index=True)
            qsresult=pd.concat([qsresult, self.QS_o], ignore_index=True)
            i+=1
            self.init_parameter()
        return xgresult,qsresult

    def xg_2022_mp(self): 
        #计算2022中的股票
        starttime=time.time()
        self.xgresult=pd.DataFrame()
        self.qsresult=pd.DataFrame()
        #result=pd.DataFrame()
        stocklist = pd.read_csv(r"./csv/2022.csv")
        print(f"former qty = {stocklist.shape[0]}")
        stocklist=stocklist.drop_duplicates(['stockcode'])
        print(f"former qty = {stocklist.shape[0]}")
        stockqty=stocklist.shape[0]
        threadqty=6
        pool=mp.Pool(threadqty)
        qtyperthread=math.ceil(stockqty/threadqty)
        print("qtyperthread",qtyperthread)
        #corelist=[0,10,20,30,40,50]
        corelist=[0,30,60,90,120,150]
        print(corelist)
        #self.xgresult=self.xgresult.append(pool.map(self.xg_2022_for_mp,corelist))
        result=pool.map(self.xg_2022_for_mp,corelist)
        a,b=zip(*result)
        for i in range(len(a)):
            self.xgresult=self.xgresult.append(a[i])
            self.qsresult=self.qsresult.append(b[i])
        self.xgresult = self.xgresult.replace([np.inf, -np.inf], 0)
        self.qsresult = self.qsresult.replace([np.inf, -np.inf], 0)
        onedb=Onedb()
        
        onedb.del_table("xg2022")
        onedb.del_table("qs2022")

        onedb.into_table(self.xgresult,"xg2022","stockcode",9)
        onedb.into_table(self.qsresult,"qs2022","stockcode",9)

        onedb.execute_sql("delete `xgall` from `xgall`,`xg2022` where `xgall`.`stockcode`=`xg2022`.`stockcode`")
        onedb.into_table(self.xgresult,"xgall","stockcode",9)
        
        #onedb.execute_sql("select * from xgall a left join xg2022 b on a.stockcode=b.stockcode where b.stockcode is NULL")
        #onedb.into_table(self.xgresult,"xgall","stockcode",9)
        #self.xgresult.to_csv(rf"./tmpout/xg2022.csv",encoding="utf_8_sig",index=True)
        #self.qsresult.to_csv(rf"./tmpout/qs2022.csv",encoding="utf_8_sig",index=True)
        #_=input("export here")
        #self.xg_2022_after_mp()
        print("TTL time:", time.time()-starttime)
    def xg_2022_for_mp(self,n):
        xgresult=pd.DataFrame()
        qsresult=pd.DataFrame()
        stocklist = pd.read_csv(r"./csv/2022.csv")
        stocklist=stocklist.drop_duplicates(['stockcode'])
        stocklist=stocklist[n:n+30]
        print("stock qty =", stocklist.shape[0])
        for index,stock in stocklist.iterrows():
            if len(stock['stockcode'])<9:
                if stock['stockcode'][1:2]=="3" or stock['stockcode'][1:2]=="0":
                    stock['stockcode']=stock['stockcode'][1:7]+".SZ"
                elif stock['stockcode'][1:2]=="6":
                    stock['stockcode']=stock['stockcode'][1:7]+".SH"
                elif stock['stockcode'][1:2]=="8" or stock['stockcode'][1:2]=="4":
                    stock['stockcode']=stock['stockcode'][1:7]+".BJ"
            else:
                stock['stockcode']=stock['stockcode'][1:10]
        i=1
        for index,row in stocklist.iterrows():
            self.stockcode=row['stockcode']
            print(i,self.stockcode)
            if self.stockcode[-3:]==".BJ":
                self.onedata=Onedata(0)
            else:
                self.onedata=Onedata(1)
            '''
            self.get_div()
            try:
                self.get_K_D()
            except:
                continue
            if self.kdata_d.shape[0]==0: continue
            #self.kdata_d=self.wash_K_div(self.kdata_d)
            #self.get_K_MW()
            self.get_K_w()
            self.get_K_m()
            self.kdata_d=self.kdata_d[-300:]            #缩减日K线数量以加速计算
            self.kdata_t=self.get_K_TFO('m30')          #得到30分钟数据
            self.kdata_t=self.wash_K_div(self.kdata_t)
            self.kdata_f=self.get_K_TFO('m5')           #得到5分钟数据
            self.kdata_f=self.wash_K_div(self.kdata_f)
            self.kdata_o=self.get_K_TFO('m1')           #得到1分钟数据
            self.kdata_o=self.wash_K_div(self.kdata_o)
            '''
            #'''
            try:
                self.kdata_o,self.kdata_f,self.kdata_t,self.kdata_d,self.kdata_w,self.kdata_m=self.onedata.k(self.stockcode,"all")
            except:
                continue
            #'''
            #only cal ma
            '''
            self.kdata_m = self.cal_ma_K(self.kdata_m)
            self.kdata_w = self.cal_ma_K(self.kdata_w)
            self.kdata_d = self.cal_ma_K(self.kdata_d)
            self.kdata_t = self.cal_ma_K(self.kdata_t)
            self.kdata_f = self.cal_ma_K(self.kdata_f)
            self.kdata_o = self.cal_ma_K(self.kdata_o)
            '''
            self.cal_ma_all()
            #only cal QS
            self.kdata_m,self.QS_m,self.JG_m = self.cal_qs(self.kdata_m, self.stockcode, 'month')
            self.kdata_w,self.QS_w,self.JG_w = self.cal_qs(self.kdata_w, self.stockcode, 'week')
            self.kdata_d,self.QS_d,self.JG_d = self.cal_qs(self.kdata_d, self.stockcode, 'day')
            self.kdata_t,self.QS_t,self.JG_t = self.cal_qs(self.kdata_t, self.stockcode, 'm30')
            self.kdata_f,self.QS_f,self.JG_f = self.cal_qs(self.kdata_f, self.stockcode, 'm5')
            self.kdata_o,self.QS_o,self.JG_o = self.cal_qs(self.kdata_o, self.stockcode, 'm1')
            
            #print("periodJG_m",self.JG_m,self.JG_w)

            print(self.QS['month'],self.QS['week'],self.QS['day'],self.QS['m30'],self.QS['m5'],self.QS['m1'])
            try:
                #[ttl:93]代码/名称/修改时间/趋势信号[6mwdtfo]
                #/趋势数据[84spaceP/profitP/riskP/NDG/NKL/DD/Kai/GG/Luo/CHL1/DDCGorGGCD/CHL/DDCGorGGCD/C[mwdtfo]
                #print("self.QS_m",self.stockcode,self.QS_m)
                tmp={'scode':self.stockcode[0:6],'stockcode':self.stockcode,'stockname':row['name'],'time':self.QS_t['reviseTime'],'c':self.QS_t['C'],\
                     'QSm':self.QS['month'],'QSw':self.QS['week'],'QSd':self.QS['day'],'QSt':self.QS['m30'],'QSf':self.QS['m5'],'QSo':self.QS['m1'],\
                     'ma30m':self.QS_m['ma30'],'ma30w':self.QS_w['ma30'],'ma30d':self.QS_d['ma30'],'ma30t':self.QS_t['ma30'],'ma30f':self.QS_f['ma30'],'ma30o':self.QS_o['ma30'],\
                     'ma10m':self.QS_m['ma10'],'ma10w':self.QS_w['ma10'],'ma10d':self.QS_d['ma10'],'ma10t':self.QS_t['ma10'],'ma10f':self.QS_f['ma10'],'ma10o':self.QS_o['ma10'],\
                     'spacePm':self.QS_m['spaceP'],'profitPm':self.QS_m['profitP'],'riskPm':self.QS_m['riskP'],\
                     'NDGm':self.QS_m['NDG'],'NKLm':self.QS_m['NKL'],'DDm':self.QS_m['DD'],'Kaim':self.QS_m['Kai'],'GGm':self.QS_m['GG'],'Luom':self.QS_m['Luo'],\
                     'CHL1m':self.QS_m['CHL1'],'DDCGorGGCD1m':self.QS_m['DDCGorGGCD1'], 'CHLm':self.QS_m['CHL'],'DDCGorGGCDm':self.QS_m['DDCGorGGCD'],
                     'spacePw':self.QS_w['spaceP'],'profitPw':self.QS_w['profitP'],'riskPw':self.QS_w['riskP'],\
                     'NDGw':self.QS_w['NDG'],'NKLw':self.QS_w['NKL'],'DDw':self.QS_w['DD'],'Kaiw':self.QS_w['Kai'],'GGw':self.QS_w['GG'],'Luow':self.QS_w['Luo'],\
                     'CHL1w':self.QS_w['CHL1'],'DDCGorGGCD1w':self.QS_w['DDCGorGGCD1'], 'CHLw':self.QS_w['CHL'],'DDCGorGGCDw':self.QS_m['DDCGorGGCD'],
                     'spacePd':self.QS_d['spaceP'],'profitPd':self.QS_d['profitP'],'riskPd':self.QS_d['riskP'],\
                     'NDGd':self.QS_d['NDG'],'NKLd':self.QS_d['NKL'],'DDd':self.QS_d['DD'],'Kaid':self.QS_d['Kai'],'GGd':self.QS_d['GG'],'Luod':self.QS_d['Luo'],\
                     'CHL1d':self.QS_d['CHL1'],'DDCGorGGCD1d':self.QS_d['DDCGorGGCD1'], 'CHLd':self.QS_d['CHL'],'DDCGorGGCDd':self.QS_d['DDCGorGGCD'],
                     'spacePt':self.QS_t['spaceP'],'profitPt':self.QS_t['profitP'],'riskPt':self.QS_t['riskP'],\
                     'NDGt':self.QS_t['NDG'],'NKLt':self.QS_t['NKL'],'DDt':self.QS_t['DD'],'Kait':self.QS_t['Kai'],'GGt':self.QS_t['GG'],'Luot':self.QS_t['Luo'],\
                     'CHL1t':self.QS_t['CHL1'],'DDCGorGGCD1t':self.QS_t['DDCGorGGCD1'], 'CHLt':self.QS_t['CHL'],'DDCGorGGCDt':self.QS_t['DDCGorGGCD'],
                     'spacePf':self.QS_f['spaceP'],'profitPf':self.QS_f['profitP'],'riskPf':self.QS_f['riskP'],\
                     'NDGf':self.QS_f['NDG'],'NKLf':self.QS_f['NKL'],'DDf':self.QS_f['DD'],'Kaif':self.QS_f['Kai'],'GGf':self.QS_f['GG'],'Luof':self.QS_f['Luo'],\
                     'CHL1f':self.QS_f['CHL1'],'DDCGorGGCD1f':self.QS_f['DDCGorGGCD1'], 'CHLf':self.QS_f['CHL'],'DDCGorGGCDf':self.QS_f['DDCGorGGCD'],
                     'spacePo':self.QS_o['spaceP'],'profitPo':self.QS_o['profitP'],'riskPo':self.QS_o['riskP'],\
                     'NDGo':self.QS_o['NDG'],'NKLo':self.QS_o['NKL'],'DDo':self.QS_o['DD'],'Kaio':self.QS_o['Kai'],'GGo':self.QS_o['GG'],'Luoo':self.QS_o['Luo'],\
                     'CHL1o':self.QS_o['CHL1'],'DDCGorGGCD1o':self.QS_o['DDCGorGGCD1'], 'CHLo':self.QS_o['CHL'],'DDCGorGGCDo':self.QS_o['DDCGorGGCD'],\
                     'ConfirmedJGm':self.JG_m['ConfirmedJG'],'CurrentJGm':self.JG_m['CurrentJG'],'JGdonem':self.JG_m['JGdone'],'QXm':self.JG_m['QX'],'JGQRm':self.JG_m['JGQR'],\
                     'ConfirmedJGw':self.JG_w['ConfirmedJG'],'CurrentJGw':self.JG_w['CurrentJG'],'JGdonew':self.JG_w['JGdone'],'QXw':self.JG_w['QX'],'JGQRw':self.JG_w['JGQR'],\
                     'ConfirmedJGd':self.JG_d['ConfirmedJG'],'CurrentJGd':self.JG_d['CurrentJG'],'JGdoned':self.JG_d['JGdone'],'QXd':self.JG_d['QX'],'JGQRd':self.JG_d['JGQR'],\
                     'ConfirmedJGt':self.JG_t['ConfirmedJG'],'CurrentJGt':self.JG_t['CurrentJG'],'JGdonet':self.JG_t['JGdone'],'QXt':self.JG_t['QX'],'JGQRt':self.JG_t['JGQR'],\
                     'ConfirmedJGf':self.JG_f['ConfirmedJG'],'CurrentJGf':self.JG_f['CurrentJG'],'JGdonef':self.JG_f['JGdone'],'QXf':self.JG_f['QX'],'JGQRf':self.JG_f['JGQR'],\
                     'ConfirmedJGo':self.JG_o['ConfirmedJG'],'CurrentJGo':self.JG_o['CurrentJG'],'JGdoneo':self.JG_o['JGdone'],'QXo':self.JG_o['QX'],'JGQRo':self.JG_o['JGQR'],\
                     'hp':self.hp,'ttlup':self.ttlup,'ttldown':self.ttldown,'mstatus':self.mstatus
                    }
                for key,value in tmp.items():
                    try:
                        if value>1000:
                            value=round(value)
                            tmp[key]=value
                    except:
                        pass
                #print("tmp",tmp)
                xgresult=xgresult.append(tmp,ignore_index=True)
            except:
                pass
            qsresult=qsresult.append(self.QS_m,ignore_index=True)
            qsresult=qsresult.append(self.QS_w,ignore_index=True)
            qsresult=qsresult.append(self.QS_d,ignore_index=True)
            qsresult=qsresult.append(self.QS_t,ignore_index=True)
            qsresult=qsresult.append(self.QS_f,ignore_index=True)
            qsresult=qsresult.append(self.QS_o,ignore_index=True)
            #print("qsresult",qsresult)
            i+=1
            self.init_parameter()
            #print("xgresult inside mp",xgresult)
        return xgresult,qsresult
        #xgresult.to_cs v(rf"./tmpout/2022result.csv",encoding="utf_8_sig",index=True)
    def xg_2022_after_mp(self):
        #print("self.xgresult after mp",self.xgresult)
        newlist=pd.DataFrame()
        newlistt=pd.DataFrame()
        for key,stock in self.xgresult.iterrows():
            if "-1abc" in stock.day or "-1abc" in stock.m30:
                newlist=pd.concat([newlist, pd.DataFrame([stock])], ignore_index=True)
            if "-1a" in stock.m30 or "-2" in stock.m30:
                newlistt=pd.concat([newlistt, pd.DataFrame([stock])], ignore_index=True)
        print("day -1abc and m30 -1abc")
        print(newlist)
        print("m30 -1a or m30 -2:")
        print(newlistt)
        
    def xg_havelist(self):
        global xgresult
        mycode=pd.DataFrame()
        starttime=time.time()
        print(self.havelist)
        stocklist=self.havelist
        for index,stock in stocklist.iterrows():
            if stock['code'][:1]=="3" or stock['code'][:1]=="0":
                stock['code']=stock['code'][:6]+".SZ"
                mycode=mycode.append(stock)
            if stock['code'][:1]=="6":
                stock['code']=stock['code'][:6]+".SH"
                mycode=mycode.append(stock)
            if stock['code'][:1]=="8" or stock['code'][:1]=="4":
                stock['code']=stock['code'][:6]+".BJ"
                mycode=mycode.append(stock)
        print(mycode)
        for index,row in mycode.iterrows():
            self.stockcode=row['code']
            self.run()
            print("in xg_havelist")
            print(self.newpnsttl)
            self.init_parameter()
        print("TTL time:", time.time()-starttime)

    def export(self):
        # 输出所有K线数据(除权后的)到kdata/文件夹下
        self.kdata_m.to_csv(rf"./kdata/kdata_m.csv", encoding="utf_8_sig", index=True)
        self.kdata_w.to_csv(rf"./kdata/kdata_w.csv", encoding="utf_8_sig", index=True)
        self.kdata_d.to_csv(rf"./kdata/kdata_d.csv", encoding="utf_8_sig", index=True)
        self.kdata_t.to_csv(rf"./kdata/kdata_t.csv", encoding="utf_8_sig", index=True)
        self.kdata_f.to_csv(rf"./kdata/kdata_f.csv", encoding="utf_8_sig", index=True)
        self.kdata_o.to_csv(rf"./kdata/kdata_o.csv", encoding="utf_8_sig", index=True)
        logging.info("fake export K data done!")

    def show_log(self):
        logging.info("fake show_log done!")

    def get_div_fromdb(self):
        #从onedb取除权数据 并 存放到 ./csv/divdata.csv
        #每天早上执行一次,当天就不用重复执行
        #是否需要重新索引和重新排序???
        #应该是在读取SPLIT.PWR并存放到db前,做索引和排序的工作
        print("start get_divdata_fromdb")
        onedb=Onedb()
        mydiv = onedb.From_table("select * from divdata")
        mydiv.to_csv(rf"./csv/divdata.csv",encoding="utf_8_sig",index=False)
        print("end get_divdata_fromdb")

    def get_div(self):
        #从csv/divdata.csv读取当前分析股票的除权数据
        self.divpd = pd.read_csv(r"./csv/divdata.csv")
        self.divpd = self.divpd[self.divpd['code'] == self.stockcode]
        self.divpd['date'] = pd.to_datetime(self.divpd['date'])
        self.divpd = self.divpd.set_index('date')
        self.divpd = self.divpd.sort_index(ascending=False)

    def wash_K_div(self,kdata):
        #使用除权数据清洗K线
        #self.divpd['date'] = pd.to_datetime(self.divpd['date'])
        #self.divpd = self.divpd.set_index('date')
        #self.divpd = self.divpd.sort_index(ascending=False)
        #self.divpd中有没有数据
        for key, val in self.divpd.iterrows():
            date = key - datetime.timedelta(minutes=1)
            if date < kdata.index[0]: break
            for field in kdata.columns.values:
                if field != 'volume' and field != 'amount':  # open	close	high	low	    vol
                    kdata.loc[:date, field] -= val.bonus / 10
                    kdata.loc[:date, field] += val.price * (val.rationed / 10)
                    kdata.loc[:date:, field] /= 1 + val.present / 10 + val.rationed / 10
        return kdata
    
    def get_K_all(self):
        #多线程一次性获取6个周期的K线数据，并存放到6个dataframe中
        self.get_K_D()
        self.get_K_w()
        self.get_K_m()
        #self.kdata_d=self.wash_K_div(self.kdata_d)
        #self.get_K_MW()
        self.kdata_d=self.kdata_d[-300:]            #缩减日K线数量以加速计算
        self.kdata_t=self.get_K_TFO('m30')          #得到30分钟数据
        self.kdata_t=self.wash_K_div(self.kdata_t)
        self.kdata_f=self.get_K_TFO('m5')           #得到5分钟数据
        self.kdata_f=self.wash_K_div(self.kdata_f)
        self.kdata_o=self.get_K_TFO('m1')           #得到1分钟数据
        self.kdata_o=self.wash_K_div(self.kdata_o)

    def get_K_D(self):
        my_k=0
        urlstockcode = self.stockcode[-2:].lower() + self.stockcode[:6]
        # http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param=sz300027,month,1990-12-01,,10240,qfq
        #url = rf'http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param={urlstockcode},day,1990-12-01,,10240,bfq'
        url = rf'http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param={urlstockcode},day,1990-12-01,,2000,qfq'
        originaltxt = self.gethtml(url)
        goodtxt = re.sub(',{(.+?)}]', ']', originaltxt)

        my_json = json.loads(goodtxt)
        #my_k = my_json['data'][urlstockcode]['day']
        if not(urlstockcode=="sz399001" or urlstockcode=="sz399006" or urlstockcode=="sh000001"):
            my_k = my_json['data'][urlstockcode]['qfqday']
        else:
            my_k = my_json['data'][urlstockcode]['day']
        
        arrayk = np.array(my_k)
        self.kdata_d = pd.DataFrame(arrayk, columns=['date', 'open', 'close', 'high', 'low', 'vol'])  # ???ul1
        self.kdata_d[['open', 'close', 'high', 'low']] = self.kdata_d[['open', 'close', 'high', 'low']].apply(pd.to_numeric).round(2)
        self.kdata_d['vol'] = self.kdata_d['vol'].apply(pd.to_numeric).astype(int)  # vol 转换为 整型
        self.kdata_d['date'] = pd.to_datetime(self.kdata_d['date'])
        self.kdata_d.set_index(["date"], inplace=True)  # set date as index
        self.kdata_d['vol'] = self.kdata_d['vol'].map(lambda x: x / 1000).round(3)  # 成交量/1000,避免溢出？？？有没有问题

    def get_K_w(self):
        urlstockcode = self.stockcode[-2:].lower() + self.stockcode[:6]
        # http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param=sz300027,month,1990-12-01,,10240,qfq
        #url = rf'http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param={urlstockcode},day,1990-12-01,,10240,bfq'
        url = rf'http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param={urlstockcode},week,1990-12-01,,2000,qfq'
        originaltxt = self.gethtml(url)
        goodtxt = re.sub(',{(.+?)}]', ']', originaltxt)
        #print("week goodtxt",goodtxt)

        my_json = json.loads(goodtxt)
        if not(urlstockcode=="sz399001" or urlstockcode=="sz399006" or urlstockcode=="sh000001"):
            my_k = my_json['data'][urlstockcode]['qfqweek']
        else:
            my_k = my_json['data'][urlstockcode]['week']

        arrayk = np.array(my_k)
        self.kdata_w = pd.DataFrame(arrayk, columns=['date', 'open', 'close', 'high', 'low', 'vol'])  # ???ul1
        self.kdata_w[['open', 'close', 'high', 'low']] = self.kdata_w[['open', 'close', 'high', 'low']].apply(pd.to_numeric).round(2)
        self.kdata_w['vol'] = self.kdata_w['vol'].apply(pd.to_numeric).astype(int)  # vol 转换为 整型
        self.kdata_w['date'] = pd.to_datetime(self.kdata_w['date'])
        self.kdata_w.set_index(["date"], inplace=True)  # set date as index
        self.kdata_w['vol'] = self.kdata_w['vol'].map(lambda x: x / 1000).round(3)  # 成交量/1000,避免溢出？？？有没有问题

    def get_K_m(self):
        urlstockcode = self.stockcode[-2:].lower() + self.stockcode[:6]
        # http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param=sz300027,month,1990-12-01,,10240,qfq
        #url = rf'http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param={urlstockcode},day,1990-12-01,,10240,bfq'
        #https://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param=bj830799,day,1990-12-01,,2000,qfq
        url = rf'http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param={urlstockcode},month,1990-12-01,,2000,qfq'
        originaltxt = self.gethtml(url)
        goodtxt = re.sub(',{(.+?)}]', ']', originaltxt)

        my_json = json.loads(goodtxt)
        if not(urlstockcode=="sz399001" or urlstockcode=="sz399006" or urlstockcode=="sh000001"):
            my_k = my_json['data'][urlstockcode]['qfqmonth']
        else:
            my_k = my_json['data'][urlstockcode]['month']
        arrayk = np.array(my_k)
        self.kdata_m = pd.DataFrame(arrayk, columns=['date', 'open', 'close', 'high', 'low', 'vol'])  # ???ul1
        self.kdata_m[['open', 'close', 'high', 'low']] = self.kdata_m[['open', 'close', 'high', 'low']].apply(pd.to_numeric).round(2)
        self.kdata_m['vol'] = self.kdata_m['vol'].apply(pd.to_numeric).astype(int)  # vol 转换为 整型
        self.kdata_m['date'] = pd.to_datetime(self.kdata_m['date'])
        self.kdata_m.set_index(["date"], inplace=True)  # set date as index
        self.kdata_m['vol'] = self.kdata_m['vol'].map(lambda x: x / 1000).round(3)  # 成交量/1000,避免溢出？？？有没有问题

    def get_K_D_csv(self):
        urlstockcode = self.stockcode[-2:].lower() + self.stockcode[:6]
        self.kdata_d=pd.read_csv(f"kdata/{self.stockcode[:6]}_d.csv")#,index_col=0)
        self.kdata_d['date'] = pd.to_datetime(self.kdata_d['date'])
        self.kdata_d.set_index(["date"], inplace=True)  # set date as index

    def get_K_T_csv(self): 
        urlstockcode = self.stockcode[-2:].lower() + self.stockcode[:6]
        self.kdata_t=pd.read_csv(f"kdata/{self.stockcode[:6]}_t.csv")#,index_col=0)
        self.kdata_t['date'] = pd.to_datetime(self.kdata_t['date'])
        self.kdata_t.set_index(["date"], inplace=True)  # set date as index

    def get_K_F_csv(self):
        urlstockcode = self.stockcode[-2:].lower() + self.stockcode[:6]
        self.kdata_f=pd.read_csv(f"kdata/{self.stockcode[:6]}_f.csv")#,index_col=0)
        self.kdata_f['date'] = pd.to_datetime(self.kdata_f['date'])
        self.kdata_f.set_index(["date"], inplace=True)  # set date as index

    def get_K_O_csv(self):
        urlstockcode = self.stockcode[-2:].lower() + self.stockcode[:6]
        self.kdata_o=pd.read_csv(f"kdata/{self.stockcode[:6]}_o.csv")#,index_col=0)
        self.kdata_o['date'] = pd.to_datetime(self.kdata_o['date'])
        self.kdata_o.set_index(["date"], inplace=True)  # set date as index

    def get_K_MW(self):
        mvol    = self.kdata_d['vol'].resample('M').sum().round(2)
        mopen   = self.kdata_d['open'].resample('M').first().round(2)
        mclose  = self.kdata_d['close'].resample('M').last().round(2)
        mhigh   = self.kdata_d['high'].resample('M').max().round(2)
        mlow    = self.kdata_d['low'].resample('M').min().round(2)
        self.kdata_m = pd.concat([mopen, mclose, mhigh, mlow, mvol], axis=1)
        self.kdata_m = self.kdata_m.dropna(axis=0, how='any')

        hhh=self.kdata_d['high'].max().round(2)
        lll=self.kdata_d['low'].min().round(2)
        ttlk=self.kdata_d.shape[0]
        cp=self.kdata_d['close'][ttlk-1].round(2)
        try:
            #把历史最高价与历史最低价的差等分10份,现在处在第几份
            self.hp=(cp-lll)/((hhh-lll)/100)
            self.hp=self.hp.round(1)
            #print("hhh,lll,ttlk,self.hp",hhh,lll,ttlk,self.hp)
        except:
            print("calculate self.hp error")

        wvol    = self.kdata_d['vol'].resample('W-FRI').sum().round(2)
        wopen   = self.kdata_d['open'].resample('W-FRI').first().round(2)
        wclose  = self.kdata_d['close'].resample('W-FRI').last().round(2)
        whigh   = self.kdata_d['high'].resample('W-FRI').max().round(2)
        wlow    = self.kdata_d['low'].resample('W-FRI').min().round(2)
        self.kdata_w = pd.concat([wopen, wclose, whigh, wlow, wvol], axis=1)
        self.kdata_w = self.kdata_w.dropna(axis=0, how='any')

    def gethtml(self,url):
        ''' 
        最多读取10次，每次等待3秒钟
        如果超过3次没有抓到K线数据，就把 i+url 输出到htmlerror.txt文件中
        每次程序开始运行的时候，清空 htmlerror.txt 文件
        '''
        i = 0
        while i < 10:
            try:
                html = requests.get(url, timeout=3).text
                return html
            except requests.exceptions.RequestException:
                i += 1
        if i==10:   #10次都没有取得数据
            print(f"尝试过{i}次后，依然没有通过{url}得到数据")
        if i > 1 and i!=10:
            #self.string2txt(1, str(i) + url)
            print(f"{i} 次通过{url} 没有得到数据")

    def get_K_TFO(self,period):
        urlstockcode = self.stockcode[-2:].lower() + self.stockcode[:6]

        url = rf'http://ifzq.gtimg.cn/appstock/app/kline/mkline?param={urlstockcode},{period},,320&_var=m1_today&r=0.260880015116'
            # vol后面多了两列 {} 和 类似成交量的一个数字, 用 un1 和 un2替代后，再删除
        originaltxt = self.gethtml(url)
        goodtxt = re.sub(',{}(.+?)]', ']', originaltxt)
        goodtxt = goodtxt[9:]

        #logging.info(goodtxt)

        my_json = json.loads(goodtxt)
        my_k = my_json['data'][urlstockcode][period]
        arrayk = np.array(my_k)
        kdata = pd.DataFrame(arrayk, columns=['date', 'open', 'close', 'high', 'low', 'vol'])  # ???ul1
        kdata[['open', 'close', 'high', 'low']] = kdata[['open', 'close', 'high', 'low']].apply(
            pd.to_numeric).round(2)
        kdata['vol'] = kdata['vol'].apply(pd.to_numeric).astype(int)  # vol 转换为 整型
        kdata['date'] = pd.to_datetime(kdata['date'])
        kdata.set_index(["date"], inplace=True)  # set date as index
        kdata['vol'] = kdata['vol'].map(lambda x: x / 1000).round(3)  # 成交量/1000,避免溢出？？？有没有问题
        #logging.info("kdata",kdata)
        return(kdata)

    def cal_ma_all(self):
        self.kdata_m = self.cal_ma_K(self.kdata_m)
        self.kdata_w = self.cal_ma_K(self.kdata_w)
        self.kdata_d = self.cal_ma_K(self.kdata_d)
        self.kdata_t = self.cal_ma_K(self.kdata_t)
        self.kdata_f = self.cal_ma_K(self.kdata_f)
        self.kdata_o = self.cal_ma_K(self.kdata_o)
        #如果月K线多于60根, 且股价在月线ma30上以的时间超过80%,则可以认为是有价值投资的股票
        ttlkm=self.kdata_m.shape[0]
        if ttlkm>60:
            df=self.kdata_m
            #print("month_kdata:",self.kdata_m[:10])
            self.ttlup  =int(df[df['low'] >=df['ma30']].shape[0]/ttlkm*100)
            self.ttldown=int(df[(df['high']+df['low'])/2<df['ma30']].shape[0]/ttlkm*100)
            if df['high'][ttlkm-5] >=df['ma30'][ttlkm-5] or df['high'][ttlkm-1] >=df['ma30'][ttlkm-1]: 
                self.mstatus=1
            else:
                self.mstatus=2
                '''
                if df['high'][ttlkm-1]<=df['ma30'][ttlkm-1]: 
                    self.mstatus=3
                if df['low'][ttlkm-1]<df['ma30'][ttlkm-1] and df['high'][ttlkm-1]>df['ma30'][ttlkm-1]: 
                    self.mstatus=2
                '''
        
    def cal_ma_K(self,kdata):
        kdata['ma5']  = kdata['close'].rolling(5).mean().round(3)
        kdata['ma10'] = kdata['close'].rolling(10).mean().round(3)
        kdata['ma30'] = kdata['close'].rolling(30).mean().round(3)
        kdata           = kdata.fillna(method='bfill')  # bfill由后向前填充 ffill由前向后填充
        '''
        ma5             = kdata["close"].rolling(5).mean()
        ma10            = kdata["close"].rolling(10).mean()
        ma30            = kdata["close"].rolling(30).mean()
        kdata.insert(5, 'ma5', ma5)
        kdata.insert(6, 'ma10', ma10)
        kdata.insert(7, 'ma30', ma30)
        kdata           = kdata.fillna(method='bfill')  # bfill由后向前填充 ffill由前向后填充
        kdata['ma5']    = kdata['ma5'].round(3)  # 保留4位是为了计算的准确性？？？
        kdata['ma10']   = kdata['ma10'].round(3)  # 最大的计算是除权
        kdata['ma30']   = kdata['ma30'].round(3)  # 除权与均线无关，且是除权后算均线
        '''
        return kdata

    def Merge(self, dict1, dict2):
        res = {**dict1, **dict2}
        return res 
        
    def get_havelist(self):
        onedb=Onedb()
        #self.havelist = self.From_table("select * from havelist")
        self.havelist = onedb.From_table("select * from havelist")
        self.havelist.index = self.havelist.index + 1
        self.havelist=self.havelist[['代码','成本','数量','名称']]
        self.havelist.columns=['code','cost','qty','name']
        self.havelist['qty']=self.havelist['qty']/100
        self.havelist['qty']=self.havelist['qty'].round(0)
        insertx=3
        '''
        self.havelist.insert(insertx,"%",0.00)
        self.havelist.insert(insertx+1,"S1Q",0)
        self.havelist.insert(insertx+2, "S1", 0.00)
        self.havelist.insert(insertx+3, "B1", 0.00)
        self.havelist.insert(insertx+4, "B1Q", 0)
        self.havelist.insert(insertx+5, "amt", self.havelist['cost']*self.havelist['qty']/100)
        '''
        self.havelist["%"]=0.00
        self.havelist["S1Q"]=0
        self.havelist["S1"]=0.00
        self.havelist["B1"]=0.00
        self.havelist["B1Q"]=0
        self.havelist["amt"]=self.havelist['cost']*self.havelist['qty']/100
        self.havelist['amt']=self.havelist['amt'].round(2)
        #self.havelist=self.havelist.set_index['amt']
        self.havelist=self.havelist.sort_values(axis=0,by='amt',ascending=False,ignore_index=True)
        self.havelist.index=self.havelist.index+1
        #self.havelist=self.havelist.reset_index(drop=True)
        '''
        self.havelist.insert(insertx+6,'Q',0.00)
        self.havelist.insert(insertx+7,'+',0.00)
        self.havelist.insert(insertx+8,'-',0.00)
        self.havelist.insert(insertx+9,'sn',self.havelist.index)
        '''
        self.havelist['Q']=0.00
        self.havelist['+']=0.00
        self.havelist['-']=0.00
        self.havelist['sn']=self.havelist.index
        self.get_hq()

    def get_hq(self):
        seq="http://qt.gtimg.cn/q="
        for key,have in self.havelist.iterrows():
            if have.code[:1]=="6":
                seq=seq+"sh"+have.code+","
            else:
                seq=seq+"sz"+have.code+","
        html=requests.get(seq,timeout=3).text
        sp=html.split(";")
        for spn in sp:
            if len(spn)>10:
                spnn=spn.split("~")
                #print("spnn",i,spnn[3],spnn[2],spnn[20],spnn[19],spnn[9],spnn[10],spnn[32])
                ttl=self.havelist.shape[0]
                for j in range(1,ttl+1):
                    if self.havelist['code'][j]==spnn[2]:
                        self.havelist['%'][j]=spnn[32]
                        self.havelist['S1Q'][j]=int(spnn[20])
                        self.havelist['S1'][j]=spnn[19]
                        self.havelist['B1'][j]=spnn[9]
                        self.havelist['B1Q'][j]=int(spnn[10])
                        self.havelist['Q'][j]=spnn[49]
                        self.havelist['+'][j]=spnn[47]
                        self.havelist['-'][j]=spnn[48]

    def get_hq_all(self):
        pro = ts.pro_api()
        stocklist = pro.query('stock_basic', exchange='', list_status='L')
        stocklist.index = stocklist.index + 1 
        #stocklist=stocklist[(stocklist['list_date']<"20180101")]
        stocklist=stocklist[:800]
        stocklist['close']=0.00
        stocklist['percent']=0.00
        stocklist['highmax']=0.00
        stocklist['lowmax']=0.00
        seq="http://qt.gtimg.cn/q="
        for key,stock in stocklist.iterrows():
            if stock.ts_code[:1]=="6":
                seq=seq+"sh"+stock.ts_code[:6]+","
            else:
                seq=seq+"sz"+stock.ts_code[:6]+","
        html=requests.get(seq,timeout=3).text
        sp=html.split(";")
        for spn in sp:
            if len(spn)>10:
                spnn=spn.split("~")
                ttl=stocklist.shape[0]
                for j in range(1,ttl+1):
                    if (stocklist['ts_code'][j][:6]==spnn[2]):
                        stocklist['close'][j]=spnn[3]
                        stocklist['percent'][j]=spnn[32]
                        stocklist['highmax'][j]=spnn[47]
                        stocklist['lowmax'][j]=spnn[48]
        print(stocklist)

    def show(self,showtype):
        #os.system("clear")
        if showtype==1:
            self.get_havelist()
            print(self.havelist)
        if showtype==2:    #select stock
            self.get_havelist()
            self.stockcode=self.havelist.iloc[havelistseq-1,0]
            if self.stockcode[:1]=='6':
                self.stockcode=self.stockcode+".SH"
            elif self.stockcode[:1]=='8' or self.stockcode[:1]=='4':
                self.stockcode=self.stockcode+".BJ"
            else:
                self.stockcode = self.stockcode + ".SZ"
            self.run()
            print("\033[0;31;40m\tstockcode:\033[0m", self.stockcode)
            print("seq stockcode",self.stockcode)
        if showtype==3:    #keyin stock
            self.run()

    def cal_qs_KaiLuo(self,kdata,ttlk):
        #找到可能的Kai 和 Luo两种信号
        # 从第31根K线开始，到ttlk-10,计算MA30上的起涨点和起跌点 +1代表起跌点 -1代表起涨点
        kdata['kkll']=0
        kdata['kkllx']=0
        kdata['kkllv']=0.0
        kdata['kkllxv']=0.0
        '''
        kdata.insert(8, 'kkll', 0)  # -1起涨点 +1起跌点
        kdata.insert(9, 'kkllv', 0.00)  # 起涨价和起跌价
        kdata.insert(10, 'kkllx', 0)  # 最高价点+2 和 最低价点-2
        kdata.insert(11, 'kkllxv', 0.00)  # 最高价 和 最低价
        '''
        for i in range(30, ttlk - 10):  #
            bcheckttl = 0;
            # 如果是V型，即可能的起涨点
            if kdata['ma30'][i] <= kdata['ma30'][i - 1] and kdata['ma30'][i] < kdata['ma30'][i + 1]:
                # 如果后面9根K线中，有6根K线的重心（H+L）/2在MA30以上，并且MA30持续向上，则确定为一个起涨点
                for k in range(9):
                    if (kdata['high'][i + k] + kdata['low'][i + k]) / 2 > kdata['ma30'][i + k] \
                            and kdata['ma30'][i + k] < kdata['ma30'][i + k + 1]:
                        bcheckttl = bcheckttl + 1
                if bcheckttl >= 6: kdata['kkll'][i] = -1  # 起涨点 V 型

                tmpk=kdata[i+4:i+9]
                if tmpk[(tmpk["low"]>tmpk["ma30"])].shape[0]>=4:
                    kdata['kkll'][i]=-1 
            # 如果是A型，即可能的起跌点
            elif kdata['ma30'][i] >= kdata['ma30'][i - 1] and kdata['ma30'][i] > kdata['ma30'][i + 1]:
                # 如果后面9根K线中，有6极K线的重心在MA30以下，并且MA30持续向下，则确定为一个起跌点
                for k in range(9):
                    if (kdata['high'][i + k] + kdata['low'][i + k]) / 2 < kdata['ma30'][i + k] \
                            and kdata['ma30'][i + k] > kdata['ma30'][i + k + 1]:
                        bcheckttl = bcheckttl + 1
                if bcheckttl >= 6: kdata['kkll'][i] = 1  # 起跌点  A 型
                tmpk=kdata[i+4:i+9]
                if tmpk[(tmpk["high"]<tmpk["ma30"])].shape[0]>=4:
                    kdata['kkll'][i]=1 
                #data_df = data_df[(data_df["risk"] >=0) & (data_df["time"] <60)]
        # 最后10根K线，从后向前找，只要找到最近的第一次 MA30出现V型 或是 A型 就直接标注并退出
        for i in range(2, 10):  # 算最后的几根K线，看有没有趋势
            j = ttlk - i
            if (kdata['ma30'][j] <= kdata['ma30'][j - 1] and kdata['ma30'][j] < kdata['ma30'][j + 1] and kdata['high'][j + 1] >kdata['ma30'][j + 1]):
                kdata['kkll'][j] = -1
                break
            elif (kdata['ma30'][j] >= kdata['ma30'][j - 1] and kdata['ma30'][j] > kdata['ma30'][j + 1] and kdata['low'][j + 1] <kdata['ma30'][j + 1]):
                kdata['kkll'][j] = 1
                break
        # =================================================================================
        # 从前向后找连续重复的 +1 或 -1 信号，
        # 连续 + 1信号，保留“最高价”最大的那个
        # 连续 - 1信号，保留“最低价”最小的那个
        for i in range(29, ttlk):
            if kdata['kkll'][i] == 1:
                for j in range(i + 1, ttlk):
                    if kdata['kkll'][j] == -1:
                        i = j - 1  # !!!!!!i=j-1
                        break
                    if kdata['kkll'][j] == 1:
                        if kdata['high'][j] > kdata['high'][i]:  # 起跌点找重复1中的H的最高值
                            kdata['kkll'][i] = 0
                            i = j
                        else:
                            kdata['kkll'][j] = 0
            elif kdata['kkll'][i] == -1:  # !!!!!!!
                for j in range(i + 1, ttlk):
                    if kdata['kkll'][j] == 1:
                        i = j - 1  # !!!!!
                        break
                    if kdata['kkll'][j] == -1:
                        if kdata['low'][j] < kdata['low'][i]:  # 起涨点找重复-1中L的最低值
                            kdata['kkll'][i] = 0
                            i = j
                        else:
                            kdata['kkll'][j] = 0
        return kdata
    def cal_qs_GGDD(self,kdata,ttlk):
        # =================================================================================
        # 从后向前找，如果碰到-1，则找出与下一个+1之间的最低点，作为-2（最低价）
        #          如果碰到+1，则找出与下一个-1之间的最高点，作为+2（最高价）
        for i in range(ttlk - 1, 30, -1):
            if kdata['kkll'][i] == -1:  # 如果碰到-1
                LL = kdata['low'][i]
                disLL = 0
                # logging.info(data.iloc[i].name)
                for j in range(i - 1, -1, -1):
                    # logging.info(data.iloc[j].name,j)
                    if kdata['kkll'][j] == 1 or j == 0:  # 定义找-2的区间，从-1到（要么找到下一个+1，要么找到第一根K线）
                        for k in range(i - 1, j, -1):
                            if kdata['low'][k] <= LL:
                                disLL = i - k
                                LL = kdata['low'][k]
                        kdata['kkllx'][i - disLL] = -2
                        kdata['kkllxv'][i - disLL] = LL
                        break
            if kdata['kkll'][i] == 1:  # 如果碰到+1
                HH = kdata['high'][i]
                disHH = 0
                for j in range(i - 1, -1, -1):
                    if kdata['kkll'][j] == -1 or j == 0:  # 定义找+2的区间，从+1到（要么找到下一个-1，要么找到第一根K线）
                        for k in range(i - 1, j, -1):
                            if kdata['high'][k] >= HH:
                                disHH = i - k
                                HH = kdata['high'][k]
                        kdata['kkllx'][i - disHH] = 2
                        kdata['kkllxv'][i - disHH] = HH
                        break
        return kdata
    def cal_qs_kkllv(self,kdata,ttlk):
        # range可以带三个参数，但是这个地方只带了一个？？？
        for i in range(ttlk):  ### 计算平均价 kai/luo 1和-1这两个位置的，因为大智慧计算太慢 ###
            if kdata['kkllx'][i] == 2:
                TTLa = 0
                TTLv = 0
                for j in range(i, ttlk):
                    #TTLa= TTLa+ kdata['amt'][j] #kdata['close'][j] * kdata['vol'][j]
                    TTLa = TTLa + kdata['close'][j] * kdata['vol'][j]
                    TTLv = TTLv + kdata['vol'][j]
                    if kdata['kkll'][j] == 1:
                        i = j
                        if TTLv == 0:  # 如果TTLv==0，则直接提示并将kkllv置零，避免/0错误！！！
                            #logging.info(stockcode, period, "TTLv=0")
                            kdata['kkllv'][j] = 0
                        else:
                            kdata['kkllv'][j] = TTLa / TTLv
                        break
            if kdata['kkllx'][i] == -2:
                TTLa = 0
                TTLv = 0
                for j in range(i, ttlk):
                    #TTLa = TTLa+ kdata['amt'][j] #kdata['close'][j] * kdata['vol'][j]
                    TTLa = TTLa + kdata['close'][j] * kdata['vol'][j]
                    TTLv = TTLv + kdata['vol'][j]
                    if kdata['kkll'][j] == -1:
                        i = j
                        if TTLv == 0:
                            #logging.info(stockcode, period, "TTLv=0")
                            kdata['kkllv'][j] = 0
                        else:
                            kdata['kkllv'][j] = TTLa / TTLv
                        break
        kdata['kkll'] = kdata['kkll'].round(0)
        kdata['kkllx'] = kdata['kkllx'].round(0)
        kdata['kkllv'] = kdata['kkllv'].round(2)
        kdata['kkllxv'] = kdata['kkllxv'].round(2)
        return kdata
    def cal_qs_QSmodule_NDGNKL(self,kdata,ttlk):
        #计算11点趋势模型中的NKL和NDG
        NDG=NKL=0
        DDday=GGday=0
        for i in range(ttlk - 1, -1, -1):
        # 即最近一个最值点如果是-2（下跌趋势中），则NKL=NLuo NDG=NGG
            if kdata['kkllx'][i] == -2:  # DD
                DDday = i  # !!!!!
                for j in range(i - 1, -1, -1):
                    if kdata['kkll'][j] == -1:
                        NKL = kdata['kkllv'][j]
                    if kdata['kkllx'][j] == -2:
                        NDG = kdata['kkllxv'][j]
                        break
                break
            elif kdata['kkllx'][i] == 2:  # GG
                    GGday = i  # !!!!!
                    for j in range(i - 1, -1, -1):
                        if kdata['kkll'][j] == 1:
                            NKL = kdata['kkllv'][j]
                        if kdata['kkllx'][j] == 2:
                            NDG = kdata['kkllxv'][j]
                            break
                    break
        self.keypoint['NDG']=NDG
        self.keypoint['NKL']=NKL
        self.keypoint['GGday']=GGday
        self.keypoint['DDday']=DDday
        return kdata
    def cal_qs_QSmodule_QSDDKaiGGLuo(self,kdata,ttlk):
        DD=Kai=GG=Luo=Kaiday=Luoday=0
        for i in range(ttlk - 1, -1, -1):
            if kdata['kkllx'][i] == -2:  # DD
                #kdata.insert(12, 'DD', kdata['kkllxv'][i])  # 所有的DD都设置为最后一个DD
                kdata['DD']=kdata['kkllxv'][i]  # 所有的DD都设置为最后一个DD
                DD = kdata['kkllxv'][i]
                break  # 只找最后一个
        added = kdata.shape[1]  # 如果没有DD，则 加一列 DD
        if added == 12:  
            #kdata.insert(12, 'DD', 0)  # 如果趋势不全，找不到-2，则所有DD为0 XXXXXXXX
            kdata['DD']=0  # 如果趋势不全，找不到-2，则所有DD为0 XXXXXXXX

        for i in range(ttlk - 1, -1, -1):
            if kdata['kkll'][i] == -1:  # Kai
                #kdata.insert(13, 'Kai', kdata['kkllv'][i])
                kdata['Kai']=kdata['kkllv'][i]
                Kai = kdata['kkllv'][i]
                break
        Kaiday = ttlk - i  # 和Luoday比较大小，Kaiday小，是上涨趋势，Kaiday大，是下跌趋势
        added = kdata.shape[1]
        if added == 13:  
            #kdata.insert(13, 'Kai', 0)  # 如果趋势不全，找不到-1
            kdata['Kai']=0

        for i in range(ttlk - 1, -1, -1):
            if kdata['kkllx'][i] == 2:  # GG
                #kdata.insert(14, 'GG', kdata['kkllxv'][i])
                kdata['GG']=kdata['kkllxv'][i]
                GG = kdata['kkllxv'][i]
                break
        added = kdata.shape[1]
        if added == 14:  
            #kdata.insert(14, 'GG', 0)
            kdata['GG']=0

        for i in range(ttlk - 1, -1, -1):
            if kdata['kkll'][i] == 1:  # Luo
                #kdata.insert(15, 'Luo', kdata['kkllv'][i])
                kdata['Luo']=kdata['kkllv'][i]
                Luo = kdata['kkllv'][i]
                break
        Luoday = ttlk - i
        added = kdata.shape[1]
        if added == 15:  
            #kdata.insert(15, 'Luo', 0)
            kdata['Luo']=0
        if Kaiday >= Luoday:
            QS = -1
        else:
            QS = 1
        self.keypoint['QS']=QS
        self.keypoint['DD']=DD
        self.keypoint['Kai']=Kai
        self.keypoint['GG']=GG
        self.keypoint['Luo']=Luo
        return kdata
    def cal_qs_QSmodule_CHL1andCHL(self,stockcode,kdata,ttlk,period):
        NDG=self.keypoint['NDG']
        NKL=self.keypoint['NKL']
        DD=self.keypoint['DD']
        Kai=self.keypoint['Kai']
        GG=self.keypoint['GG']
        Luo=self.keypoint['Luo']
        QS=self.keypoint['QS']

        # 周期 方向 指导建议 空间[起涨 起跌]    [收益 % 风险 % 益险 %][最低  最高]    当前极值
        periodsuggestion = " "  # 操盘建议
        profitP = 0             # 收益%        LUO/C            ()
        riskP = 0               # 风险%        C/Kai            (if Kai<>0, C/Kai else 100)
        PLP = 0                 # 收益风险率    profitP/riskP    ()
        CHL = 0.0  
        CHLP = 0                #
        DDCGorGGCD = 0.0  
        DDCGorGGCDma30 = 0.0
        closeprice = kdata['close'][-1]

        CHL1=0
        DDCGorGGCD1=0
        DDCGorGGCD1ma30=0
        DDCGorGGCD1location=0
        CHL1location=0

        HHHlocation = 0
        LLLlocation = 0
        # 从后向前找趋势极值
        #2-28-2022
        #WWW服务器只抓数据,不运算,是否会加快计算进度[每天收盘做一次]
        #DDCGorGGCD1是CHL向[ 前 ]再找一个HHH或LLL碰Ma30的位置
        #CHL1在DDCGorGGCD[ 前 ]与CHL的性质相同的最高价或最低价
        #CHL与CHL1相比较,用来判断有没有创新高或创新低
        #QStask1: 完成趋势空间        [CHL完成? CHL1完成?]
        #QStask2: 完成趋势结构        [如果CHL与CHL1之前,有一个H或L碰到Ma30,则完成趋势结构]
        #QStask3: 创新,创新低或创新高 [+1 创新高 -1创新低 还是1就代表创新]
        #QStask4: 趋势转折点          [本趋势转折点,即下一个MA30会让生命线变红]
        #QStask5: 趋势启动            [L-2级别连续放量大涨,还是只针对日线级别]
        for i in range(ttlk - 1, -1, -1):
            if i == ttlk - 1:
                HHH = kdata['high'][i]
                LLL = kdata['low'][i]
                HHHlocation = i
                LLLlocation = i
            if kdata['high'][i] > HHH:  #如果==则记录后一个高点
                HHH = kdata['high'][i]
                HHHlocation = i
            if kdata['low'][i] < LLL:   #如果==则记录后一个低点
                LLL = kdata['low'][i]
                LLLlocation = i

            if kdata['kkll'][i] == 1:  # Luo    =>[[[[下跌趋势中...]]]]
                CHL = LLL  # 下跌趋势中CHL取最低价
                CHLlocation=LLLlocation
                #1 Luo的位置 [Luo | CHL1 DDCGorGGCD1 CHL DDCGorGGCD C] 
                Luolocation=i         
                if Kai != 0:
                    CHLP = (CHL / Kai * 100 - 100).round(1)
                    # 判断下跌趋势极值离完成任务还有多远，负数代表超额完成下跌任务
                else:
                    CHLP = 0  # 999代表趋势不全，即Kai=0, 直接除会程序报错
                
                #1 [Luo] DDCGorGGCD1 and DDCGorGGCD1ma30
                for k in range(CHLlocation-1,Luolocation,-1):     #从CHL向前找一个[完成止跌结构]的"伪"高点,这个高点不是DDCGorGGCD1
                    if kdata['high'][k]>kdata['ma30'][k]:       #如果找到,再向前到Luo后,找CHL1
                        CHL1=kdata['low'][k]                    #如果没有找到,就不用DDCGorGGCD1和CHL这两个参考点
                        CHL1location=k
                        for m in range(k,Luolocation,-1):       #即没有完成止跌结构,就不用比是否创新低
                            if kdata['low'][m]<CHL1:
                                CHL1=kdata['low'][m]
                                CHL1location=m
                        DDCGorGGCD1=kdata['high'][CHL1location]
                        for m in range(CHL1location,CHLlocation,1):
                            if kdata['high'][m]>DDCGorGGCD1:
                                DDCGorGGCD1=kdata['high'][m]
                                DDCGorGGCD1ma30=kdata['ma30'][m]
                                DDCGorGGCD1location=m
                        break #只要找到一个high>ma30的伪"高点"就向前找最低点CHL1,再向CHL找DDCGorGGCD1

                for k in range(ttlk - 1, CHLlocation, -1):  # 如果找到的是下跌趋势中的最低值，则找C与趋势最低值之间的最高价
                    if k == ttlk - 1:
                        DDCGorGGCD = kdata['high'][k]
                        DDCGorGGCDma30 = kdata['ma30'][k]
                    if kdata['high'][k] > DDCGorGGCD:
                        DDCGorGGCD = kdata['high'][k]
                        DDCGorGGCDma30 = kdata['ma30'][k]
                if DDCGorGGCD == 0:
                    DDCGorGGCD = kdata['high'][ttlk - 1]
                    DDCGorGGCDma30 = kdata['ma30'][ttlk - 1]
                break

            if kdata['kkll'][i] == -1:  # Kai   =>[[[[...上涨趋势中...]]]
                CHL = HHH  # 上涨趋势中CHL取最高价
                CHLlocation=HHHlocation
                #1 Kai的位置
                Kailocation=i         
                #1 end
                CHLP = (Luo / CHL * 100 - 100).round(1)
                # 判断上涨趋势极值离完成任务还有多远，负数代表超额完成上涨任务
                #1 [如果创新低后再一次形成DDCGorGGCD]找DDCGorDDCG1
                # 上涨趋势中形成的最高CHL向前找DDCGorGGCD1的前提是
                # 下跌趋势中形成的最低CHL向前找DDCGorGGCD1的前提是向上碰Ma30(完成止跌结构,否则没有DDCGorGGCD1也就没有CHL

                for k in range(CHLlocation-1,Kailocation,-1):   #从CHL(最高)向前找一个[完成止跌结构]的"伪"低点,这个低点不是DDCGorGGCD1
                    if kdata['low'][k]<kdata['ma30'][k]:        #如果找到,再向前到Kai后,找CHL1
                        CHL1=kdata['high'][k]                   #如果没有找到,就不用DDCGorGGCD1和CHL1这两个参考点
                        CHL1location=k
                        for m in range(k,Kailocation,-1):       #即没有完成止跌结构,就不用比是否创新低
                            if kdata['high'][m]>CHL1:
                                CHL1=kdata['high'][m]
                                CHL1location=m
                        DDCGorGGCD1=kdata['low'][CHL1location]
                        for m in range(CHL1location,CHLlocation,1):
                            if kdata['low'][m]<DDCGorGGCD1:
                                DDCGorGGCD1=kdata['low'][m]
                                DDCGorGGCD1ma30=kdata['ma30'][m]
                                DDCGorGGCD1location=m
                        break

                for k in range(ttlk - 1, HHHlocation, -1):  # 如果找到的是上涨趋势中的最高值，则找C与趋势最高值之间的最低价
                    if k == ttlk - 1:
                        DDCGorGGCD = kdata['low'][k]
                        DDCGorGGCDma30 = kdata['ma30'][k]
                    if kdata['low'][k] < DDCGorGGCD:
                        DDCGorGGCD = kdata['low'][k]
                        DDCGorGGCDma30 = kdata['ma30'][k]
                if DDCGorGGCD == 0:
                    DDCGorGGCD = kdata['low'][ttlk - 1]
                    DDCGorGGCDma30 = kdata['ma30'][ttlk - 1]
                break
                # 趋势极值为正数，代表还有%多少能完成任务，如果为负数，则代表超额完成上涨或下跌任务的%
        profitP = (Luo / closeprice * 100 - 100).round(1)
        if Kai != 0:
            riskP = (closeprice / Kai * 100 - 100).round(1)
        else:
            riskP = 999.0
        PLP = ((profitP + 100) / (riskP + 100) * 100 - 100).round(1)

        if closeprice > GG * 1.01 or closeprice < DD * 0.99:
            outofrange = 1
        else:
            outofrange = 0

        if GG == 0 or DD == 0 or Kai == 0 or Luo == 0:
            QSabnormal = 1
        else:
            QSabnormal = 0

        if Kai != 0:
            spaceP = (Luo / Kai * 100 - 100).round(1)
        else:
            spaceP = 0

        revisetime = datetime.datetime.strftime(datetime.datetime.now(), '%m-%d %H:%M')

        try:
            CHL=CHL.round(2)
            CHL1=CHL1.round(2)
        except:
            pass

        periodQS = {'code':         stockcode + period,
                    'stockcode':    stockcode,
                    'period':       period,
                    'C':            closeprice,  # data['close'][-1],
                    'QS':           QS,
                    'DD':           DD,
                    'Kai':          Kai,
                    'GG':           GG,
                    'Luo':          Luo,
                    'profitP':      profitP,
                    'riskP':        riskP,
                    'PLP':          PLP,
                    'CHL':          CHL,
                    'CHLP':         CHLP,
                    'spaceP':       spaceP,
                    'outofrange':   outofrange,
                    'QSabnormal':   DDCGorGGCDma30,  # QSabnormal,
                    'ma5':          kdata['ma5'][-1].round(2),
                    'ma10':         kdata['ma10'][-1].round(2),
                    'ma30':         kdata['ma30'][-1].round(2),
                    'ma5P':         (closeprice / kdata['ma5'][-1] * 100 - 100).round(2),
                    'ma10P':        (closeprice / kdata['ma10'][-1] * 100 - 100).round(2),
                    'ma30P':        (closeprice / kdata['ma30'][-1] * 100 - 100).round(2),
                    'periodSugg':   periodsuggestion,
                    'DDCGorGGCD':   DDCGorGGCD,
                    'reviseTime':   revisetime,
                    'NDG'	:       NDG,
                    'NKL'	    :   NKL,
                    'CHL1'      :   CHL1,
                    'DDCGorGGCD1':  DDCGorGGCD1
                    }

        periodQStime={
                    'code'          :stockcode+period,
                    'stockcode'     :stockcode,
                    'period'        :period,
                    #'DDtime'        : DDtime,
                    #'Kaitime'       : Kaitime,
                    #'GGtime'        : GGtime,
                    #'Luotime'       : Luotime,
                    #'CHLtime'       : CHLtime,
                    #'DDCGorGGCDtime': DDCGorGGCDtime,
                    #'NDGtime'	    : NDGtime,
                    #'NKLtime'	    : NKLtime
                    'reviseTime': revisetime
                    }
        self.keypoint['CHL1']=CHL1
        self.keypoint['DDCGorGGCD1']=DDCGorGGCD1
        self.keypoint['CHL']=CHL
        self.keypoint['DDCGorGGCD']=DDCGorGGCD
        self.keypoint['DDCGorGGCD1ma30']=DDCGorGGCD1ma30
        self.keypoint['DDCGorGGCDma30']=DDCGorGGCDma30
        return kdata,periodQS #,GGday,DDday
    def cal_qs_QSmessage(self,kdata,ttlk,period):
        NDG=self.keypoint['NDG']
        NKL=self.keypoint['NKL']
        DD=self.keypoint['DD']
        Kai=self.keypoint['Kai']
        GG=self.keypoint['GG']
        Luo=self.keypoint['Luo']
        QS=self.keypoint['QS']
        CHL1=self.keypoint['CHL1']
        CHL=self.keypoint['CHL']
        DDCGorGGCD1=self.keypoint['DDCGorGGCD1']
        DDCGorGGCD1ma30=self.keypoint['DDCGorGGCD1ma30']
        DDCGorGGCD=self.keypoint['DDCGorGGCD']
        DDCGorGGCDma30=self.keypoint['DDCGorGGCDma30']
        #如果趋势空间合理 + 收盘价在趋势空间[DD,GG]以内,当前趋势就有价值
        closeprice=kdata['close'][ttlk-1]
        goodspace=False
        insidespace=False

        self.QS[period]=""  #avoid nan error
        #self.space={"month": 1,"week":0.2,"day":0.08,"m30":0.04,"m5":0.02,"m1":0.01}
        #趋势空间 月线100% 周线20% 日线8% 30分钟4% 5分钟2% 1分钟1%
        #self.diffbyp ={"month":0.08,"week":  0.04,"day":0.02   ,"m30":0.01   ,"m5":0.005   ,"m1":0.0025 }
        #容错率   月线  8% 周线 4% 日线2% 30分钟1% 5分钟0.5% 1分钟0.25%
        if Kai!=0:
            if Luo/Kai>(1+self.space[period]):
                goodspace=True
                #下跌趋势中，如果CHL和CHL1中有一个是0，那么minchl就是0，则趋势就自动变为-2，因为minchl不可能大于DD
                #上涨趋势中，不存在这个问题
                minchl=min(CHL,CHL1)
                maxchl=max(CHL,CHL1)
                if CHL==0 or CHL1==0: minchl=maxchl

                #if closeprice>DD*(1-self.diffbyp[period]) and closeprice<GG*(1+self.diffbyp[period]):
                if minchl>DD*(1-self.diffbyp[period]) and maxchl<GG*(1+self.diffbyp[period]):
                    insidespace=True
                    #self.diffbyp ={"month":0.08,"week":  0.04,"day":0.02   ,"m30":0.01   ,"m5":0.005   ,"m1":0.0025 }
                    if QS==-1:
                        self.QS[period]+="-1"       #正常下跌
                    else:
                        self.QS[period]+="+1"
                else:   
                    if QS==-1:
                        self.QS[period]+="-2"       #破位下跌
                    else:
                        self.QS[period]+="+2"
            else:
                #超过盘整GG +0, 小于盘整DD -0, 位于盘整中间 =0
                if closeprice>GG*(1+self.diffbyp[period]):
                    self.QS[period]+="+0"             #盘整
                else:
                    if closeprice<DD*(1-self.diffbyp[period]):
                        self.QS[period]+="-0"
                    else:
                        self.QS[period]+="=0"

        if QS==-1:    #下跌趋势中
            #计算QStask1   
            #CHL或CHL1中小的那个完成了趋势空间,就行
            if min(CHL,CHL1)<Kai*(1+self.diffbyp[period]):
                self.QS[period]+="a"
            #计算QStask2
            #如果DDCGorGGCD  上碰Ma30,完成止跌结构                #如果DDCGorGGCD1 上碰Ma30,完成止跌结构
            DoGfinishJG=False
            DoG1finishJG=False
            if DDCGorGGCD>DDCGorGGCDma30 and DDCGorGGCD*DDCGorGGCDma30!=0: 
                DoGfinishJG=True
            if DDCGorGGCD1>DDCGorGGCD1ma30 and DDCGorGGCD1*DDCGorGGCD1ma30!=0: 
                DoG1finishJG=True
            if DoGfinishJG or DoG1finishJG:
                self.QS[period]+="b"
            #1 计算QStask3
            #下跌趋势中是完成趋势任务后创新低
            if CHL1>0 and CHL<CHL1 and CHL1<Kai*(1+self.diffbyp[period]):
                self.QS[period]+="c"
            #下跌趋势中的趋势突破是下一根K线让生命线向上    
            tmpk=kdata[-29:]
            newma30=tmpk['close'].sum()+kdata['close'][ttlk-1]
            newma30=round(newma30/30,4)
            #print(f"{period} newma30:{newma30} vs {tmpk['ma30'][28]}")
            try:
                if newma30>=tmpk['ma30'][28]:
                    self.QS[period]+="d"
            except:
                pass
        elif QS==1:       #上涨趋势
            #计算本级别趋势是否有意义[上涨趋势]
            #如果趋势空间合理 + 收盘价在趋势空间[DD,GG]以内,当前趋势就有价值
            #计算QStask1   
            #CHL或CHL1中小的那个完成了趋势空间,就行
            if min(CHL,CHL1)>Luo*(1-self.diffbyp[period]):
                self.QS[period]+="a"
            #计算QStask2
            #如果DDCGorGGCD  上碰Ma30,完成止跌结构
            #如果DDCGorGGCD1 上碰Ma30,完成止跌结构
            DoGfinishJG=False
            DoG1finishJG=False
            if DDCGorGGCD<DDCGorGGCDma30: 
                DoGfinishJG=True
            if DDCGorGGCD1<DDCGorGGCD1ma30: 
                DoG1finishJG=True
            if DoGfinishJG or DoG1finishJG:
                self.QS[period]+="b"
            #1 计算QStask3
            #下跌趋势中是完成趋势任务后创新低
            if CHL1>0 and CHL>CHL1 and CHL1>Luo*(1-self.diffbyp[period]):
                #print(period,"CHL,CHL1",CHL1,CHL)
                self.QS[period]+="c"
            #下跌趋势中的趋势突破是下一根K线让生命线向上    
            tmpk=kdata[-29:]
            newma30=tmpk['close'].sum()+kdata['close'][ttlk-1]
            newma30=round(newma30/30,4)
            try:
                if newma30<=tmpk['ma30'][28]:
                    self.QS[period]+="d"
            except:
                pass
        #如果30天内有连续两个涨停,则e
        df=self.kdata_d[-30:]
        #df['zdf']=(df['close']-df['close'].shift(1))/df['close'].shift(1)
        try:
            for i in range(2,30,1): #连续两天上涨超过9%则为+e,连续两天下跌超过9%则为-e, 同时出现+e和-e看先后顺序
                if df.close[i]/df.close[i-1]>1.08 and df.close[i-1]/df.close[i-2]>1.08:
                    self.QS[period]+="+e"
                    break
            for i in range(2,30,1): #连续两天上涨超过9%则为+e,连续两天下跌超过9%则为-e, 同时出现+e和-e看先后顺序
                if df.close[i]/df.close[i-1]<0.92 and df.close[i-1]/df.close[i-2]<0.92:
                    self.QS[period]+="-e"
                    break
        except:
            pass
    def cal_jg_JGmodule(self,kdata,ttlk,period,periodQS):
        # 计算结构
        # ====================================================
        '''
        DD -2
        Kai -1
        GG 2
        Luo 1
        从后向前找，如果第一个找到-2，即当前在上涨趋势中
        1，下跌趋势中找底分型，
        2，两个底分型之间找最高点（或碰MA10或MA30的点）
        '''
        CHL  =periodQS['CHL']
        Kai  =periodQS['Kai']
        Luo  =periodQS['Luo']
        QS  =periodQS['QS']
        GGday=self.keypoint['GGday']
        DDday=self.keypoint['DDday']
        revisetime  =periodQS['reviseTime']

        '''
        kdata.insert(16, 'JGVFX', 0.00)  # 结构中的V分型
        kdata.insert(17, 'JGAFX', 0.00)  # 结构中的A分型
        kdata.insert(18, 'JG', ' ')  # 结构
        kdata.insert(19, 'JGV', 0.00)  # 结构特征价格
        '''
        kdata['JGVFX']=0.00  # 结构中的V分型
        kdata['JGAFX']=0.00  # 结构中的A分型
        kdata['JG']=' '  # 结构
        kdata['JGV']=0.00  # 结构特征价格

        JGdone      = 0  # 完成止跌结构     #JGdone
        KJdone      = 0  # 完成下跌空间     #KJdone
        JGQR        = 0  # 结构强弱         #JGQR 1代表强(创新高/不创新低) -1代表弱(不创新高/创新低)
        QX          = 0  # 情绪, 代替以前的KongHuang和KangFen两个指标,完成止跌结构后创新低制造恐慌
        ConfirmedJG =   ' '     #当前能确认的结构???
        CurrentJG   =   ' '     #最后一根K线可能的结构
        CurrentJGV  =   0       #当前结构value

        minlpercent =0
        minllocation = 0
        maxhpercent=0
        maxhlocation=0

        for i in range(ttlk - 1, -1, -1):  # 0<=i<=ttlk-1
            # 下跌趋势中上结构判断
            if kdata['kkllx'][i] == 2:
                # 从最高点开始找L离MA30最远的那根K线，开始找第一个底
                minlpercent = kdata['low'][i] /kdata['ma30'][i]
                minllocation = i

                for j in range(i ,ttlk -1 ,1):
                    minlpercentnew =kdata['low'][j] /kdata['ma30'][j]
                    if minlpercentnew <minlpercent:
                        minllocation = j
                        minlpercent =minlpercentnew

                kdata['JGVFX'][minllocation ] =-1  # 最远点为底分型
                kdata['JG'][minllocation] = "6"  # 最远点为结构6
                kdata['JGV'][minllocation] = kdata['low'][minllocation]
                if minllocation == ttlk - 1: break  # 如果6是最后一根K线，则不计算其它结构只有6

                # 不同的结构算法，可能的计算起点不同，但是下面的计算都是一致的
                # 从6+1开始找下跌趋势中的V分型
                for j in range(minllocation +1, ttlk -1 ,1):
                    if kdata['low'][j] <kdata['low'][j -1]:
                        lowhigh =kdata['high'][j]
                        lowlow =kdata['low'][j]
                        for k in range(j +1 ,ttlk -1 ,1):
                            if lowlow >kdata['low'][k]:
                                j=k  # 如果在找到顶分型找到更低的底，则
                                break
                            if lowhigh<kdata['high'][k]:
                                kdata['JGVFX'][j] = -1
                                j=k
                                break
                                # 找到一个高顶
                # 从6开始找下跌趋势中的A分型
                for j in range(minllocation,ttlk-1,1):
                    if kdata ['JGVFX'][j]==-1:
                        currentHigh=kdata['high'][j]
                        currentHighLocation=j
                        k=0
                        for k in range(j+1,ttlk-1,1):
                            if kdata['high'][k]>currentHigh:
                                currentHigh=kdata['high'][k]
                                currentHighLocation=k
                            if kdata['JGVFX'][k]==-1:
                                j=k
                                break
                        if k!=ttlk-1:
                            kdata['JGAFX'][currentHighLocation]=1

                # 删除下跌趋势中无效A分型信号和左右两边较高的那个V分型信号 # 如果要删除的那个V是起始的6，则必须保留(当前是保留 因为其比例意义）
                # （或者换6到新的底）
                # 如果移动6，则minllocation要跟着一起改

                #删除碰不到MA10或MA30的A分型信号
                for j in range(minllocation,ttlk-1,1):
                    if kdata['JGAFX'][j]==1:
                        high2ma10 =abs(kdata['ma10'][j]-kdata['high'][j])
                        high2ma5=abs(kdata['ma5'][j]-kdata['high' ] [j])
                        if kdata['high'][j]< kdata['ma10'][j] \
                                and high2ma5/2<high2ma10:   #？？？high超过ma10或high离ma5的距离是到ma10距离的2倍
                            #如果下跌过程中的A分型不满足79的结构条件，则删除这个A分型
                            kdata['JGAFX'][j] = 0
                                # 2 for debug
                            #找A分型的 下一个 V分型 （可能没有）
                            comp_OK=0
                            for k in  range(j,ttlk-1,1):
                                if kdata ['JGVFX'][k]==-1:
                                    nextVFX=k   #如果后面没有V分型，则nextVFX=?
                                    comp_OK=comp_OK+1   #后面有个V
                                    break
                            #找A分型的 上一个 V分型 （必定有，至少有6）
                            for k in range(j,-1,-1):
                                if kdata['JGVFX'][k]==-1:
                                    lastVFX=k
                                    comp_OK=comp_OK+1   #前面有个V
                                    break

                            if comp_OK==2:  #确保有两个V分型，再比较，否则程序报错
                                if kdata['low'][nextVFX]<=kdata['low'][lastVFX]:    #如果下一个low更低
                                    if kdata['JGVFX'][lastVFX]!="6":                  #上一个不是6，就把上一个V分型信号删除
                                        try:                                        #任何一个A分型前都能找到至少一个V分型信号（6）
                                            kdata['JGVFX '][lastVFX]=0#这个地方应该不会出错 lastVFX下标一定能找到
                                        except:
                                            pass
                                    else:
                                        kdata['JGVFX'][nextVFX] =0                  #???A后是否必定有nextVFX
                                else:
                                    kdata['JGVFX'][nextVFX]=0                       #???删除下一个V分型信号

                # 计算其它结构
                for j in range(minllocation+1,ttlk-1,1):
                    if kdata['JGAFX'][j]!=0:
                        high2ma30 = abs(kdata ['ma30'][j] - kdata['high'][j])
                        high2ma10 = abs(kdata['ma10'][j] - kdata['high'][j])
                        high2ma5 = abs(kdata['ma5'][j] - kdata['high'][j])
                        if kdata['high'][j]>kdata['ma30'][j] or high2ma30<high2ma10/2:
                            kdata['JG'][j]='9'
                            JGdone=1
                            if CHL<Kai*1.1: # and spaceP>normalspaceP[period]!!!
                                KJdone=1  # 需要参考对应级别的正常趋势空间  ZDJG=1  # 完成止跌结构
                                #10%以内都算完成趋势空间XXX CHL<Kai+normalspaceP[period]*10%
                            kdata['JGV'][j] = kdata['high'][j] #如果9与A重合，则JGV中只能保存一个值
                            for k in range(j,ttlk-1,1):     #有了9，后面的V分型就是0
                                if kdata['JGVFX'][k]==-1:
                                    kdata['JG'][k]='0'
                                    kdata['JGV'][k] = kdata['low'][k]
                                    break
                        else:
                            if kdata['high'][j]>kdata['ma10'][j] or high2ma10<high2ma5/2:
                                kdata['JG'][j]='7'
                                kdata['JGV'] [j] = kdata['high'][j]
                                for k in range(j,ttlk-1,1):
                                    if kdata['JGVFX'][k] ==-1: # logging.info("6+")
                                        kdata['JG'][k] = '8'
                                        kdata['JGV'][k] = kdata['low'][k]
                                        break

                for j in range(minllocation, ttlk - 1, 1):
                    if kdata['JGVFX'][j]==-1:
                        for k in range(j+1, ttlk-1,1):
                            if kdata['JGAFX'][k]==1:
                                break
                            if kdata['JGVFX'][k]==-1:
                                if kdata['JG'][j]!='6':
                                    if kdata['low'][j]<kdata['low'][k]:
                                        kdata['JGVFX'][k]=0
                                    else:
                                        kdata['JGVFX'][j]=0
                                else:
                                    kdata['JGVFX'][k] = 0

                # 定义最后一根K线的结构
                for j in range(ttlk-1, minllocation-1, -1):
                    lastFXis=kdata['JG'][j]
                    if lastFXis!=' ':
                        logging.info(f"-i am here {period} {lastFXis}")
                        if lastFXis == '6':
                            if kdata['high'][ttlk-1]>kdata['high'][j]:
                                CurrentJG = '7'
                                CurrentJGV = kdata['high'][ttlk - 1]
                            else:
                                CurrentJG ='6'
                                CurrentJGV=kdata['low'][ttlk-1]
                        if lastFXis == '7':
                            if kdata['low'][ttlk-1]<kdata['low'][j]:
                                CurrentJG = '8'
                                CurrentJGV = kdata['low'][ttlk - 1]
                            else:
                                CurrentJG ='7'
                                CurrentJGV=kdata['high'][ttlk-1]
                        if lastFXis == '8':
                            if kdata['high'][ttlk-1]>kdata['high'][j]:
                                CurrentJG = '9'
                                CurrentJGV = kdata['high'][ttlk - 1]
                            else:
                                CurrentJG ='8'
                                CurrentJGV=kdata['low'][ttlk-1]
                        if lastFXis == '9':
                            if kdata['low'][ttlk-1]<kdata['low'][j]:
                                CurrentJG = '0'
                                CurrentJGV = kdata['low'][ttlk - 1]
                            else:
                                CurrentJG ='9'
                                CurrentJGV=kdata['high'][ttlk-1]
                        if lastFXis == '0':
                            if kdata['high'][ttlk-1]>kdata['high'][j]:
                                CurrentJG ='01'  #'1?'
                                CurrentJGV = kdata['high'][ttlk - 1]
                            else:
                                CurrentJG ='0'
                                CurrentJGV=kdata['low'][ttlk-1]
                        kdata['JG'][ttlk-1]=CurrentJG
                        kdata['JGV'][ttlk-1] = CurrentJGV
                        ConfirmedJG=lastFXis
                        break

                #完成结构9后是否创新低 //KongHuang?
                for j in range(GGday,ttlk-1,1):
                    if kdata['JG'][j]=='9':
                        lowbefore   =kdata.iloc[GGday:j, 3].min()   # 3 'low'
                        lowafter    = kdata.iloc[j:ttlk-1, 3].min()  # 2 high 1  c losee 0 open
                        if lowafter<lowbefore: QX=1

                #比较下跌结构强弱       //JGQR
                for j in range(ttlk-2,minllocation-1,-1):   #从后向前找
                    if kdata['JG'][j] == '6' or kdata['JG'][j] == '8' or kdata[ 'JG'][j] == '0':
                        for k in range(j-1 , minllocation-1 , -1 ):
                            if kdata['JG'][k] == '6' or kdata['JG'][k]=='8' or kdata['JG'][k]=='0':
                                if kdata['low'][j]>kdata ['low'][k]:
                                    JGQR=1  # 结构强弱  //后面一个V比前面一个高, 则下跌结构强
                                    break
                                else:
                                    JGQR=-1 #后面一个V比前面一个低,则下跌结构弱
                                    break
                        break  # 只找最近的两个下跌的结构，比较强弱
                break  # 计算完下跌趋势的结构后退出程序（不用再向前找了）
            # 上涨趋势中上结构判断
            if kdata['kkllx'][i] == -2:
                # 从最高点开始找L离MA30最远的那根K线，开始找第一个底
                #logging.info(f"{period}是下跌趋势")
                maxhpercent = kdata['high'][i] /kdata['ma30'][i]
                maxhlocation = i

                for j in range(i ,ttlk -1 ,1):
                    maxhpercentnew =kdata['high'][j] /kdata['ma30'][j]
                    if maxhpercentnew > maxhpercent:
                        maxhlocation = j
                        maxhpercent =maxhpercentnew

                kdata['JGAFX'][maxhlocation ] =1  # 最远点为顶分型
                kdata['JG'][maxhlocation] = "1"  # 最远点为结构1
                kdata['JGV'][maxhlocation] = kdata['high'][maxhlocation]
                if maxhlocation == ttlk - 1: break  # 如果6是最后一根K线，则不计算其它结构只有6

                # 不同的结构算法，可能的计算起点不同，但是下面的计算都是一致的
                # 从1+1开始找下跌趋势中的A分型
                for j in range(maxhlocation +1, ttlk -1 ,1):
                    if kdata['high'][j] >kdata['high'][j -1]:
                        highlow =kdata['low'][j]
                        highhigh =kdata['high'][j]
                        for k in range(j +1 ,ttlk -1 ,1):
                            if highhigh <kdata['high'][k]:
                                j=k  # 如果在找到顶分型找到更低的底，则
                                break
                            if highlow>kdata['low'][k]:
                                kdata['JGAFX'][j] = 1
                                j=k
                                break
                                # 找到一个高顶
                # 1开始找上涨趋势中的V分型
                k=0
                for j in range(maxhlocation,ttlk-1,1):
                    if kdata ['JGAFX'][j]==1:
                        currentLow=kdata['low'][j]
                        currentLowLocation=j
                        for k in range(j+1,ttlk-1,1):
                            if kdata['low'][k]<currentLow:
                                currentLow=kdata['low'][k]
                                currentLowLocation=k
                            if kdata['JGAFX'][k]==1:
                                j=k
                                break
                        if k!=ttlk-1:
                            kdata['JGVFX'][currentLowLocation]=-1

                # 删除下跌趋势中无效A分型信号和左右两边较高的那个V分型信号 # 如果要删除的那个V是起始的6，则必须保留(当前是保留 因为其比例意义）
                # （或者换6到新的底）
                # 如果移动6，则minllocation要跟着一起改

                #logging.info(f"period:{period}")
                #logging.info(f"kdata:{kdata}")
                #删除碰不到MA10或MA30的V分型信号

                for j in range(maxhlocation,ttlk-1,1):
                    if kdata['JGVFX'][j]==-1:
                        low2ma10 =abs(kdata['ma10'][j]-kdata['low'][j])
                        low2ma5=abs(kdata['ma5'][j]-kdata['low' ] [j])
                        if kdata['low'][j]> kdata['ma10'][j] \
                                and low2ma5/2>low2ma10:   #？？？high超过ma10或high离ma5的距离是到ma10距离的2倍
                            #如果下跌过程中的A分型不满足79的结构条件，则删除这个A分型
                            kdata['JGVFX'][j] = 0
                                # 2 for debug
                            #找A分型的 下一个 A分型 （可能没有）
                            comp_OK=0
                            for k in  range(j,ttlk-1,1):
                                if kdata ['JGAFX'][k]==1:
                                    nextAFX=k   #如果后面没有V分型，则nextVFX=?
                                    comp_OK=comp_OK+1   #后面有个V
                                    break
                            #找A分型的 上一个 A分型 （必定有，至少有6）
                            for k in range(j,-1,-1):
                                if kdata['JGAFX'][k]==1:
                                    lastAFX=k
                                    comp_OK=comp_OK+1   #前面有个V
                                    break

                            if comp_OK==2:  #确保有两个V分型，再比较，否则程序报错
                                logging.info(f"lastAFX is {lastAFX} ||| nextAFX is {nextAFX}")
                                if kdata['high'][nextAFX]>=kdata['high'][lastAFX]:    #如果下一个low更低
                                    if kdata['JG'][lastAFX]!="1":                  #上一个不是6，就把上一个V分型信号删除
                                        #try:                                        #任何一个A分型前都能找到至少一个V分型信号（6）
                                        kdata['JGAFX'][lastAFX]=0              #这个地方应该不会出错 lastVFX下标一定能找到
                                    else:
                                        kdata['JGAFX'][nextAFX] =0                  #???A后是否必定有nextVFX
                                else:
                                    kdata['JGAFX'][nextAFX]=0                       #???删除下一个V分型信号

                # 计算其它结构
                # have 7  have8
                # lastFXis='6'
                # lastVFXis='6'
                # lastAFXis='0'
                # 从6后面的第一根K线开始找分型

                # 判断 9 和 是否完成下跌空间指标 XDKJ
                for j in range(maxhlocation+1,ttlk-1,1):
                    if kdata['JGVFX'][j]!=0:
                        low2ma30 = abs(kdata ['ma30'][j] - kdata['low'][j])
                        low2ma10 = abs(kdata['ma10'][j] - kdata['low'][j])
                        low2ma5 = abs(kdata['ma5'][j] - kdata['low'][j])
                        if kdata['low'][j]<kdata['ma30'][j] or low2ma30<low2ma10/2:
                            kdata['JG'][j]='4'
                            JGdone=1
                            if CHL>Luo/1.1: # and spaceP>normalspaceP[period]!!!
                                XDKJ=1  # 需要参考对应级别的正常趋势空间  ZDJG=1  # 完成止跌结构
                                #10%以内都算完成趋势空间XXX CHL<Kai+normalspaceP[period]*10%
                            kdata['JGV'][j] = kdata['low'][j] #如果9与A重合，则JGV中只能保存一个值
                            for k in range(j,ttlk-1,1):     #有了9，后面的V分型就是0
                                if kdata['JGAFX'][k]==1:
                                    kdata['JG'][k]='5'
                                    kdata['JGV'][k] = kdata['high'][k]
                                    break
                        else:
                            if kdata['low'][j]<kdata['ma10'][j] or low2ma10<low2ma5/2:
                                kdata['JG'][j]='2'
                                kdata['JGV'][j] = kdata['low'][j]
                                for k in range(j,ttlk-1,1):
                                    if kdata['JGAFX'][k] ==1: # logging.info("6+")
                                        kdata['JG'][k] = '3'
                                        kdata['JGV'][k] = kdata['high'][k]
                                        break

                for j in range(maxhlocation, ttlk - 1, 1):
                    if kdata['JGAFX'][j]==1:
                        for k in range(j+1, ttlk-1,1):
                            if kdata['JGVFX'][k]==-1:
                                break
                            if kdata['JGAFX'][k]==1:
                                if kdata['JG'][j]!='1':
                                    if kdata['high'][j]>kdata['high'][k]:
                                        kdata['JGAFX'][k]=0
                                    else:
                                        kdata['JGAFX'][j]=0
                                else:
                                    kdata['JGAFX'][k] = 0

                # 定义最后一根K线的结构
                #logging.info(f"{period},{kdata}")

                for j in range(ttlk-1, maxhlocation-1, -1):
                    lastFXis=kdata['JG'][j]
                    if lastFXis!=' ':
                        if lastFXis == '1':
                            if kdata['low'][ttlk-1]<kdata['low'][j]:
                                CurrentJG = '2'
                                CurrentJGV = kdata['low'][ttlk - 1]
                            else:
                                CurrentJG ='1'
                                CurrentJGV=kdata['high'][ttlk-1]
                        if lastFXis == '2':
                            if kdata['high'][ttlk-1]>kdata['high'][j]:
                                CurrentJG = '3'
                                CurrentJGV = kdata['high'][ttlk - 1]
                            else:
                                CurrentJG ='2'
                                CurrentJGV=kdata['low'][ttlk-1]
                        if lastFXis == '3':
                            if kdata['low'][ttlk-1]<kdata['low'][j]:
                                CurrentJG = '4'
                                CurrentJGV = kdata['low'][ttlk - 1]
                            else:
                                CurrentJG ='3'
                                CurrentJGV=kdata['high'][ttlk-1]
                        if lastFXis == '4':
                            if kdata['high'][ttlk-1]>kdata['high'][j]:
                                CurrentJG = '5'
                                CurrentJGV = kdata['low'][ttlk - 1]
                            else:
                                CurrentJG ='4'
                                CurrentJGV=kdata['low'][ttlk-1]
                        if lastFXis == '5':
                            if kdata['low'][ttlk-1]<kdata['low'][j]:
                                CurrentJG = '06' #'6?'
                                CurrentJGV = kdata['low'][ttlk - 1]
                            else:
                                CurrentJG ='5'
                                CurrentJGV=kdata['high'][ttlk-1]
                        kdata['JG'][ttlk-1]=CurrentJG
                        kdata['JGV'][ttlk-1] = CurrentJGV
                        ConfirmedJG=lastFXis
                        #logging.info(rf"Confirmed JG  now:{ConfirmedJG}")
                        break

                #完成结构4后是否创新高
                for j in range(DDday,ttlk-1,1):
                    if kdata['JG'][j]=='4':
                        highbefore   =kdata.iloc[DDday:j, 2].max()   # 3 'low'
                        highafter    = kdata.iloc[j:ttlk-1, 2].max()  # 2 high 1  c losee 0 open
                        if highafter>highbefore: QX=1

                #比较下跌结构强弱
                for j in range(ttlk-2,maxhlocation-1,-1):
                    if kdata['JG'][j] == '1' or kdata['JG'][j] == '3' or kdata[ 'JG'][j] == '5':
                        for k in range(j-1 , maxhlocation-1 , -1 ):
                            if kdata['JG'][k] == '1' or kdata['JG'][k]=='3' or kdata['JG'][k]=='5':
                                if kdata['high'][j]<kdata ['high'][k]:
                                    JGQR=-1  # 结构强弱
                                    #logging.info(rf"{period}结构强 {kdata['low'][k]} < {kdata['low' ] [j]}")
                                    break
                                else:
                                    JGQR=1
                                    #logging.info(rf"{period}结构弱 {kdata['low'][k]} > {kdata['low'][j]}")
                                    break
                        break  # 只找最近的两个下跌的结构，比较强弱
                break  # 计算完下跌趋势的结构后退出程序（不用再向前找了）
        periodJG={
            #'code'          :   stockcode+period,
            #'stockcode'     :   stockcode,
            #'period'        :   period,
            #'QS'            :   QS,         # 趋势方向
            'ConfirmedJG'   :   ConfirmedJG,# 确认的结构
            'CurrentJG'     :   CurrentJG,  # 当前（可能）结构'XDKJ'          :   XDKJ,  # 完成下跌空间？
            'JGdone'        :   JGdone,     #完成结构 有9或4且又没有大幅创新高或创新低 与ma30的相对距离判断
            #'KJDone'        :   KJdone,     #完成空间   #这个应该是在趋势计算中判断
            #'ZDJG'          :   ZDJG,       # 形成止跌结构？
            'QX'     :   QX,  # 制造恐慌？
            'JGQR'          :   JGQR,       # 结构强弱
            #'XDKJ'          :   XDKJ,       # 完成下跌空间
            #'reviseTime'    :   revisetime
        }
        #kdata.to_csv(rf"./tmpout/{period}.csv", encoding="utf_8_sig", index=True)
        return kdata, periodJG
    def topns(self,module,pns,reason,price,period):
        tmppns={'module':module,'pns':pns,'reason':reason,'price':price,'per':0,'period':period}
        self.pns=pd.concat([self.pns, pd.DataFrame([tmppns])], ignore_index=True)
    def cal_qsjg_pns(self,periodQS,periodJG,period):
        self.topns("QS","P","GG",periodQS['GG'],self.p2ab[period])
        self.topns("QS","P","Luo",periodQS['Luo'],self.p2ab[period])
        self.topns("QS","S","Kai",periodQS['Kai'],self.p2ab[period])
        self.topns("QS","S","DD",periodQS['DD'],self.p2ab[period])
        tmpqs=self.QS[period]
        #print(f"period:{period}")
        if ("-1" in tmpqs or "-2" in tmpqs or "0" in tmpqs) and period!="m1":
            self.topns("JG","P","ma30",periodQS['ma30'],self.p2ab[period])
            if int(periodJG['CurrentJG'])<=7 and periodJG['CurrentJG']!="0" and period!="m1" and period!="m5":
                self.topns("JG","P","ma10",periodQS['ma10'],self.p2ab[period])
        if ("+1" in tmpqs or "+2" in tmpqs) and period!="m1":
            self.topns("JG","S","ma30",periodQS['ma30'],self.p2ab[period])
            if int(periodJG['CurrentJG'])<=2 and period!="m1" and period!="m5":
                self.topns("JG","S","ma10",periodQS['ma10'],self.p2ab[period])

    def cal_qs_pnsall(self):
        if self.QS_m['Kai']!=0:
            if self.QS_m['Luo']/self.QS_m['Kai']-1>=self.space['month']:
                self.PnS=\
                    {'mGG': self.QS_m['GG'],'mLuo':self.QS_m['Luo'],'mDD': self.QS_m['DD'],'mKai':self.QS_m['Kai']\
                ,'mma5':self.QS_m['ma5'],'mma10':self.QS_m['ma10'],'mma30':self.QS_m['ma30']
                     }

        if self.QS_w['Kai']!=0:
            if self.QS_w['Luo']/self.QS_w['Kai']-1>=self.space['week']:
                self.PnS=self.Merge(self.PnS,\
                    {'wGG': self.QS_w['GG'],'wLuo':self.QS_w['Luo'],'wDD': self.QS_w['DD'],'wKai':self.QS_w['Kai']\
                ,'wma5':self.QS_w['ma5'],'wma10':self.QS_w['ma10'],'wma30':self.QS_w['ma30']
                     })

        if self.QS_d['Kai']!=0:
            if self.QS_d['Luo']/self.QS_d['Kai']-1>=self.space['day']:
                self.PnS=self.Merge(self.PnS,\
                    {'dGG': self.QS_d['GG'],'dLuo':self.QS_d['Luo'],'dDD': self.QS_d['DD'],'dKai':self.QS_d['Kai']\
                ,'dma5':self.QS_d['ma5'],'dma10':self.QS_d['ma10'],'dma30':self.QS_d['ma30']
                     })

        if self.QS_t['Kai']!=0:
            if self.QS_t['Luo']/self.QS_t['Kai']-1>=self.space['m30']:
                self.PnS=self.Merge(self.PnS,\
                    {'tGG': self.QS_t['GG'],'tLuo':self.QS_t['Luo'],'tDD': self.QS_t['DD'],'tKai':self.QS_t['Kai']\
                ,'tma5':self.QS_t['ma5'],'tma10':self.QS_t['ma10'],'tma30':self.QS_t['ma30']
                     })

        if self.QS_f['Kai']!=0:
            if self.QS_f['Luo']/self.QS_f['Kai']-1>=self.space['m5']:
                self.PnS=self.Merge(self.PnS,\
                    {'fGG': self.QS_f['GG'],'fLuo':self.QS_f['Luo'],'fDD': self.QS_f['DD'],'fKai':self.QS_f['Kai']\
                ,'fma5':self.QS_f['ma5'],'fma10':self.QS_f['ma10'],'fma30':self.QS_f['ma30']
                     })

        if self.QS_o['Kai']!=0:
            if self.QS_o['Luo']/self.QS_o['Kai']-1>=self.space['m1']:
                self.PnS=self.Merge(self.PnS,\
                    {'oGG': self.QS_o['GG'],'oLuo':self.QS_o['Luo'],'oDD': self.QS_o['DD'],'oKai':self.QS_o['Kai']\
                ,'oma5':self.QS_o['ma5'],'oma10':self.QS_o['ma10'],'oma30':self.QS_o['ma30']
                     })
        
        self.PnS = self.Merge(self.PnS, \
                              {'C':self.QS_m['C'],'H':self.kdata_d['high'][(self.kdata_d.shape[0]-1)],'L':self.kdata_d['low'][(self.kdata_d.shape[0]-1)]
                               })

        tmppd=pd.DataFrame.from_dict(self.PnS,orient='index',columns=['value'])
        tmppd=tmppd.reset_index().rename(columns={'index':'name'})
        #tmppd.insert(2, 'pct', 0.00)  # -1起涨点 +1起跌点
        tmppd['pct']=0.00  # -1起涨点 +1起跌点
        tmppd['pct'] = tmppd['value'].map(lambda x: (x / self.QS_m['C']-1)*100)
        tmppd['pct']=tmppd['pct'].round(2)
        tmppd=tmppd.sort_values(by="pct", ascending=False)
        tmppd=tmppd.reset_index(drop=True)
        tmppd.index=tmppd.index+1
        self.PnSpd=tmppd
    def cal_qs_pnsbyperiod(self):  
        #数据 - > 趋势分析 -> 结构分析 ->pns -> BSZC
        #print("by period self.QS_m:",self.QS_m)
        #print("by period self.JG_m:",self.JG_m)
        for i in self.periodab:
            #print(i)
            pass
        pass
    def cal_pns(self):
        newpns=self.pns
        #月线pns
        if "0" in self.QS['month']:newpns=newpns[(newpns['period']!="m")]
        if "0" in self.QS['week']:newpns=newpns[(newpns['period']!="w")]
        if "0" in self.QS['day']:newpns=newpns[(newpns['period']!="d")]
        if "0" in self.QS['m30']:newpns=newpns[(newpns['period']!="t")]
        if "0" in self.QS['m5']:newpns=newpns[(newpns['period']!="f")]
        if "0" in self.QS['m1']:newpns=newpns[(newpns['period']!="o")]
        newhavelist=self.havelist[(self.havelist['code']==self.stockcode[:6])]
        newhavelist=newhavelist.reset_index(drop=True)
        maxprice=newhavelist['+'][0]
        minprice=newhavelist['-'][0]
        newpns=newpns[(newpns['price']<maxprice) & (newpns['price']>minprice)]
        newpns=newpns.reset_index(drop=True)
        print(newpns)
        #self.pns=newpns

        pnsm=self.pns[(self.pns['period']=="m") | (self.pns['module']=="")]
        pnsm=pnsm[['reason','price','per']]
        pnsm=pnsm.reset_index(drop=True)
        #周线pns
        try: 
            pnsw=self.pns[(self.pns['period'] =="m") | (self.pns['period']=="w")  | (self.pns['module']=="")]
            pnsw=pnsw.reset_index(drop=True)
            try:
                startx=pnsw[pnsw['reason']=="GG_w"].index[0]
            except:
                startx=100
            startx1=pnsw[pnsw['reason']=="H_"].index[0]
            startx=min(startx,startx1)

            try:
                endx=pnsw[pnsw['reason']=="DD_w"].index[0]
            except:
                endx=0
            endx1=pnsw[pnsw['reason']=="L_"].index[0]
            endx=max(endx,endx1)
            pnsw=pnsw[startx:endx+1]
            pnsw=pnsw[['reason','price','per']]
            pnsw=pnsw.reset_index(drop=True)
        except:
            pnsw=pd.DataFrame()

        #日线pns
        try: 
            pnsd=self.pns[(self.pns['period'] =="m") | (self.pns['period']=="w") | (self.pns['period']=="d")  | (self.pns['module']=="")]
            pnsd=pnsd.reset_index(drop=True)
            try:
                startx=pnsd[pnsd['reason']=="GG_d"].index[0]
            except:
                startx=100
            startx1=pnsd[pnsd['reason']=="H_"].index[0]
            startx=min(startx,startx1)

            try:
                endx=pnsd[pnsd['reason']=="DD_d"].index[0]
            except:
                endx=0
            endx1=pnsd[pnsd['reason']=="L_"].index[0]
            endx=max(endx,endx1)

            pnsd=pnsd[startx:endx+1]
            pnsd=pnsd[['reason','price','per']]
            pnsd=pnsd.reset_index(drop=True)
        except:
            pnsd=pd.DataFrame()

        #30分钟pns
        try: 
            pnst=self.pns[(self.pns['period'] =="m") | (self.pns['period']=="w") | (self.pns['period']=="d") | (self.pns['period']=="t")  | (self.pns['module']=="")]
            pnst=pnst.reset_index(drop=True)
            try:
                startx=pnst[pnst['reason']=="GG_t"].index[0]
            except:
                startx=100
            startx1=pnst[pnst['reason']=="H_"].index[0]
            startx=min(startx,startx1)
            
            try:
                endx=pnst[pnst['reason']=="DD_t"].index[0]
            except:
                endx=0
            endx1=pnst[pnst['reason']=="L_"].index[0]
            endx=max(endx,endx1)

            pnst=pnst[startx:endx+1]
            pnst=pnst[['reason','price','per']]
            pnst=pnst.reset_index(drop=True)
        except:
            pnst=pd.DataFrame()

        #5分钟pns
        try:
            pnsf=self.pns[(self.pns['period'] =="m") | (self.pns['period']=="w") | (self.pns['period']=="d") | (self.pns['period']=="t") | (self.pns['period']=="f")   | (self.pns['module']=="")]
            pnsf=pnsf.reset_index(drop=True)
            try:
                startx=pnsf[pnsf['reason']=="GG_f"].index[0]
            except:
                startx=100
            startx1=pnsf[pnsf['reason']=="H_"].index[0]
            startx=min(startx,startx1)
                
            try:
                endx=pnsf[pnsf['reason']=="DD_f"].index[0]
            except:
                endx=0
            endx1=pnsf[pnsf['reason']=="L_"].index[0]
            endx=max(endx,endx1)

            pnsf=pnsf[startx:endx+1]
            pnsf=pnsf[['reason','price','per']]
            pnsf=pnsf.reset_index(drop=True)
        except:
            pass

        #1分钟pns
        try:
            pnso=self.pns[(self.pns['period'] =="m") | (self.pns['period']=="w") | (self.pns['period']=="d") | (self.pns['period']=="t") | (self.pns['period']=="f") | (self.pns['period']=="o")  | (self.pns['module']=="")]
            pnso=pnso.reset_index(drop=True)
            try:
                startx=pnso[pnso['reason']=="GG_o"].index[0]
            except:
                startx=100
            startx1=pnso[pnso['reason']=="H_"].index[0]
            startx=min(startx,startx1)
                
            try:
                endx=pnso[pnso['reason']=="DD_o"].index[0]
            except:
                endx=0
            endx1=pnso[pnso['reason']=="L_"].index[0]
            endx=max(endx,endx1)

            pnso=pnso[startx:endx+1]
            pnso=pnso[['reason','price','per']]
            pnso=pnso.reset_index(drop=True)
        except:
            pass
        pnsttl=pd.concat([pnsm,pnsw,pnsd,pnst,pnsf,pnso],axis=1)
        pnsttl=pnsttl.fillna("")
        
        newpnsm=pnsm[(pnsm['reason']=="fake")]
        newpnsw=newpnsm
        newpnsd=newpnsm
        newpnst=newpnsm
        newpnsf=newpnsm
        newpnso=newpnsm

        if "0" not in self.QS['month']: newpnsm=pnsm[(pnsm['price']<maxprice) & (pnsm['price']>minprice)]
        if "0" not in self.QS['week']:  newpnsw=pnsw[(pnsw['price']<maxprice) & (pnsw['price']>minprice)]
        if "0" not in self.QS['day']:   newpnsd=pnsd[(pnsd['price']<maxprice) & (pnsd['price']>minprice)]
        if "0" not in self.QS['m30']:   newpnst=pnst[(pnst['price']<maxprice) & (pnst['price']>minprice)]
        if "0" not in self.QS['m5']:    newpnsf=pnsf[(pnsf['price']<maxprice) & (pnsf['price']>minprice)]
        if "0" not in self.QS['m1']:    newpnso=pnso[(pnso['price']<maxprice) & (pnso['price']>minprice)]
        newpnsttl=pd.concat([newpnsm,newpnsw,newpnsd,newpnst,newpnsf,newpnso],axis=1)
        newpnsttl=newpnsttl.fillna("")

        self.get_havelist()
        #os.system("clear")
        print(self.havelist)
        #print(self.QS)
        tmpstr=f"--M:{self.QS['month']}-------------W:{self.QS['week']}-------------D:{self.QS['day']}-------------T:{self.QS['m30']}--------------F:{self.QS['m5']}-------------O:{self.QS['m1']}----------"
        #print(f"-------------------M:{self.QS['month']}-------------W:{self.QS['week']}-------------D:{self.QS['day']}-------------T:{self.QS['m30']}--------------F:{self.QS['m5']}-------------O:{self.QS['m1']}----------")
        print(f"\033[0;31;40m\t {tmpstr} \033[0m")
        print(pnsttl)
        print(f"\033[0;31;40m\t {tmpstr} \033[0m")
        print(newpnsttl)
        print(f"\033[0;31;40m\t {tmpstr} \033[0m")
        #print(f"-------------------M:{self.QS['month']}-------------W:{self.QS['week']}-------------D:{self.QS['day']}-------------T:{self.QS['m30']}--------------F:{self.QS['m5']}-------------O:{self.QS['m1']}----------")
        #print("-------------------M------------------W------------------D------------------T-------------------F------------------O----------")
        self.pnsttl=pnsttl
        self.newpnsttl=newpnsttl

    def cal_qs(self,kdata, stockcode, period):
        #periodQS={}
        closeprice=kdata['close'][-1]
        '''
        periodQS = {'code':         stockcode + period,
                    'stockcode':    stockcode,
                    'period':       period,
                    'C':            closeprice,  # data['close'][-1],
                    'QS':           0,
                    'DD':           0,
                    'Kai':          0,
                    'GG':           0,
                    'Luo':          0,
                    'profitP':      0,
                    'riskP':        0,
                    'PLP':          0,
                    'CHL':          0,
                    'CHLP':         0,
                    'spaceP':       0,
                    'outofrange':   0,
                    'QSabnormal':   0,  # QSabnormal,
                    'ma5':          kdata['ma5'][-1].round(2),
                    'ma10':         kdata['ma10'][-1].round(2),
                    'ma30':         kdata['ma30'][-1].round(2),
                    'ma5P':         (closeprice / kdata['ma5'][-1] * 100 - 100).round(2),
                    'ma10P':        (closeprice / kdata['ma10'][-1] * 100 - 100).round(2),
                    'ma30P':        (closeprice / kdata['ma30'][-1] * 100 - 100).round(2),
                    'periodSugg':   0,
                    'DDCGorGGCD':   0,
                    'reviseTime':   "nodata"+period,
                    'NDG'	:   0,
                    'NKL'       :   0,
                    'CHL1'      :   0,
                    'DDCGorGGCD1':  0
                    }
        '''
        periodQS = {'code':         stockcode + period,
                    'stockcode':    stockcode,
                    'period':       period,
                    'C':            99,#closeprice,  # data['close'][-1],
                    'QS':           99,
                    'DD':           99,
                    'Kai':          99,
                    'GG':           99,
                    'Luo':          99,
                    'profitP':      99,
                    'riskP':        99,
                    'PLP':          99,
                    'CHL':          99,
                    'CHLP':         99,
                    'spaceP':       99,
                    'outofrange':   99,
                    'QSabnormal':   99,  # QSabnormal,
                    'ma5':          99,#kdata['ma5'][-1].round(2),
                    'ma10':         99,#kdata['ma10'][-1].round(2),
                    'ma30':         99,#kdata['ma30'][-1].round(2),
                    'ma5P':         99,#(closeprice / kdata['ma5'][-1] * 100 - 100).round(2),
                    'ma10P':        99,#(closeprice / kdata['ma10'][-1] * 100 - 100).round(2),
                    'ma30P':        99,#(closeprice / kdata['ma30'][-1] * 100 - 100).round(2),
                    'periodSugg':   99,
                    'DDCGorGGCD':   99,
                    'reviseTime':   99,#"nodata"+period,
                    'NDG'	:   99,
                    'NKL'       :   99,
                    'CHL1'      :   99,
                    'DDCGorGGCD1':  99
                    }
        #periodJG={}
        periodJG={
             'ConfirmedJG'   :   99,# 确认的结构
             'CurrentJG'     :   99,  # 当前（可能）结构'XDKJ'          :   XDKJ,  # 完成下跌空间？
             'JGdone'        :   99,     #完成结构 有9或4且又没有大幅创新高或创新低 与ma30的相对距离判断
             'QX'            :   99,  # 制造恐慌？
             'JGQR'          :   99       # 结构强弱
         }
        ttlk = kdata.shape[0]
        if ttlk<50: return kdata,periodQS,periodJG
        kdata=self.cal_qs_KaiLuo(kdata,ttlk)                        #+1 -1 [Luo 和 Kai]
        kdata=self.cal_qs_GGDD(kdata,ttlk)                          #+2 -2 [GG 和 DD]
        kdata=self.cal_qs_kkllv(kdata,ttlk)                         #计算+1 和 -1的数值
        #趋势模型
        kdata=self.cal_qs_QSmodule_NDGNKL(kdata,ttlk)
        kdata=self.cal_qs_QSmodule_QSDDKaiGGLuo(kdata,ttlk)
        kdata,periodQS=self.cal_qs_QSmodule_CHL1andCHL(stockcode,kdata,ttlk,period)
        #趋势信号
        self.cal_qs_QSmessage(kdata,ttlk,period)
        #结构模型
        kdata,periodJG=self.cal_jg_JGmodule(kdata,ttlk,period,periodQS)
        self.cal_qsjg_pns(periodQS,periodJG,period)
        return kdata, periodQS, periodJG
    def cal_qs_all(self):
        self.kdata_m,self.QS_m,self.JG_m = self.cal_qs(self.kdata_m, self.stockcode, 'month')
        self.kdata_w,self.QS_w,self.JG_w = self.cal_qs(self.kdata_w, self.stockcode, 'week')
        self.kdata_d,self.QS_d,self.JG_d = self.cal_qs(self.kdata_d, self.stockcode, 'day')
        self.kdata_t,self.QS_t,self.JG_t = self.cal_qs(self.kdata_t, self.stockcode, 'm30')
        self.kdata_f,self.QS_f,self.JG_f = self.cal_qs(self.kdata_f, self.stockcode, 'm5')
        self.kdata_o,self.QS_o,self.JG_o = self.cal_qs(self.kdata_o, self.stockcode, 'm1')
        self.cal_qs_pnsall()        #所有级别的ps放在一起
        self.cal_qs_pnsbyperiod()   #单独计算每个级别的ps

        self.topns("","","H",self.kdata_d['high'][(self.kdata_d.shape[0]-1)],"")
        self.topns("","","L",self.kdata_d['low'][(self.kdata_d.shape[0]-1)],"")
        self.topns("","","C",self.QS_m['C'],"")
        self.pns['per']=round((self.pns['price']/self.QS_m['C']-1)*100,1)
        #print("all",self.pns)
        pns1=self.pns[(self.pns['per']>0) & (self.pns['pns']=="S")]
        self.pns=pd.concat([self.pns, pns1]).drop_duplicates(keep=False)
        pns1=self.pns[(self.pns['per']<0) & (self.pns['pns']=="P")]
        self.pns=pd.concat([self.pns, pns1]).drop_duplicates(keep=False)
        self.pns=self.pns.sort_values(by=['per'],ascending=False)
        self.pns['reason']=self.pns['reason']+"_"+self.pns['period']
        self.cal_pns()
