import sys, time, random, os import json # load strategy # from strategies.indicator import StrategyIndicator from backtesting import Backtest # short-tp error # load functions # from indicator_util import get_indicators_values from signal_helper import * # load db from db import DB from itertools import combinations from datetime import datetime from dateutil.relativedelta import relativedelta # from trade.candle import CandlePatterns import warnings from time import sleep from strategy import StrategyCandlePattern from multiprocessing import Process, freeze_support import gc warnings.filterwarnings(action='ignore') _db = DB() # set config start_time = time.time() top_cash = 0 top_profit = 20 top_win_rate = 90 # best_pattern_arr = [] # [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) # 시그널 보조 지표 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}, ] ''' # for test # base_indicators = [{'RSI': 14}, {'BBANDS': [34, 2]}, {'CCI': 20}, {'MFI': 14}, {'MOM': 14}] # signal_indicators = [{'STOCH_DIV': [14, 3, 3]}, {'ROC_DIV': 14}, {'STOCH_DIV': [14, 3, 5]}] data = _db.get_price_data_from_item_table('crypto/bithumb/KRW-BTC/day', '6_M') df = pd.DataFrame(data) df.set_index(df['date'], inplace=True) data_columns_init(df) df.index.name = str('crypto/bithumb/KRW-BTC/day').replace('/', '_') StrategyCandlePattern.use_indicators = [{'HEI': None}] StrategyCandlePattern.up_target = float(0) StrategyCandlePattern.down_target = float(0) bt = Backtest(df, StrategyCandlePattern, cash=cash, commission=commission) bt.run() print(bt._results) bt.plot() sys.exit(1) ''' # multi Treading - item def simulrating_by_item(item, data, all_indicators, idx, t_time): # from guppy.heapy import RM # for monitoring global start_time # global _db _db = DB() cash = 1000 commission = .005 print('작업 시작 : %s / 지표 수 : %s / 시간프레임 : %s' % (item['job'], idx, t_time)) # get top_profit and win rate from item-t_time top_info = _db.select_top_date(item['job']) min_profit = 22 if str(item['trade_type']) == 'double': min_profit = 30 if top_info['profit_rate'] is None: global top_profit global top_win_rate else: top_profit = float(top_info['profit_rate']) top_win_rate = float(top_info['win_rate']) # bt = Backtest(data, StrategyCandlePattern, cash=cash, commission=commission) for indicators in list(combinations(all_indicators, idx)): for profit in profit_arr: for loss in 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 StrategyCandlePattern.use_indicators = list(indicators) StrategyCandlePattern.up_target = float(profit) StrategyCandlePattern.down_target = float(loss) StrategyCandlePattern.trade_type = str(item['trade_type']) bt = Backtest(data, StrategyCandlePattern, cash=cash, commission=commission) bt.run() # 수익 및 거래 수 제한 if bt._results['# Trades'] >= 5 and bt._results['Return [%]'] > min_profit and \ (bt._results['Return [%]'] > top_profit or float(bt._results['Win Rate [%]']) >= 100): filename = 'chart/' + str(item['job']).replace('/', '_') + '_' + str(t_time) + '_' + str( time.time()) _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(StrategyCandlePattern.use_indicators), 'use_pattern_cnt': len(StrategyCandlePattern.use_indicators), 'filename': filename, 'period_cycle': item['period_cycle'], 'trade_type': item['trade_type'], }) if bt._results['Return [%]'] > top_profit: top_profit = bt._results['Return [%]'] # print('-' * 60) # print('트레이딩 종류 :', item['trade_type']) # print('시간봉 :', t_time) # print('지표 조합 개수 :', idx) # print('지표 :', StrategyCandlePattern.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 [%]'] > 50 and float( bt._results['Win Rate [%]']) >= 100: # 최상의 수익인 경우 차트 저장 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()) del [[cash, commission, top_info, _db]] # del [[item, data, all_indicators, idx, t_time]] gc.collect() # multi Treading - fackage def simulrating_by_item_fackage(item, data, t_time): global start_time global base_indicators global signal_indicators global _db # _db = DB() cash = 1000 commission = .005 top_info = _db.select_top_date(item['job']) min_profit = 17 if str(item['trade_type']) == 'double': min_profit = 17 if top_info['profit_rate'] is None: global top_profit global top_win_rate else: top_profit = float(top_info['profit_rate']) top_win_rate = float(top_info['win_rate']) # bt = Backtest(data, StrategyCandlePattern, cash=cash, commission=commission) filtered_signal_indicators = [] for indicator in signal_indicators: for profit in profit_arr: for loss in 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 # for test # StrategyCandlePattern.use_indicators = [{"WMA": 30}, {"EMA": 30}, {"STOCHF": [14, 3]}] StrategyCandlePattern.use_indicators = [indicator] StrategyCandlePattern.up_target = float(profit) StrategyCandlePattern.down_target = float(loss) StrategyCandlePattern.trade_type = str(item['trade_type']) bt = Backtest(data, StrategyCandlePattern, cash=cash, commission=commission) bt.run() # 수익 및 거래 수 제한 if float(bt._results['Return [%]']) > min_profit and float(bt._results['# Trades']) >= 5: if indicator not in filtered_signal_indicators: filtered_signal_indicators.append(indicator) # if float(bt._results['Return [%]']) > top_profit or float(bt._results['Win Rate [%]']) >= 60: # filename = 'chart/' + str(item['job']).replace('/', '_') + '_' + str(t_time) + '_' + str( # time.time()) # 단일 지표 미사용 # _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(StrategyCandlePattern.use_indicators), # 'use_pattern_cnt': len(StrategyCandlePattern.use_indicators), # 'filename': filename, # 'period_cycle': item['period_cycle'], # 'trade_type': item['trade_type'], # }) # if bt._results['Return [%]'] > top_profit: # top_profit = bt._results['Return [%]'] # if bt._results['Win Rate [%]'] > top_win_rate: # top_win_rate = bt._results['Win Rate [%]'] # bt.plot(filename=filename, open_browser=False) # best_pattern_arr.append({ # 't_time': t_time, # 'indicators': [indicator], # 'profit': profit, # 'loss': loss, # 'return': bt._results['Return [%]'], # 'trades': bt._results['# Trades'], # }) bt = None del [[bt]] # 총 32개 이하로 유지 filtered_signal_indicators = filtered_signal_indicators[:12] e = int(time.time() - start_time) print('시그널 지표 필터링 완료 :', '{:02d}:{:02d}:{:02d}'.format(e // 3600, (e % 3600 // 60), e % 60)) print('지표 총합 :', len(filtered_signal_indicators) + len(base_indicators)) print('필터 지표 리스트', filtered_signal_indicators) if len(filtered_signal_indicators) < 2: print(item, t_time, '- 수익 모델 조건을 만족하는 전략이 없습니다.') return all_indicators = filtered_signal_indicators[::-1] + base_indicators joined = [] for idx in range(2, 5): _p = Process(target=simulrating_by_item, args=(item, data, all_indicators, idx, t_time,)) _p.start() joined.append(_p) del [[item, data, all_indicators, idx, t_time, cash, commission, top_info]] gc.collect() # 프로세스 조인 for _p in joined: _p.join() # multi Treading - time def simulrating_by_time(item, t_time): global _db ''' "day": "24H", "hour12": "12H", "hour6": "06H", "hour": "01H", "minute30": "30M", "minute10": "10M", "minute5": "05M", "minute3": "03M", ''' data = _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=180) # UTC (트레이딩뷰) df = df.resample(time_type[t_time], how=ohlc_dict, label='left', base=540) # UTC (트레이딩뷰) df = df[:-1] simulrating_by_item_fackage(item, df, t_time) df = None del [[df]] def is_bot_by_exchange_name(item): target = item['job'].split('/') return _db.is_bot_by_exchange_name(target[1]) # reboot for windows def reboot(): print('재부팅 예약 되었습니다.', datetime.now()) return os.system("shutdown -t 60 -r -f") def record_item_per_time(): # 테이블 생성해서 쓰고 지우기 print('record_item_per_time') print(os.path.expanduser()) def start_backtest(): global _db print('Started Simulating.', datetime.now()) zzz = True for item in _db.get_cron_list(): # 이미 작동중인 봇이 있을 경우 제외 - 거래소 기준 if is_bot_by_exchange_name(item): continue if item['time_unit'] == 'hour': for t_time in ['hour6']: # 6시간봉만 시뮬레이팅 # for t_time in ['hour6', 'hour4']: # 4시간, 6시간봉 시뮬레이팅 if _db.is_simulated_item_per_hour(item['job'], t_time): continue simulrating_by_time(item, t_time) # 타임프레임 시뮬레이터 상태 임시 저장 _db.insert_item_from_simul_item_per_hour(item['job'], t_time) return reboot() # 타임프레임 시뮬레이터 상태 삭제 _db.remove_item_from_simul_item_per_hour(item['job']) _db.update_simul_init_value(item['job']) return reboot() simulrating_by_time(item, item['time_unit']) _db.update_simul_init_value(item['job']) return reboot() if zzz: print('There is no list of items to run.', datetime.now()) time.sleep(43400) return reboot() if __name__ == '__main__': freeze_support() start_backtest()