def screening(self): """ Method to start the screening once, should be executed in a THREAD. :return: nothing, results are saved in the model. """ try: if not self._check_if_strategy_can_run(): return self.model.is_background_thread_running.set(True) selection_values = self.model.selected_strategies_list.get() logger.info("Screening started...") self.model.result_stock_data_container_list.clear() analysis_params = self.model.analysis_parameters.get() results = run_analysis(selection_values, analysis_params['Strategies'], analysis_params['OtherParameters']) self.model.result_stock_data_container_list.extend(results) except Exception as e: logger.error("Exception while screening: " + str(e) + "\n" + str(traceback.format_exc())) self.model.is_background_thread_running.set(False)
def _log_order(self, date, order, text): logger.info('--------- NOTIFY ORDER:') logger.info((' {} Order ' + text).format(order.info['name'])) logger.info( ' {}, Status {}: Ref: {}, Size: {}, Price: {}, Position: {}'. format( date, order.status, order.ref, order.size, 'NA' if not order.price else round(order.price, 5), 'NA' if not order.price else round(order.price * order.size, 5)))
def run_test(self, data_file_list, strategy_to_test, backtesting_parameters, analysis_parameters, risk_models, analyzers=[], **kwargs): """ Run method for the wrapper which wrap the ASTA-Framework structure to backtrader structure. :param analysis_parameters: dict with analysis parameters for strategy :param strategy_to_test: name of the strategy as string :param data_file_list: a list with files to read as string :param backtesting_parameters: Dict with parameters for testing, the Key "strategy_to_test" contains the strategy class to test. :param analyzers: List with class of btanalyzer, ex.: [btanalyzer.TradeAnalyzer] :param risk_models: other testing relevant parameters as dict :return: backtesting_result_instance final instance, backtrader test result """ cerebro = bt.Cerebro() # add the backtrader strategy wrapper, real strategy will be build there with the backtesting_parameters dict # backtesting_result_instance.addstrategy(BacktraderStrategyWrapper, all_parameter, news_data) cerebro.addstrategy(BacktraderStrategyWrapper, strategy_to_test=strategy_to_test, backtesting_parameters=backtesting_parameters, analysis_parameters=analysis_parameters, risk_model=risk_models, status_update=False, **kwargs) # load the data from given file list and add it to backtrader instance if isinstance(data_file_list, list): for file_path in data_file_list: # TODO warum string? if isinstance(file_path, str): stock_name = basename(file_path) data = btfeeds.GenericCSVData( name=stock_name, dataname=file_path, dtformat=GlobalVariables.get_stock_data_dtformat(), nullvalue=0.0, datetime=0, open=1, high=2, low=3, close=4, volume=5, openinterest=-1) cerebro.adddata(data, name=data._name) else: # compatibility for backtrader pandas data feed cerebro.adddata(file_path, name=file_path._name) else: raise NotImplementedError("Data must be a list") # Set our desired cash start cerebro.broker.setcash(backtesting_parameters['initial_cash']) for analyzer in analyzers: cerebro.addanalyzer(analyzer) # Set the commission # https://www.backtrader.com/docu/commission-schemes/commission-schemes.html # 0.5% of the operation value --> 2500 € --> 12.5 per Buy/Sell cerebro.broker.setcommission( commission=backtesting_parameters['trade_commission_percent']) # Print out the starting conditions logger.info('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) logger.info('--------------------') backtest_result = cerebro.run() analyzers = backtest_result[0].analyzers for analyzer in analyzers: test = analyzer.get_analysis() logger.info(str(analyzer) + ": " + str(test)) # Print out the final result logger.info('Final Portfolio Value: %.2f' % cerebro.broker.getvalue()) return cerebro, backtest_result
def identify_stock_name_and_stock_ticker_and_target_price_from_news_nltk_german_classifier( self, single_news_to_analyze): """ Identifies a stock name within a news and returns the name and ticker :param single_news_to_analyze: news text itself :return: {'name': name_to_find, 'ticker': self.tickers[idx]} or " " if no name found """ if single_news_to_analyze is None: raise NotImplementedError preprocessed_news = self.optimize_text_for_german_tagger( single_news_to_analyze) # TODO: http://dsspace.wzb.eu/pyug/text_proc_feature_extraction/ tokens = nltk.word_tokenize(preprocessed_news, language="german") tokens_removed_words = [ t for t in tokens if t.lower() not in self.stopwords ] # http: // dsspace.wzb.eu / pyug / text_proc_feature_extraction / # tmp_tokens = {} # for doc_label, doc_tok in tokens_removed_words: # tmp_tokens[doc_label] = [] # for t in doc_tok: # t_parts = self.expand_compound_token(t) # tmp_tokens[doc_label].extend(t_parts) tags = self.german_tagger.tag(tokens_removed_words) noun_tags = "" enable_tags = False for i in range(len(tags)): # TODO gscheider: erst nach dem ersten verb lesen if tags[i][1].startswith("V"): enable_tags = True if enable_tags: if tags[i][1].startswith("N"): if i > 1 and tags[i - 1][1].startswith("ADJ"): noun_tags = (tags[i - 1][0] + " " + tags[i][0]) break if tags[i][1].startswith("NE") or tags[i][1].startswith( "NN"): noun_tags = (tags[i][0]) break if noun_tags is not None and len(noun_tags) > 0: name_return = "" target_price_return = 0 ticker_return = "" stock_exchange_return = "" stock_to_check = noun_tags # [0] --> first tag in list price_tuple = [i for i in tags if i[1].startswith("CARD")] try: name_to_find = self.lookup_stock_abr_in_all_names( stock_to_check) idx = self._names.index(name_to_find) name_return = self._names[idx] ticker_return = self.tickers[idx] stock_exchange_return = self.stock_exchanges[idx] except Exception as e: # look up symbol in web instead of list try: name_return, ticker_return = get_symbol_and_real_name_from_abbrev_name_from_topforeignstocks( stock_to_check) except Exception as e: (", No STOCK found for news: " + str(single_news_to_analyze)) return None if len(price_tuple) > 0: price = price_tuple[len(price_tuple) - 1][0] # TODO 1: comment price = price.replace(",", ".") # replace german comma if CommonUtils.is_float(price): # price_tuple: [0] --> number, [1]--> CD target_price_return = float(price) # news_dec = NewsDataContainerDecorator(StockDataContainer(name_return, ticker_return, stock_exchange_return), # target_price_return, "", single_news_to_analyze, 0) ret = StockNameTickerExchangeAndTargetPrize( name_return, ticker_return, stock_exchange_return, target_price_return) return ret logger.info("No STOCK found for news: " + str(single_news_to_analyze)) return None
def buy_recommendations(broker, stocks, max_num_of_different_stocks_to_buy): """ Automatically buy the recommendations from result list :return: - """ from Utils.Logger_Instance import logger broker.connect() if len(stocks) <= 0: return try: # sort stocks by rank sorted_stock_container_list = sorted(stocks, key=lambda x: x.get_rank(), reverse=True) for i in range(len(sorted_stock_container_list)): if max_num_of_different_stocks_to_buy <= 0: # do not buy more stocks logger.info("Max number of stocks to buy reached.") return # check if there are enough data to create stop buy and stop loss limit orders if not are_order_information_available("BUY", sorted_stock_container_list[i]) or \ not are_order_information_available("SELL", sorted_stock_container_list[i]): logger.info("Not enough information for order available: " + str(sorted_stock_container_list[i])) break # trade only, if not already traded today orders = broker.read_orders() date_time_str = None # find the last entry for curr_order_num in range(len(orders)): if orders['stock_ticker'][curr_order_num].startswith( sorted_stock_container_list[i].stock_ticker()): date_time_str = (orders['datetime'][curr_order_num]) if date_time_str is not None: next_day_or_later = is_next_day_or_later( str(datetime.now()), "%Y-%m-%d %H:%M:%S.%f", date_time_str, "%Y-%m-%d %H:%M:%S.%f") # do not trade same recommendation again on one day if not next_day_or_later: logger.info( "No current recommendations to buy available for " + str(sorted_stock_container_list[i])) break # get stock quantity, only even number qty = int(sorted_stock_container_list[i].get_position_size()) # rank < 0 means sell recommendation, > 0 a buy if sorted_stock_container_list[i].get_rank() > 0: # stop buy limit order broker.execute_order( sorted_stock_container_list[i].stock_ticker(), 'LMT', 'BUY', qty, sorted_stock_container_list[i].get_stop_buy()) # stop loss limit order broker.execute_order( sorted_stock_container_list[i].stock_ticker(), 'LMT', 'SELL', qty, sorted_stock_container_list[i].get_stop_loss()) max_num_of_different_stocks_to_buy = max_num_of_different_stocks_to_buy - 1 # get the response # TODO without sleep sleep(0.5) error_message_list = broker.get_and_clear_error_message_list() if len(error_message_list) > 0: for error_msg in error_message_list: logger.error( "Unexpected response from broker while autotrading: " + str(error_msg)) # TODO what to do in case of an error? except Exception as e: err_msg = "Unexpected Exception while autotrading: " + str( e) + "\n" + str(traceback.format_exc()) logger.error(err_msg) print(err_msg) broker.disconnect()
def log(self, txt, dt=None): """ Logging function fot this strategy""" dt = dt or self.datas[0].datetime.date(0) logger.info('%s, %s' % (dt.isoformat(), txt))
def reply_handler(self, msg): """Handles of server replies""" print("Server Response: %s, %s" % (msg.typeName, msg)) logger.info("Server Response: %s, %s" % (msg.typeName, msg))
def load_backtesting_stocks_from_file(self, multi_file_path): self.model.available_backtesting_stocks_list.set(multi_file_path) logger.info("Backtesting stocks read")
def backtesting(self): """ Method to start the backtesting once, should be executed in a THREAD. :return: nothing, results are saved in the model. """ try: strategy_selections = self.model.selected_strategies_list.get() selected_backtesting_analyzers_str = self.model.selected_backtesting_analyzers_list.get( ) selected_backtesting_stocks = self.model.selected_backtesting_stocks_list.get( ) if strategy_selections == "" or not len(strategy_selections) is 1: messagebox.showerror( "Selection Error", "Please select exactly ONE strategie to run in backtesting!" ) return if selected_backtesting_stocks == "" or len( selected_backtesting_stocks) <= 0: messagebox.showerror( "Selection Error", "Please select stocks to run in backtesting first!") return if selected_backtesting_analyzers_str == "" or len( selected_backtesting_analyzers_str) <= 0: continue_backtesting = messagebox.askyesno( "Analyzer Selection", "No additional analyzer ist selected! Do you want to start backtesting anyway?" ) if not continue_backtesting: return data_backtesting_analyzers = [] for ana in self.model.available_backtesting_analyzers_list.get(): for selected_backtesting_analyzer_str in selected_backtesting_analyzers_str: if selected_backtesting_analyzer_str in ana.__name__: data_backtesting_analyzers.append(ana) available_backtesting_stocks_data = self.model.available_backtesting_stocks_list.get( ) selected_backtesting_stocks_data = [] for selected_backtesting_stock_str in selected_backtesting_stocks: for available_backtesting_stock_data in available_backtesting_stocks_data: if selected_backtesting_stock_str in available_backtesting_stock_data: selected_backtesting_stocks_data.append( available_backtesting_stock_data) break req_params = StrategyFactory.get_required_parameters_with_default_parameters( ) at_objects = w.scrollable_frame_parameters.form.at_objects content_others = w.scrollable_frame_parameters.form.get_parameters( at_objects) if not self.accept_parameters_from_text(content_others, req_params): messagebox.showerror("Parameter file is not valid!", "Please choose a valid parameters file!") return self.model.is_background_thread_running.set(True) logger.info("") logger.info( "*********************************************************************************************" ) logger.info( "******************** Backtesting started... *************************************************" ) bf = BacktestingFactory() backtesting_parameters = self.model.analysis_parameters.get( )["BacktestingParameters"] bt_framework_name = backtesting_parameters['BacktestingFramework'] tbt = bf.prepare(bt_framework_name) # get the selection of the first strategy analysis_params = self.model.analysis_parameters.get( )['Strategies'][strategy_selections[0]] # get the risk model value without key risk_models = self.model.analysis_parameters.get( )['OtherParameters']['RiskModels'] backtesting_result_instance, backtest_result = tbt.run_test( selected_backtesting_stocks_data, strategy_selections[0], backtesting_parameters, analysis_params, risk_models, data_backtesting_analyzers) insert_text_into_gui(self.view.Scrolledtext_analyzer_results, "", delete=True, start=1.0) # get items of analyzers and append it to the name analyzers = backtest_result[0].analyzers for analyzer in analyzers: ana_res = analyzer.get_analysis() items = list(ana_res.items()) text_list = [] for i in items: text = ': '.join(str(e) for e in i) text_list.append(text) final_text = '\n'.join(str(e) for e in text_list) insert_text_into_gui( self.view.Scrolledtext_analyzer_results, str(analyzer.__class__.__name__) + ":\n" + str(final_text) + "\n\n") portvalue = round(backtesting_result_instance.broker.getvalue(), 2) pnl = round(portvalue - backtesting_parameters['initial_cash'], 2) # Print out the final result insert_text_into_gui( self.view.Scrolledtext_analyzer_results, 'Final Portfolio Value: ${}'.format(portvalue) + "\n") insert_text_into_gui( self.view.Scrolledtext_analyzer_results, 'Profit/Loss (rounded 2 places): ${}'.format(pnl)) self.model.backtesting_result_instance.set( backtesting_result_instance) except Exception as e: logger.error("Exception while backtesting: " + str(e) + "\n" + str(traceback.format_exc())) self.model.is_background_thread_running.set(False)