import sys, time, random, os import json # load strategy from backtesting import Backtest # short-tp error # load functions from signal_helper import * # load db from db import DB from itertools import combinations from datetime import datetime from dateutil.relativedelta import relativedelta from strategy import StrategyCandlePattern from multiprocessing import Process, freeze_support import gc class Simulator: _db = DB() data = None # set config top_cash = 0 top_profit = 20 top_win_rate = 60 # best_pattern_arr = [] cash = float(1000) commission = float(.005) # set strategy strategy = StrategyCandlePattern # [0, 0.23, 0.38, 0.5, 0.61, 0.78, 0.88, 1] # pivonachi profit_arr = [0] + pivo(25) loss_arr = [0] + pivo(25) filtered_signal_indicators = [] # 시그널 보조 지표 base_indicators = [ {'HEI': None}, {'RSI_DIV': 14}, {'MFI_DIV': 14}, {'CCI_DIV': 20}, {'WILLR_DIV': 28}, {'RSI': 14}, {'BBANDS': [20, 2]}, {'BBANDS': [34, 2]}, {'CCI': 14}, {'AROON': 14}, {'SAR': [0.00252, 0.22]}, {'AROONOSC': 14}, {'BOP': 14}, {'CCI': 20}, {'MFI': 14}, {'MOM': 10}, {'MOM': 14}, {'ROC': 9}, {'ROC': 14}, {'WILLR': 14}, ] # 시그널 주도 지표(필터링될 지표) signal_indicators = [ {'STOCH_DIV': [14, 1, 1]}, {'STOCH_DIV': [14, 3, 3]}, # {'STOCH_DIV': [20, 12, 12]}, {'STOCHRSI_DIV': [14, 14, 3]}, {'CMO_DIV': 14}, {'CCI_DIV': 14}, {'ADX_DIV': 14}, {'BOP_DIV': 0}, {'OBV_DIV': 0}, {'MOM_DIV': 10}, {'ROC_DIV': 14}, {'ROC_DIV': 9}, {'STOCH_DIV': [14, 3, 14]}, {'STOCH_DIV': [14, 3, 5]}, {'ADOSC_DIV': [3, 10]}, {'ULTOSC_DIV': [7, 14, 28]}, {'TRIX': [14, 9]}, {'STOCH': [20, 12, 12]}, {'STOCH': [14, 3, 14]}, {'STOCH': [14, 3, 5]}, {'DMI': 14}, {'DI': 21}, {'APO': [10, 20]}, {'MACD': [12, 26, 9]}, {'MACDFIX': 26}, {'MACDFIX': 9}, {'MACDFIX': 14}, {'MACDFIX': 31}, {'PPO': [12, 26, 9]}, {'STOCHF': [14, 3]}, {'STOCHRSI': [14, 14, 3]}, {'ULTOSC': [7, 14, 28]}, {'EMA': 30}, {'EMA': 55}, {'DEMA': 55}, {'DEMA': 100}, {'DEMA': 200}, {'MA': 21}, {'MA': 55}, {'MA': 100}, {'MAMA': [0.5, 0.05]}, {'T3': [100, 10]}, {'TRIMA': 30}, {'TRIMA': 50}, {'WMA': 30}, {'WMA': 20}, ] def run(self): print('Started Simulating.', datetime.now()) zzz = True for item in self._db.get_cron_list(): # 이미 작동중인 봇이 있을 경우 제외 - 거래소 기준 if self.is_bot_by_exchange_name(item): continue if item['time_unit'] == 'hour': for t_time in ['hour6', 'hour4']: # 4시간, 6시간봉 시뮬레이팅 self.simulrating_by_time(item, t_time) self._db.update_simul_init_value(item['job']) return self.reboot() self.simulrating_by_time(item, item['time_unit']) self._db.update_simul_init_value(item['job']) return self.reboot() if zzz: print('There is no list of items to run.', datetime.now()) time.sleep(43200) return self.reboot() # multi Treading - item def simulrating_by_item(self, item, all_indicators, idx, t_time): start_time = self.get_this_time() print('작업 시작 : %s / 지표 수 : %s / 시간프레임 : %s' % (item['job'], idx, t_time)) # get top_profit and win rate from item-t_time top_info = self._db.select_top_date(item['job']) min_profit = 17 if str(item['trade_type']) == 'double': min_profit = 35 # bt = Backtest(data, StrategyCandlePattern, cash=cash, commission=commission) for indicators in list(combinations(all_indicators, idx)): for profit in self.profit_arr: for loss in self.loss_arr: # if str(item['trade_type']) == 'double' and loss > 0 and profit == 0: # 숏 포지션 목표가만 있을 시 에러 # continue # if str(item['trade_type']) == 'double' and (loss != 0 or profit != 0): # continue self.strategy.use_indicators = list(indicators) self.strategy.up_target = float(profit) self.strategy.down_target = float(loss) self.strategy.trade_type = str(item['trade_type']) bt = Backtest(self.data, self.strategy, cash=self.cash, commission=self.commission) bt.run() # 수익 및 거래 수 제한 if bt._results['# Trades'] >= 5 and bt._results['Return [%]'] > min_profit and \ (bt._results['Return [%]'] > self.top_profit or float(bt._results['Win Rate [%]']) >= 100): filename = 'chart/' + str(item['job']).replace('/', '_') + '_' + str(t_time) + '_' + str( time.time()) self._db.insert_simul_result( { 'item': str(item['job']).replace('/', '_'), 'time_type': t_time, 'results': bt._results, 'stop_profit': profit, 'stop_loss': loss, 'use_patterns': json.dumps(self.strategy.use_indicators), 'use_pattern_cnt': len(self.strategy.use_indicators), 'filename': filename, 'period_cycle': item['period_cycle'], 'trade_type': item['trade_type'], }) if bt._results['Return [%]'] > self.top_profit: self.top_profit = bt._results['Return [%]'] # print('-' * 60) # print('트레이딩 종류 :', item['trade_type']) # print('시간봉 :', t_time) # print('지표 조합 개수 :', idx) # print('지표 :', self.strategy.use_indicators) # print("적용된 스탑프로핏 : %0.2f%%" % profit) # print("적용된 스탑로스 : %0.2f%%" % loss) # print("총 수익률 : %0.2f%%" % bt._results['Return [%]']) # print("최종 금액 : %0.2f" % bt._results['Equity Final [$]']) # print("거래 수 :", bt._results['# Trades']) # print("파일명 :", filename) # print('-' * 60) # bt.plot() if bt._results['Return [%]'] > 40 and float( bt._results['Win Rate [%]']) >= 80: # 최상의 수익인 경우 차트 저장 bt.plot(filename=filename, open_browser=False) del [[filename]] if bt._results['Win Rate [%]'] >= top_win_rate: top_win_rate = bt._results['Win Rate [%]'] # best_pattern_arr.append({ # 't_time': t_time, # 'indicators': indicators, # 'profit': profit, # 'loss': loss, # 'return': bt._results['Return [%]'], # 'trades': bt._results['# Trades'], # }) bt = None del [[bt]] gc.collect() e = int(time.time() - start_time) print('(완료) 조합 지표 개수 :', idx, t_time, '{:02d}:{:02d}:{:02d}'.format(e // 3600, (e % 3600 // 60), e % 60)) print(datetime.now()) gc.collect() # multi Treading - fackage def simulrating_by_item_fackage(self, item, t_time): start_time = self.get_this_time() top_info = self._db.select_top_date(item['job']) min_profit = 7 if str(item['trade_type']) == 'double': min_profit = 16 for indicator in self.signal_indicators: for profit in self.profit_arr: for loss in self.loss_arr: self.strategy.use_indicators = [indicator] self.strategy.up_target = float(profit) self.strategy.down_target = float(loss) self.strategy.trade_type = str(item['trade_type']) bt = Backtest(self.data, self.strategy, cash=self.cash, commission=self.commission) bt.run() # 수익 및 거래 수 제한 if float(bt._results['Return [%]']) > min_profit and float(bt._results['# Trades']) >= 5: if indicator not in self.filtered_signal_indicators: self.filtered_signal_indicators.append(indicator) bt = None del [[bt]] e = int(time.time() - start_time) print('시그널 지표 필터링 완료 :', '{:02d}:{:02d}:{:02d}'.format(e // 3600, (e % 3600 // 60), e % 60)) print('지표 총합 :', len(self.filtered_signal_indicators) + len(self.base_indicators)) print('필터 지표 리스트', self.filtered_signal_indicators) if len(self.filtered_signal_indicators) < 2: print(item, t_time, '- 수익 모델 조건을 만족하는 전략이 없습니다.') return all_indicators = self.filtered_signal_indicators[::-1] + self.base_indicators joined = [] for idx in range(2, 5): _p = Process(target=self.simulrating_by_item, args=(item, all_indicators, idx, t_time,)) _p.start() joined.append(_p) # 프로세스 조인 for _p in joined: _p.join() def simulrating_by_time(self, item, t_time): self.top_profit = 20 self.top_win_rate = 60 ''' "day": "24H", "hour12": "12H", "hour6": "06H", "hour": "01H", "minute30": "30M", "minute10": "10M", "minute5": "05M", "minute3": "03M", ''' data = self._db.get_price_data_from_item_table(item['job'], item['period_cycle']) df = pd.DataFrame(data) # date = df['date'].copy() # 최소 데이터 기준 일자 조건문(2달) std_date = datetime.now() - relativedelta(months=2) if df['date'][0] > std_date: del [[df]] return df.set_index(df['date'], inplace=True) data_columns_init(df) df.index.name = str(item['job']).replace('/', '_') if t_time != 'hour' and t_time != 'day': time_type = { 'hour': '60min', 'hour2': '120min', 'hour4': '240min', 'hour6': '360min', 'hour12': '720min', # 'week': 'W', # 'month': 'M', } ohlc_dict = { 'Open': 'first', 'High': 'max', 'Low': 'min', 'Close': 'last', 'Volume': 'sum' } # df = df.resample(time_type[t_time], how=ohlc_dict, label='left', base=540) df = df.resample(time_type[t_time], label='left', base=540).agg(ohlc_dict) df = df[:-1] self.data = df self.simulrating_by_item_fackage(item, t_time) self.data = None def get_this_time(self): return time.time() def is_bot_by_exchange_name(self, item): target = item['job'].split('/') return self._db.is_bot_by_exchange_name(target[1]) # reboot for windows def reboot(self): print('재부팅 예약 되었습니다.') return os.system("shutdown -t 60 -r -f") if __name__ == '__main__': b = Simulator() b.run()