from oneclass.onedb import Onedb
import pandas as pd
from datetime import datetime
import time
import pyautogui as auto
import threading
durtime=0.001
auto.FAILSAFE = True
auto.PAUSE=1.0

class autotrade:
    def __init__(self):
        self.init_parameter()
        self.read_config()
    def init_parameter(self):
        self.stockcode=""
        self.location={}
        self.process={}
        self.screenpic=0 
        self.autotradelist=pd.DataFrame()
        self.applylist=pd.DataFrame()
        self.onedb=Onedb()
    def read_config(self):
        with open("./config/autotrade.config", 'r',encoding='utf-8') as file_to_read:
            i=0
            while True:
                lines = file_to_read.readline()
                lines=lines.strip()
                if not lines:
                    break               #如果是文件结尾,则退出
                else:
                    if lines=="[坐标]":
                        while True:
                            lines = file_to_read.readline() 
                            lines=lines.strip()
                            i+=1
                            if lines=="[流程]":                 #流程的处理                     
                                while True:
                                    lines = file_to_read.readline() 
                                    lines=lines.strip()
                                    i+=1
                                    if not lines:
                                        print("self.location",self.location)
                                        print("self.process",self.process)
                                        return 1                #EOF!!!
                                    else:
                                        npos=lines.index(",")
                                        tmpwhat=lines[:npos].strip()
                                        tmpprocess=lines[npos+2:-1].split(",")
                                        self.process[tmpwhat]=tmpprocess
                            else:                               #坐标的处理
                                npos=lines.index(",")       #到第一个逗号前的中文名称
                                tmpwhere=lines[:npos].strip()
                                tmpxy=lines[npos+2:-1].split(",")          #第一个逗号后的元组
                                self.location[tmpwhere]=(int(tmpxy[0]),int(tmpxy[1]))
    def thread_it(self, func, *args):  
        # '''将函数放入线程中执行''' #有两个参数 1，函数名称 func 2,函数变量 **args
        task = threading.Thread(target=func, args=args)  # 创建线程
        task.setDaemon(True)  # 守护线程
        task.start()
    def moveandclick(self,location):
        x,y=location[0],location[1]
        auto.moveTo(x, y, duration=durtime)
        auto.click(button='left')
        
    #解析autotrade.config的[流程]中定义的每一步操作该如何处理
    def deal_process(self, task, stockcode, price,qty):
        if len(task)==1:
            time.sleep(int(task))
        elif   task =='stockcode':
            auto.typewrite(stockcode, durtime)
        elif   task =='price':
            auto.typewrite(str(price),durtime)
        elif   task =='qty':
            auto.typewrite(str(qty),durtime)
        elif   task[:2] =='d:':
            auto.typewrite(task,durtime)
        elif   task in ['enter','tab','space']:
            auto.press(task)
        else:
            self.moveandclick(self.location[task])

    #股票交易操作(异常状况的处理方法 - 例如出了一个特殊的子窗口,且如果不关闭这个子窗口则所有操作没有办法继续)
    def sell_stock(self,stockcode, sellingprice, sellingqty):
        print("sell stock is start")
        for task in self.process['卖出股票']:
            self.deal_process(task,stockcode,sellingprice,sellingqty)
        print("sell stock is end")
    def buy_stock(self,stockcode, buyprice, buyqty):
        print("buy stock is start")
        for task in self.process['买入股票']:
            self.deal_process(task,stockcode,buyprice,buyqty)
        print("buy stock end")
    def sell_131(self,stockcode,price=0,qty=0): 
        print(f"sell {self.stockcode} is start")
        for task in self.process['国债逆回购']:
            self.deal_process(task,stockcode,0,0)
        print(f"sell {self.stockcode} end")
    #如果没有"买入"单, 则没有需要撤销的"买入单"是会出错还是可以正常运行???
    def withdraw(self,stockcode=0,price=0,qty=0):
        print(f"withdraw is start")
        for task in self.process['撤全买']:
            self.deal_process(task,0,0,0)
        print(f"withdraw end")
    def apply_newstock(self,stockcode=0,price=0,qty=0): 
        print(f"apply new stock is start")
        for task in self.process['申购新股']:
            self.deal_process(task,0,0,0)
        print(f"apply new stock end")
    #当天还没有一笔"申请"时, "输出"按钮"是灰色的, 没有办法输出Xls文件, 但是程序不会出错
    def export_applylist (self): 
        print(f"export application txt file start......")
        for task in self.process['输出当日委托']:
            self.deal_process(task,0,0,0)
        print(f"export application txt file done!!!!!!")
        
    #读取交易系统输出到/tmpout/applylist.xls里面的记录
    def read_applylist(self):
        file_data = ""
        i=rawdata=0
        with open(r"./tmpout/applylist.xls", "r",encoding="GBK") as f:
            for line in f:
                line = line.replace("=", "")
                file_data += line
                i+=1
        with open(r"./tmpout/applylist1.xls", "w",encoding="GBK") as f:
            f.write(file_data)
        df = pd.read_table(r"./tmpout/applylist1.xls", sep='\t', encoding="GBK")
        df=df.reset_index(drop=True)
        df = df.iloc[:, :df.shape[1] - 1] #删除最后列 
        self.applylist=df
        print(self.applylist)
    #从db 读取 autotradelist表 (需要执行的交易清单)
    def read_autotradelist(self): 
        #onedb=Onedb()
        sql="SELECT * FROM autotradelist" 
        self.autotradelist=self.onedb.From_table(sql)
        print(self.autotradelist)
    def timeisok(self, now, plantime):
        curhour=int(now.strftime("%H"))
        curmin=int(now.strftime("%M"))
        planhour=int(plantime[:2])
        planmin=int(plantime[-2:])
        if (curhour>=planhour and curmin>=planmin) or curhour>planhour:
            return 1
        else:
            return 0
    def mark_applyed_yes(self, stockcode, time, ntype=0):
        #onedb=Onedb()
        self.onedb.update_table(stockcode, time, ntype)
    def trade_time(self):
        now=datetime.now()
        tmphour=int(now.strftime("%H"))
        #9点开始到15:59都会执行
        #不需要执行的时段
        #
        #11:31-12:59也会执行
        #15:30-15:59
        if tmphour >=9 and tmphour<=15:
            return 1
        else:
            return 0

    def get_havelist(self):
        file_data = ""
        i=0
        with open(r"./tmpout/havelist.xls", "r") as f:
            for line in f:
                if i>=2:
                    line=line.replace("=","")
                    file_data+=line
                i+=1
        #print(file_data)
        with open(r"./tmpout/havelist1.xls", "w") as f:
            #f.write("file_table",file_data)
            f.write(file_data)
        # 重读 持仓
        df = pd.read_table(r"./havelist1.xls", sep='\t', encoding="ansi")
        #df=df[['证券代码', '证券名称', '证券数量', '可卖数量', '摊簿成本价', '当前价', '摊簿浮动盈亏', '实现盈亏', '参考盈亏比例(%)']]#, '冻结数量']]
        print(df)
        df = df[['证券代码', '证券名称', '证券数量','摊簿成本价', '当前价', '摊簿浮动盈亏', '参考盈亏比例(%)']]  # , '冻结数量']]
        df['证券代码'] = df['证券代码'].map(lambda x: str(x).rjust(6,'0'))
        df.columns = ['代码', '名称', '数量','成本', '当前价', '盈亏', '盈亏%']
        self.onedb.del_table("havelist")
        self.onedb.into_table(df, "havelist", "代码", 9)
        return df

    def isdone(self):
        tradetype={"B":"买入","S":"卖出","Z":"卖出","":""}
        now=datetime.now()
        strdate=now.strftime('%m')+"-"+now.strftime('%d')
        #print("strdate of today is:",strdate)
        for keyauto,autotradelist in self.autotradelist.iterrows():
            BSZname=tradetype[autotradelist.BSZ]
            autotradetime=autotradelist.time[-8:]
            autotradedate=autotradelist.time[5:10]
            if autotradedate!=strdate: continue
            for keyapply, applylist in self.applylist.iterrows():
                #print("BSZname",BSZname)
                #print("autotradetime:",autotradetime)
                #print("tradedate",autotradedate)
                if  autotradelist.stockcode==str(applylist['证券代码']) and \
                    BSZname==applylist['委托类别'] and \
                    autotradelist.qty==str(applylist['委托数量']) and \
                    autotradetime<applylist['委托时间']:
                    print(type(autotradelist.stockcode), type(applylist['证券代码']),BSZname, applylist['委托类别'], \
                        type(autotradelist.qty), type(applylist['委托数量']), autotradetime, applylist['委托时间'])
                    #update[db:autotradelist] with str(成交数量)
                    print("inside isdone")
                    strqty=str(applylist['成交数量'])   #???
                    print(strqty)
                    sql=f"UPDATE autotradelist SET done='{strqty}' WHERE stockcode='{autotradelist.stockcode}' and time='{autotradelist.time}'"
                    print("sql:",sql)
                    self.onedb.execute_sql(sql)                   

    def trade_loop(self):
        i=0
        while 1:
            print(i, datetime.now())
            if not self.trade_time():
                print("非交易时段......")
                time.sleep(10)
                continue
            self.read_autotradelist()   #读取需要交易的单据清单
            self.trade_decision()       #决定怎么交易
            if i%5 == 0:
                self.export_applylist() #输出是否交易成功的xls文件
                self.read_applylist()   #读取是否交易成功的xls文件
                print("autotradelist",self.autotradelist)
                print("applylist",self.applylist)
                self.isdone()
            print("waiting......")
            time.sleep(10)
            i+=1 

    def trade_decision(self):
        now=datetime.now()
        tmpweekday=str(now.weekday()+1)
        tmphour=now.strftime("%H")
        tmpmin=now.strftime("%M")
        if tmpweekday=="6" or tmpweekday=="7": return 0                 #周六和周日就直接退出, 非交易日
        for key, trade in self.autotradelist.iterrows():
            if trade.optime=="asap" and trade.applyed=="no":
                if trade.BSZ=="S":
                    self.sell_stock(trade.stockcode,trade.price,trade.qty)
                    self.mark_applyed_yes(trade.stockcode, trade.time, 1)
                    #读取委托, 并修正是否成交,放到loop中,每5次查询一次
                if trade.BSZ=="B":
                    self.buy_stock(trade.stockcode,trade.price,trade.qty)
                    self.mark_applyed_yes(trade.stockcode, trade.time, 1)
                    #读取委托, 并修正是否成交,放到loop中,每5次查询一次
            if trade.stockcode=="000000":                               #撤"买",为卖钱做准备
                if tmpweekday in trade.loopornot:
                    if self.timeisok(now,trade.optime) and trade.applyed=="no":
                        self.withdraw()
                        self.mark_applyed_yes(trade.stockcode, trade.time, 0)
            if trade.stockcode=="999999":                               #申购新股
                if tmpweekday in trade.loopornot:
                    if self.timeisok(now,trade.optime) and trade.applyed=="no":
                        self.apply_newstock()
                        self.mark_applyed_yes(trade.stockcode, trade.time, 0)
            if trade.stockcode=="131810" or trade.stockcode=="131800":   #国债逆回购
                if tmpweekday in trade.loopornot:                            #今天应该下单
                    if self.timeisok(now,trade.optime) and trade.applyed=="no":         #到了下单时间, 但还没有下单的
                        self.sell_131(trade.stockcode)                  #下单 并结束今天的交易(把一些yes变no)
                        self.mark_applyed_yes(trade.stockcode, trade.time, 0)
            if trade.stockcode=="update": #收盘后的数据表状态字段修正工作
                #if reason!=当天日期: #执行and 修改reason为当天日期
                dt=datetime.today()
                dttoday=str(dt.month)+str(dt.day)
                #print("dttoday",dttoday)
                if trade.reason!=dttoday:
                    self.onedb.update_applyed()
                    self.onedb.update_datestring(dttoday)               
                    self.mark_applyed_yes(trade.stockcode, trade.time, 0)
