Esempio n. 1
0
class TopTrader(QMainWindow, ui):
    def __init__(self):
        super().__init__()
        self.logger = TTlog().logger
        self.mongo = MongoClient()
        self.tt_db = self.mongo.TopTrader
        self.slack = Slack(config_manager.get_slack_token())
        self.kw = Kiwoom()
        self.init_trading()
        # self.just_sell_all_stocks()
        self.auto_trading()

    def init_trading(self):
        self.login()
        # self.update_stock_info()
        self.load_stock_info()
        self.set_account()
        self.my_stock_pocket = set()  # 보유중인 종목의 code를 저장
        t = datetime.today()
        self.s_time = datetime(t.year, t.month, t.day, 9, 0, 0)  # 장 시작시간, 오전9시

    def login(self):
        # Login
        err_code = self.kw.login()
        if err_code != 0:
            self.logger.error("Login Fail")
            exit(-1)
        self.logger.info("Login success")

    def load_stock_info(self):
        self.stock_dict = {}
        doc = self.tt_db.stock_information.find({})
        for d in doc:
            code = d["code"]
            self.stock_dict[code] = d
        self.logger.info("loading stock_information completed.")

    def update_stock_info(self):
        # kospi
        kospi = []
        code_list = self.kw.get_code_list_by_market("0")
        for code in code_list:
            stock_name = self.kw.get_master_stock_name(code)
            kospi.append({
                "code": code,
                "stock_name": stock_name,
                "market": "kospi"
            })
        self.tt_db.stock_information.insert(kospi)

        # kosdaq
        kosdaq = []
        code_list = self.kw.get_code_list_by_market("10")
        for code in code_list:
            stock_name = self.kw.get_master_stock_name(code)
            kosdaq.append({
                "code": code,
                "stock_name": stock_name,
                "market": "kosdaq"
            })
        self.tt_db.stock_information.insert(kosdaq)

    def set_account(self):
        self.acc_no = self.kw.get_login_info("ACCNO")
        self.acc_no = self.acc_no.strip(";")  # 계좌 1개를 가정함.
        self.stock_account = self.get_account_info(self.acc_no)

        # kiwoom default account setting
        self.kw.set_account(self.acc_no)

    def start_timer(self):
        if self.timer:
            self.timer.stop()
            self.timer.deleteLater()
        self.timer = QTimer()
        self.timer.timeout.connect(self.check_stocks_to_sell)
        # self.timer.setSingleShot(True)
        self.timer.start(30000)  # 30 sec interval

    def just_sell_all_stocks(self):
        curr_time = datetime.today()
        self.stock_account = self.get_account_info(self.acc_no)
        for data in self.stock_account["종목정보"]:
            self.logger.info("Trading시간 종료되어 보유한 종목 모두 매도처리합니다.")
            code, stock_name, quantity = data["종목코드"][1:], data["종목명"], int(
                data["보유수량"])
            self.kw.시장가_신규매도(code, quantity)
            손익율 = data["손익율"]
            self.tt_db.trading_history.insert({
                'date':
                curr_time,
                'code':
                code,
                'stock_name':
                self.stock_dict[code]["stock_name"],
                'market':
                self.stock_dict[code]["market"],
                'event':
                '',
                'condi_name':
                '',
                'trade':
                'sell',
                'profit':
                손익율,
                'quantity':
                quantity,
                'hoga_gubun':
                '시장가',
                'account_no':
                self.acc_no
            })
            time.sleep(0.5)

    def check_stocks_to_sell(self):
        self.logger.info("[Timer Interrupt] 30 second")
        self.stock_account = self.get_account_info(self.acc_no)
        curr_time = datetime.today()
        self.logger.info("=" * 50)
        self.logger.info("현재 계좌 현황입니다...")

        if not bool(self.stock_account):
            self.logger.error("계좌정보를 제대로 받아오지 못했습니다.")
            return

        if datetime.today() < self.s_time:
            self.logger.info("시작시간이 되지 않아 매도하지 않습니다.")
            return

        self.my_stock_pocket = set()
        for data in self.stock_account["종목정보"]:
            code, stock_name, quantity = data["종목코드"][1:], data["종목명"], int(
                data["보유수량"])
            self.logger.info("* 종목: {}, 손익율: {}%, 보유수량: {}, 평가금액: {}원".format(
                data["종목명"], ("%.2f" % data["손익율"]), int(data["보유수량"]),
                format(int(data["평가금액"]), ',')))
            self.my_stock_pocket.add(code)
            손익율 = data["손익율"]
            if 손익율 >= 3.0 or 손익율 <= -2.0:
                if 손익율 > 0:
                    self.logger.info(
                        "시장가로 물량 전부 익절합니다. ^^    [{}:{}, {}주]".format(
                            stock_name, code, quantity))
                else:
                    self.logger.info(
                        "시장가로 물량 전부 손절합니다. ㅜㅜ. [{}:{}, {}주]".format(
                            stock_name, code, quantity))

                self.my_stock_pocket.remove(code)
                self.kw.시장가_신규매도(code, quantity)
                self.tt_db.trading_history.insert({
                    'date':
                    curr_time,
                    'code':
                    code,
                    'stock_name':
                    self.stock_dict[code]["stock_name"],
                    'market':
                    self.stock_dict[code]["market"],
                    'event':
                    '',
                    'condi_name':
                    '',
                    'trade':
                    'sell',
                    'profit':
                    손익율,
                    'quantity':
                    quantity,
                    'hoga_gubun':
                    '시장가',
                    'account_no':
                    self.acc_no
                })

    def get_account_info(self, acc_no):
        self.logger.info("계좌평가현황요청")
        ret = self.kw.계좌평가현황요청("계좌평가현황요청", acc_no, "", "1", "6001")
        return ret

    def search_condi(self, event_data):
        """키움모듈의 OnReceiveRealCondition 이벤트 수신되면 호출되는 callback함수
        이벤트 정보는 event_data 변수로 전달된다.

            ex)
            event_data = {
                "code": code, # "066570"
                "event_type": event_type, # "I"(종목편입), "D"(종목이탈)
                "condi_name": condi_name, # "스켈핑"
                "condi_index": condi_index # "004"
            }
        :param dict event_data:
        :return:
        """
        curr_time = datetime.today()
        if curr_time < self.s_time:
            self.logger.info("시작시간이 되지 않아 매수하지 않습니다.")
            return

        # 실시간 조건검색 이력정보
        self.tt_db.real_condi_search.insert({
            'date':
            curr_time,
            'code':
            event_data["code"],
            'stock_name':
            self.stock_dict[event_data["code"]]["stock_name"],
            'market':
            self.stock_dict[event_data["code"]]["market"],
            'event':
            event_data["event_type"],
            'condi_name':
            event_data["condi_name"]
        })

        if event_data["event_type"] == "I":
            예수금 = self.stock_account["계좌정보"]["예수금"]
            D2_예수금 = self.stock_account["계좌정보"]["예수금"]
            총예수금 = 예수금 + D2_예수금
            if 총예수금 < 100000:  # 잔고가 10만원 미만이면 매수 안함
                self.logger.info("총예수금({}) 부족으로 추가 매수하지 않습니다.".format(총예수금))
                return

            if event_data["code"] in self.my_stock_pocket:
                self.logger.info("해당 종목({}) 이미 보유중이라 추가매수하지 않습니다.".format(
                    self.stock_dict[event_data["code"]]["stock_name"]))
                return
            # curr_price = self.kw.get_curr_price(event_data["code"])
            # quantity = int(100000/curr_price)
            quantity = 20
            # self.kw.reg_callback("OnReceiveChejanData", ("조건식매수", "5000"), self.account_stat)
            stock_name = self.stock_dict[event_data["code"]]["stock_name"]
            market = self.stock_dict[event_data["code"]]["market"]
            self.tt_db.trading_history.insert({
                'date':
                curr_time,
                'code':
                event_data["code"],
                'stock_name':
                stock_name,
                'market':
                market,
                'event':
                event_data["event_type"],
                'condi_name':
                event_data["condi_name"],
                'trade':
                'buy',
                'quantity':
                quantity,
                'hoga_gubun':
                '시장가',
                'account_no':
                self.acc_no
            })
            self.logger.info("{}:{}를 {}주 시장가_신규매수합니다.".format(
                stock_name, event_data["code"], quantity))
            self.my_stock_pocket.add(event_data["code"])
            self.kw.시장가_신규매수(event_data["code"], quantity)
            # self.kw.send_order("조건식매수", "5000", self.acc_no, 1, event_data["code"], quantity, 0, "03", "")

    def auto_trading(self):
        """키움증권 HTS에 등록한 조건검색식에서 검출한 종목을 매수하고
        -2%, +3%에 손절/익절 매도하는 기본적인 자동매매 함수

        :return:
        """
        self.logger.info("TopTrader 자동매매 시작합니다...")

        self.timer = None
        self.start_timer()

        # callback fn 등록
        self.kw.reg_callback("OnReceiveRealCondition", "", self.search_condi)

        screen_no, cnt = 4000, 0
        condi_info = self.kw.get_condition_load()
        self.logger.info("실시간 조건 검색 시작합니다.")
        for condi_name, condi_id in condi_info.items():
            # 화면번호, 조건식이름, 조건식ID, 실시간조건검색(1)
            self.logger.info("화면번호: {}, 조건식명: {}, 조건식ID: {}".format(
                screen_no, condi_name, condi_id))
            self.kw.send_condition(str(screen_no), condi_name, int(condi_id),
                                   1)
            time.sleep(0.5)
            cnt += 1
            if cnt == 10:
                screen_no += 1
                cnt = 0
