Пример #1
0
    def _treeview_sort_column(tv, col, reverse):
        """
        https://stackoverflow.com/questions/1966929/tk-treeview-column-sort
        :param tv: tree view to sort
        :param col: column index to sort
        :param reverse:  True: reverse sort
        :return: -
        """
        try:
            l = [(tv.set(k, col), k) for k in tv.get_children('')]
            try:
                l.sort(key=lambda t: float(t[0]), reverse=reverse)
            except ValueError as e:
                l.sort(reverse=reverse)

            for index, (val, k) in enumerate(l):
                tv.move(k, '', index)

            tv.heading(col,
                       command=lambda: GuiUtils._treeview_sort_column(
                           tv, col, not reverse))

        except Exception as e:
            logger.error("Exception Could not sort the given treeview: " +
                         str(e) + "\n" + str(traceback.format_exc()))
    def _method_to_execute(self, stock_data_container):
        """
        Method to execute implemented for multi threading, executed for every sublist
        :param stock_data_container_sub_list: sub list of the whole stock data container (already split)
        :return: nothing, sublist in changed
        """
        if stock_data_container.stock_ticker() != "":
            if stock_data_container not in self.stock_data_container_list \
                    or len(stock_data_container.historical_stock_data()) <= 0 \
                    or self.reload_stockdata:
                stock52_w = self._get_ticker_data_with_webreader(
                    stock_data_container.stock_ticker(),
                    stock_data_container.stock_exchange(),
                    self._parameter_dict['data_source'],
                    self._parameter_dict['weeks_delta'])

                stock_data_container.set_historical_stock_data(stock52_w)
                try:
                    if stock52_w is not None and len(stock52_w) > 0:
                        curr_prize = stock52_w[
                            GlobalVariables.get_stock_data_labels_dict()
                            ["Close"]][len(stock52_w) - 1]
                        stock_data_container.set_stock_current_prize(
                            curr_prize)

                except Exception as e:
                    logger.error("Could not set curr_prize of stock " +
                                 stock_data_container.get_stock_name() + " " +
                                 str(e) + "\n" + str(traceback.format_exc()))

                self.update_status("HistoricalDataReader:")
