import time
import os
from datetime import datetime, timedelta
import pandas as pd

from hts.HTS import HTS
from hts.OrderType import OrderType

from hts.BuySellChecker import BuySellChecker
from hts.OrderChecker import OrderChecker
from stock.util.LabelChecker import LabelChecker

class HTS_122630 (HTS):
    RESOURCE_PATH = None
    stock_code = None
    buy_count = None
    orderChecker = None
    buySellChecker = None
    labelChecker = None

    def __init__(self, RESOURCE_PATH, stock_code, buy_count):
        super().__init__(RESOURCE_PATH)

        self.RESOURCE_PATH = RESOURCE_PATH
        self.stock_code = stock_code
        self.buy_count = buy_count

        self.orderChecker = OrderChecker(self.RESOURCE_PATH, self.stock_code)
        self.buySellChecker = BuySellChecker()
        self.labelChecker = LabelChecker(RESOURCE_PATH)
        return

    def getSellingPrice(self, log_time, stock_code, final_price, check=False):
        # final_price와 diff를 받으면, 해당 가격으로 그냥 매도한다는 의미
        # final_price와 diff가 None이면 장부가와 final 중 max로 팔겠다는 의미
        # final_price가 0이고 diff가 None이면 장부가로 팔겠다는 의미임
        jangoDic = self.requstJango()
        if jangoDic and len(jangoDic.keys()) > 0:
            for code in jangoDic:
                if jangoDic[code]['매도가능'] > 0:
                    if check:
                        if jangoDic[code]['장부가'] * 0.05 < jangoDic[code]['장부가'] - final_price:
                            sell_price = jangoDic[code]['장부가']
                            if code == "A" + stock_code:
                                orderNum = self.requestOrder(OrderType.sell, stock_code, jangoDic[code]['매도가능'], sell_price)
                                print("ORDER_SELL", stock_code, log_time.strftime('%Y%m%d %H%M%S'), jangoDic[code]['매도가능'], sell_price)
                    else:
                        max_price = max(jangoDic[code]['장부가'], final_price)
                        sell_price = (int(max_price) - int(max_price) % 5) + 5
                        if code == "A" + stock_code:
                            orderNum = self.requestOrder(OrderType.sell, stock_code, jangoDic[code]['매도가능'], sell_price)
                            print("ORDER_SELL", stock_code, log_time.strftime('%Y%m%d %H%M%S'), jangoDic[code]['매도가능'], sell_price)
        return

    def buyRealTime(self, today):

        print ("START...")
        THIS_TIME = datetime.now()
        final_sell_check = False
        LAST_DATA = self.getLastData(self.stock_code, today)

        while datetime.strptime(today + " 070000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 153100", '%Y%m%d %H%M%S'):

            if datetime.strptime(today + " 090000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 151500", '%Y%m%d %H%M%S'):
                # 3시 까지만 매수를 시도한다.

                if THIS_TIME < datetime.strptime(today + " 145000", '%Y%m%d %H%M%S'):
                    if THIS_TIME.strftime('%S') in ("09", "19", "29", "39", "49", "59"):
                        # 데이터를 가지고 온다.
                        result = self.getRealTime(self.stock_code, today, LAST_DATA)
                        final_price = result["close"][len(result["close"])-1]

                        # 10초마다 체크하여 체결된 내역이 있으면 50원 높게 매도를 주문한다.
                        self.getSellingPrice(THIS_TIME, self.stock_code, final_price, check=True)

                if THIS_TIME.strftime('%S') == "05":
                    # 매분 5초마다 실행한다.

                    # 데이터를 가지고 온다.
                    result = self.getRealTime(self.stock_code, today, LAST_DATA)

                    # 규칙 기반의 분석을 통해서 볼린저밴드 상/하단을 계산한다.
                    data = self.buySellChecker.analyze(result)

                    # 만약 미체결 내역이 있는데, 지표가 꺽여 내려온다면, 매수 주문을 취소 시킨다.
                    last_index = len(data['close']) - 1
                    if data['slow_k'][last_index - 1] >= 80 and data['slow_k'][last_index - 1] > data['slow_k'][
                        last_index]:
                        # 미체결 기록을 가져온다.
                        ORDER_LIST = self.requestOrderList()
                        orderListToCancel = self.orderChecker.remove(self.stock_code, OrderType.sell, ORDER_LIST)
                        self.cancelOrderList(orderListToCancel)
                        print("CANCEL", THIS_TIME.strftime('%Y%m%d %H%M%S'), len(orderListToCancel), len(ORDER_LIST))


                    # 사야 할 시점/가격과 팔아야 할 시점/가격을 체크한다.
                    bsLine, data = self.buySellChecker.checkTransaction(data, self.stock_code, isRealTime=True)
                    bs_buy_price = bsLine['buy'][0]
                    bs_buy_weight = bsLine['buy_weight'][0]
                    bs_sell_price = bsLine['sell'][0]

                    data_size = len(data["close"])
                    final_price = data["close"][data_size-1]

                    if bs_buy_price > 0:
                        # 기본 100 주에 가중치를 추가해서 매수한다.
                        BUY_COUNT = int(self.buy_count * bs_buy_weight)

                        # 매수를 주문한다.
                        orderNum = self.requestOrder(OrderType.buy, self.stock_code, BUY_COUNT, bs_buy_price)

                        # 미체결 기록을 가져온다.
                        ORDER_LIST = self.requestOrderList()
                        # 매수 주문을 기록한다.
                        orderListToCancel = self.orderChecker.add(self.stock_code, OrderType.buy, orderNum, BUY_COUNT, bs_buy_price, ORDER_LIST)
                        # 두 시간 이전 미체결을 모두 취소한다.
                        self.cancelOrderList(orderListToCancel)
                        # 로그 출력
                        print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), BUY_COUNT, bs_buy_price, len(orderListToCancel), len(ORDER_LIST))


                    if bs_sell_price > 0:
                        # 미체결 기록을 가져온다.
                        ORDER_LIST = self.requestOrderList()
                        # 매도 주문을 기록을 가져온다.
                        orderListToCancel = self.orderChecker.remove(self.stock_code, OrderType.sell, ORDER_LIST)
                        # 매도 미체결을 모두 취소한다.
                        self.cancelOrderList(orderListToCancel)

                        # 매도 한다.
                        self.getSellingPrice(THIS_TIME, self.stock_code, final_price)


                    # 로그 출력
                    print("TIMECHECK: %s, price: %d, avg3: %.2f, avg5: %.2f, avg10: %.2f, slow_k: %.2f, open: %d, high: %d, low: %d" %
                          (str(THIS_TIME), final_price,
                           data["avg3"][data_size - 1], data["avg6"][data_size - 1], data["avg9"][data_size - 1], data["slow_k"][data_size - 2],
                           data["open"][data_size - 1], data["high"][data_size - 1], data["low"][data_size - 1],))

            elif datetime.strptime(today + " 151530", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 151600", '%Y%m%d %H%M%S'):
                # 3시 15분 30초부터 3시 16분 사이는 잔량을 매도한다.

                if not final_sell_check:
                    ####
                    # 손해봐도 매도한다.
                    ####

                    # 주문 리스트를 가져온다.
                    orderList = self.requestOrderList()
                    # 15:10:00 이후라면 모든 미체결 취소한다.
                    self.cancelOrderList(orderList)

                    # 매도 가격을 가져온다.
                    result = self.getRealTime(self.stock_code, today, LAST_DATA)
                    final_price = result["close"][len(result["close"]) - 1]

                    self.getSellingPrice(THIS_TIME, self.stock_code, final_price)

                    final_sell_check = True

            time.sleep(10)
            THIS_TIME = datetime.now()
        return

    def updteTodayStock(self, db_filename, stock_code, today_str):
        bsLine, data = self.labelChecker.makeCandidate(stock_code, today_str)
        self.labelChecker.updateLabel(db_filename, stock_code, bsLine, data, today_str)
        return

if __name__ == "__main__":

    week = datetime.today().weekday()
    if week in (0, 1, 2, 3, 4):

        today = datetime.today()

        PROJECT_HOME = os.getcwd()
        RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources")

        # KODEX 인버스 * 2
        stock_code = "122630"
        stock_name = "KODEX 레버리지"
        buy_count = 50

        hts = HTS_122630(RESOURCE_PATH, stock_code, buy_count)
        today_str = today.strftime('%Y%m%d')
        #today_str = "20220902"
        hts.buyRealTime(today_str)

        db_filename = os.path.join(RESOURCE_PATH, "hts.db")
        hts.insertStockData(db_filename, stock_code, stock_name, today_str)
        #hts.updteTodayStock(db_filename, stock_code, today_str)

    print ("done...")
