# -*- coding: utf-8 -*- from db import DB from datetime import datetime, timedelta import sys from trader import Trader # Email from mail import Mail ''' 완료 항목 # Bot Table : 금융 아이디, 거래소 아이디, 아이템, 예상수익, 실제 수익, 예상 승률, # 실제 승률, 거래수, 매매전략, 시간종류 # 봇 생성 조건 # 1. 시뮬레이팅 완료된 종목 # 2. 수익률 15프로 이상 / 승률 80프로 이상의 매매전략이 있을 경우만 # 봇 매매전략 업데이트 # 중지된 봇을 재 시뮬레이팅 후 최고 수익률로 전략 업데이트 # 봇 삭제 조건 # 거래수 5번이상 일 때, 실제 수익이 3퍼센트 미만일 경우 봇 상태값 N으로 변경 => 수익성 없음 판단 ''' ''' 진행중 항목 # 포지션 존재 => 트레이더 객체를 통해 포지션이 있을 경우 포지션은 종료한다. => 트레이더 객체 구현 시 적용 ''' class Bot: db = DB() trader = Trader() mail = Mail() def send_email(self, title, msg): self.mail.send_email(title, msg) def run(self): # 테이블 존재 체크 if not (self.db.is_table('bot') or self.db.is_table('simulation')): return print('Started. Bot Process') # 2달 지난 시뮬레이터 기록 삭제 self._remove_simul_results_deadline() # 거래소별 봇 생성 및 업데이트 for e in self.db.select_exchange_list_for_bot(): info = e['exchange_info'] # 시뮬레이팅이 완료된 종목만 실행 if not self.is_exchange_complete_sumulations(info): continue # 봇 생성 및 갱신 self._make_update_bots(info) # 봇 생성 및 업데이트 # for i in self._get_trade_list(): # # 해당 거래소 시뮬레이팅 완료 체크 # self._make_update_bots(i) # 수익이 저조한 봇 중지 for bot in self.get_running_bots(): self._check_bot_profit_and_stop(bot) # 초기 시드 갱신 # self.update_seed_data_in_bot(bot) print('Ended. Bot Process') def is_exchange_complete_sumulations(self, exchange_info): # i = info['job'].split('/') # ex = '_'.join(i[:-2]) job_info = self.db.select_tb_cron_simul_status(exchange_info) for s in job_info: if s['init_simul'] == 'N': return False return True def update_seed_data_in_bot(self, bot): deadline_date = datetime.now() - timedelta(weeks=5) if bot['update_date'] < deadline_date: updated_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.db.update_first_seed_by_now_seed(bot, updated_date) def _remove_simul_results_deadline(self): deadline_date = datetime.now() - timedelta(weeks=10) self.db.delete_simul_results_by_deadline(deadline_date) # 트레이더 객체를 통해 해당 봇의 포지션을 종료한다. def _close_bot_position(self, bot_info): if bot_info['position'] != 'None': self.trader.force_close_position(bot_info) def _check_bot_profit_and_stop(self, bot): if int(bot['trade_cnt']) >= 6 and float(bot['profit']) < -1 or float(bot['last_profit']) <= -2: self._close_bot_position(bot) self._stop_bot_by_id(bot['id']) self._init_simul_status(bot['target']) title = '[%s] %s mode - 해당 거래소 봇이 수익 미달로 중지되었습니다' % (bot['target'], bot['mode']) body = "\n".join('{} : {}'.format(key, value) for key, value in bot.items()) self.send_email(title, body) def _stop_bot_by_id(self, bot_id): self.db.update_bot_data_for_stop_by_id(bot_id) def _init_simul_status(self, target): t = str(target).split('_') i = '/'.join(t[:-1]) self.db.update_tb_cron_simul_status(i) def get_running_bots(self): return self.db.select_running_bots() def _make_update_bots(self, e_info): # s_item = t_item['job'].split('/') # e_i = self.db.get_id_by_exchange_name(s_item[1]) res = self._get_satisfy_condition_result_row(e_info) if res: self._upsert_bot_data(res) def _upsert_bot_data(self, this_bot): item = this_bot['t_table_name'].split('_') target = '_'.join(item[:-1]) this_bot['target'] = target prev_bot = self.db.get_bot_data_by_target(target) return self.compare_prev_bot_and_new_bot(prev_bot, this_bot) def compare_prev_bot_and_new_bot(self, prev_bot, this_bot): # 수익률이 없다고 판단 될 시 봇 생성 거부 if float(this_bot['profit_rate']) < 15: return False # 봇이 없을 경우 새로운 봇 생성 if prev_bot is (): title = '[%s] - 해당 거래소 봇이 생성되었습니다.' % (this_bot['target']) body = "\n".join('{} : {}'.format(key, value) for key, value in this_bot.items()) self.send_email(title, body) return self.db.upsert_bot_data(this_bot) # 현재 봇이 최신 봇일 경우 if prev_bot['strategy'] == this_bot['used_patterns']: return False # 봇이 중지 상태이고, 이전 전략과 다를 경우 갱신 if str(prev_bot['status']) == 'N' and \ str(prev_bot['strategy']).replace('"', '') != str(this_bot['used_patterns']).replace('"', ''): title = '[%s] - 해당 거래소 봇이 갱신되었습니다.' % (this_bot['target']) body = "\n".join('{} : {}'.format(key, value) for key, value in this_bot.items()) self.send_email(title, body) return self.db.upsert_bot_data(this_bot) # 비교 로직(수익률/승률 비교) # if float(this_bot['profit_rate']) > float(prev_bot['p_profit']) and \ # float(this_bot['win_rate']) >= float(prev_bot['p_winrate']): # return self.db.upsert_bot_data(this_bot) # 시뮬레이션 결과 중 조건에 만족하는 데이터 가져오기 def _get_satisfy_condition_result_row(self, t_name): res = self.db.get_simul_res_top_row(t_name.replace('/', '_')) if res is (): return False return res def _get_trade_list(self): return self.db.get_completed_simul_list() if __name__ == "__main__": b = Bot() b.run()