Пример #3
0
    def execute_order(self, stock_ticker, order_type='LMT', action='SELL', quantity=1, limit_price=1,
                      security_type='STK', exchange='SMART', currency='USD'):
        """
        Create a contract and a order, read order id, execute the order, save the order to file.
        :param stock_ticker: stock ticker
        :param order_type: oder type , ex: LMT for limit orders
        :param action: BUY / SELL
        :param quantity: number of stocks to order
        :param limit_price: limit price to buy or sell
        :param security_type: STK for stocks
        :param exchange: echange to trade, SMART
        :param currency: USD / EUR
        :return:
        """

        # Create a contract  via SMART order routing
        current_contract = self._create_contract(stock_ticker, security_type, exchange, exchange, currency)
        current_order = self._create_order(order_type, quantity, action, limit_price)

        # Use the connection to the send the order to IB
        order_id = self._read_current_order_id()
        try:
            self.tws_conn.placeOrder(int(order_id), current_contract, current_order)
            text_line = str(datetime.now()) + "," + str(stock_ticker) + "," + str(order_id) + "," + str(
                order_type) + "," + str(action) + "," + str(quantity) + "," + str(limit_price) + "," + str(
                security_type) + "," + str(exchange) + "," + str(currency)
            logger.info("***************************************")
            logger.info("Order was placed: " + text_line)
            logger.info("***************************************")
            print(text_line)
        except Exception as e:
            logger.error("Unexpected Exception : " + str(e) + "\n" + str(traceback.format_exc()))

        self._save_current_order(order_id, stock_ticker, order_type, action,
                                 quantity, limit_price, security_type, exchange, currency)
    def get_required_parameters_with_default_parameters():
        """
        Return a dict with required strategy parameters and default parameter values.
        :return: dict with required values and default parameters
        """
        all_strategy_parameters_dict = {}
        strat_factory = StrategyFactory()
        strategies_dict = strat_factory.get_implemented_classes()

        for strat_class_key in list(strategies_dict.keys()):
            try:
                def_params = strategies_dict[
                    strat_class_key].get_required_parameters_with_default_parameters(
                    )
                all_strategy_parameters_dict.update(def_params)
            except NotImplementedError as nie:
                logger.error("Exception for strategy class " +
                             strat_class_key + ": " + str(nie) + "\n" +
                             str(traceback.format_exc()))

        all_strategy_parameters_dict = {
            'Strategies': all_strategy_parameters_dict
        }
        other_params = GlobalVariables.get_other_parameters_with_default_parameters(
        )
        all_strategy_parameters_dict.update({"OtherParameters": other_params})

        backtesting_params = GlobalVariables.get_backtesting_parameters_with_default_parameters(
        )
        all_strategy_parameters_dict.update(backtesting_params)

        return all_strategy_parameters_dict
    def result_stock_data_container_list_changed(self):
        """
        Update the columns and data of the view, of stock data container list changed.
        Additionally, it adds the not already available columns to the MvcModel and fill not available columns with dummy.
        :return: -
        """
        tree = w.Scrolledtreeview1
        tree.delete(*tree.get_children())
        stock_data_container_list = self.model.result_stock_data_container_list.get(
        )

        # sort the list by rank
        newlist = sorted(stock_data_container_list,
                         key=lambda x: x.get_rank(),
                         reverse=True)

        for result_container in newlist:
            try:
                is_updated = self.model.update_column_list(
                    result_container.get_names_and_values().keys())

                if is_updated:
                    init_result_table(self.view.Scrolledtreeview1,
                                      self.model.get_column_list())

                GuiUtils.insert_into_treeview(
                    self.view.Scrolledtreeview1, self.model.get_column_list(),
                    result_container.get_names_and_values(), "Stock")

                # append all COLUMNS to file --> new layout leads to new line with header
                FileUtils.append_text_list_to_file(
                    self.model.get_column_list(),
                    GlobalVariables.get_data_files_path() +
                    "ScreeningResults.csv", True, ",")

                # append VALUES to file
                values = result_container.get_names_and_values().values()
                text = ','.join(str(e) for e in values)
                FileUtils.append_textline_to_file(
                    text,
                    GlobalVariables.get_data_files_path() +
                    "ScreeningResults.csv", True)

            except Exception as e:
                logger.error("Exception: " + str(e) + "\n" +
                             str(traceback.format_exc()))
                continue

        # add a sort functionality for each column, when click on header
        GuiUtils.advanced_sorting(self.view.Scrolledtreeview1,
                                  self.model.get_column_list(), True)

        # add a color for the entries in tree view
        for color in GlobalVariables.get_row_colors().keys():
            tree.tag_configure(
                GlobalVariables.get_row_colors()[color],
                background=GlobalVariables.get_row_colors()[color])
Пример #6
0
def signal_is_volume_raising_within_check_days(stock, check_days, min_cnt):
    """
    Checks, if the volume is rising within the check days, with at least minimum value.

    Args:
        stock: stock data
        check_days: number of days to check
        min_cnt: min raising days within check days

    Returns:
        True, if volume is raising

    Raises:
        NotImplementedError: if parameters are None

    """

    if stock is None or check_days is None or min_cnt is None:
        raise NotImplementedError

    data_len = len(stock)

    if data_len < 5: #must have enough data
        return None #TODO
        #TOD raise IndexError

    raise_cnt = 0
    i = check_days
    save_val = False
    while i > 0:
        try:
            vol_cur = stock.iloc[data_len - i][GlobalVariables.get_stock_data_labels_dict()['Volume']]
            if not save_val:
                if i is data_len:
                    vol_last = 0
                else:
                    vol_last = stock.iloc[data_len - i - 1][GlobalVariables.get_stock_data_labels_dict()['Volume']]
            if vol_cur > vol_last:
                raise_cnt += 1
                save_val = False
            else:
                save_val = True

        except Exception as e:
            logger.error("Unexpected Exception : " + str(e) + "\n" + str(traceback.format_exc()))

        i -= 1

    if raise_cnt < min_cnt:
        return None

    return True
