예제 #1
0
class TopTrader(QMainWindow, ui):
    def __init__(self):
        super().__init__()
        # self.setupUi(self)  # load app screen
        self.logger = TTlog().logger
        self.db = MongoClient().TopTrader
        self.kw = Kiwoom()
        self.login()
        self.realtime_stream()
        self.timer = None
        self.start_timer()

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

    def start_timer(self):
        if self.timer:
            self.timer.stop()
            self.timer.deleteLater()
        self.timer = QTimer()
        self.timer.timeout.connect(self.timer_call)
        # self.timer.setSingleShot(True)
        self.timer.start(10000)  # 10 sec interval

    def timer_call(self):
        self.logger.info("")
        self.logger.info("=" * 100)
        self.logger.info("Timer Call !")
        self.logger.info("=" * 100)

    def realtime_stream_callback(self, data):
        self.logger.info("[realtime_stream_callback]")
        self.logger.info("data: {}".format(data))
        self.db.realtime_stream.insert({'real_data': data})

    def realtime_stream(self):
        code_list = "066570;000030;000270;000660;005930;068270;045390;064350;011390;025560"
        screen_no = "6001"
        self.kw.reg_callback("OnReceiveRealData", "",
                             self.realtime_stream_callback)
        self.kw.set_real_reg(screen_no, code_list,
                             "10;11;12;13;14;16;17;27;28;", 0)
예제 #2
0
class TopTrader(QMainWindow, ui):
    def __init__(self):
        QMainWindow.__init__(self)

        # Application Configuration
        # UI
        self.setupUi(self)

        # Font(ko)
        self.set_ko_font()

        # Logger
        self.logger = TTlog(logger_name="TTRealCondi").logger

        # DB
        self.mongo = MongoClient()
        self.db = self.mongo.TopTrader

        # Slack
        #self.slack = Slacker(cfg_mgr.get_slack_token())

        # Kiwoom
        self.kw = Kiwoom()
        self.login()
        cfg_mgr.stock_info = self.kw.get_stock_basic_info()

        # app main
        self.main()

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

    def set_ko_font(self):
        # 그래프에서 마이너스 폰트 깨지는 문제에 대한 대처
        mpl.rcParams['axes.unicode_minus'] = False

        #path = 'c:/Windows/Fonts/D2Coding-Ver1.3-20171129.ttc'
        path = 'c:/Windows/Fonts/gulim.ttc'
        font_name = fm.FontProperties(fname=path).get_name()
        plt.rcParams["font.family"] = font_name

    def main(self):
        print("Start Application")
class TopTrader(QMainWindow, ui):
    def __init__(self):
        QMainWindow.__init__(self)

        # Application Configuration
        # UI
        self.setupUi(self)

        # Font(ko)
        self.set_ko_font()

        # Logger
        self.logger = TTlog(logger_name="TTRealCondi").logger

        # DB
        self.mongo = MongoClient()
        self.db = self.mongo.TopTrader

        # Slack
        self.slack = Slacker(config_manager.get_slack_token())

        # Kiwoom
        self.kw = Kiwoom()
        self.login()
        self.stock_info = self.kw.get_stock_basic_info()

        # app main
        self.main()

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

    def set_ko_font(self):
        # 그래프에서 마이너스 폰트 깨지는 문제에 대한 대처
        mpl.rcParams['axes.unicode_minus'] = False

        path = 'c:/Windows/Fonts/D2Coding-Ver1.3.2-20180524.ttf'
        font_name = fm.FontProperties(fname=path).get_name()
        plt.rcParams["font.family"] = font_name

    def main(self):
        print("Start Application")
        # 금일 급등했던 종목 정보를 가져온다.
        stock_info = self.kw.rapidly_rising_price_stock(market="000",
                                                        time_gubun="2",
                                                        time="0",
                                                        vol_gubun="00000",
                                                        screen_no="5000")

        # 급등했던 종목중 상위 20개를 추린다.
        stock_info = stock_info[:20]

        # 상위 20개에 대해 체결강도 정보를 수집하여 DB에 저장한다.
        for stock in stock_info:
            code = stock['종목코드']
            ret = self.kw.get_chegyul_info(code, "9000")
            pdb.set_trace()
            for data in ret:
                h, m, s = data['시간'][:2], data['시간'][2:4], data['시간'][4:]
                t = datetime.today()
                data['date'] = datetime(t.year, t.month, t.day, int(h), int(m),
                                        int(s))
                data['code'] = code
                data['stock_name'] = self.stock_info[code]["stock_name"]
                data['market'] = self.stock_info[code]["market"]
            self.db.short_trading_info_chegyul.insert(ret)
            print(ret)

        # 상위 20개에 대해 분봉/틱봉 정보를 수집하여 DB에 저장한다.
        t = datetime.today()
        s_date = datetime(t.year, t.month, t.day, 9, 0, 0)
        e_date = datetime(t.year, t.month, t.day, 17, 0, 0)

        for stock in stock_info:
            code = stock['종목코드']
            ret = self.kw.stock_price_by_min(code, "1", "9001", s_date, e_date)
            for data in ret:
                data['stock_name'] = self.stock_info[code]["stock_name"]
                data['market'] = self.stock_info[code]["market"]
            self.db.time_series_min1.insert(ret)

            ret = self.kw.stock_price_by_tick(code, "10", "9002", s_date,
                                              e_date)
            for data in ret:
                data['stock_name'] = self.stock_info[code]["stock_name"]
                data['market'] = self.stock_info[code]["market"]
            self.db.time_series_tick10.insert(ret)

        # 상위 20개에 대해 호가 정보를 수집하여 DB에 저장한다.
        # for stock in stock_info:
        #     code = stock['종목코드']
        #     ret = self.kw.get_hoga_info(code, "9001")
        #     self.db.short_trading_info_hoga.insert(ret)
        #     print(ret)
        print("end")