Esempio n. 2
0
class TopTrader(QMainWindow, ui):
    def __init__(self):
        super().__init__()
        # self.setupUi(self)  # load app screen
        self.logger = TTlog(logger_name="RealCondi").logger
        self.mongo = MongoClient()
        self.tt_db = self.mongo.TopTrader
        self.slack = Slack(config_manager.get_slack_token())
        self.kw = Kiwoom()
        self.login()

        # ready to search condi
        self.load_stock_info()
        t = datetime.today()
        self.s_time = datetime(t.year, t.month, t.day, 9, 0, 0)  # 장 시작시간, 오전9시

        # fake trading
        self.timer = None
        self.start_timer()

        # core function
        self.screen_no = 4000
        self.N1, self.N2 = 0, 10

        # self.screen_no = 4001
        # self.N1, self.N2 = 10, 20

        self.real_condi_search()

    def load_stock_info(self):
        self.stock_dict = {}
        doc = self.tt_db.stock_information.find({})
        for d in doc:
            code = d["code"]
            self.stock_dict[code] = d
        self.logger.info("loading stock_information completed.")

    def start_timer(self):
        if self.timer:
            self.timer.stop()
            self.timer.deleteLater()
        self.timer = QTimer()
        self.timer.timeout.connect(self.fake_check_to_sell)
        # self.timer.setSingleShot(True)
        self.timer.start(1000) # 1 sec interval

    def fake_check_to_sell(self):
        """

        :return:
        """

    def search_result(self, event_data):
        """

        :param event_data:
        :return:
        """
        curr_time = datetime.today()

        if curr_time < self.s_time:
            self.logger.info("=" * 100)
            self.logger.info("장 Open 전 입니다. 오전 9:00 이후에 검색 시작합니다.")
            self.logger.info("=" * 100)
            return

        # 실시간 조건검색 이력정보
        self.tt_db.real_condi_search.insert({
            'date': curr_time,
            'code': event_data["code"],
            'stock_name': self.stock_dict[event_data["code"]]["stock_name"],
            'market': self.stock_dict[event_data["code"]]["market"],
            'event': event_data["event_type"],
            'condi_index': event_data["condi_index"],
            'condi_name': event_data["condi_name"]
        })

    def real_condi_search(self):
        # callback fn 등록
        self.kw.reg_callback("OnReceiveRealCondition", "", self.search_result)
        # self.kw.notify_callback["OnReceiveRealCondition"] = self.search_condi

        condi_info = self.kw.get_condition_load()
        self.logger.info("실시간 조건 검색 시작합니다.")
        for condi_name, condi_id in list(condi_info.items())[self.N1:self.N2]:
            # 화면번호, 조건식이름, 조건식ID, 실시간조건검색(1)
            self.logger.info("화면번호: {}, 조건식명: {}, 조건식ID: {}".format(
                self.screen_no, condi_name, condi_id
            ))
            self.kw.send_condition(str(self.screen_no), condi_name, int(condi_id), 1)
            time.sleep(0.5)

    def login(self):
        err_code = self.kw.login()
        if err_code != 0:
            self.logger.error("Login Fail")
            exit(-1)
        self.logger.info("Login success")