Пример #7
0
    def evaluate_list_box_selection(evt, log_text, own_widget=None):
        widget = evt.widget

        if own_widget is None or own_widget is widget:
            try:
                selected_text_list = [
                    widget.get(i) for i in widget.curselection()
                ]
            except Exception as e:
                logger.error("Selection failed:" + str(e) + "\n" +
                             str(traceback.format_exc()))
                selected_text_list = []

            logger.info(log_text + str(selected_text_list))
            return selected_text_list
    def load_analysis_parameters_from_file(self, file_path,
                                           required_parameters):
        """
        Loads the parameters into the GUI from a given filepath and file.
        :param required_parameters: a dict with all required parameters, must be all in file
        :param file_path: file path and name as string to load file
        :return: nothing
        """
        try:
            items = None
            if os.path.isfile(file_path):
                with open(file_path, "rb") as f:
                    items = pickle.load(f)

                self.current_parameterfile = file_path
                if self.accept_parameters_from_text(items,
                                                    required_parameters):
                    override_params = False
                else:
                    override_params = messagebox.askyesno(
                        "Parameter file is not valid!",
                        "Do you want to CREATE a new file with default parameters?"
                    )
            else:
                override_params = True

            if override_params:
                self.model.analysis_parameters.clear()
                self.model.analysis_parameters.update(required_parameters)
                self.model.available_strategies_list.clear()
                for item in required_parameters['Strategies']:
                    self.model.available_strategies_list.append(item)

                messagebox.showinfo("Parameterfile created",
                                    "New parameters created!")

        except Exception as e:
            messagebox.showerror(
                "Parameter file is not valid!",
                "Please choose a valid parameters file:" + str(e) + "\n" +
                str(traceback.format_exc()))
            logger.error(
                "Exception while loading other parameter from file: " +
                str(e) + "\n" + str(traceback.format_exc()))
            return
Пример #9
0
    def read_tickers_and_data_from_file(stock_data_container_file):
        """
        Read the pickle file with stock data container for tickers and data.
        :param stock_data_container_file: pickle data file
        :return: container list
        """
        stock_data_container_list = []

        if ".pickle" in stock_data_container_file:
            if os.path.exists(stock_data_container_file):
                logger.info("Start reading tickers from file...")

                with open(stock_data_container_file, "rb") as f:
                    stock_data_container_list += pickle.load(f)
        else:
            logger.error("Please select a *.pickle file for the stock_data_container_file!")

        return stock_data_container_list
Пример #10
0
    def treeview_add_header_sort_column(tv, col, reverse):
        """
        Adds a sort function to header
        https://stackoverflow.com/questions/1966929/tk-treeview-column-sort
        :param tv: tree view to sort
        :param col: column index to sort
        :param reverse:  True: reverse sort
        :return: -
        """
        try:
            l = [(tv.set(k, col), k) for k in tv.get_children('')]
            tv.heading(col,
                       command=lambda: GuiUtils._treeview_sort_column(
                           tv, col, not reverse))

        except Exception as e:
            logger.error("Exception Could not sort the given treeview: " +
                         str(e) + "\n" + str(traceback.format_exc()))
Пример #11
0
    def _method_to_execute(self, stock_data_container):
        """
        This method is abstract, implement the real list execution instead.
        :param argument: A single element of the list to execute
        :return: should return the result or add it to the list and return nothing
        """
        try:
            if len(stock_data_container.historical_stock_data()) > 0:
                self.add_signals(stock_data_container,
                                 self.analysis_parameters)
                result = evaluate_signals(self.signal_list)

                if result is not None:
                    stock_data_container.update_used_strategy_and_recommendation(
                        self.__class__.__name__, "BUY")
                    self.result_list.append(stock_data_container)
        except Exception as e:
            logger.error("Unexpected Exception : " + str(e) + "\n" +
                         str(traceback.format_exc()))