예제 #4
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
예제 #5
0
class TopTrader(QMainWindow, ui):
    def __init__(self):
        super().__init__()
        # self.setupUi(self)  # load app screen
        duration = sys.argv[1]
        self.logger = TTlog(logger_name="TT"+duration).logger
        self.mongo = MongoClient()
        self.tt_db = self.mongo.TopTrader
        self.slack = Slack(config_manager.get_slack_token())
        today = datetime.today()
        self.end_date = datetime(today.year, today.month, today.day, 16, 0, 0)
        self.kw = Kiwoom()
        self.login()
        self.get_screen_no = {
            "min1": "3000",
            "min3": "3001",
            "min5": "3002",
            "min10": "3003",
            "min60": "3004",
            "day": "3005",
            "week": "3006",
            "month": "3007",
            "year": "3008"
        }
        if duration.startswith("min"):
            self.collect_n_save_data_min(duration)
        else:
            self.collect_n_save_data(duration)

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

    def upsert_db(self, col, datas):
        self.logger.info("Upsert Data to DB")
        s_time = time.time()
        for doc in datas:
            # col.update(condition, new_data, upsert=True)
            col.update({'date': doc['date'], 'code': doc['code']}, doc, upsert=True)
        e_time = time.time()
        print("Time: ", int(e_time-s_time))

    def get_stock_list(self, market):
        kospi_code_list = self.kw.get_code_list_by_market(market)
        stock_list = [[c, self.kw.get_master_stock_name(c)] for c in kospi_code_list]
        stock_list = [(c, name) for c, name in stock_list if not any(map(lambda x: x in name, constant.FILTER_KEYWORD))]
        stock_list.sort()
        return stock_list

    def get_last_data(self, cur, duration):
        current_flag = True
        if duration.startswith("min"):
            first_date = datetime(2018, 7, 23, 0, 0, 0)
        else:
            first_date = datetime(2018, 6, 1, 0, 0, 0)

        # 최초 저장하는 경우
        if cur.count() == 0:
            s_date, e_date, s_index = first_date, self.end_date, 0
        else:
            data = cur.next()
            if (data['last'] + 1) != data['total']:
                # 지난번에 저장하다가 중간에 멈춘 경우
                if data['end_date'] != self.end_date:
                    s_date, e_date, s_index = data['start_date'], data['end_date'], data['last'] + 1
                    current_flag = False
                # 이번에 저장하다가 중간에 멈춘 경우
                else:
                    s_date, e_date, s_index = data['start_date'], self.end_date, data['last'] + 1
            else:
                # 지난번에 저장을 완료, 이번에 저장해야 하는 경우
                if data['end_date'] != self.end_date:
                    s_date, e_date, s_index = data['end_date'], self.end_date, 0
                # 이번에 저장을 완료
                else:
                    s_date, e_date, s_index = data['end_date'], self.end_date, data['last'] + 1
        return s_date, e_date, s_index, current_flag

    def collect_n_save_data_min(self, duration):
        """
        코스피 종목의 분단위 데이터를 수집한다.

        1. 한번도 db에 저장한적이 없다면 6/1일부터 오늘까지의 데이터를 저장한다.
        2. 지난번에 저장하다가 중간에 멈췄다면, 나머지 작업을 모두 완료 후, 해당시점의 e_date 부터 오늘까지의 데이터를 전 종목에 대해 저장한다.
        3.   이번에 저장하다가 중간에 멈췄다면, 이전 e_date 부터 오늘까지의 데이터를 전 종목에 대해 저장한다.
        4. 지난번에 저장을 완료했다면, 해당시점의 e_date 부터 오늘까지의 데이터를 전 종목에 대해 저장한다.

        :param duration: min1, min3, min5, min10, min60 중 하나의 값
        :return:
        """
        # stock_list = self.get_stock_list(constant.KOSPI)
        # stock_list += self.get_stock_list(constant.KOSDAQ)

        stock_list = self.get_stock_list(constant.KOSDAQ)
        cur = self.tt_db.time_series_temp2.find({'type': duration})
        s_date, e_date, s_index, current_flag = self.get_last_data(cur, duration)

        if not current_flag:
            msg = "[{}] {} ~ {}. start to collect stock data. this is previous process.".format(
                duration, s_date, e_date, e_date, self.end_date
            )
        else:
            msg = "[{}] {} ~ {}. start to collect stock data. this is current process.".format(
                duration, s_date, e_date
            )
        self.slack.log(msg)

        col = {
            "min1": self.tt_db.time_series_min1,
            "min3": self.tt_db.time_series_min3,
            "min5": self.tt_db.time_series_min5,
            "min10": self.tt_db.time_series_min10,
            "min60": self.tt_db.time_series_min60
        }[duration]
        fn = self.kw.stock_price_by_min

        total = len(stock_list)
        msg = "[{}] {} / {} -> start to collect stock data".format(duration, s_index, total)
        self.slack.log(msg)

        for i, stock in enumerate(stock_list[s_index:], s_index):
            code, stock_name = stock
            self.logger.info("%s/%s - %s/%s" % (i, total, code, stock_name))
            self.logger.info("period : {} ~ {}".format(s_date, e_date))
            self.logger.info("time_series_{}".format(duration))

            try:
                doc = fn(code, tick=duration.strip("min"), screen_no=self.get_screen_no[duration],
                         start_date=s_date, end_date=e_date)
            except KiwoomServerCheckTimeError as e:
                self.logger.error("[KiwoomServerCheckTimeError] {}".format(duration))
                self.tt_db.urgent2.update({'type': 'error'},
                                         {'type': 'error', 'error_code': e.error_code},
                                         upsert=True)
                exit(0)

            try:
                self.upsert_db(col, doc)
            except pymongo.errors.InvalidOperation as e:
                # cannot do an empty bulk write ?
                self.logger.error(e)

            self.tt_db.time_series_temp2.update({'type': duration},
                                               {'type': duration,
                                                'code': code,
                                                'stock_name': stock_name,
                                                'last': i,
                                                'start_date': s_date,
                                                'end_date': e_date,
                                                'total': total},
                                               upsert=True)
            self.tt_db.urgent2.update({'type': 'error'},
                                     {'type': 'error', 'error_code': 0},
                                     upsert=True)
        exit(0)  # Program exit

    def collect_n_save_data(self, duration):
        """
        코스피 종목의 분단위 데이터를 제외한 나머지 데이터를 수집한다.

        1. 한번도 db에 저장한적이 없다면 6/1일부터 오늘까지의 데이터를 저장한다.
        2. 지난번에 저장하다가 중간에 멈췄다면, 나머지 작업을 모두 완료 후, 해당시점의 e_date 부터 오늘까지의 데이터를 전 종목에 대해 저장한다.
        3.   이번에 저장하다가 중간에 멈췄다면, 이전 e_date 부터 오늘까지의 데이터를 전 종목에 대해 저장한다.
        4. 지난번에 저장을 완료했다면, 해당시점의 e_date 부터 오늘까지의 데이터를 전 종목에 대해 저장한다.

        :param duration: str - day, week, month, year 중 하나의 값
        :return:
        """
        stock_list = self.get_stock_list(constant.KOSPI)
        stock_list += self.get_stock_list(constant.KOSDAQ)
        cur = self.tt_db.time_series_temp2.find({'type': duration})
        s_date, e_date, s_index, current_flag = self.get_last_data(cur, duration)

        if not current_flag:
            msg = "[{}] {} ~ {}. start to collect stock data. this is previous process.".format(
                duration, s_date, e_date, e_date, self.end_date
            )
        else:
            msg = "[{}] {} ~ {}. start to collect stock data. this is current process.".format(
                duration, s_date, e_date
            )
            self.slack.log(msg)

        col = {
            "day": self.tt_db.time_series_day,
            "week": self.tt_db.time_series_week,
            "month": self.tt_db.time_series_month,
            "year": self.tt_db.time_series_year
        }[duration]

        fn = {
            "day": self.kw.stock_price_by_day,
            "week": self.kw.stock_price_by_week,
            "month": self.kw.stock_price_by_month
            # "year": self.kw.stock_price_by_year
        }[duration]

        total = len(stock_list)
        msg = "[{}] {} / {} -> start to collect stock data".format(duration, s_index, total)
        self.slack.log(msg)

        for i, stock in enumerate(stock_list[s_index:], s_index):
            code, stock_name = stock
            self.logger.info("%s/%s - %s/%s" % (i, total, code, stock_name))
            self.logger.info("time_series_{}".format(duration))
            try:
                doc = fn(code, screen_no=self.get_screen_no[duration], start_date=s_date, end_date=e_date)
            except KiwoomServerCheckTimeError as e:
                self.logger.error("[KiwoomServerCheckTimeError] {}".format(duration))
                self.tt_db.urgent2.update({'type': 'error'},
                                         {'type': 'error', 'error_code': e.error_code},
                                         upsert=True)
                exit(0)
            self.upsert_db(col, doc)
            self.tt_db.time_series_temp2.update({'type': duration},
                                               {'type': duration,
                                                'code': code,
                                                'stock_name': stock_name,
                                                'last': i,
                                                'start_date': s_date,
                                                'end_date': e_date,
                                                'total': total},
                                               upsert=True)

            self.tt_db.urgent2.update({'type': 'error'},
                                     {'type': 'error', 'error_code': 0},
                                     upsert=True)
        exit(0)  # Program exit
