'''
myBT = engine(portforlio,money,startDate,endDate,turnover,benchmark,price)
myBT.backTesting()
myBT.getDailyResult()
'''
import logging
import sys
import os
logger = logging.getLogger(__name__)
logger.setLevel(logging.CRITICAL) # higher level, less showing 

twoLevelUp = os.path.abspath(os.path.join(__file__ ,"../.."))
oneLevelUp = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0,twoLevelUp)
#print(sys.path)
from util.kySDK import * 
from ..API.highway import highwayAPI
from .position import Position
from .account import Account
from datetime import datetime
from dataTable import DataTable
import os
import time
import sys
import pyodbc
import json

class Engine():
    myAPI = highwayAPI()
    myAPI.init()
    
    def __str__(self):
        print('This is a backtesting engine')

    def __init__(self,inputJson):
        '''
        ID = '1'
        strategy = \
        {
            "stockPicker":{'pick':False,'dateList':None},
            "criteriaDict" : {"PE(TTM)":["PE","CY_ValueDaily_Quote"]},
            "portforlio": ['600000','000002'], 
            "benchmark": 'HS300', 
            "money": 5000000, 
            "startDate": '2014-07-01', 
            "endDate": '2016-02-01', 
            "turnover": 10, 
            "tradingHabit": "OpenPrice",
            "status":0
        }

        inputJson = \
        {
            ID:strategy 
        }
        '''

        self.inputJson = inputJson
        self.strategyID = inputJson['strategyID']
        self.stockPicker = inputJson['stockPicker']
        self.criteriaDict = inputJson['criteriaDict']
        portforlio = inputJson['portforlio']
        self.benchmark = inputJson['benchmark']
        self.initialCash = inputJson['money']
        self.startDate = inputJson['startDate']
        self.endDate = inputJson['endDate']
        self.turnover = inputJson['turnover']
        self.tradingHabit = inputJson['tradingHabit']
        self.status = inputJson['status']
        logger.critical('\n开始运行策略：%s'%self.strategyID)

        
        if self.stockPicker['pick'] == True:
            if isinstance(self.stockPicker['dateList'],list) is not True:
                raise ValueError("['stockPicker'][bool,list of date]")
            
            if False in [True if self.endDate >= x and x>= self.startDate else False for x in self.stockPicker['dateList'] ]:
                raise ValueError("['stockPicker'][bool,list of date], stockPicking list of date should be within startDate and endDate")

        if self.endDate < self.startDate:
            raise ValueError('endDate cannot be smaller than startDate')
        
        if self.endDate >= self.myAPI.getYesterday():
            self.endDate = self.myAPI.getYesterday()

        if self.turnover == 1:
            raise ValueError('没有T+0,-买-持-卖-整个周期不可能是1天')

        if self.turnover == 0:
            self.turnover = 10000000

        if isinstance(portforlio,str) and portforlio in ['HS300','ZZ500','SZ50']:
            if portforlio == 'HS300':
                portforlio = 'SHSE.000300'
            elif portforlio == 'ZZ500':
                portforlio = 'SHSE.000905'
            elif portforlio == 'SZ50':
                portforlio = 'SHSE.000016'
            
            self.portforlio = [stockCode[-6:] for stockCode in getIndexPoolFromKy(portforlio)] #['SHSE.600000','SHSE.000002'] 

        elif isinstance(portforlio,str) and portforlio == 'all':
            
            self.portforlio = self.myAPI.getAllStockCode(self.startDate)

        elif isinstance(portforlio,list):
            self.portforlio = portforlio

        print('len(self.portforlio)',len(self.portforlio))

        # download and process all data needed
        self.downloadA = time.time()
        self.bulk = self.myAPI.getAllNeeded(self.inputJson)
        self.downloadB = time.time()
        #print('self.bulk: ',self.bulk)

        self.BTRecords = dict()     
        self.IndexRecords = None  
        self.tradingDayHistory = list() # will help get the previous trading day

    @staticmethod
    def findRightDate(oneDay,option):
        '''
        根据oneDay和option找出最近的一期（几期）财报
        option = '最近三年','最近一年','最近一期'
        比如 
        oneDay = '2014-12-30'
        option = '最近三年'
        则返回  ['2013-12-31','2012-12-31','2011-12-30']
        '''
        reportDateList = ['03-31','06-30','09-30','12-31']
        #fisrtYear = oneDay[:4]
        #recentMonthDay = oneDay[5:]
        #recentReportDate = recentYear + '-' + [x for x in reportDateList if oneDay[5:] > x][0]

        if option == '最近三年':
            if '12-31' not in oneDay:  
                firstYear = str(eval('int(oneDay[:4]) - 1')) + '-' + '12-31'
                secondYear = str(eval('int(oneDay[:4]) - 2')) + '-' + '12-31'
                thirdYear = str(eval('int(oneDay[:4]) - 3')) + '-' + '12-31'
                fourthYear = str(eval('int(oneDay[:4]) - 4')) + '-' + '12-31' # 多加一年，保险起见
            else:
                firstYear = oneDay
                secondYear = str(eval('int(firstYear[:4]) - 1')) + '-' + '12-31'
                thirdYear = str(eval('int(firstYear[:4]) - 2')) + '-' + '12-31'
                fourthYear = str(eval('int(firstYear[:4]) - 3')) + '-' + '12-31'
            return [firstYear,secondYear,thirdYear,fourthYear]

        elif option == '最近一年':  
            if '12-31' not in oneDay:
                firstYear = str(eval('int(oneDay[:4]) - 1')) + '-' + '12-31'
                secondYear = str(eval('int(oneDay[:4]) - 2')) + '-' + '12-31'
            else:
                firstYear = oneDay
                secondYear = str(eval('int(firstYear[:4]) - 1')) + '-' + [x for x in reportDateList if firstYear[5:] > x][0]
            return [firstYear,secondYear]

        elif option == '最近一期':
            if oneDay[5:] not in reportDateList:
                if oneDay[5:] < reportDateList[0]: #'01-02' < '03-31'
                    firstYear = str(eval('int(oneDay[:4]) - 1'))
                    firstPeriod = firstYear + '-' + reportDateList[-1]
                    secondPeriod = firstYear + '-' + reportDateList[-2]
                elif oneDay[5:] < reportDateList[1]: #'04-05' < '06-30'
                    firstYear = oneDay[:4]
                    firstPeriod = firstYear + '-' + reportDateList[0]
                    secondPeriod = str(eval('int(firstYear) - 1'))+ '-' + reportDateList[3]
                else:
                    firstYear = oneDay[:4]
                    #print('test: ',[x for x in reportDateList if oneDay[5:] > x])
                    firstPeriod = firstYear + '-' + [x for x in reportDateList if oneDay[5:] > x][-1]
                    secondPeriod = firstYear + '-' + [x for x in reportDateList if oneDay[5:] > x][-2]
            else: #oneDay = '2015-03-31' or '2016-12-31'
                if oneDay[5:] == '03-31':
                    firstPeriod = oneDay
                    secondPeriod = str(eval('int(oneDay[:4]) - 1')) + '-' + '12-31'
                else:
                    firstPeriod = oneDay
                    secondPeriod = oneDay[:4] + '-' + [x for x in reportDateList if oneDay[5:] > x][-1]
            return [firstPeriod,secondPeriod]
        else:
            raise ValueError('输入要是最近一期，最近一年，最近三年，请检查Json的输入') 

    def extractBulk(self,oneDay):
        '''
        oneDay = '2013-05-03' #'2014-12-30'
        extract from myAPI.getAllNeeded(inputJson)

        {'EM_QUOTE_STOCK_DAILY':{date:[stockObj]},
        'CY_FinacialRatio_RP':{date:[financialRatioObj]},

        return is

        {'600485': {'主营收入同比': [Decimal('13.2225'), Decimal('33.8532'), Decimal('851.6680')]}, 
         '600000': {'主营收入同比': [Decimal('18.9713'), Decimal('18.9713'), Decimal('23.1625'), Decimal('23.1625'), Decimal('20.5
          697'), Decimal('20.5697')]}, 
         '000002': {'主营收入同比': [Decimal('33.5828'), Decimal('8.1002'), Decimal('31.3263')]}}
        '''

        resultDict = dict()
        
        for stock in self.portforlio:
            resultDict[stock] = dict()
            for criteria in self.inputJson['criteriaDict']:
                #print('extractBulk: ',self.inputJson[self.strategyID]['criteriaDict'][criteria][0])
                if self.inputJson['criteriaDict'][criteria][0] == '最近三年':
                    DateList = self.findRightDate(oneDay,self.inputJson['criteriaDict'][criteria][0])
                    firstYear = DateList[0]
                    secondYear = DateList[1]
                    thirdYear = DateList[2]
                    #找到相对应的criteria数据
                    criteriaList = []          
                    for year in [firstYear,secondYear,thirdYear]:
                        tableName = DataTable[criteria][1]
                        matchedObj = [x for x in self.bulk[tableName][year] if x.SecuCode == stock and x.EndDate == year]
                        if not matchedObj:
                            oneObj = matchedObj[0] if len(matchedObj) > 1 else matchedObj[0] # 可能重复，需要去重，这里是简单地取第一个
                            criteriaList.append(eval('oneObj.%s'%(DataTable[criteria][0])))
                        '''    
                        for finObj in bulk['CY_FinacialRatio_RP'][year]:
                            #print(finObj.SecuCode,finObj.EndDate)
                            
                            
                            if finObj.SecuCode == stock and finObj.EndDate == year:
                                criteriaList.append(eval('finObj.%s'%(DataTable[criteria][0])))
                        '''

                    resultDict[stock][criteria] = criteriaList
        
                elif self.inputJson['criteriaDict'][criteria][0] == '最近一年':
                    DateList = self.findRightDate(oneDay,self.inputJson['criteriaDict'][criteria][0])
                    '''
                    for spotDate in list(bulk['CY_FinacialRatio_RP'].keys()): #dict_keys(['2015-12-31', '2015-09-30', '2015-06-30', '2015-03-31', '2014-12-31'])
                        if '-12-31' in spotDate:
                            firstYear = spotDate  #'2015-12-31'
                        break
                    '''
                    firstYear = DateList[0]  #还没有考虑

                    #找到相对应的criteria数据
                    criteriaList = []          
                    #print(self.bulk['CY_FinacialRatio_RP'])
                    tableName = DataTable[criteria][1]
                    try:
                        matchedObj = [x for x in self.bulk[tableName][firstYear] if x.SecuCode == stock and x.EndDate == firstYear]
                    except KeyError:
                        matchedObj = [x for x in self.bulk[tableName][DateList[1]] if x.SecuCode == stock and x.EndDate == DateList[1]]

                    if matchedObj:
                        oneObj = matchedObj[0] if len(matchedObj) > 1 else matchedObj[0] # 可能重复，需要去重，这里是简单地取第一个
                        criteriaList.append(eval('oneObj.%s'%(DataTable[criteria][0])))


                    '''
                    for finObj in bulk['CY_FinacialRatio_RP'][firstYear]:
                        #print(finObj.SecuCode,finObj.EndDate)
                        if finObj.SecuCode == stock and finObj.EndDate == firstYear:
                            criteriaList.append(eval('finObj.%s'%(DataTable[criteria][0])))
                    '''
                    resultDict[stock][criteria] = criteriaList

                elif self.inputJson['criteriaDict'][criteria][0] == '最近一期':
                    DateList = self.findRightDate(oneDay,self.inputJson['criteriaDict'][criteria][0])
                    firstPeriod = DateList[0]

                    #找到相对应的criteria数据
                    criteriaList = []  
                    tableName = DataTable[criteria][1]
                    try:
                        matchedObj = [x for x in self.bulk[tableName][firstYear] if x.SecuCode == stock and x.EndDate == firstYear]
                    except KeyError:
                        matchedObj = [x for x in self.bulk[tableName][DateList[1]] if x.SecuCode == stock and x.EndDate == DateList[1]]

                    if matchedObj:
                        oneObj = matchedObj[0] if len(matchedObj) > 1 else matchedObj[0] # 可能重复，需要去重，这里是简单地取第一个
                        criteriaList.append(eval('oneObj.%s'%(DataTable[criteria][0])))
                    '''       
                    for finObj in bulk['CY_FinacialRatio_RP'][firstPeriod]:
                        #print(finObj.SecuCode,finObj.EndDate)
                        if finObj.SecuCode == stock and finObj.EndDate == firstPeriod:
                            criteriaList.append(eval('finObj.%s'%(DataTable[criteria][0])))
                    '''
                    resultDict[stock][criteria] = criteriaList
                else:
                    raise ValueError('输入要是最近一期，最近一年，最近三年，请检查Json的输入') 

        #print('extractBulk: ',resultDict,)    
        return resultDict


    def screenStock(self,resultDict,oneDay):
        """
        {'600485': {'主营收入同比': [Decimal('13.2225'), Decimal('33.8532'), Decimal('851.6680')]}, 
         '600000': {'主营收入同比': [Decimal('18.9713'), Decimal('18.9713'), Decimal('23.1625'), Decimal('23.1625'), Decimal('20.5
          697'), Decimal('20.5697')]}, 
         '000002': {'主营收入同比': [Decimal('33.5828'), Decimal('8.1002'), Decimal('31.3263')]}}
            
            
         {'600485':True,
         '600000':False,
         ...
         }
        """
        screenResult = dict()

        for stock,value in resultDict.items():
            multiple = []
            for criteria,valueList in value.items():

                upperbound = self.inputJson['criteriaDict'][criteria][1]
                lowerbound = self.inputJson['criteriaDict'][criteria][2]

                if upperbound == None:
                    upperbound = float('inf')

                if lowerbound == None:
                    lowerbound = -float('inf')

                if len(valueList) == 0:
                    single = False
                else:
                    # 全真则为真，否则为假
                    single = False if False in [True if x > lowerbound and x < upperbound else False for x in valueList] else True #[Decimal('13.2225'), Decimal('33.8532'), Decimal('851.6680')]
                multiple.append(single)

            consilidatedResult = False if False in multiple else True
            screenResult[stock] = consilidatedResult

        #print('screenStock: ',screenResult)
        return screenResult
                
    @staticmethod
    def getTrueStock(screenResult):
        mylist = []
        for key,value in screenResult.items():
            if value == True:
                mylist.append(key)
        #print('getTrueStock: ',mylist)
        return mylist
    
    @staticmethod
    def printRecord(mydict):
        #print('mydict: ',mydict)
        for x in mydict:
            print(x,mydict[x])

    def keepRecord(self,DBcnxn,oneDay,positionList,totalValue,cash,positionListValue):
        '''
        put daily BT record into Json 
        '''
        if oneDay == self.startDate:
            self.status = 0
        elif oneDay == self.endDate:
            self.status = 2
        else:
            self.status = 1
            
        #time.sleep(0.1)
        self.BTRecords[oneDay] = dict()
        self.BTRecords[oneDay]['positionList'] = positionList
        self.BTRecords[oneDay]['totalValue'] = totalValue
        self.BTRecords[oneDay]['cash'] = cash
        self.BTRecords[oneDay]['positionListValue'] = positionListValue
        self.tradingDayHistory.append(oneDay)
        '''
        if not os.path.exists('./Strategy Records'):
            os.makedirs('./Strategy Records')

        
        with open('./Strategy Records/strategy_%s.txt'%self.strategyID,'a+') as f:
            f.write('--------' + oneDay + '----------\n')
            f.write('positionList: %s\n'%len(positionList))
            f.write('cash: %s\n'%cash)
            f.write('positionListValue: %s\n'%positionListValue)
            f.write('totalValue: %s\n'%totalValue)
            f.write('\n')
        '''

        insertCommand = "INSERT INTO BT.dbo.BTrecords VALUES (%s,%i,'%s','%s',%i,'%s',%i,%0.2f,%0.2f,%0.2f,'%s');"%(
            self.strategyID,self.status,self.startDate,self.endDate,self.length,
            oneDay,len(positionList),cash,positionListValue,totalValue,json.dumps(self.tradingDayAPI))
        #print(insertCommand)
        try:
            DBcnxn.cursor().execute(insertCommand)
            DBcnxn.commit()
        except:
            DBcnxn.rollback()
        


    def getRecord(self,oneDay):
        return self.BTRecords[oneDay]
    
    def stockPicking(self,oneDay):
        if self.stockPicker['pick'] == True:
            logger.critical('################################ stockPicking ###################################: %s'%(self.strategyID))
        resultDict = self.extractBulk(oneDay)
        screenDict = self.screenStock(resultDict,oneDay)
        screenStocks = self.getTrueStock(screenDict)
        return screenStocks

    def getMarketDailyValue(self,oneDay,stockList):
        
        return [obj for obj in self.bulk['EM_QUOTE_STOCK_DAILY'][oneDay] if obj.SecuCode in stockList]
        
    def backTesting(self):
        self.tradingDayAPI = self.myAPI.getTradingDays(self.startDate,self.endDate)
        self.length = len(self.tradingDayAPI)
        a = time.time()
        DBcnxn = pyodbc.connect(DSN = 'TEST',autocommit=True)
        DBcursor = DBcnxn.cursor()

        createDBcommand = \
        '''
            if not exists(select * from sys.databases where name = N'BT')
            BEGIN
                CREATE database BT;
            END
        '''

        createTableCommand = """
            IF NOT EXISTS (SELECT * FROM BT.INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'BTrecords')
            begin
                create table BT.[dbo].BTrecords(
                    strategyID VARCHAR(255),
                    status VARCHAR(255),
                    startDate VARCHAR(255),
                    endDate VARCHAR(255),
                    length VARCHAR(255),
                    btdate VARCHAR(255),
                    positionList VARCHAR(255),
                    cash VARCHAR(255),
                    positionListValue VARCHAR(255),
                    totalValue VARCHAR(255),
                    tradingDayAPI VARCHAR(8000));
            end
            """
        #DBcursor.execute(createCommand)

        dropTableCommand = """
            IF EXISTS (SELECT * FROM BT.INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'BTrecords')
            begin
                drop table BT.[dbo].BTrecords;
            end
        """
        #DBcursor.execute(dropCommand)
        DBcursor.execute(createDBcommand + createTableCommand )

        logger.critical('################################ backtesting ###################################: %s'%(self.strategyID)) 
        self.myaccount = Account(self.initialCash,'OpenPrice')

        '''
        tradingHabit: 'OpenPrice'|'ClosePrice'|   OpenPrice is prefered

        criteriaDict: {'DeductNetProfitYoY':[None,5,'最近一期']}   #dict(item:[period,upperbound,lowerbound])

        if turnover is int, then turnover for every N days
        if turnover is None, then buy and sell according to specific condition,
        if turnover is flexible, then buy and sell according to specific condition, + turnover days
        '''
        #time.sleep(2)
        #print('aaaaaaaaaaaaaaaaaaaaaa','./Strategy Records/strategy_%s.txt'%(self.strategyID))
        '''
        try:
            with open('./Strategy Records/strategy_%s.txt'%self.strategyID,'w+') as f:
                f.write('             |' + self.strategyID + '|                \n')
        except:
            e = sys.exc_info()[0]
            print( "Error: %s" % e )
        '''
        if isinstance(self.turnover,int) and self.turnover > 0: # keep turnover
            self.totalRuningDays = 1
            turnoverDays = 0 #this one is crucial! 0 instead of 1 
            self.sold = self.bought = False
            
            for day in self.myAPI.getTradingDays(self.startDate,self.endDate):
                logger.critical('%s ########## %s ############ totalRuningDays %s'%(self.strategyID,day,self.totalRuningDays))  
                self.myaccount.printMe()
                self.keepRecord(DBcnxn,day,self.myaccount.positionList,self.myaccount.totalValue,self.myaccount.cash,self.myaccount.positionListValue) # keep daily BT record 
                
                previousPositionList = None
                if len(self.tradingDayHistory) > 1: 
                    previousTradingDay = self.tradingDayHistory[-2]
                    previousRecord = self.getRecord(previousTradingDay)
                    previousPositionList = previousRecord['positionList']

                ###############
                #print('bought: %s,  sold: %s,turnoverDays: %d'%(str(self.bought),str(self.sold),turnoverDays))
                if turnoverDays < self.turnover: 
                    if self.bought == False:
                        self.executeBuy(day,previousPositionList)
                        if self.bought == True: #如果当日成功买入，turnoverDays 才会变化
                            turnoverDays += 1
                    else:
                        self.executeHeld(day)
                        turnoverDays += 1
                    self.totalRuningDays += 1
                    
                elif turnoverDays == self.turnover:

                    self.executeSell(day)
                    if self.sold == True: # 如当日成功卖出去了，才会买入，turnoverDays才会变化，如当日没有成功卖出去了，第二天继续试着卖
                        self.executeBuy(day,previousPositionList)
                        turnoverDays = 1
                    self.totalRuningDays += 1

        elif self.turnover is None:
            #if stock.SecuCode == '600000' and round(stock.OpenPrice)%2 == 1:
                pass
        elif self.turnover == 'flexible':
            pass
        self.getIndexResult()
        
        logger.critical('######################### backtesting completed ############ strategyID: %s, 下载耗时 %0.1f秒, 运行耗时 %0.1f秒'%
        (self.strategyID,self.downloadB-self.downloadA,time.time()-a)) 

    def executeHeld(self,day):
        print('持有更新')
        heldPosition = self.myaccount.positionList
        try:
            updatedStock = self.getMarketDailyValue(day,[x.SecuCode for x in heldPosition])
        except:
            updatedStock = []

        if len(updatedStock) != len(heldPosition):
            print(
            '''
            昨日持仓的数目，今天想更新，但是近日的股票数目少了，数据问题
            昨今持仓差：''',(set(x.SecuCode for x in heldPosition) - set(x.SecuCode for x in updatedStock)))
            # this is bad, the remedy is to use yesterday's position to pretend as today's stockBar
            for p in heldPosition:
                for SecuCode in set(x.SecuCode for x in heldPosition) - set(x.SecuCode for x in updatedStock):
                    if p.SecuCode == SecuCode:
                        updatedStock.append(p)

        #print('hehe',[x.TradeStatus for x in updatedStock])
        #print('haha',[x.PreClosePrice for x in updatedStock])
        temp = self.myaccount.held(day,updatedStock)

        if isinstance(temp,str):
            return 

    def executeSell(self,day):
        print('卖出')
        if self.myaccount.isempty(): 
            logger.warn('empty nothing to sell in this account')
            self.sold = False
            return None 

        #卖掉
        positionStock = self.myaccount.positionList # get positions in account and sell
        
        try:
            marketValueOneDay = self.getMarketDailyValue(day,[x.SecuCode for x in positionStock])
        except:
            marketValueOneDay = []

        if len(positionStock) != len(marketValueOneDay):
            logger.warn(
            '''
            昨日持仓的数目，今天想更新，但是近日的股票数目少了，数据问题
            昨今持仓差：''',(set(x.SecuCode for x in positionStock) - set(x.SecuCode for x in marketValueOneDay)))
            # this is bad, the remedy is to use yesterday's position to pretend as today's stockBar
            for p in positionStock:
                for SecuCode in set(x.SecuCode for x in positionStock) - set(x.SecuCode for x in marketValueOneDay):
                    if p.SecuCode == SecuCode:
                        marketValueOneDay.append(p)

        logger.warn(marketValueOneDay)
        
        for stock in list(marketValueOneDay):
            #print(stock.TradeStatus)
            #print('stock.LLimitUpTime',stock.LLimitUpTime,' ',type(stock.LLimitUpTime)) # exclude Tingpai or LimitUp before the market is open
            if stock.TradeStatus == '0':
                logger.warn('TradeStatus = "0" , 当日交易被禁止，从卖出列表中删除之,: %s'%stock.SecuCode)
                marketValueOneDay.remove(stock)

            if stock.RiseOrDown == '-1' and datetime.strptime(stock.LLimitUpTime[11:],'%H:%M:%S') < datetime(1900, 1, 1, 9, 30,0):
                logger.warn('9:30以前跌停，无法卖出，从卖出列表中删除之') # 还没有考虑之后打开跌停的情况
                marketValueOneDay.remove(stock)

        if marketValueOneDay is None: #if marketValueOneDay has no data
            logger.warn('%s has no data, will sell the next day'%day)
            self.sold = False
            return

        self.myaccount.sellAvailableForSell([x.SecuCode for x in marketValueOneDay])
        self.sold = True

    def executeBuy(self,day,previousPositionList):    
        trueStocks = self.stockPicking(day)
        print('买入')
        # update 
        if len(trueStocks) == 0:
            self.bought = False
            logger.warn('%s has no data, continue'%day)
            return

        try:
            marketValueOneDay = self.getMarketDailyValue(day,trueStocks)
        except:
            marketValueOneDay = []

        updatedStock = list(marketValueOneDay)

        logger.warn(marketValueOneDay)
        
        for stock in list(marketValueOneDay):
            #print('stock.LLimitUpTime',stock.LLimitUpTime,' ',type(stock.LLimitUpTime)) # exclude Tingpai or LimitUp before the market is open
            if stock.TradeStatus == '0':
                logger.warn('TradeStatus = "0" , 当日交易被禁止，从需买列表中删除之,:%s'%stock.SecuCode)
                marketValueOneDay.remove(stock)
            if stock.RiseOrDown == '1' and datetime.strptime(stock.LLimitUpTime[11:],'%H:%M:%S') < datetime(1900, 1, 1, 9, 30,0):
                logger.warn('9:30以前涨停，无法买入，从需买列表中删除之')
                marketValueOneDay.remove(stock)

        if previousPositionList: 
            if stock.SecuCode in [x.SecuCode for x in previousPositionList]:
                logger.warn('昨日的positionList中已有该票，无法买入，从需买列表中删除之: %s'%stock.SecuCode)
                if stock.SecuCode in [x.SecuCode for x in marketValueOneDay]:
                    marketValueOneDay.remove(stock)

        if len(marketValueOneDay) == 0: #if marketValueOneDay has no data，
            logger.warn('%s 今日无可买入票，明日继续买；如有持仓，今日更新持仓，'%day)
            self.bought = False
            temp = self.myaccount.held(day,updatedStock)

            if isinstance(temp,str):
                return 
            
        


                        
        #print('len(marketValueOneDay)  ',len(marketValueOneDay))        
        for stock in marketValueOneDay: # buy the stock that is available to buy  
            #print('backtesting check: %s',stock.SecuCode)
            #print('len(marketValueOneDay)  ',len(marketValueOneDay))
            #print('myaccount.cash  ',myaccount.cash)
            self.myaccount.buy(stock,self.myaccount.initialCash*0.95/len(marketValueOneDay))  # need to be very careful, make sure the initialCash won't change constantly 
            self.bought = True

    def getIndexResult(self):
        indexList = [self.bulk['EM_QUOTE_INDEX_DAILY'][x][0] for x in self.bulk['EM_QUOTE_INDEX_DAILY']]
        indexList.reverse()
        #print('indexList[0].TradeDate,self.startDate: ',indexList[0].TradeDate,self.startDate)
        #print('indexList',indexList)
        #print(indexList[-1].TradeDate,' ', indexList[-1].ClosePrice,' ', indexList[0].TradeDate,' ', indexList[0].ClosePrice)
        #zhangfu1 = (indexList[-1].ClosePrice - indexList[0].ClosePrice ) / indexList[0].ClosePrice   
        #print('zhangfu of index', zhangfu1)
        self.IndexRecords = indexList

        #with open('result.txt','a+') as f:
        #    f.write(str(zhangfu1) + str(datetime.now()) + '\n')
            
        #self.printRecord(self.BTRecords)

        
    

    
        