Пример #12
0
def init(top, gui, *args, **kwargs):
    logging.basicConfig(level=logging.INFO)
    global w, top_level, root, app
    w = gui
    top_level = top
    root = top
    app = MvcController(root, w)

    # ########################
    try:
        # load the last saved file path
        req_params = StrategyFactory.get_required_parameters_with_default_parameters(
        )
        last_used_parameter_file_path = GlobalVariables.get_last_used_parameter_file(
        )

        config = configparser.ConfigParser()
        config.read(last_used_parameter_file_path)

        try:
            param_file = (config["Parameters"]['parameterfile'])

            multi_file_path_str = config["Parameters"][
                'backteststockselection']
            if "," in multi_file_path_str:
                multi_file_path = multi_file_path_str.split(',')
            else:
                multi_file_path = [multi_file_path_str]
            # multi_file_path = ast.literal_eval(multi_file_path_str)
            app.load_backtesting_stocks_from_file(multi_file_path)

        except Exception as e:
            param_file = ""

        app.load_analysis_parameters_from_file(param_file, req_params)

    except Exception as e:
        logger.error("Exception while opening last saved file path: " +
                     str(e) + "\n" + str(traceback.format_exc()))

    # ########################
    return app
Пример #13
0
def insert_text_into_gui(element, text, delete=False, start=1.0, end=END):
    """
    optionally deletes the given element and optionally insert text into given element.
    :param element: element to insert into (ex: Scrolledtext)
    :param text: text to insert
    :param delete: true, if delete content first
    :param start: start case, ex.: 1.0 or 0
    :param end: END tag
    :return: nothing
    """
    try:
        if delete:
            element.delete(start, end)
        if text is not None and len(text) > 0:
            element.insert(end, text)

        element.see("end")
    except Exception as e:
        logger.error("Can not insert text into gui: " + str(e) + "\n" +
                     str(traceback.format_exc()))
Пример #14
0
    def on_double_click_Scrolledtreeview1(self, event):
        """
        On double click event for scrolledtreeview1,
        opens a finance web page
        :param event:
        :return:
        """
        try:
            cur_selection = self.view.Scrolledtreeview1.selection()[0]
            cur_stock = self.view.Scrolledtreeview1.item(cur_selection)

            # TODO je nachj container unterschiedlich 2 --> name is first
            # TODO einstellen der aufruf seite
            stock_name = cur_stock['values'][2]
            url_to_open = "http://www.finanzen.at/suchergebnisse?_type=Aktien&_search="
            wb.open_new_tab(url_to_open + stock_name)
        except IndexError as e:
            pass  # nothing to do for index error (may clicked at header)
        except Exception as e:
            logger.error("Exception while opening result stock: " + str(e) +
                         "\n" + str(traceback.format_exc()))
Пример #15
0
    def start_screening_repetitive(self):
        """
        Start the screening repetitive, due to interval, if screening is not already running.
        :return: nothing
        """

        if self.model.thread_state.get(
        ) is GlobalVariables.get_screening_states()['repetitive_screening']:
            try:
                self.background_scheduler.shutdown()
            except Exception as e:
                logger.error("Unexpected Exception : " + str(e) + "\n" +
                             str(traceback.format_exc()))
            self.model.thread_state.set(
                GlobalVariables.get_screening_states()['not_running'])

        else:
            try:
                if not self._check_if_strategy_can_run():
                    return
                #  interval time, defines the cycle time to restart the screening
                interval_sec = self.model.analysis_parameters.get(
                )['OtherParameters']['AutoTrading'][
                    'RepetitiveScreeningInterval']

                self.background_scheduler.add_job(
                    self.start_screening_repetitive_mode,
                    'interval',
                    seconds=interval_sec,
                    next_run_time=datetime.now())
                self.background_scheduler.start()
                self.model.thread_state.set(
                    GlobalVariables.get_screening_states()
                    ['repetitive_screening'])

            except Exception as e:
                logger.error("Unexpected Exception : " + str(e) + "\n" +
                             str(traceback.format_exc()))
                self.model.thread_state.set(
                    GlobalVariables.get_screening_states()['not_running'])
    def _method_to_execute(self, stock_data_container):
        try:

            self.add_signals(stock_data_container, self.analysis_parameters)
            result = evaluate_signals(self.signal_list)

            if result is not None and result is not False:
                ppd = stock_data_container.positive_prob_dist()
                if ppd >= 0.5:
                    rec = "BUY"
                else:
                    rec = "SELL"

                stock_data_container.update_used_strategy_and_recommendation(
                    self.__class__.__name__, rec)
                self.result_list.append(stock_data_container)
        except Exception as e:
            logger.error("For stock: " +
                         str(stock_data_container.get_stock_name()) + ": " +
                         str(e) + "\n" + str(traceback.format_exc()))

        self.update_status("SimplePatternNewsStrategy:")