예제 #6
0
class TopTrader(QMainWindow, ui):
    def __init__(self):
        QMainWindow.__init__(self)

        # Application Configuration
        # UI
        self.setupUi(self)

        # Font(ko)
        self.set_ko_font()

        # Logger
        self.logger = TTlog(logger_name="TTRealCondi").logger

        # DB
        self.dbm = DBM('TopTrader')

        # Slack
        self.slack = Slacker(config_manager.get_slack_token())

        # Kiwoom
        self.kw = Kiwoom()
        self.login()
        self.stock_info = self.kw.get_stock_basic_info()

        # app main
        self.main()

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

    def set_ko_font(self):
        # 그래프에서 마이너스 폰트 깨지는 문제에 대한 대처
        mpl.rcParams['axes.unicode_minus'] = False

        path = 'c:/Windows/Fonts/D2Coding-Ver1.3-20171129.ttc'
        font_name = fm.FontProperties(fname=path).get_name()
        plt.rcParams["font.family"] = font_name

    def main(self):
        print("Start Application")
        target_date = datetime(2018, 8, 2)
        y, m, d = target_date.year, target_date.month, target_date.day
        s_time = datetime(y, m, d, 9, 0, 0)
        e_time = datetime(y, m, d, 15, 30, 0)
        self.code = '000020'
        df = pd.DataFrame(
            self.dbm.get_tick_data(self.code, target_date, tick="1"))
        ts_group = df.groupby('timestamp')
        volumn = pd.DataFrame(ts_group.sum()['거래량'])
        price = pd.DataFrame(ts_group.max()['현재가'])
        index = pd.date_range(s_time, e_time, freq='S')
        volumn = volumn.reindex(index, method='ffill', fill_value=0)
        price = price.reindex(index, method='ffill', fill_value=0)
        price['volumn'] = volumn

        from trading.account import Stock

        tick_data = defaultdict(list)
        stock_list = [
            Stock('900100', '주식1'),
            Stock('200710', '주식2'),
            Stock('206560', '주식3')
        ]
        for stock in stock_list:
            stock.gen_time_series_sec1(target_date)
            tick_data[stock.code] = stock.time_series_sec1
        pdb.set_trace()

        db_data = self.dbm.get_real_condi_search_data(target_date,
                                                      "소형주_급등_005_003")

        condi_hist = defaultdict(defaultdict)
        for data in db_data[:5]:
            code, date = data['code'], data['date'].replace(microsecond=0)
            price = tick_data[code].ix[date]['현재가']
            condi_hist[code][date] = price

        pdb.set_trace()
        print("End Application")
