def get_coin_data(self, ptime, symbol): """ coin data from redis by ptime and symbol :param ptime:string :param symbol: :return: """ if self.__df is None: raise Exception( 'Please call init_data before using get_coin_data') try: return True, self.__df.loc[symbol, ptime] except KeyError as e: logger.warning( "(KeyError) There is no {} for {} (human date {}), error: {}" .format(symbol, ptime, TimeHelper.epoch_to_date_time(ptime), e)) return False, [] except TypeError as e2: logger.warning( "(TypeError) There is no {} for {} (human date {}), error: {}" .format(symbol, ptime, TimeHelper.epoch_to_date_time(ptime), e2)) return False, []
def run(path_to_data_file, current_time=TimeHelper.current_time_stamp(), tick_time_hours=Consts.TICK_TIME_HOURS, benchmark_symbols_list=None): """ 1) fetch data from files - 1.a. simulation params 1.b. fees 1.c. ml result 2) run multiprocess all simulation 3) concate all result(analytics) files from simulation. :param id: :param tick_time_hours: :param benchmark_symbols_list: :return: """ if benchmark_symbols_list is None: benchmark_symbols_list = [['BTC']] # Anlayze results logger.info("Getting alto results") df_ml_results, df_simulations = LoaderHelper.fetch_simulations(benchmark_symbols_list, path_to_data_file) _fees = Fees.Fees() # Multi proccesing to run simulation classes which writes results into Simulator/Results/{id} data_for_run = [] df_simulations.index.names = ['index'] gb = df_simulations.groupby('index') for _df in [gb.get_group(x) for x in gb.groups]: data_for_run.append((df_ml_results, _df, tick_time_hours, _fees, current_time, benchmark_symbols_list)) pbar = tqdm(total=len(data_for_run)) def print_progress(res): pbar.update() with multiprocessing.Pool(multiprocessing.cpu_count()) as p: print(data_for_run) res = [p.apply_async(Simulation.Simulation, args=(_single_run,), callback=print_progress) for _single_run in data_for_run] for func_res in res: func_res.get() p.close() p.join() pbar.close() path_to_analytics = os.path.join(Consts.PATH_TO_WRITE_RESULT, TimeHelper.epoch_to_date_time( current_time).strftime( Consts.WRITE_DATE_FORMAT), 'analytics') analytics_files = os.listdir(path_to_analytics) list_analytics_files_dfs = [] for file_name in analytics_files: list_analytics_files_dfs.append(pd.read_csv(os.path.join(path_to_analytics, file_name))) all_analytics_files_df = pd.concat(list_analytics_files_dfs, ignore_index=True, sort=True) path_to_write_summery = os.path.join(path_to_analytics, 'Simulations__Summery__Analytics.csv') all_analytics_files_df.set_index('simulation_id', inplace=True) all_analytics_files_df.to_csv(path_to_write_summery) logger.info('Finished all simlations, base path result:{}, analytics summery: {}'.format(os.path.join(Consts.PATH_TO_WRITE_RESULT, TimeHelper.epoch_to_date_time( current_time).strftime( Consts.WRITE_DATE_FORMAT)), path_to_write_summery))
def fetch_simulations(benchmark_symbols_list, path_to_data_file): """ init coins data to redis Creates 3 dataframe 1.MLResult. 2.all simulation params options. 3. fees a data frame with index as simulation_id and the following columns: [amount_of_capital, max_percante_cap_invested_in_a_round, max_percentage_out_of_volume, :return: params, ml_results, prices """ # benchmark_symbols_list, can be list in a list so this how i'm init all coins data to redis list_coins_to_init = [] for temp_obj in benchmark_symbols_list: if not isinstance(temp_obj, list): list_coins_to_init.append(temp_obj) continue list_coins_to_init += temp_obj ml_results = pd.concat([ load_ml_results(Consts.ML_RESULT_LONG_PATH, Consts.LONG), load_ml_results(Consts.ML_RESULT_SHORT_PATH, Consts.SHORT) ], ignore_index=True, sort=True) ml_results['prediction_time'] = pd.to_datetime( ml_results['prediction_time'], format=Consts.READ_DATE_FORMAT).apply( lambda x: TimeHelper.datetime_to_epoch(x)) simulations_options_df = load_simulation_params() _data_helper.init_data( list(set(list_coins_to_init).union(set(ml_results.coin_symbol))), path_to_data_file, ml_results['prediction_time'].min(), ml_results['prediction_time'].max()) convert_dfs_int_to_float([ml_results, simulations_options_df]) return [ml_results, simulations_options_df]
def advance_one_step(self): """ Advances current time by ticktime interval :return: """ self.current_time += (self.hours_tick_time_interval * 60 * 60) logger.debug("Simulation has advance to time {}".format( TimeHelper.epoch_to_date_time(self.current_time)))
def __init__(self, coin_symbol, order_type, time_ticker, positive_target, negative_target, capital, trailing, fees, leverage_capital, apply_leverage_fees_on_all_capital, leverage, long_trailing_strategy, short_trailing_strategy, time_predict, active_long_investment_strategy, active_short_investment_strategy): self.coin_symbol = coin_symbol # name of the coin self.order_type = order_type # position is short or long self.initial_time = time_ticker.current_time # the timestamp the position has been opened self.active = True # position status self.position_end_time = None # time position finished self.position_life_time = time_predict self.initial_position_life_time = time_predict self.positive_target = positive_target self.negative_target = negative_target self.current_capital = capital self.initial_capital = capital self.trailing = trailing # Boolean self.buy_price = [] self.last_price = None self.hit_profit_target = False self.hit_loss_target = False self.expired = False self.stopped = False self.liquidated = False self.trailing_activated = 0 self.long_trailing_strategy = long_trailing_strategy self.short_trailing_strategy = short_trailing_strategy self.active_long_investment_strategy = active_long_investment_strategy self.active_short_investment_strategy = active_short_investment_strategy self.fees = fees self.hours_position_open = 0 self.fees_paid = 0 self.leverage_capital = leverage_capital self.leverage = leverage self.time_ticker = time_ticker self.apply_leverage_fees_on_all_capital = apply_leverage_fees_on_all_capital # Initializes position once created self.enter_position() logger.debug( "{} position for {} in {} has been created successfully with {} capital which includes {} leverage, with the cost of {} fees" .format(self.order_type, self.coin_symbol, TimeHelper.epoch_to_date_time(self.initial_time), self.initial_capital, self.leverage_capital, self.fees_paid))
def updates_new_time_is_liquidate(self, ml_results=None): """ Updates capital and hours positions open according to new time :return: Boolean if liquidated or not """ # Updates Capital success, coins_data = \ coins_market_data_getter.get_coin_data(int(self.time_ticker.current_time), self.coin_symbol) if not success: logger.error("No open price for coin {} at time {}".format( self.coin_symbol, self.initial_time)) raise Exception("No open price for coin {} at time {}".format( self.coin_symbol, self.initial_time)) new_price = coins_data['_open'] # If Long then we profit from positive change and if short we profit from negative change if self.order_type == Consts.LONG: current_change = (new_price / self.last_price) - 1 else: current_change = ((new_price / self.last_price) - 1) * (-1) self.current_capital += (self.current_capital * current_change) # Updates last price self.last_price = new_price # Updates hours position opened self.hours_position_open += self.time_ticker.hours_tick_time_interval # Check if position got liquidated if self.current_capital <= self.leverage_capital: logger.error( "The position with coin symbol: {} got liquidated at {}". format( self.coin_symbol, TimeHelper.epoch_to_date_time( self.time_ticker.current_time))) self.liquidated = True self.close_position() return True else: return False
def fetch_coins_24h_volumeto(self, coin_symbol): """ Aggregated volumeto for the last 24h :param coin_symbol: :return: success, volumeto24h """ volumeto = 0 hours_to_calculate = 25 counter = 1 while counter <= hours_to_calculate: _time_to_fetch = self.time_ticker.current_time - (counter * 60 * 60) success, coins_market = coins_market_data_getter.get_coin_data( int(_time_to_fetch), coin_symbol) if not success: logger.error( "Skipping coin {}, there is no market data from db in {}". format(coin_symbol, TimeHelper.epoch_to_date_time(_time_to_fetch))) raise Exception volumeto += coins_market['_volumeto'] counter += 1 return True, volumeto
const=True, default=[['BTC']], help="The coin/coins for benchmark, for 2 benchmarks for BTC and ETH write \"BTC ETH\", " "for 1 benchmark of BTC and ETH (new index) write \"BTC,ETH\". default: \"BTC\".") parser.add_argument("-resultPath", type=str, nargs='?', const=True, default=os.getcwd(), help="The path to create the results folder. default the working dir.") parser.add_argument("-AnalyzeExistingResults", type=bool, nargs='?', const=True, default=None, help="take the result of the simulation that already finished. and summarizes it.") args = parser.parse_args() if __name__ == '__main__': current_time = TimeHelper.current_time_stamp() Consts.BENCHMARKS = args.benchmarkCoins Consts.set_path_to_write_result(args.resultPath) if not args.RunSimulations and not args.AnalyzeExistingResults: print("Please select at least one runStage in order to start Manager.") quit(1) if args.RunSimulations: if args.pathToCoinsPrice is None: print("Please specify the pathToCoinsPrice.") quit(1) if not os.path.isfile(args.pathToCoinsPrice): print("pathToCoinsPrice does not exist {}.".format(args.pathToCoinsPrice)) quit(1) if not args.pathToCoinsPrice.endswith('.csv.gz'): print("pathToCoinsPrice must be csv and gzip compressed.")
def start(start_running_time, coins_for_benchmark, df_simulation, positions_history, capital_history): """ function "get statistics" was build before in version one. and this function arrange the dataframe to be sent to "get statistics" correctly. acc = [{date_time,capital},..],benchmark = [{date_time,capital},..] :param simulation_result_with_benchmark: dataframe with acc capital and benchmarks capital example pd.DataFrame( # data={'date_time': ['1483228800', '1483232400', '1483236000', '1483239600'], # 'capital': [123, 213, 342, 44324], 'benchmark_BTC': [222, 222, 222, 222], :return: dataframe {'subject': ['ACC-BTC', 'ACC-ETH'], # 'alpha': [123, 213, 342, 44324], 'betta': [222, 222, 222, 222], # 'benchmark_ETH': [222, 222, 222, 222], 'rsquared': [222, 222, 222, 222], """ # simulation_result_with_benchmark = pd.DataFrame( # data={'date_time': ['1483228800', '1483232400', '1483236000', '1483239600'], # 'capital': [123, 213, 342, 44324], 'benchmark_BTC': [222, 222, 222, 222], # 'benchmark_ETH': [222, 222, 222, 222]}) # final_result1 = {'subject': ['ACC-BTC', 'ACC-ETH'], # 'alpha': [123, 213, 342, 44324], 'betta': [222, 222, 222, 222], # 'benchmark_ETH': [222, 222, 222, 222], 'rsquared': [222, 222, 222, 222], # 'standard_deviation': [222, 222, 222, 222], 'sharp_ratio': [222, 222, 222, 222]} path = os.path.join( Consts.PATH_TO_WRITE_RESULT, TimeHelper.epoch_to_date_time(start_running_time).strftime( Consts.WRITE_DATE_FORMAT), str(df_simulation.index[0])) os.makedirs(path, exist_ok=True) positions_history.to_csv(os.path.join(path, 'positions.csv'), index=False) df_simulation.index.names = ['simulation_id'] df_simulation.to_csv(os.path.join(path, 'simulation.csv')) capital_history['date_time'] = pd.to_datetime( capital_history['date_time'], format=Consts.READ_DATE_FORMAT).apply( lambda x: TimeHelper.datetime_to_epoch(x)) capital_history['capital'] = capital_history['liquid_capital'] + capital_history['shorts_capital'] + \ capital_history['long_capital'] # acc_capital = capital_history.drop(capital_history.columns.difference(['capital', 'date_time']), 1).to_dict( # 'record') acc_capital_with_banchmark_df, benchmark_column_names = add_benchmarks( capital_history, coins_for_benchmark, df_simulation['amount_of_capital'].iloc[0]) acc_capital_with_banchmark_df['date_time'] = acc_capital_with_banchmark_df[ 'date_time'].apply(lambda x: TimeHelper.epoch_to_date_time(x)) acc_capital_with_banchmark_df.set_index('date_time', inplace=True) acc_capital_with_banchmark_df.sort_index(inplace=True) acc_capital_with_banchmark_df.to_csv( os.path.join(path, 'capital_history.csv')) analytics_result_list = [] for column_benchmark in benchmark_column_names: temp_obj = get_statistics( df_simulation.index[0], 'ACC-{}'.format(column_benchmark), acc_capital_with_banchmark_df['capital'].values, acc_capital_with_banchmark_df[column_benchmark].values) analytics_result_list.append(temp_obj) analytics_result_df = pd.DataFrame(data=analytics_result_list) analytics_result_df['ACC_ROI'] = ( acc_capital_with_banchmark_df['capital'].values[-1] / acc_capital_with_banchmark_df['capital'].values[0]) - 1 last_row_capital_history = capital_history.tail(1).copy() last_row_capital_history['simulation_id'] = df_simulation.index[0] last_row_capital_history.set_index(['simulation_id'], inplace=True) analytics_result_df.set_index(['simulation_id'], inplace=True) analytics_result_df = analytics_result_df.join(df_simulation).join( last_row_capital_history) path_to_analytics = os.path.join( Consts.PATH_TO_WRITE_RESULT, TimeHelper.epoch_to_date_time(start_running_time).strftime( Consts.WRITE_DATE_FORMAT), 'analytics') os.makedirs(path_to_analytics, exist_ok=True) path_to_create_result = os.path.join( path_to_analytics, 'Simulation__{}__Analytics.csv'.format(df_simulation.index[0])) analytics_result_df.to_csv(path_to_create_result, index=True) logger.info( 'Finish creating analytics file for simulation ID: {}, you can look in: {}' .format(df_simulation.index[0], path_to_create_result))
def capital_allocation_strategy(self, coins_to_invest, available_capital): """ Recursive function which allocates funds according to simulation conditions and then allocates capital according to probability and 24h volume :param coins_to_invest: :param available_capital: :return: coins_to_invest and Adds 'capital_to_invest' column and 'fully_invested' column to each row """ coins_available_capital = 0 used_capital = 0 # Count positions which capital size is not equal to max capacity of investment total_positions_count = len( coins_to_invest[coins_to_invest[Consts.FULLY_INVESTED] == False]) if total_positions_count > 0: # Divide all available capital equally by all the positions coins_available_capital = available_capital / total_positions_count # Stopping condition: If there are no more position not fully invested or coins_available_capital is smaller then min investment if total_positions_count == 0 or coins_available_capital < self.min_investment: return coins_to_invest # Iterate all coins to invest which are not fully invested for index, coins_prediction in coins_to_invest[coins_to_invest[ Consts.FULLY_INVESTED] == False].copy().iterrows(): coin_symbol = coins_prediction['coin_symbol'] success, coin_current_volume = self.fetch_coins_24h_volumeto( coin_symbol) # exit if failed to fetch volume if not success: raise Exception if coin_current_volume == 0.0: logger.debug( "Volume is zero. Not investing in: {}, at time: {}".format( coin_symbol, TimeHelper.epoch_to_date_time( self.time_ticker.current_time))) coins_to_invest.loc[index, Consts.FULLY_INVESTED] = True continue # Volume boundary of the specific coin symbol at the specific time coins_max_capital_volume_boundary = self.max_percent_out_of_volume * coin_current_volume # If the volume boundary is smaller then available capital, then there is maximum capital in current position means = fully invested if coins_max_capital_volume_boundary < coins_available_capital: coins_to_invest.loc[index, Consts.FULLY_INVESTED] = True max_amount_to_invest_in_coin = coins_max_capital_volume_boundary else: max_amount_to_invest_in_coin = coins_available_capital # Risk indicator which decreases positions size according to probability capital_percent = self.percent_capital_according_to_probability( coins_prediction[Consts.PROB_POSITIVE_HEADER], coins_prediction[Consts.PROB_NEGATIVE_HEADER], coins_prediction['order_type']) current_capital_to_invest_in_position = capital_percent * max_amount_to_invest_in_coin # Add to capital to invest for current row coins_to_invest.loc[ index, Consts.CAPITAL_TO_INVEST] = coins_to_invest.loc[ index, Consts. CAPITAL_TO_INVEST] + current_capital_to_invest_in_position used_capital += current_capital_to_invest_in_position available_capital -= used_capital return self.capital_allocation_strategy(coins_to_invest, available_capital)
def invest(self, new_positions): """ Invests in new positions. :param new_positions: df :return: """ # Add three columns to df and initialize new_positions.loc[:, Consts.FULLY_INVESTED] = False new_positions.loc[:, Consts.CAPITAL_TO_INVEST] = 0 new_positions.loc[:, Consts.LEVERAGED_CAPITAL] = 0 # Available capital for current round available_capital = self.liquid_capital * self.max_percent_cap_investment_in_a_round if available_capital < self.min_investment: logger.debug( "The available capital for this round is smaller then the min investment. There are no new positions for time:{}" .format( TimeHelper.epoch_to_date_time( self.time_ticker.current_time))) return # Adds 'capital_to_invest' column and 'fully_invested' column to each row new_positions = self.capital_allocation_strategy( new_positions, available_capital) if len(new_positions) == 0: logger.debug("There are no new positions for time:{}".format( TimeHelper.epoch_to_date_time(self.time_ticker.current_time))) return # If simulation has leverage, fills Consts.LEVERAGE_CAPITAL with relevant leverage if self.leverage > 1: new_positions = self.add_leverage_by_conditions(new_positions) # Create new positions for index, position in new_positions.iterrows(): order_type = position['order_type'] # Create a new position pos = Position.Position( position['coin_symbol'], order_type, self.time_ticker, position['high_boundary'], position['low_boundary'], position['capital_to_invest'] + position[Consts.LEVERAGED_CAPITAL], self.trailing_strategy, self.fees, position[Consts.LEVERAGED_CAPITAL], self.apply_leverage_fees_on_all_capital, self.leverage, self.long_trailing_strategy, self.short_trailing_strategy, position['time_predict'], self.active_long_investment_strategy, self.active_short_investment_strategy) # Allocates each order to its relevant statistics if order_type == Consts.SHORT: self.active_short_positions.append(pos) self.short_capital += pos.get_current_liquid_capital() else: self.active_long_positions.append(pos) self.long_capital += pos.get_current_liquid_capital() # Update portfolio liquid capital and leverage capital self.liquid_capital -= pos.get_current_liquid_capital() self.leverage_capital += pos.leverage_capital logger.debug("Finished investment cycle for time {}".format( TimeHelper.epoch_to_date_time(self.time_ticker.current_time))) logger.debug( "liquid capital: {}, leverage capital: {}, long capital: {}, short capital: {}" .format(self.liquid_capital, self.leverage_capital, self.long_capital, self.short_capital))
def enter_new_positions(self, current_ml_results): """" Iterates MLResults and handles each one :param current_ml_results: df :return: None """ # If we simulation does not accept short and long positon on the same coin at the same time if not self.accept_short_and_long_same_tick_and_symbol: current_ml_results = current_ml_results.drop_duplicates( 'coin_symbol') if not self.longs: current_ml_results = current_ml_results[ current_ml_results['order_type'] != Consts.LONG] if not self.shorts: current_ml_results = current_ml_results[ current_ml_results['order_type'] != Consts.SHORT] index_to_delete = [] # Iterate ml results and add to new_positions accordingly for index, row in current_ml_results.copy().iterrows(): # Skip prediction if simulation is limited to invest in specific coins. Notice, if the list is ALL then the simulation has no limitations. coin_symbol = row['coin_symbol'] success, coin_current_volume = self.fetch_coins_24h_volumeto( coin_symbol) # exit if failed to fetch volume if not success: raise Exception # Volume boundary of the specific coin symbol at the specific time coins_max_capital_volume_boundary = self.max_percent_out_of_volume * coin_current_volume # Not enough volume to invest if coins_max_capital_volume_boundary < self.min_investment: logger.warning( "Not enough volume to invest in {} at {}".format( coin_symbol, TimeHelper.epoch_to_date_time( self.time_ticker.current_time))) index_to_delete.append(index) continue prob_positive = row[Consts.PROB_POSITIVE_HEADER] prob_negative = row[Consts.PROB_NEGATIVE_HEADER] # Check if we should invest long according to long investment strategy then remain in df. If not, deletes the prediction from current_ml_results if row['order_type'] == Consts.LONG and not self.is_long_according_to_invest_strategy( prob_positive, prob_negative): index_to_delete.append(index) # Check if we should invest short according to short investment strategy then remain. If not, deletes the prediction from current_ml_results elif row[ 'order_type'] == Consts.SHORT and not self.is_short_according_to_invest_strategy( prob_positive, prob_negative): index_to_delete.append(index) current_ml_results.drop(index_to_delete, inplace=True) # There are no new positions if len(current_ml_results) == 0: logger.debug( "There are no new positions according to current strategy, at time: {}" .format( TimeHelper.epoch_to_date_time( self.time_ticker.current_time))) else: self.invest(current_ml_results)
def run(self): """ Runs simulation with the following order: 0. Updates all run according to new time. 1. Apply hourly fees if exist 2. Check if positions reached the high or low target and close/trail them accordingly 3. Check if positions expired and close accordingly 4. Apply active positions strategy on all open positions and close accordingly 5. Check if there are new MLResults and invest accordingly At the end of the run, creates 3 files for each simulation and 1 file which aggregates all together: ( path = /opt/simulation a. capital_history.csv - the status of the portfolio every tick time. b. positions.csv - all the positions for the simulation. c. simulation.csv - documentation of all params of the simulation. :return: """ logger.info('Starting simulation ID: {}'.format( self.df_simulation.index[0])) # Start time is according to oldest ML result start_timestamp, end_timestamp = self.simulation_time_interval() # Create a time ticker for simulation self.time_ticker = TimeTicker.TimeTicker(start_timestamp, self.tick_time_hours) # Initial Portfolio active_portfolio = Portfolio.Portfolio(self.df_simulation, self.fees, self.time_ticker) # Loop according to tick time, while there are still positions open or while there are still MLResults left to iterate while self.time_ticker.current_time < end_timestamp: # Update portfolio according to new time for next round active_portfolio.updater(Consts.UPDATES_NEW_TIME_IS_LIQUIDATE) # If There are leveraged positions, decrease fees active_portfolio.apply_time_leverage_fees() # If active positions, update them if active_portfolio.is_there_open_positions(): active_portfolio.updater(Consts.REACH_TARGET_UPDATE) active_portfolio.updater(Consts.IS_EXPIRED) # Fetch ml results for current_ml_results = self.ml_results_df.loc[ self.ml_results_df['prediction_time'] == self.time_ticker.current_time] if len(current_ml_results) == 0: self.hours_with_no_predictions += 1 # Filter according to coin_to_invest if self.coins_to_invest[0] != Consts.ALL: current_ml_results = current_ml_results.loc[ self.ml_results_df['coin_symbol'].isin( self.coins_to_invest)] # If there is MLResult in current time if len(current_ml_results) > 0: active_portfolio.updater(Consts.IS_ACTIVE_INVEST_STRATEGY, ml_results=current_ml_results) active_portfolio.enter_new_positions(current_ml_results) # Update capital history self.capital_history = self.capital_history.append( pd.DataFrame( data={ 'date_time': [ TimeHelper.epoch_to_date_time( self.time_ticker.current_time) ], 'liquid_capital': [active_portfolio.liquid_capital], 'shorts_capital': [active_portfolio.short_capital], 'long_capital': [active_portfolio.long_capital], 'leverage_capital': [active_portfolio.leverage_capital], 'fees_paid': [active_portfolio.fees_paid], 'miss_positions': [active_portfolio.miss_positions], 'hit_positions': [active_portfolio.hit_positions], 'stopped_positions': [active_portfolio.stopped_positions_counter], 'expired_positions': [active_portfolio.expired_positions_counter], 'hit_trail_positions': [active_portfolio.hit_trail_positions], 'hours_with_no_predictions': [self.hours_with_no_predictions], 'total_number_of_active_positions': [ len(active_portfolio.active_long_positions + active_portfolio.active_short_positions) ] }), ignore_index=True, sort=True) # Advance current_timestamp self.time_ticker.advance_one_step() # Closing all open positions if active_portfolio.is_there_open_positions(): logger.info("There are open positions, closing all") active_portfolio.updater(Consts.FORCE_CLOSE_ALL_POSITIONS) logger.info('Creating analytics file for simulation ID: {}'.format( self.df_simulation.index[0])) positions_history = self.fetch_positions_history_df(active_portfolio) AnalyticsFactory.start(self.start_running_time, self.coins_for_benchmark, self.df_simulation, positions_history, self.capital_history) logger.info('end of simulation ID: {}'.format( self.df_simulation.index[0]))
def fetch_positions_history_df(self, active_portfolio): """ creates a df of all the positions in the simulation :param active_portfolio: :return: df of positions histroy """ positions_history = pd.DataFrame( data={ 'initial_time': [], 'end_time': [], 'coin_symbol': [], 'order_type': [], 'life_time_in_hours': [], 'positive_target': [], 'negative_target': [], 'initial_capital_include_leverage': [], 'final_capital': [], 'buy_price': [], 'last_price': [], 'hit_profit_target': [], 'hit_loss_target': [], 'expired': [], 'stopped': [], 'liquidated': [], 'trailing_activated': [], 'hours_position_open': [], 'fees_paid': [], 'leverage_capital': [], 'leverage': [], 'ROI': [] }) for pos in active_portfolio.closed_long_positions + active_portfolio.closed_short_positions: positions_history = positions_history.append(pd.DataFrame( data={ 'initial_time': [TimeHelper.epoch_to_date_time(pos.initial_time)], 'end_time': [TimeHelper.epoch_to_date_time(pos.position_end_time)], 'coin_symbol': [pos.coin_symbol], 'order_type': [pos.order_type], 'life_time_in_hours': [pos.initial_position_life_time], 'positive_target': [pos.positive_target], 'negative_target': [pos.negative_target], 'initial_capital_include_leverage': [pos.initial_capital], 'final_capital': [pos.current_capital], 'buy_price': [pos.buy_price], 'last_price': [pos.last_price], 'hit_profit_target': [pos.hit_profit_target], 'hit_loss_target': [pos.hit_loss_target], 'expired': [pos.expired], 'stopped': [pos.stopped], 'liquidated': [pos.liquidated], 'trailing_activated': [pos.trailing_activated], 'hours_position_open': [pos.hours_position_open], 'fees_paid': [pos.fees_paid], 'leverage_capital': [pos.leverage_capital], 'leverage': [pos.leverage], 'ROI': [pos.get_roi_status()] }), ignore_index=True, sort=True) return positions_history
def reach_target_update(self, ml_results=None): """ Checks if position reached target, and updates accordingly :return: Boolean if reach positive or negative target """ success, coins_data = coins_market_data_getter.get_coin_data( int(self.time_ticker.current_time), self.coin_symbol) if not success: raise Exception diff_high = ((coins_data['_high'] / self.buy_price[-1]) - 1) diff_low = ((coins_data['_low'] / self.buy_price[-1]) - 1) if coins_data['_high'] / coins_data['_low'] > 2: logger.error( "In time {} there was 2 times jump between high and low price for coin {}" .format( TimeHelper.epoch_to_date_time( self.time_ticker.current_time), self.coin_symbol)) self.hit_loss_target += 1 self.close_position(profit=False) return True if diff_high >= self.positive_target and diff_low <= self.negative_target: logger.error( "In time {} the price reached the high and low boundary for coin {}" .format( TimeHelper.epoch_to_date_time( self.time_ticker.current_time), self.coin_symbol)) self.hit_loss_target += 1 self.close_position(profit=False) return True # If hits target for short or long if (diff_low <= self.negative_target and self.order_type == Consts.SHORT) or (diff_high >= self.positive_target and self.order_type == Consts.LONG): # If trailing is on, apply if self.trailing: if (self.order_type == Consts.SHORT and len(self.short_trailing_strategy) != 0) or ( self.order_type == Consts.LONG and len(self.long_trailing_strategy) != 0): self.handle_trailing() return False self.close_position(profit=True) self.hit_profit_target = True return True # if miss target for short or long elif (diff_high >= self.positive_target and self.order_type == Consts.SHORT) or (diff_low <= self.negative_target and self.order_type == Consts.LONG): self.close_position(profit=False) self.hit_loss_target = True return True # Did not reach either targets else: return False