if __name__=="__main__":

    at=autotrade()
    at.get_havelist()
    #at.trade_loop()

'''
两个文件
1, ./config/autotrade.config 
[坐标] + [流程]
[坐标]
卖出,(294,44)
买入,(247,44)
撤单,(340,44)
成交,(392,44)
持仓,(439,44)
刷新,(483,44)
买5,(567,226)
卖出全部,(440,162)
卖出下单,(440,237)
新股批量申购,(99,685)
申购,(496,199)
确认申购,(462,450)
全选中,(410,75)
只选撤买,(483,75)
撤单命令,(337,75)
当日委托,(88,269)
输出,(769,74)
输出到xls,(356,397)
输出确认,(598,534)
关闭txt,(1189,159)
[流程]
卖出股票,[5,卖出,stockcode,price,tab,qty,tab,space,enter,2,enter,持仓]
买入股票,[5,买入,stockcode,price,tab,qty,tab,space,enter,2,enter,enter,持仓]
申购新股,[5,新股批量申购,申购,确认申购,enter,持仓]
撤全买,[5,撤单,全选中,只选撤买,撤单命令,enter,持仓]
国债逆回购,[5,卖出,stockcode,买5,卖出全部,卖出下单,enter,enter,持仓]
输出当日委托,[2,当日委托,输出,输出到xls,tab,tab,d:\autotrade\tmpout\applylist.xls,输出确认,关闭txt,持仓]

2, ./csv/autotrade.csv
stockcode,BSZ,price,qty,time,optime,loopornot,applyed,done,stockname,reason
'131810',,,,,15:15,1234,no,no,1天回购,
'131800',,,,,15:15,5,no,no,3天回购,
'000000',,,,,15:10,12345,no,no,撤买,
'999999',,,,,14:30,12345,no,no,申购新股,
'update',,,,,9:10,12345,no,no,修正成交,
存放需要执行的定期任务

[程序流程]
1-5开盘以前 9:10
-读取autotradelist表
-把loopornot字段含有"1-5"的记录的"applyed"修改为"no" (当天下单后这个字段会变为"yes")

1, 下单
2, 
3, 
4, 


'''