예제 #7
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")
예제 #8
0
class TopTrader(QMainWindow, ui):
    def __init__(self):
        super().__init__()
        # self.setupUi(self)  # load app screen
        self.logger = TTlog().logger
        self.dbm = DBM('TopTrader')
        self.mongo = MongoClient()
        self.db = self.mongo.TopTrader
        self.slack = Slack(config_manager.get_slack_token())
        self.kw = Kiwoom()
        self.login()
        self.main()

    def load_tick_data(self,
                       code,
                       stock_name,
                       date,
                       tick="1",
                       screen_no="1234"):
        """특정 종목의 하루단위 tick data를 가져오는 함수
        tick_data가 DB에 있으면 DB에서 가져오고, 없으면 kw module로부터 가져온다.

        :param code:
        :param stock_name:
        :param date:
        :param tick:
        :param screen_no:
        :return:
        """
        ret, cur = self.dbm.check_tick_cache(code, date, tick="1")

        if ret:
            tick_data = cur.next()
        else:
            base_date = datetime(date.year, date.month, date.day, 0, 0, 0)
            raw_data = self.kw.stock_price_by_tick(code,
                                                   tick=tick,
                                                   screen_no=screen_no,
                                                   date=base_date)
            tick_data = {
                'code':
                code,
                'stock_name':
                stock_name,
                'date':
                base_date,
                'time_series_1tick': [{
                    'timestamp': _d['date'],
                    '현재가': _d['현재가'],
                    '거래량': _d['거래량']
                } for _d in raw_data]
            }
        return tick_data

    def collect_tick_data(self,
                          code,
                          stock_name,
                          s_date,
                          e_date,
                          tick="1",
                          screen_no="1234"):
        """특정 종목의 일정 기간의 tick data를 DB에 저장하는 함수
        DB에 이미 값이 저장되어 있으면 저장하지 않고 skip 한다.
        s_date, e_date는 초단위까지 지정이 가능하지만, 저장은 일단위로 저장한다.
        tick은 1, 3, 5, 10, 30 선택 가능하다.

        :param code:
        :param stock_name:
        :param tick:
        :param s_date:
        :param e_date:
        :return:
        """
        s_base_date = datetime(s_date.year, s_date.month, s_date.day, 0, 0, 0)
        e_base_date = datetime(e_date.year, e_date.month, e_date.day, 0, 0, 0)
        days = (e_base_date - s_base_date).days + 1
        date_list = [s_base_date + timedelta(days=x) for x in range(0, days)]
        for base_date in date_list:
            ret, cur = self.dbm.check_tick_cache(code, base_date, tick="1")
            if ret:
                self.logger.debug(
                    "No need to save data. already has data in DB")
                continue

            raw_data = self.kw.stock_price_by_tick(code,
                                                   tick=tick,
                                                   screen_no=screen_no,
                                                   date=base_date)
            tick_data = {
                'code':
                code,
                'stock_name':
                stock_name,
                'date':
                base_date,
                'time_series_1tick': [{
                    'timestamp': _d['date'],
                    '현재가': _d['현재가'],
                    '거래량': _d['거래량']
                } for _d in raw_data]
                # 'time_series': [{'timestamp': _d['date'], '현재가': _d['현재가'], '거래량': _d['거래량']} for _d in raw_data]
            }
            # DB에 없으면 수행되는 부분이라서 insert 함수를 사용.
            self.dbm.save_tick_data(tick_data, tick="1")

    def main(self):
        # 사용자 정의 부분_S
        # 8/2일자 조건검색식으로 검출된 모든 종목의 1tick data를 수집한다.
        with open("base_date_when_collect_tick_data.txt") as f:
            year, month, day = [int(i) for i in f.read().strip().split(" ")]
        self.base_date = datetime(year, month, day)
        # 사용자 정의 부분_E

        # kospi, kosdaq 모든 종목의 코드와 종목명 정보를 불러온다.
        self.stock_info = self.kw.get_stock_basic_info()

        code_list = self.dbm.get_code_list_condi_search_result(self.base_date)
        code_list.sort()
        self.dbm.record_collect_tick_data_status("START",
                                                 self.base_date,
                                                 tick="1")
        for num, code in enumerate(code_list, 1):
            stock_name = self.stock_info[code]["stock_name"]
            if self.dbm.already_collect_tick_data(code,
                                                  self.base_date,
                                                  tick="1"):
                self.logger.debug(
                    "{}/{} - {}:{} Skip. Already saved data!".format(
                        num, len(code_list), code, stock_name))
                continue

            self.logger.debug("{}/{} - {}:{} Start !".format(
                num, len(code_list), code, stock_name))
            self.collect_tick_data(code,
                                   stock_name,
                                   self.base_date,
                                   self.base_date,
                                   tick="1",
                                   screen_no="1234")
            self.logger.debug("{}/{} - {}:{} Completed !".format(
                num, len(code_list), code, stock_name))

            self.dbm.save_collect_tick_data_history(code,
                                                    self.base_date,
                                                    tick="1")
            self.dbm.record_collect_tick_data_status("WORKING",
                                                     self.base_date,
                                                     tick="1")

        self.dbm.record_collect_tick_data_status("END",
                                                 self.base_date,
                                                 tick="1")
        self.logger.debug("save all 1tick information..")
        exit(0)  # program exit

    def login(self):
        err_code = self.kw.login()
        if err_code != 0:
            self.logger.error("Login Fail")
            exit(-1)
        self.logger.info("Login success")