Пример #17
0
    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)
Пример #18
0
    def accept_parameters_from_text(self, params_dict, required_parameters):
        """
        Method to accept the changes in the scrolled text for the parameters,
         if the shape and keys of parameters dict is same as required parameters dict.
        :return: True, if parameters are valid and updated.
        """
        try:
            if isinstance(params_dict, dict):
                for param_key in params_dict.keys():
                    if not param_key in required_parameters.keys() or len(
                            params_dict[param_key]) <= 0:
                        logger.error(
                            "Parameter keys faulty, please insert correct parameters!"
                        )
                        return False

                    if not CommonUtils.have_dicts_same_shape(
                            required_parameters, params_dict):
                        logger.error(
                            "Parameter shapes are faulty, please insert correct parameters!"
                        )
                        return False

                self.model.analysis_parameters.clear()
                self.model.analysis_parameters.update(params_dict)
                self.model.available_strategies_list.clear()
                for item in params_dict['Strategies']:
                    self.model.available_strategies_list.append(item)
                logger.info("Analysis parameters Read")
            else:
                logger.error(
                    "Parameters are no dict, please insert correct parameters!"
                )
                return False

        except Exception as e:
            logger.error("Exception while opening result stock: " + str(e) +
                         "\n" + str(traceback.format_exc()))
            return False

        return True
Пример #19
0
    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)
Пример #20
0
    def error_handler(self, msg):
        """Handles the capturing of error messages"""
        print("Server Error: %s" % msg)

        if msg.errorCode not in info_codes:  # this is just a ping
            logger.error("Unexpected Exception : %s" % msg)
    def _get_ticker_data_with_webreader(self, ticker, stock_exchange,
                                        data_source, weeks_delta):
        """
        Method to read the data from the web or from temp file.
        :param stock_exchange: current stock exchange place (de, en..)
        :param ticker: ticker of the stock
        :param stock_dfs_file: file to load data or save the data from web
        :param data_source: google or yahoo
        :param reload_stockdata: true, to load from web, otherwise from temp file
        :param weeks_delta: delta from now to read the past: 52 means 52 weeks in the past
        :return: a dataframe df with ticker data
        """
        assert len(
            ticker
        ) < 17, "ATTENTION: ticker length is long, maybe it is a name not a ticker: " + ticker
        df = []

        if ticker == "" or ticker == '' or len(ticker) <= 0:
            logger.error("EXCEPTION reading because ticker is empty")
            return df

        # TODO 11 ticker = optimize_name_for_yahoo(ticker)  # TODO nicht nur für yahoo
        ticker_exchange = ticker

        if ticker_exchange == "" or ticker_exchange == '' or len(
                ticker_exchange) <= 0:
            logger.error("EXCEPTION reading because ticker is empty (2)")
            return df

        # TODO 3: yahoo does not take en, so skip
        # if _stock_exchange != '' and _stock_exchange is not None and _stock_exchange != "en" and data_source == 'yahoo':
        # ticker_exchange += "." + _stock_exchange

        # TODO autmatisieren von pandas=??
        # for i in range(0, 2): #TODO 4
        try:
            end = dt.datetime.now()
            start = (end - dt.timedelta(weeks=weeks_delta))

            df = data.DataReader(ticker_exchange, data_source, start, end, 3,
                                 0.05)

        #        if len(df) > 0:
        #            break

        except KeyError as ke:
            logger.error("No Stock data read for: " + str(ticker_exchange))
        except Exception as e:
            logger.error(str(e) + "\n" + str(traceback.format_exc()))
            # exception but the df is filled --> ok

        #       if len(df) > 0:
        #           break

        # TODO performance: wird dann langsam
        # from time import sleep
        # sleep(0.1)  # Time in seconds.

        if len(df) <= 0:
            logger.error("EXCEPTION reading because data is empty, " +
                         'FAILED: Reading {}'.format(ticker_exchange))

        return df
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()