예제 #9
0
class TopTrader(QMainWindow, ui):
    def __init__(self):
        QMainWindow.__init__(self)

        # Application Configuration
        # UI
        self.setupUi(self)

        # Font(ko)
        self.set_ko_font()

        # Logger
        self.logger = TTlog(logger_name="TTRealCondi").logger

        # DB
        self.mongo = MongoClient()
        self.db = self.mongo.TopTrader
        self.dbm = DBM('TopTrader')

        # Slack
        self.slack = Slack(cfg_mgr.get_slack_token())

        # Kiwoom
        self.kw = Kiwoom()
        self.login()
        cfg_mgr.STOCK_INFO = self.kw.get_stock_basic_info()

        # app main
        cfg_mgr.MODE = constant.DEBUG
        self.main()

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

    def set_ko_font(self):
        # 그래프에서 마이너스 폰트 깨지는 문제에 대한 대처
        mpl.rcParams['axes.unicode_minus'] = False
        try:
            path = 'c:/Windows/Fonts/D2Coding-Ver1.3-20171129.ttc'
            font_name = fm.FontProperties(fname=path).get_name()
            plt.rcParams["font.family"] = font_name
        except FileNotFoundError as e:
            path = 'c:/Windows/Fonts/D2Coding-Ver1.3.2-20180524.ttf'
            font_name = fm.FontProperties(fname=path).get_name()
            plt.rcParams["font.family"] = font_name

    def collect_1tick_data(self, code, stock_name, date):
        col_tick1 = self.db.time_series_tick1
        cur = col_tick1.find({'code': code, 'date': date})
        if cur.count() != 0:
            print("{}:{} Already save data. so Skip to save data !".format(
                code, stock_name))
            return

        s_date = date
        e_date = date + timedelta(days=1)
        raw_data = self.kw.stock_price_by_tick(code,
                                               tick="1",
                                               screen_no="1234",
                                               start_date=s_date,
                                               end_date=e_date)
        data = {
            'code':
            code,
            'stock_name':
            stock_name,
            'date':
            date,
            'time_series_1tick': [{
                'timestamp': _d['date'],
                '현재가': _d['현재가'],
                '거래량': _d['거래량']
            } for _d in raw_data]
        }
        # col_tick1.insert(data)
        return data

    def check_cache_tick1(self, code, s_date, e_date):
        col_tick1 = self.db.time_series_tick1
        s_base_date = datetime(s_date.year, s_date.month, s_date.day, 0, 0, 0)
        cur = col_tick1.find({
            'code': code,
            'date': {
                '$gte': s_base_date,
                '$lte': e_date
            }
        })
        if cur.count() != 0:
            return True, cur
        return False, None

    def main(self):
        # 목표 !!!
        # 하루 단위의 조건검색 결과를 분석한다.

        # 사용자 지정 변수__S
        self.target_date = datetime.today()
        self.target_date = datetime(2018, 8, 2)  # temp code
        # 사용자 지정 변수__E

        # 조건검색식 load
        condi_info = self.kw.get_condition_load()
        strg_list = []
        # loop를 돌면서 각각의 조건검색식에 대해 결과 분석
        for condi_name, condi_index in condi_info.items():
            # 특정일의 특정조건검색식을 특정전략으로 검증
            condi = ConditionalSearch.get_instance(condi_index, condi_name)

            self.logger.info("=======[ Smulation(%s) Start! ]=======" %
                             condi.condi_name)
            strg = Strategy("short_trading.strategy", condi)
            strg.simulate(self.target_date)
            strg_list.append(strg)
            self.logger.info("=======[ Smulation(%s) End! ]=======" %
                             condi.condi_name)
            self.logger.info("\n\n\n")

        self.logger.info("end")
        exit(0)
예제 #10
0
class Account(object):
    """
    [Todo]
    구현되어야 할 api list
    -

    """
    def __init__(self, init_balance, th):

        self.시작잔고 = init_balance
        self.예수금 = init_balance
        self.총평가금액 = 0.0
        self.총매입금액 = 0.0
        self.총최대매입금액 = 0.0
        self.총평가손익 = 0.0
        self.총손익 = 0.0  # 총평가손익 + 총누적손익
        self.추정자산 = init_balance
        self.총수익률 = 0.0
        self.총누적손익 = 0.0
        self.총누적수익률 = 0.0
        self.보유주식 = {}
        self.core_index = ['시작잔고', '예수금', '총평가금액', '총최대매입금액', '총매입금액', '총평가손익', '총손익',
                           '추정자산', '총수익률', '총누적손익', '총누적수익률']

        self.core_index = ['총누적손익', '총누적수익률', '총손익', '총수익률', '총평가손익', '총평가금액', '총매입금액',
                           '추정자산', '총최대매입금액', '예수금', '시작잔고']

        self.check_core_index()

        self.dbm = DBM('TopTrader')
        self.timestamp = None
        self.trading_history = th
        self.logger = TTlog().logger

    def print_attr(self, trading_type, stock_name, code, reason, attr_list=None):
        if not cfg_mgr.ACCOUNT_MONITOR:
            return
        self.logger.debug("\n" + ("-" * 100))
        self.logger.debug("[Account] Information : {}".format(self.timestamp))
        self.logger.debug("[Trading Type] -> {}-{} ( {}/{} )".format(trading_type, reason, stock_name, code))
        if bool(attr_list):
            attr_val = []
            for attr in attr_list:
                val = self.__getattribute__(attr)
                log_str = "{}: {}".format(attr, val)
                if isinstance(val, float):
                    log_str = "{}: {:.2f}".format(attr, val)
                attr_val.append(log_str)
            self.logger.debug("\n".join(attr_val))
        else:
            self.logger.debug(self.__repr__())

    def __repr__(self):
        core_index = ['timestamp'] + self.core_index

        # log = ["{}: {}".format(attr, str(self.__getattribute__(attr))) for attr in core_index]
        log = []
        for attr in core_index:
            val = self.__getattribute__(attr)
            log_str = "{}: {}".format(attr, val)
            if isinstance(val, float):
                log_str = "{}: {:.2f}".format(attr, val)
            log.append(log_str)
        return "\t".join(log)

    def sync(self):
        """실제 계좌 정보를 불러와서 멤버 변수를 초기화 한다.

        :return:
        """

    @common.type_check
    def update_sell(self, stock: Stock, price_per_stock: int, amount: int, reason: str):
        """특정 주식을 매도했을때, 계좌정보를 업데이트

        :param code:
        :param amount:
        :return:
        """
        # stock 객체 업데이트
        stock.trading_reason = reason
        stock.update_sell(price_per_stock, amount)
        if cfg_mgr.debug_mode():
            pass
            # self.print_attr('SELL', stock.stock_name, stock.code, reason)
            # pdb.set_trace()

        # 계좌 정보 업데이트
        self.예수금 += stock.매매금액
        self.총평가금액 += stock.평가금액변동
        self.총매입금액 += stock.매입금액변동
        self.총최대매입금액 = max(self.총매입금액, self.총최대매입금액)
        self.추정자산 = self.예수금 + self.총평가금액  # 현금(예수금) + 주식(총평가금액)
        self.총누적손익 += stock.실현손익
        self.총평가손익 = float(self.총평가금액 - self.총매입금액)  # 보유한 주식의가치로 얻은 손익
        self.총손익 = self.총평가손익 + self.총누적손익  # 개념상 손익 (현금의 손익 + 가치의 손익)
        try:
            self.총수익률 = self.총평가손익 / self.총매입금액 * 100  # 보유한 주식에 대한 총 수익률
        except ZeroDivisionError as e:
            self.총수익률 = 0.0
        self.총누적수익률 = float(self.총누적손익) / self.총최대매입금액 * 100  # 실현한 수익에 대한 총 수익률

        self.sell_transaction(stock)

        if stock.보유수량 == 0:
            del self.보유주식[stock.code]
        else:
            self.보유주식[stock.code] = stock

        try:
            if cfg_mgr.debug_mode():
                self.print_attr('SELL', stock.stock_name, stock.code, reason)
                # pdb.set_trace()
        except Exception:
            pdb.set_trace()
            print("Exception")
        return ""

    def gen_trading_info(self, stock, trading_type):
        """
            self.time = ""  # 또는 체결시간?
            self.trading_type = ""  # [B]uy, [S]ell
            self.code = ""  # 종목의 코드
            self.stock_name = ""  # 종목 이름
            self.stock_price = ""  # buy, sell 시 얼마에 사고팔았는지?
            self.loss_flag = None  # 손해를 봤는지, 안봤는지 (buy 일땐 None, sell 일땐 True/False
            self.profit_amount = 0  # 손해 또는 이익을 본 금액 (sell에서만 사용)
            self.profit_rate = 0.0  # 손해 또는 이익을 본 비율 (sell에서만 사용)

        :return:
        """
        tr = Trading(trading_type)

        # 속성값이 겹치지 않게 잘 관리되어야 함.
        # 겹치는 속성이 있다면, Account속성에는 '총' 붙이도록 함.
        stock_index = stock.get_core_index()
        account_index = self.get_core_index()

        # temp code - allow to duplicate 'timestamp'
        ret = (set(stock_index) & set(account_index)) - set('timestamp')
        if bool(ret):
            self.logger.error("{} is duplicate index. program exit")
            exit(-1)

        tr = common.copy_attr(stock, tr, stock_index)
        tr = common.copy_attr(self, tr, account_index)

        return tr

    def sell_transaction(self, stock):
        """

        :return:
        """
        tr = self.gen_trading_info(stock, constant.SELL_TRADING_TYPE)
        self.trading_history.record_sell_transaction(tr)

    @common.type_check
    def update_buy(self, stock: Stock, price_per_stock: int, amount: int, reason: str):
        """특정 주식을 매수했을때, 계좌정보를 업데이트

        :param code:
        :param price_per_stock:
        :param amount:
        :return:
        """
        # stock 객체 업데이트
        stock.trading_reason = reason
        stock.update_buy(price_per_stock, amount)

        if cfg_mgr.debug_mode():
            pass
            # self.print_attr('BUY', stock.stock_name, stock.code, reason)  # need to move to util/common pkg
            # pdb.set_trace()

        # 계좌 정보 업데이트
        self.예수금 -= stock.매매금액
        self.총평가금액 += stock.평가금액변동
        self.총매입금액 += stock.매입금액변동
        self.총최대매입금액 = max(self.총매입금액, self.총최대매입금액)
        self.추정자산 = self.예수금 + self.총평가금액  # 현금(예수금) + 주식(총평가금액)
        # self.총누적손익 += self.총누적손익 --> 변동없음
        self.총평가손익 = float(self.총평가금액 - self.총매입금액)  # 보유한 주식의가치로 얻은 손익
        self.총손익 = self.총평가손익 + self.총누적손익  # 개념상 손익 (현금의 손익 + 가치의 손익)
        self.총수익률 = self.총평가손익 / self.총매입금액 * 100  # 보유한 주식에 대한 총 수익률
        self.총누적수익률 = float(self.총누적손익) / self.총최대매입금액 * 100  # 실현한 수익에 대한 총 수익률

        # 보유주식에 포함
        self.보유주식[stock.code] = stock

        self.buy_transaction(stock)
        try:
            if cfg_mgr.debug_mode():
                self.print_attr('BUY', stock.stock_name, stock.code, reason)  # need to move to util/common pkg
                # pdb.set_trace()

        except Exception:
            # pdb.set_trace()
            print("Exception")

    def buy_transaction(self, stock):
        """

        :return:
        """
        tr = self.gen_trading_info(stock, constant.BUY_TRADING_TYPE)
        self.trading_history.record_buy_transaction(tr)

    def revaluate(self):
        """주식가치가 변경(현재가 변경)되면서 계좌에 업데이트 해야 하는 정보를 모두 업데이트

            총평가금액
            추정자산 = 예수금 + 총평가금액
            총수익률 = 총평가금액 - 총매입금액 / 총매입금액 * 100
            총손익 = (총평가금액 - 총매입금액) + 실현손익
        :return:
        """
        # self.총평가금액 = 0
        for stock in self.보유주식.values():
            # if cfg_mgr.debug_mode():
            #     self.print_attr('KEEP', stock.stock_name, stock.code, 'CHANGE_PRICE')  # need to move to util/common pkg
            #     pdb.set_trace()

            # 계좌 정보 업데이트
            # self.예수금 -= stock.매매금액
            self.총평가금액 += stock.평가금액변동
            # self.총매입금액 += stock.매입금액변동
            # self.총최대매입금액 = max(self.총매입금액, self.총최대매입금액)
            self.추정자산 = self.예수금 + self.총평가금액  # 현금(예수금) + 주식(총평가금액)
            # self.총누적손익 += self.총누적손익 --> 변동없음
            self.총평가손익 = float(self.총평가금액 - self.총매입금액)  # 보유한 주식의가치로 얻은 손익
            self.총손익 = self.총평가손익 + self.총누적손익  # 개념상 손익 (현금의 손익 + 가치의 손익)
            self.총수익률 = self.총평가손익 / self.총매입금액 * 100  # 보유한 주식에 대한 총 수익률
            # self.총누적수익률 = float(self.총누적손익) / self.총최대매입금액 * 100  # 실현한 수익에 대한 총 수익률

        # if cfg_mgr.debug_mode():
        #     self.print_attr('KEEP', stock.stock_name, stock.code, 'CHANGE_PRICE')  # need to move to util/common pkg
        #     pdb.set_trace()

    def update_account_value(self, timestamp):
        """보유주식을 현 timestamp에 맞게 내부 정보를 업데이트 한다.

            변경된 현재가를 기준으로 아래 필드가 함께 업데이트 된다.
            self.수익률 = (self.현재가 - self.매입평균가) / self.매입평균가 * 100
            self.평가손익 = self.총매입금액 * self.수익률
            self.총평가금액 = self.현재가 * self.보유수량

        :param timestamp:
        :return:
        """
        self.timestamp = timestamp

        if not bool(self.보유주식):
            return

        for stock in self.보유주식.values():
            stock.update_stock_value(timestamp)

        self.revaluate()

    def add_stocks(self, code_list):
        """보유주식에 포함시킨다.

        :param code:
        :return:
        """
        for code in code_list:
            self.보유주식[code] = Stock.get_instance(code)

    def set_tick1_data(self, target_date):
        """보유한 주식(Stock)에 대해 tick1 data를 생성한다.

        :param target_date:
        :return:
        """
        for stock in self.보유주식.values():
            stock.gen_time_series_sec1(target_date)

    def get_tick_data(self, code):
        """

        :param code:
        :return:
        """
        return self.보유주식[code].tick_data

    def get_balance(self):
        """현재 잔고를 반환

        :return:
        """
        return self.balance

    def has_code(self, code):
        """해당 종목을 현재 보유중인지

        :param code:
        :return:
        """
        return code in self.보유주식

    def get_stock_count(self):
        """현재 보유중인 종목의 갯수를 반환

        :return:
        """
        return self.get_code_count()

    def get_code_count(self):
        """현재 보유중인 종목의 갯수를 반환

        :return:
        """
        return len(self.get_code_list_in_account())

    def get_code_list_in_account(self):
        """현재 보유중인 종목코드를 반환

        :return:
        """
        return self.보유주식.keys()

    def get_stock_list_in_account(self):
        """현재 보유중인 종목(Stock)을 반환

        :return:
        """
        return [stock for stock in self.보유주식.values()]

    def clear_stock(self, stock, price, reason):
        """보유한 주식중 특정 종목 일괄 청산

        :param code:
        :return:
        """
        stock.trading_reason = reason
        stock.update_sell(int(price), int(stock.보유수량))

    def all_clear_stocks(self, timestamp):
        """보유한 주식을 모두 일괄 청산

        :return:
        """
        for stock in self.보유주식.values():
            self.clear_stock(stock, stock.get_curr_price(timestamp), constant.TRADING_TIME_EXPIRED)

    def get_core_index(self):
        """Account 객체의 핵심 지표 리스트. 반드시 Account 객체의 속성값과 동기화가 되어야 함.

        :return:
        """
        return self.core_index

    def check_core_index(self):
        """계좌의 핵심 지표들이 모두 설정되었는지 check.
        누락된 지표가 있다면 Exception 발생하고 프로그램 종료

        :return:
        """
        for index in self.get_core_index():
            self.__getattribute__(index)

    def is_empty(self):
        return bool(self.보유주식)