示例#1
0
def test_make_strategy_fail(config, broker):
    sf = StrategyFactory(config, broker)
    strategy = sf.make_strategy("")
    assert strategy is None

    strategy = sf.make_strategy("wrong")
    assert strategy is None
示例#2
0
    def test_run_strategy__no_gap_EMPTY_RESULT(self):
        analysis_parameters = {'min_gap_factor': 1.1}
        labels = []
        for key, value in GlobalVariables.get_stock_data_labels_dict().items():
            labels.append(value)
        data = [('2016-09-13', 23.6, 23.73, 23.15, 23.26, 31000),
                ('2016-09-14', 23.33, 23.43, 22.95, 23.11, 31000),
                ('2016-09-15', 23.15, 23.77, 23.14, 23.62, 31000),
                ('2016-09-16', 23.57, 23.68, 23.38, 23.5, 31000),
                ('2016-09-19', 23.6, 23.77, 23.46, 23.51, 31000),
                ('2016-09-20', 23.73, 23.76, 23.26, 23.31, 31000),
                ('2016-09-21', 23.36, 23.78, 23.35, 23.73, 31000),
                ('2016-09-22', 23.36, 23.78, 23.35, 23.73, 31000), ]

        df = DataFrame.from_records(data, columns=labels)
        stock_data_container = StockDataContainer("Apple Inc.", "AAPL", "")
        stock_data_container.set_historical_stock_data(df)
        stock_data_container_list = [stock_data_container]

        ##################################################
        stock_screener = StrategyFactory()
        strat = stock_screener.prepare("GapUpHighVolumeStrategy",
                                       stock_data_container_list=stock_data_container_list,
                                       analysis_parameters=analysis_parameters)
        results = strat.run_strategy()
        self.assertEqual(len(results), 0)
示例#3
0
def test_make_strategy(config, broker):
    sf = StrategyFactory(config, broker)
    strategy = sf.make_strategy("simple_macd")
    assert isinstance(strategy, SimpleMACD)

    strategy = sf.make_strategy("weighted_avg_peak")
    assert isinstance(strategy, WeightedAvgPeak)
    def test_run_strategy__no52high__empty_result(self):
        w52hi_parameter_dict = {
            'check_days': 5,
            'min_cnt': 3,
            'min_vol_dev_fact': 1.2,
            'within52w_high_fact': 0.98
        }
        # volume higher, but stock value under 52w high within 98%
        labels = []
        for key, value in GlobalVariables.get_stock_data_labels_dict().items():
            labels.append(value)
        data = [
            ('2016-09-30', 23.35, 23.91, 23.24, 23.8,
             31000),  # --> 23.91 is highest high
            ('2016-10-03', 23.68, 23.69, 23.39, 23.5, 31000),
            ('2016-10-04', 23.52, 23.64, 23.18, 23.28, 31000),
            ('2016-10-05', 23.28, 23.51, 23.27, 23.43, 31000),
            ('2016-10-06', 23.38, 23.56, 23.29, 23.48, 42000),
            ('2016-10-07', 23.58, 23.65, 23.37, 23.48, 43000),
            ('2016-10-10', 23.62, 23.88, 23.55, 23.77, 44000),
            ('2016-10-11', 23.62, 23.74, 23.01, 23.16, 45000),
            ('2016-10-12', 23.16, 23.21, 23.11, 23.18, 46000)
        ]  # --> 23.91 * 0, 98 = 23.431 > 23.21

        df = DataFrame.from_records(data, columns=labels)
        stock_data_container = StockDataContainer("Apple Inc.", "AAPL", "")
        stock_data_container.set_historical_stock_data(df)
        stock_data_container_list = [stock_data_container]
        stock_screener = StrategyFactory()
        w52_hi_strat = stock_screener.prepare(
            "W52HighTechnicalStrategy",
            stock_data_container_list=stock_data_container_list,
            analysis_parameters=w52hi_parameter_dict)
        results = w52_hi_strat.run_strategy()
        self.assertEqual(0, len(results))
示例#5
0
    def __init__(self, time_provider=None, config_filepath=None):
        # Time manager
        self.time_provider = time_provider if time_provider else TimeProvider()
        # Set timezone
        set(pytz.all_timezones_set)

        # Load configuration
        if config_filepath is None:
            config_filepath = "/opt/TradingBot/config/config.json"
        config = self.load_json_file(config_filepath)
        self.read_configuration(config)

        # Read credentials file
        credentials = self.load_json_file(self.credentials_filepath)

        # Setup the global logger
        self.setup_logging()

        # Init trade services and create the broker interface
        self.broker = self.init_trading_services(config, credentials)

        # Create strategy from the factory class
        self.strategy = StrategyFactory(config, self.broker).make_strategy(
            self.active_strategy)

        # Create the market provider
        self.market_provider = MarketProvider(config, self.broker)
示例#6
0
    def __init__(self):
        # Set timezone
        set(pytz.all_timezones_set)

        # Load configuration
        home_path = os.path.expanduser("~")
        config_filepath = "{}/.TradingBot/config/config.json".format(home_path)
        config = self.load_json_file(config_filepath)
        self.read_configuration(config)

        # Read credentials file
        credentials = self.load_json_file(self.credentials_filepath)

        # Setup the global logger
        self.setup_logging()

        # Init trade services and create the broker interface
        self.broker = self.init_trading_services(config, credentials)

        # Create strategy from the factory class
        self.strategy = StrategyFactory(config, self.broker).make_strategy(
            self.active_strategy)

        # Create the market provider
        self.market_provider = MarketProvider(config, self.broker)
    def test_get_implemented_strategies_list(self):
        w52hi_parameter_dict = {
            'check_days': 5,
            'min_cnt': 3,
            'min_vol_dev_fact': 1.2,
            'within52w_high_fact': 0.98
        }

        labels = []
        for key, value in GlobalVariables.get_stock_data_labels_dict().items():
            labels.append(value)
        data = [
            ('2016-09-30', 23.35, 23.91, 23.24, 23.8, 31000),
        ]

        df = DataFrame.from_records(data, columns=labels)
        stock_data_container = StockDataContainer("Apple Inc.", "AAPL", "")
        stock_data_container.set_historical_stock_data(df)
        stock_data_container_list = [stock_data_container]

        ##################################################
        # 52 w strategy
        stock_screener = StrategyFactory()
        w52_hi_strat = stock_screener.prepare(
            "W52HighTechnicalStrategy",
            stock_data_container_list=stock_data_container_list,
            analysis_parameters=w52hi_parameter_dict)

        self.assertNotEqual(None, w52_hi_strat)
        self.assertTrue(isinstance(w52_hi_strat, Abstract_Strategy))
    def test_StrategyAsta_SMA_and__EMA_or_RoC__result_one_SELL_entry(self):
        strategy_name = "StrategyAsta_SMA_and__EMA_or_RoC"
        parameter_dict = {
            'sma_timeperiod': 5,
            'ema_timeperiod': 5,
            'roc_timeperiod': 5,
            'data_readers': {
                'HistoricalDataReader': {
                    'weeks_delta': 52,
                    'data_source': 'iex',
                    'reload_data': False,
                    'ticker_needed': False
                }
            }
        }

        labels = []
        for key, value in GlobalVariables.get_stock_data_labels_dict().items():
            labels.append(value)
        data = [
            ('2016-09-30', 23.35, 23.91, 23.24, 23.8, 31000),
            ('2016-10-03', 23.68, 23.69, 23.39, 23.5, 31000),
            ('2016-10-04', 23.52, 23.64, 23.18, 23.28, 31000),
            ('2016-10-05', 23.28, 23.51, 23.27, 23.43, 31000),
            ('2016-10-06', 23.38, 23.56, 23.29, 23.48, 42000),
            ('2016-10-07', 23.58, 23.65, 23.37, 23.48, 43000),
            ('2016-10-10', 25.62, 25.88, 25.55, 25.77,
             44000),  # raising prices --> sma, ema, roc
            ('2016-10-11', 26.62, 26.74, 26.01, 26.16, 45000),
            ('2016-10-12', 27.16, 26, 27.11, 27.18, 46000),
            ('2016-10-13', 23.35, 23.91, 23.24, 23.8, 31000),
        ]

        df = DataFrame.from_records(data, columns=labels)
        stock_data_container = StockDataContainer("Apple Inc.", "AAPL", "")
        stock_data_container.set_historical_stock_data(df)
        stock_data_container_list = [stock_data_container]

        # sma_ema_roc strategy
        stock_screener = StrategyFactory()
        sma_ema_roc_strat = stock_screener.prepare(
            strategy_name,
            stock_data_container_list=stock_data_container_list,
            analysis_parameters=parameter_dict)

        results = sma_ema_roc_strat.run_strategy()
        self.assertEqual(len(results), 1)
        self.assertEqual(results[0].get_stock_name(),
                         stock_data_container.get_stock_name())
        #  get the recommendation for the given strategy (BUY / SELL)
        recommendation = results[0].get_recommendation_strategies(
        )[strategy_name][0]
        self.assertEqual('SELL', recommendation)
    def test_run_strategy_with_two_news_for_one_stock(self):
        labels = []
        for key, value in GlobalVariables.get_stock_data_labels_dict().items():
            labels.append(value)
        data = [('2016-09-13', 90, 90, 100.15, 100.26, 4000),
                ('2016-09-14', 90, 90, 22.95, 100.11, 4000),
                ('2016-09-15', 90, 90, 100.14, 100.62, 4000)]

        df = DataFrame.from_records(data, columns=labels)

        apple_stock_data_container = NewsDataContainerDecorator(
            StockDataContainer("Apple Inc.", "AAPL", ""), 0, 0,
            "ANALYSE-FLASH: Credit Suisse nimmt Apple mit 'Underperform' wieder auf"
        )
        apple_stock_data_container2 = NewsDataContainerDecorator(
            StockDataContainer("Apple Inc.", "AAPL", ""), 0, 0,
            "ANALYSE-FLASH: Sparkasse nimmt Apple mit Buy wieder auf")

        apple_stock_data_container.set_historical_stock_data(df)
        apple_stock_data_container2.set_historical_stock_data(df)
        rwe_stock_data_container = NewsDataContainerDecorator(
            StockDataContainer("RWE AG ST O.N.", "RWE", ""), 0, 0,
            "ANALYSE-FLASH: Credit Suisse nimmt RWE mit 'Outperform' wieder auf"
        )
        rwe_stock_data_container.set_historical_stock_data(df)
        stock_data_container_list = [
            apple_stock_data_container, rwe_stock_data_container
        ]

        analysis_parameters = {
            'news_threshold': 0.7,
            'german_tagger': filepath + 'nltk_german_classifier_data.pickle'
        }
        stock_screener = StrategyFactory()
        news_strategy = stock_screener.prepare(
            "SimplePatternNewsStrategy",
            stock_data_container_list=stock_data_container_list,
            analysis_parameters=analysis_parameters)

        results = news_strategy.run_strategy()

        self.assertEqual(results[0] in stock_data_container_list, True)
        apple_idx = results.index(apple_stock_data_container)
        rwe_idx = results.index(rwe_stock_data_container)

        t1 = round(results[apple_idx].positive_prob_dist(), 2)
        self.assertEqual(results[apple_idx].get_stock_name(), "Apple Inc.")
        self.assertGreater(0.7, t1)

        t1 = round(results[rwe_idx].positive_prob_dist(), 2)
        self.assertEqual(results[rwe_idx].get_stock_name(), "RWE AG ST O.N.")
        self.assertGreater(t1, 0.7)
示例#10
0
def run_analysis(selected_strategies_list,
                 strategy_parameter_dict,
                 other_params,
                 stock_data_container_list=[]):
    """
    Run the analysis due to given parameters and returns the result as container list.
    :param selected_strategies_list: lit with selected strategies to execute
    :param strategy_parameter_dict: dict with strategy dependend parameters
    :param other_params: dict with needed parameters
    :return: analysed_stocks list
    """
    thr_start = datetime.now()

    if len(stock_data_container_list) <= 0:
        stock_data_container_list = []
        stock_data_container_list = _read_data(selected_strategies_list,
                                               strategy_parameter_dict,
                                               other_params,
                                               stock_data_container_list)

    # selected strategies
    # todo News + 52 w geht schon wieda ned gleichzeitig
    analysed_stocks = []
    for strategy_name in selected_strategies_list:
        strat_factory = StrategyFactory()
        result_stock_data_container_list = stock_data_container_list

        strategy = strat_factory.prepare(
            strategy_name,
            stock_data_container_list=result_stock_data_container_list,
            analysis_parameters=strategy_parameter_dict[strategy_name])
        strategy_result = strategy.run_strategy()
        analysed_stocks.extend(strategy_result)

    # risk model
    risk_models = other_params['RiskModels']
    for rm_name in risk_models.keys():
        rm_parameters = risk_models[rm_name]
        rm_factory = RiskModelFactory()
        fsr = rm_factory.prepare(rm_name,
                                 stock_data_container_list=analysed_stocks,
                                 parameter_dict=rm_parameters)
        fsr.determine_risk()

    logger.info("Runtime at " + str(datetime.now()) +
                " for run analysis and duration: " +
                str(datetime.now() - thr_start) + " seconds.")

    return analysed_stocks
    def test_stock_data_container_file__W52HighTechnicalStrategy_msft_vfc_csx(
            self):
        raise Exception("This test is not working ")
        global val, w, root
        root = Tk()
        top = Framework(root)
        controller = MvcController.init(root, top)

        req_params = StrategyFactory.get_required_parameters_with_default_parameters(
        )

        controller.load_analysis_parameters_from_file(
            GlobalVariables.get_data_files_path() +
            '\\TestData\\OtherParameterFile_DO_NOT_RELOAD.pickle', req_params)
        controller.model.strategy_selection_values.set(
            ['W52HighTechnicalStrategy'])
        root.mainloop()

        result_container = controller.model.result_stock_data_container_list.get(
        )

        print(str(result_container))
        self.assertEqual(3, len(result_container))
        self.assertEqual('CSX Corp.', result_container[0].get_stock_name())
        self.assertEqual('Microsoft Corp.',
                         result_container[1].get_stock_name())
        self.assertEqual('V.F. Corp.', result_container[2].get_stock_name())
示例#12
0
    def test_(self):
        parameter_dict = {
            'sma_timeperiod': 5,
            'ema_timeperiod': 5,
            'roc_timeperiod': 5,
            'data_readers': {
                'HistoricalDataReader': {
                    'weeks_delta': 52,
                    'data_source': 'iex',
                    'reload_data': False,
                    'ticker_needed': True
                }
            }
        }

        labels = []
        for key, value in GlobalVariables.get_stock_data_labels_dict().items():
            labels.append(value)
        data = [('2016-09-30', 23.35, 23.91, 23.24, 23.8, 31000),
                ('2016-10-03', 23.68, 23.69, 23.39, 23.5, 31000),
                ('2016-10-04', 23.52, 23.64, 23.18, 23.28, 31000),
                ('2016-10-05', 23.28, 23.51, 23.27, 23.43, 31000),
                ('2016-10-06', 23.38, 23.56, 23.29, 23.48, 42000),
                ('2016-10-07', 23.58, 23.65, 23.37, 23.48, 43000),
                ('2016-10-10', 23.62, 23.88, 23.55, 23.77, 44000),
                ('2016-10-11', 23.62, 23.74, 23.01, 23.16, 45000),
                ('2016-10-12', 23.16, 26, 23.11, 23.18, 46000)]

        df = DataFrame.from_records(data, columns=labels)
        stock_data_container = StockDataContainer("Apple Inc.", "AAPL", "")
        stock_data_container.set_historical_stock_data(df)
        stock_data_container_list = [stock_data_container]

        ##################################################
        # 52 w strategy
        stock_screener = StrategyFactory()
        w52_hi_strat = stock_screener.prepare(
            "StrategyAsta_SMA_and__EMA_or_RoC",
            stock_data_container_list=stock_data_container_list,
            analysis_parameters=parameter_dict)

        results = w52_hi_strat.run_strategy()
        self.assertGreater(len(results), 0)
        self.assertEqual(results[0].get_stock_name(),
                         stock_data_container.get_stock_name())
示例#13
0
    def __init__(self, **kwargs):
        """
        Init method to wrap the ASTA-Strategy to the bt.Strategy
        :param kwargs: Dict with parameters for testing, the Key "strategy_to_test" contains the strategy class to test.
        """

        # Keep a reference to the "close" line in the data[0] dataseries
        self.dataclose = self.datas[0].close
        self.datavol = self.datas[0].volume
        self.datahi = self.datas[0].high
        self.datalo = self.datas[0].low
        self.buy_price = 0

        # set the given values in self
        for key, value in kwargs.items():
            setattr(self, key, value)

        # To keep track of pending orders and buy price/commission
        self.order = None
        self.buyprice = None
        self.buycomm = None
        self.highest_high = 0  # max (self.datahi)
        self.buyCnt = 0

        self.stock_screener = StrategyFactory()

        # the parameter dict contains the strategy which is build with the string
        self.strategy_instance = self.stock_screener.prepare(
            self.strategy_to_test, **kwargs)

        # only one risk model can be used, the first risk model to be taken
        first_rm_key = list(self.risk_model.keys())[0]
        self.curr_risk_model = self.risk_model[first_rm_key]
        self.order_target_method = self._get_order_target(
            self.curr_risk_model['OrderTarget'])
        self.news_data_dict = {}

        # add the news text because backtrader does not support news
        # data from pandas do not have a name --> not add news
        for i, hist_data in enumerate(self.datas):
            dataname = hist_data._dataname
            if isinstance(dataname, str) and os.path.exists(dataname):
                news_data = pd.read_csv(dataname)
                self.news_data_dict.update({dataname: news_data})
    def test_run_strategy__strat_fulfilled__stock_in_result(self):

        w52hi_parameter_dict = {
            'check_days': 5,
            'min_cnt': 3,
            'min_vol_dev_fact': 1.2,
            'within52w_high_fact': 0.98
        }

        labels = []
        for key, value in GlobalVariables.get_stock_data_labels_dict().items():
            labels.append(value)
        data = [('2016-09-30', 23.35, 23.91, 23.24, 23.8, 31000),
                ('2016-10-03', 23.68, 23.69, 23.39, 23.5, 31000),
                ('2016-10-04', 23.52, 23.64, 23.18, 23.28, 31000),
                ('2016-10-05', 23.28, 23.51, 23.27, 23.43, 31000),
                ('2016-10-06', 23.38, 23.56, 23.29, 23.48, 42000),
                ('2016-10-07', 23.58, 23.65, 23.37, 23.48, 43000),
                ('2016-10-10', 23.62, 23.88, 23.55, 23.77, 44000),
                ('2016-10-11', 23.62, 23.74, 23.01, 23.16, 45000),
                ('2016-10-12', 23.16, 26, 23.11, 23.18, 46000)]

        start_time = datetime.now()

        df = DataFrame.from_records(data, columns=labels)
        stock_data_container = StockDataContainer("Apple Inc.", "AAPL", "")
        stock_data_container.set_historical_stock_data(df)
        stock_data_container_list = [stock_data_container]

        ##################################################
        # 52 w strategy
        stock_screener = StrategyFactory()
        w52_hi_strat = stock_screener.prepare(
            "W52HighTechnicalStrategy",
            stock_data_container_list=stock_data_container_list,
            analysis_parameters=w52hi_parameter_dict)

        results = w52_hi_strat.run_strategy()

        print("Time to run strat:" + (str(datetime.now() - start_time)))

        self.assertEqual(1, len(results))
        self.assertEqual(results[0].get_stock_name(),
                         stock_data_container.get_stock_name())
def load_analysis_parameters():
    file_path = filedialog.askopenfilename(
        initialdir=GlobalVariables.get_data_files_path(),
        title="Select pickle parameterfile",
        filetypes=[("Pickle Dumps", "*.pickle")],
        defaultextension='.pickle')

    req_params = StrategyFactory.get_required_parameters_with_default_parameters(
    )
    app.load_analysis_parameters_from_file(file_path, req_params)
    def test_partial_data_in_dict(self):
        stock_data_file = GlobalVariables.get_data_files_path(
        ) + "stock_data_container_file.pickle"
        req_params = StrategyFactory.get_required_parameters_with_default_parameters(
        )

        missing_strategy_parameter_dict = {
            'W52HighTechnicalStrategy': {
                'check_days': 7,
                'min_cnt': 3,
                'min_vol_dev_fact': 1.2,
                'within52w_high_fact': 0.98,
                'data_readers': {
                    'HistoricalDataReader': {
                        'weeks_delta': 52,
                        'data_source': 'iex',
                        'reload_data': False,
                        'ticker_needed': True
                    }
                }
            }
        }

        other_params = {
            'stock_data_container_file': stock_data_file,
            'dict_with_stock_pages_to_read': {
                'SP500': {
                    'websource_address':
                    "http://en.wikipedia.org/wiki/List_of_S%26P_500_companies",
                    'find_name': 'table',
                    'class_name': 'class',
                    'table_class': 'wikitable sortable',
                    'ticker_column_to_read': 0,
                    'name_column_to_read': 1,
                    'stock_exchange': 'en'
                }
            },
            'RiskModels': {
                'FixedSizeRiskModel': {
                    'OrderTarget': 'order_target_value',
                    'TargetValue': 2500
                }
            }
        }

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

        self.assertFalse(
            CommonUtils.have_dicts_same_shape(
                req_params['Strategies']['W52HighTechnicalStrategy'],
                missing_strategy_parameter_dict))
示例#17
0
    def __init__(self, time_provider=None, config_filepath=None):
        # Time manager
        self.time_provider = time_provider if time_provider else TimeProvider()
        # Set timezone
        set(pytz.all_timezones_set)

        # Load configuration
        self.config = Configuration.from_filepath(config_filepath)

        # Setup the global logger
        self.setup_logging()

        # Init trade services and create the broker interface
        # The Factory is used to create the services from the configuration file
        self.broker = Broker(BrokerFactory(self.config))

        # Create strategy from the factory class
        self.strategy = StrategyFactory(self.config,
                                        self.broker).make_from_configuration()

        # Create the market provider
        self.market_provider = MarketProvider(self.config, self.broker)
    def test__volume_not_above__empty_result(self):
        w52hi_parameter_dict = {
            'check_days': 5,
            'min_cnt': 3,
            'min_vol_dev_fact': 1.2,
            'within52w_high_fact': 0.98
        }

        labels = []
        for key, value in GlobalVariables.get_stock_data_labels_dict().items():
            labels.append(value)
        data = [('2016-09-30', 23.35, 23.91, 23.24, 23.8, 31000),
                ('2016-10-03', 23.68, 23.69, 23.39, 23.5, 31000),
                ('2016-10-04', 23.52, 23.64, 23.18, 23.28, 31000),
                ('2016-10-05', 23.28, 23.51, 23.27, 23.43, 31000),
                ('2016-10-06', 23.38, 23.56, 23.29, 23.48, 32000),
                ('2016-10-07', 23.58, 23.65, 23.37, 23.48, 33000),
                ('2016-10-10', 23.62, 23.88, 23.55, 23.77, 34000),
                ('2016-10-11', 23.62, 23.74, 23.01, 23.16, 35000),
                ('2016-10-12', 23.16, 23.8, 23.11, 23.18, 36000)]

        # file = test_filepath + 'test_strat_52WHi_HiVolume_VolumeNotAbove.csv'
        df = DataFrame.from_records(data, columns=labels)
        stock_data_container = StockDataContainer("Apple Inc.", "AAPL", "")
        stock_data_container.set_historical_stock_data(df)
        stock_data_container_list = [stock_data_container]
        stock_screener = StrategyFactory()
        w52_hi_strat = stock_screener.prepare(
            "W52HighTechnicalStrategy",
            stock_data_container_list=stock_data_container_list,
            analysis_parameters=w52hi_parameter_dict)
        results = w52_hi_strat.run_strategy()
        self.assertEqual(0, len(results))

        labels = []
        for key, value in GlobalVariables.get_stock_data_labels_dict().items():
            labels.append(value)
        data = [('2016-09-30', 23.35, 23.91, 23.24, 23.8, 31000),
                ('2016-10-03', 23.68, 23.69, 23.39, 23.5, 31000),
                ('2016-10-04', 23.52, 23.64, 23.18, 23.28, 31000),
                ('2016-10-05', 23.28, 23.51, 23.27, 23.43, 31000),
                ('2016-10-06', 23.38, 23.56, 23.29, 23.48, 42000),
                ('2016-10-07', 23.58, 23.65, 23.37, 23.48, 43000),
                ('2016-10-10', 23.62, 23.88, 23.55, 23.77, 44000),
                ('2016-10-11', 23.62, 23.74, 23.01, 23.16, 45000),
                ('2016-10-12', 23.16, 23.0, 23.11, 23.18, 46000)]
        # file = test_filepath + 'test_strat_52WHi_HiVolume_Not52WHigh.csv'
        df = DataFrame.from_records(data, columns=labels)
        stock_data_container = StockDataContainer("Apple Inc.", "AAPL", "")
        stock_data_container.set_historical_stock_data(df)
        stock_data_container_list = [stock_data_container]
        stock_screener = StrategyFactory()
        w52_hi_strat = stock_screener.prepare(
            "W52HighTechnicalStrategy",
            stock_data_container_list=stock_data_container_list,
            analysis_parameters=w52hi_parameter_dict)
        results = w52_hi_strat.run_strategy()
        self.assertEqual(0, len(results))
def save_analysis_parameters():
    file_path = filedialog.asksaveasfilename(
        initialdir=GlobalVariables.get_data_files_path(),
        filetypes=[("Pickle Dumps", "*.pickle")],
        defaultextension='.pickle',
        title="Select pickle parameterfile")

    at_objects = w.scrollable_frame_parameters.form.at_objects
    all_txt = w.scrollable_frame_parameters.form.get_parameters(at_objects)
    req_params = StrategyFactory.get_required_parameters_with_default_parameters(
    )

    app.dump_analysis_parameters_to_file(file_path, all_txt, req_params)

    save_last_used_parameter_file()
    def _check_if_strategy_can_run(self):
        selection_values = self.model.selected_strategies_list.get()
        if selection_values == "" or len(selection_values) <= 0:
            messagebox.showerror("Selection Error",
                                 "Please select a strategy first!")
            return False

        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 False

        return True
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
    def test_dump_params(self):
        global val, w, root
        root = Tk()
        top = ASTA_Framework(root)
        controller = MvcController.init(root, top)
        data_file_path = GlobalVariables.get_data_files_path()

        strat_param_file = GlobalVariables.get_data_files_path(
        ) + '\\TestData\\ParameterFile_test_dump_and_load_strat_params.pickle'
        FileUtils.check_file_exists_and_delete(strat_param_file)

        strategy_parameter_dict = {
            'SimplePatternNewsStrategy': {
                'news_threshold': 0.7,
                'german_tagger':
                data_file_path + 'nltk_german_classifier_data.pickle',
                'data_readers': {
                    'TraderfoxNewsDataReader': {
                        'last_check_date_file':
                        data_file_path + 'TestData\\last_date_time.csv',
                        'german_tagger':
                        data_file_path + 'nltk_german_classifier_data.pickle',
                        'reload_data': True,
                        'ticker_needed': False
                    },
                    'HistoricalDataReader': {
                        'weeks_delta': 52,
                        'data_source': 'iex',
                        'reload_data': True,
                        'ticker_needed': False
                    }
                }
            }
        }
        stock_data_file = data_file_path + 'TestData\\stock_data_container_file.pickle'
        other_params = {
            'stock_data_container_file': stock_data_file,
            'dict_with_stock_pages_to_read': {
                'SP500': {
                    'websource_address':
                    "http://en.wikipedia.org/wiki/List_of_S%26P_500_companies",
                    'find_name': 'table',
                    'class_name': 'class',
                    'table_class': 'wikitable sortable',
                    'ticker_column_to_read': 0,
                    'name_column_to_read': 1,
                    'stock_exchange': 'en'
                }
            },
            'RiskModels': {
                'FixedSizeRiskModel': {
                    'OrderTarget': 'order_target_value',
                    'TargetValue': 2500
                }
            }
        }

        params = {
            'Strategies': strategy_parameter_dict,
            'OtherParameters': other_params
        }
        req_params = StrategyFactory.get_required_parameters_with_default_parameters(
        )
        import _pickle as pickle
        with open(strat_param_file, "wb") as f:
            pickle.dump(params, f)
    def test_with_real_data__strat_fulfilled__stock_in_result(self):
        labels = []
        for key, value in GlobalVariables.get_stock_data_labels_dict().items():
            labels.append(value)
        data = [
            ('2017-05-30', 112.800003, 113.660004, 112.260002, 113.160004,
             2560300),
            ('2017-05-31', 113.400002, 113.919998, 111.5, 111.769997, 3222600),
            ('2017-06-01', 111.720001, 113.120003, 110.940002, 113.029999,
             2322600),
            ('2017-06-02', 113.779999, 113.879997, 111.760002, 112.910004,
             2215100),
            ('2017-06-05', 112.739998, 113.139999, 110.230003, 110.879997,
             4008000),
            ('2017-06-06', 110.400002, 112.269997, 110.190002, 111.449997,
             2444800),
            ('2017-06-07', 111.379997, 112.080002, 110.599998, 111.169998,
             2030100),
            ('2017-06-08', 111.510002, 111.949997, 110.199997, 111.120003,
             2025100),
            ('2017-06-09', 111.160004, 111.699997, 103.620003, 105.949997,
             3025600),
            ('2017-06-12', 104.209999, 108.620003, 100.699997, 107.440002,
             5134000),
            ('2017-06-13', 107.599998, 108.239998, 105.169998, 107.550003,
             2269800),
            ('2017-06-14', 108.519997, 108.650002, 105.019997, 106.199997,
             1974800),
            ('2017-06-15', 104.769997, 106.040001, 103.480003, 105.580002,
             1824800),
            ('2017-06-16', 105.5, 105.919998, 103.629997, 104.879997, 2565400),
            ('2017-06-19', 105.599998, 106.699997, 105.160004, 106.160004,
             2481500),
            ('2017-06-20', 106.010002, 107.110001, 104.300003, 104.93,
             1956000),
            ('2017-06-21', 105.879997, 106.559998, 104.82, 105.690002,
             2645600),
            ('2017-06-22', 105.720001, 107.260002, 104.550003, 106.779999,
             2327900),
            ('2017-06-23', 106.400002, 108.760002, 105.300003, 107.75,
             3666200),
            ('2017-06-26', 107.760002, 109.07, 105.309998, 106.120003,
             1873400),
            ('2017-06-27', 105.580002, 106.449997, 102.5, 102.919998, 2269700),
            ('2017-06-28', 103.690002, 104.860001, 101.540001, 104.279999,
             1642400),
            ('2017-06-29', 103.57, 103.809998, 100.0, 101.389999, 2347000),
            ('2017-06-30', 102.32, 102.370003, 100.75, 100.82, 1671300),
            ('2017-07-03', 101.32, 101.82, 99.32, 99.360001, 1454200),
            ('2017-07-05', 99.370003, 103.040001, 99.220001, 102.599998,
             2785200),
            ('2017-07-06', 101.589996, 103.110001, 100.790001, 102.050003,
             2605700),
            ('2017-07-07', 102.290001, 104.279999, 102.290001, 103.32,
             1695300),
            ('2017-07-10', 103.330002, 104.190002, 102.379997, 103.739998,
             1191800),
            ('2017-07-11', 103.470001, 104.730003, 102.980003, 104.300003,
             1461700),
            ('2017-07-12', 105.610001, 107.080002, 104.760002, 106.68,
             2621600),
            ('2017-07-13', 107.489998, 108.5, 106.379997, 107.07, 1428000),
            ('2017-07-14', 107.459999, 108.910004, 107.010002, 108.739998,
             1480600),
            ('2017-07-17', 108.900002, 109.0, 106.559998, 106.940002, 1180700),
            ('2017-07-18', 106.669998, 107.849998, 106.230003,
             107.699997, 865700),
            ('2017-07-19', 108.5, 110.5, 108.470001, 110.25, 2044400),
            ('2017-07-20', 109.720001, 110.5, 108.879997, 109.910004, 1270900),
            ('2017-07-21', 109.410004, 110.540001, 109.080002, 109.75,
             1116400),
            ('2017-07-24', 109.589996, 110.889999, 109.339996, 110.809998,
             1953400),
            ('2017-07-25', 110.910004, 112.400002, 110.199997, 112.260002,
             1342500),
            ('2017-07-26', 112.5, 114.099998, 112.410004, 114.080002, 1891200),
            ('2017-07-27', 114.970001, 115.25, 109.32, 111.519997, 2362400),
            ('2017-07-28', 110.599998, 112.279999, 110.330002, 111.5, 946200),
            ('2017-07-31', 111.650002, 112.32, 109.779999, 110.790001,
             1393800),
            ('2017-08-01', 111.269997, 112.589996, 111.099998, 111.379997,
             1315600),
            ('2017-08-02', 111.080002, 111.379997, 107.279999, 109.129997,
             1757100),
            ('2017-08-03', 107.949997, 108.5, 105.599998, 107.879997, 2255600),
            ('2017-08-04', 108.349998, 109.040001, 107.559998, 108.389999,
             1490900),
            ('2017-08-07', 108.669998, 111.0, 108.400002, 109.82, 1493100),
            ('2017-08-08', 109.379997, 110.269997, 108.0, 108.349998, 1224200),
            ('2017-08-09', 107.690002, 107.959999, 106.540001, 107.449997,
             1151400),
            ('2017-08-10', 106.559998, 107.540001, 104.769997, 104.980003,
             1878300),
            ('2017-08-11', 105.75, 108.760002, 105.099998, 108.010002,
             1461200),
            ('2017-08-14', 109.199997, 110.0, 108.010002, 108.900002, 1637900),
            ('2017-08-15', 109.019997, 110.099998, 108.120003, 109.800003,
             1263300),
            ('2017-08-16', 110.360001, 110.93, 109.360001, 110.489998,
             1320500),
            ('2017-08-17', 110.07, 110.82, 107.730003, 107.889999, 1738700),
            ('2017-08-18', 107.860001, 110.099998, 107.190002, 108.559998,
             1164300),
            ('2017-08-21', 108.370003, 110.300003, 108.370003, 109.75,
             1279200),
            ('2017-08-22', 110.309998, 112.239998, 109.769997, 111.010002,
             1708500),
            ('2017-08-23', 110.910004, 111.339996, 110.050003, 110.650002,
             1636200),
            ('2017-08-24', 110.580002, 111.25, 109.040001, 110.610001,
             3128400),
            ('2017-08-25', 115.0, 119.730003, 113.540001, 114.970001, 7121000),
            ('2017-08-28', 115.059998, 115.139999, 110.010002, 111.480003,
             3618400),
            ('2017-08-29', 109.650002, 111.900002, 109.25, 111.269997,
             1858600),
            ('2017-08-30', 111.269997, 113.669998, 110.610001, 113.290001,
             1458900),
            ('2017-08-31', 113.629997, 114.699997, 112.82, 114.459999,
             1467200),
            ('2017-09-01', 114.629997, 115.620003, 113.650002, 113.709999,
             1566400),
            ('2017-09-05', 113.459999, 114.809998, 112.519997, 113.769997,
             3092900),
            ('2017-09-06', 114.400002, 114.779999, 112.650002, 113.790001,
             2339900),
            ('2017-09-07', 114.139999, 114.470001, 113.190002, 114.050003,
             1731400),
            ('2017-09-08', 114.169998, 115.720001, 114.099998, 114.440002,
             2656400),
            ('2017-09-11', 112.980003, 117.129997, 112.220001, 116.480003,
             2294700),
            ('2017-09-12', 116.349998, 116.989998, 114.980003, 116.160004,
             1607000),
            ('2017-09-13', 116.040001, 116.5, 115.25, 116.18, 1449900),
            ('2017-09-14', 115.620003, 116.139999, 114.5, 115.470001, 1649700),
            ('2017-09-15', 115.620003, 115.620003, 113.879997, 114.129997,
             6232600),
            ('2017-09-18', 113.739998, 114.660004, 112.870003, 113.839996,
             2030000),
            ('2017-09-19', 113.769997, 114.059998, 112.970001, 113.080002,
             1954800),
            ('2017-09-20', 113.07, 113.339996, 111.349998, 112.730003,
             1782700),
            ('2017-09-21', 112.82, 113.0, 111.370003, 112.290001, 1154500),
            ('2017-09-22', 111.68, 112.82, 111.639999, 111.779999, 1085000),
            ('2017-09-25', 111.669998, 111.830002, 108.650002, 109.82,
             2026000),
            ('2017-09-26', 110.589996, 111.379997, 108.830002, 110.610001,
             1590500),
            ('2017-09-27', 110.209999, 113.470001, 110.209999, 111.959999,
             1731400),
            ('2017-09-28', 111.400002, 111.959999, 110.519997, 111.449997,
             1358300),
            ('2017-09-29', 111.25, 112.760002, 111.0, 112.260002, 2033100),
            ('2017-10-02', 110.690002, 113.760002, 110.68, 112.470001,
             1961300),
            ('2017-10-03', 112.389999, 113.730003, 111.669998, 113.629997,
             1044800),
            ('2017-10-04', 113.790001, 114.07, 112.349998, 114.050003,
             1122300),
            ('2017-10-05', 114.5, 116.830002, 113.900002, 116.540001, 1673800),
            ('2017-10-06', 116.18, 117.610001, 115.809998, 116.959999,
             1806200),
            ('2017-10-09', 116.800003, 117.519997, 116.639999, 117.139999,
             847100),
            ('2017-10-10', 117.220001, 117.529999, 116.32, 117.050003, 931500),
            ('2017-10-11', 117.019997, 118.660004, 116.93, 118.57, 1078400),
            ('2017-10-12', 118.550003, 119.839996, 118.510002, 118.989998,
             1236600),
            ('2017-10-13', 119.769997, 119.769997, 118.449997, 119.629997,
             1262900),
            ('2017-10-16', 119.690002, 119.970001, 118.669998, 119.199997,
             1179600),
            ('2017-10-17', 119.349998, 119.760002, 118.059998, 118.720001,
             1184700),
            ('2017-10-18', 118.5, 118.860001, 117.779999, 118.540001, 1010600),
            ('2017-10-19', 119.0, 119.32, 117.57, 119.290001, 1099300),
            ('2017-10-20', 119.980003, 121.879997, 119.699997, 120.809998,
             1647600),
            ('2017-10-23', 120.989998, 121.720001, 118.730003, 118.989998,
             1487500),
            ('2017-10-24', 118.959999, 119.610001, 117.900002, 119.290001,
             1337800),
            ('2017-10-25', 119.0, 120.25, 118.050003, 119.940002, 1080000),
            ('2017-10-26', 120.209999, 121.949997, 119.459999, 121.349998,
             902700),
            ('2017-10-27', 121.610001, 123.970001, 121.400002, 123.580002,
             1523700),
            ('2017-10-30', 123.040001, 124.279999, 121.900002, 123.910004,
             1610500),
            ('2017-10-31', 124.279999, 125.010002, 123.419998, 124.959999,
             1839900),
            ('2017-11-01', 125.629997, 126.440002, 123.400002, 124.779999,
             1622800),
            ('2017-11-02', 125.5, 125.650002, 123.510002, 124.720001, 1736000),
            ('2017-11-03', 124.5, 125.5, 124.110001, 124.849998, 1309700),
            ('2017-11-06', 125.0, 125.089996, 123.190002, 123.82, 1003200),
            ('2017-11-07', 124.260002, 124.540001, 122.610001, 123.400002,
             828400),
            ('2017-11-08', 123.489998, 124.209999, 123.169998, 123.839996,
             892500),
            ('2017-11-09', 122.900002, 123.089996, 120.010002, 122.400002,
             1465500),
            ('2017-11-10', 121.949997, 123.32, 121.309998, 123.110001, 929400),
            ('2017-11-13', 124.339996, 125.019997, 122.690002, 124.639999,
             1216700),
            ('2017-11-14', 124.400002, 124.82, 123.160004, 123.870003,
             1225300),
            ('2017-11-15', 123.870003, 125.010002, 122.440002, 124.019997,
             1442100),
            ('2017-11-16', 124.790001, 127.0, 124.639999, 127.0, 1545200),
            ('2017-11-17', 127.489998, 127.919998, 125.870003, 127.489998,
             1460900),
            ('2017-11-20', 127.510002, 128.279999, 126.110001, 126.279999,
             1786200),
            ('2017-11-21', 127.129997, 128.169998, 126.970001, 127.709999,
             1642900),
            ('2017-11-22', 128.009995, 128.690002, 126.839996, 127.769997,
             1469500),
            ('2017-11-24', 127.739998, 129.539993, 127.650002, 129.5, 1013600),
            ('2017-11-27', 130.190002, 130.919998, 129.259995, 130.240005,
             2337200),
            ('2017-11-28', 130.759995, 131.100006, 127.489998, 129.949997,
             4976600),
            ('2017-11-29', 114.029999, 114.459999, 106.199997, 109.339996,
             19487000),
            ('2017-11-30', 109.639999, 111.580002, 106.540001, 109.699997,
             8481000),
            ('2017-12-01', 108.809998, 110.120003, 106.290001, 107.059998,
             4922900),
            ('2017-12-04', 108.0, 108.690002, 105.160004, 107.949997, 3986000),
            ('2017-12-05', 107.910004, 109.489998, 106.550003, 106.589996,
             3002500),
            ('2017-12-06', 105.730003, 107.830002, 105.730003, 106.919998,
             1686600),
            ('2017-12-07', 106.199997, 110.18, 106.0, 109.610001, 3074200),
            ('2017-12-08', 109.599998, 110.169998, 106.690002, 107.160004,
             3124700),
            ('2017-12-11', 106.870003, 107.949997, 106.150002, 106.830002,
             2412300),
            ('2017-12-12', 106.32, 107.980003, 105.580002, 106.330002,
             2026100),
            ('2017-12-13', 107.029999, 107.889999, 105.510002, 106.019997,
             1982900),
            ('2017-12-14', 105.949997, 107.120003, 105.949997, 106.25,
             1503900),
            ('2017-12-15', 106.550003, 108.93, 106.470001, 108.400002,
             2704200),
            ('2017-12-18', 108.660004, 109.43, 107.279999, 107.480003,
             2362600),
            ('2017-12-19', 107.239998, 107.839996, 105.370003, 105.389999,
             1862000),
            ('2017-12-20', 106.019997, 106.019997, 104.190002, 105.029999,
             2513900),
            ('2017-12-21', 105.580002, 105.669998, 103.650002, 104.43,
             3920700),
            ('2017-12-22', 104.849998, 104.849998, 103.779999, 103.889999,
             1533800),
            ('2017-12-26', 103.449997, 104.150002, 103.190002, 103.800003,
             1322200),
            ('2017-12-27', 103.970001, 105.199997, 103.480003, 104.580002,
             1111800),
            ('2017-12-28', 104.660004, 105.220001, 104.199997, 105.07, 870900),
            ('2017-12-29', 105.040001, 105.650002, 104.529999, 104.830002,
             1068400),
            ('2018-01-02', 105.339996, 107.160004, 104.389999, 107.120003,
             2040600),
            ('2018-01-03', 107.0, 109.779999, 106.989998, 109.379997, 1953800),
            ('2018-01-04', 110.129997, 112.209999, 109.230003, 112.07,
             2158700),
            ('2018-01-05', 113.07, 113.349998, 110.410004, 110.839996,
             2384200),
            ('2018-01-08', 110.419998, 111.739998, 109.040001, 111.419998,
             1782100),
            ('2018-01-09', 111.57, 112.309998, 110.650002, 112.110001,
             1848900),
            ('2018-01-10', 111.709999, 112.610001, 110.550003, 111.470001,
             1645000),
            ('2018-01-11', 111.669998, 113.959999, 111.470001, 113.260002,
             2716000),
            ('2018-01-12', 113.57, 116.089996, 113.07, 115.910004, 2553000),
            ('2018-01-16', 116.239998, 117.080002, 111.720001, 111.980003,
             2699000),
            ('2018-01-17', 112.879997, 113.099998, 111.059998, 113.0, 2932200),
            ('2018-01-18', 112.279999, 114.150002, 112.050003, 112.550003,
             1625200),
            ('2018-01-19', 112.959999, 115.910004, 112.370003, 115.290001,
             2804200),
            ('2018-01-22', 115.25, 118.449997, 114.029999, 117.43, 2905900),
            ('2018-01-23', 117.139999, 119.07, 116.5, 118.730003, 1985400),
            ('2018-01-24', 118.910004, 119.239998, 116.639999, 116.900002,
             2221700),
            ('2018-01-25', 117.949997, 118.419998, 116.57, 116.870003,
             1690400),
            ('2018-01-26', 117.550003, 118.849998, 117.120003, 117.779999,
             1836300),
            ('2018-01-29', 117.699997, 118.470001, 116.190002, 116.379997,
             1058800),
            ('2018-01-30', 115.459999, 116.349998, 113.769997, 115.019997,
             1556400),
            ('2018-01-31', 115.650002, 116.639999, 114.900002, 115.620003,
             1119800),
            ('2018-02-01', 114.720001, 117.699997, 114.080002, 115.57,
             1596400),
            ('2018-02-02', 114.120003, 115.139999, 111.599998, 111.639999,
             1808300),
            ('2018-02-05', 110.599998, 116.150002, 109.18, 109.18, 2890800),
            ('2018-02-06', 106.489998, 112.650002, 104.610001, 112.620003,
             3144800),
            ('2018-02-07', 111.769997, 113.559998, 110.510002, 110.540001,
             1599700),
            ('2018-02-08', 109.169998, 110.800003, 104.809998, 104.809998,
             3056500),
            ('2018-02-09', 105.809998, 107.919998, 101.550003, 105.940002,
             3923900),
            ('2018-02-12', 107.010002, 109.209999, 104.739998, 108.379997,
             1994100),
            ('2018-02-13', 106.5, 110.199997, 106.230003, 109.790001, 1339000),
            ('2018-02-14', 108.360001, 110.339996, 107.410004, 109.919998,
             1923900),
            ('2018-02-15', 111.160004, 114.709999, 110.010002, 113.519997,
             2555000),
            ('2018-02-16', 113.580002, 114.529999, 112.099998, 112.949997,
             1584200),
            ('2018-02-20', 112.510002, 115.059998, 112.0, 114.269997, 1354300),
            ('2018-02-21', 114.18, 115.720001, 112.32, 112.370003, 2045100),
            ('2018-02-22', 112.739998, 114.760002, 111.900002, 112.389999,
             1817200),
            ('2018-02-23', 113.669998, 115.040001, 112.379997, 115.029999,
             1818700),
            ('2018-02-26', 115.629997, 117.5, 114.730003, 116.919998, 2335200),
            ('2018-02-27', 117.0, 117.57, 115.139999, 116.120003, 1658000),
            ('2018-02-28', 117.019997, 119.739998, 116.650002, 117.470001,
             2825400),
            ('2018-03-01', 117.949997, 118.980003, 114.010002, 114.739998,
             2959600),
            ('2018-03-02', 113.300003, 116.43, 111.050003, 116.279999,
             2681700),
            ('2018-03-05', 115.18, 119.300003, 115.050003, 118.870003,
             2502600),
            ('2018-03-06', 119.25, 120.639999, 118.25, 119.870003, 4723900),
            ('2018-03-07', 133.009995, 137.899994, 130.059998, 137.699997,
             12753500),
            ('2018-03-08', 137.009995, 137.690002, 133.940002, 137.289993,
             5255200),
            ('2018-03-09', 138.440002, 140.0, 137.350006, 139.360001, 3752100),
            ('2018-03-12', 139.210007, 141.190002, 138.339996, 138.369995,
             2109300),
            ('2018-03-13', 139.740005, 141.259995, 135.070007, 136.0, 2309000),
            ('2018-03-14', 136.850006, 137.610001, 135.050003, 136.190002,
             1596400),
            ('2018-03-15', 136.690002, 137.919998, 135.429993, 136.720001,
             1319200),
            ('2018-03-16', 136.330002, 139.009995, 135.440002, 135.75,
             2438200),
            ('2018-03-19', 133.940002, 135.460007, 132.059998, 134.309998,
             2047300),
            ('2018-03-20', 134.5, 136.289993, 133.889999, 134.600006, 1760600),
            ('2018-03-21', 135.009995, 137.600006, 133.869995, 135.539993,
             2191000),
            ('2018-03-22', 133.820007, 135.929993, 131.149994,
             131.410004, 2596500),
            ('2018-03-23', 131.75, 132.5, 128.0, 128.020004, 2763400),
            ('2018-03-26', 131.050003, 134.589996, 130.059998, 134.220001,
             2290000),
            ('2018-03-27', 134.529999, 134.589996, 127.190002, 128.309998,
             3043600),
            ('2018-03-28', 127.709999, 129.389999, 124.379997, 124.550003,
             3534500),
            ('2018-03-29', 125.199997, 128.309998, 123.870003, 125.580002,
             4263800),
            ('2018-04-02', 124.559998, 125.800003, 120.800003, 122.75,
             2683300),
            ('2018-04-03', 124.18, 126.440002, 122.209999, 124.839996,
             2292300),
            ('2018-04-04', 121.720001, 128.050003, 121.360001, 127.5, 2573800),
            ('2018-04-05', 128.679993, 129.139999, 126.980003, 128.020004,
             2082200),
            ('2018-04-06', 126.690002, 127.959999, 124.959999, 125.75,
             2527800),
            ('2018-04-09', 126.720001, 129.139999, 126.389999, 127.57,
             1893000),
            ('2018-04-10', 129.25, 132.369995, 128.190002, 131.729996,
             2156900),
            ('2018-04-11', 130.5, 132.660004, 130.070007, 130.940002, 1379900),
            ('2018-04-12', 131.539993, 133.039993, 131.119995, 132.169998,
             1700300),
            ('2018-04-13', 133.550003, 133.550003, 127.980003, 129.169998,
             2023400),
            ('2018-04-16', 130.490005, 131.149994, 128.770004, 129.720001,
             1707600),
            ('2018-04-17', 131.210007, 133.639999, 130.940002, 132.580002,
             2100600),
            ('2018-04-18', 133.190002, 134.729996, 132.080002, 133.869995,
             1321600),
            ('2018-04-19', 133.490005, 134.029999, 131.490005, 132.330002,
             1250800),
            ('2018-04-20', 132.470001, 132.470001, 128.960007, 130.089996,
             1678500),
            ('2018-04-23', 130.639999, 132.039993, 128.289993, 129.179993,
             1370000),
            ('2018-04-24', 130.639999, 131.279999, 122.050003, 123.68,
             2513400),
            ('2018-04-25', 123.720001, 124.650002, 120.910004, 123.970001,
             1978300),
            ('2018-04-26', 124.620003, 127.550003, 123.970001, 126.980003,
             1912800),
            ('2018-04-27', 127.160004, 127.830002, 125.779999, 126.639999,
             1175600),
            ('2018-04-30', 127.32, 128.089996, 125.809998, 125.900002,
             1448500),
            ('2018-05-01', 125.300003, 127.370003, 125.290001, 127.059998,
             1163000),
            ('2018-05-02', 126.82, 127.209999, 124.989998, 125.260002,
             1483200),
            ('2018-05-03', 124.760002, 128.350006, 123.879997, 127.599998,
             1531800),
            ('2018-05-04', 126.489998, 130.679993, 125.589996, 129.460007,
             1632500),
            ('2018-05-07', 129.759995, 132.119995, 129.630005, 131.570007,
             1333400),
            ('2018-05-08', 131.570007, 133.160004, 130.710007, 132.759995,
             1152300),
            ('2018-05-09', 133.070007, 136.369995, 133.070007, 135.320007,
             1678400),
            ('2018-05-10', 135.960007, 137.669998, 134.899994, 136.470001,
             1374600),
            ('2018-05-11', 136.559998, 136.940002, 135.330002, 136.210007,
             1477300),
            ('2018-05-14', 136.990005, 138.380005, 133.330002, 134.110001,
             1698100),
            ('2018-05-15', 133.160004, 137.449997, 131.589996, 136.160004,
             2089000),
            ('2018-05-16', 136.470001, 136.729996, 134.889999, 135.929993,
             1465200),
            ('2018-05-17', 135.410004, 136.830002, 134.580002, 136.520004,
             1404500),
            ('2018-05-18', 136.619995, 139.669998, 136.25, 138.850006,
             1723600),
            ('2018-05-21', 139.610001, 139.940002, 136.929993, 137.669998,
             2474800),
            ('2018-05-22', 138.509995, 139.169998, 136.460007, 136.710007,
             1740500),
            ('2018-05-23', 135.309998, 139.5, 135.020004, 139.309998, 1929600),
            ('2018-05-24', 139.059998, 139.630005, 136.119995, 138.919998,
             4021000),
            ('2018-05-25', 132.710007, 139.690002, 131.149994, 132.75, 6463800)
        ]

        df = DataFrame.from_records(data, columns=labels)
        stock_data_container = StockDataContainer("Autodesk Inc.", "ADSK", "")
        stock_data_container.set_historical_stock_data(df)
        stock_data_container_list = [stock_data_container]

        ##################################################
        # 52 w strategy
        w52hi_parameter_dict = {
            'check_days': 5,
            'min_cnt': 3,
            'min_vol_dev_fact': 1.2,
            'within52w_high_fact': 0.98
        }
        stock_screener = StrategyFactory()
        w52_hi_strat = stock_screener.prepare(
            "W52HighTechnicalStrategy",
            stock_data_container_list=stock_data_container_list,
            analysis_parameters=w52hi_parameter_dict)
        results = w52_hi_strat.run_strategy()
        self.assertEqual(results[0].get_stock_name(),
                         stock_data_container.get_stock_name())
示例#24
0
class TradingBot:
    """
    Class that initialise and hold references of main components like the
    broker interface, the strategy or the epic_ids list
    """
    def __init__(self):
        # Set timezone
        set(pytz.all_timezones_set)

        # Load configuration
        home_path = os.path.expanduser("~")
        config_filepath = "{}/.TradingBot/config/config.json".format(home_path)
        config = self.load_json_file(config_filepath)
        self.read_configuration(config)

        # Read credentials file
        credentials = self.load_json_file(self.credentials_filepath)

        # Setup the global logger
        self.setup_logging()

        # Init trade services and create the broker interface
        self.broker = self.init_trading_services(config, credentials)

        # Create strategy from the factory class
        self.strategy = StrategyFactory(config, self.broker).make_strategy(
            self.active_strategy)

        # Create the market provider
        self.market_provider = MarketProvider(config, self.broker)

    def load_json_file(self, filepath):
        """
        Load a JSON formatted file from the given filepath

            - **filepath** The filepath including filename and extension
            - Return a dictionary of the loaded json
        """
        try:
            with open(filepath, "r") as file:
                return json.load(file)
        except IOError:
            logging.error("File not found ({})".format(filepath))
            exit()

    def read_configuration(self, config):
        """
        Read the configuration from the config json
        """
        home = os.path.expanduser("~")
        self.epic_ids_filepath = config["general"][
            "epic_ids_filepath"].replace("{home}", home)
        self.credentials_filepath = config["general"][
            "credentials_filepath"].replace("{home}", home)
        self.debug_log = config["general"]["debug_log"]
        self.enable_log = config["general"]["enable_log"]
        self.log_file = config["general"]["log_file"].replace("{home}", home)
        self.time_zone = config["general"]["time_zone"]
        self.max_account_usable = config["general"]["max_account_usable"]
        self.active_strategy = config["general"]["active_strategy"]

    def setup_logging(self):
        """
        Setup the global logging settings
        """
        # Define the global logging settings
        debugLevel = logging.DEBUG if self.debug_log else logging.INFO
        # If enabled define log file filename with current timestamp
        if self.enable_log:
            log_filename = self.log_file
            time_str = dt.datetime.now().isoformat()
            time_suffix = time_str.replace(":", "_").replace(".", "_")
            log_filename = log_filename.replace("{timestamp}", time_suffix)
            os.makedirs(os.path.dirname(log_filename), exist_ok=True)
            logging.basicConfig(
                filename=log_filename,
                level=debugLevel,
                format="[%(asctime)s] %(levelname)s: %(message)s",
            )
        else:
            logging.basicConfig(
                level=debugLevel,
                format="[%(asctime)s] %(levelname)s: %(message)s")

    def init_trading_services(self, config, credentials):
        """
        Create instances of the trading services required, such as web interface
        for trading and fetch market data.

            - **config** The configuration json
            - **credentials** The credentials json
            - return: An instance of Broker class initialised
        """
        services = {
            "ig_index": IGInterface(config, credentials),
            "alpha_vantage": AVInterface(credentials["av_api_key"], config),
        }
        return Broker(config, services)

    def start(self):
        """
        Starts the TradingBot main loop
        - process open positions
        - process markets from market source
        - wait for configured wait time
        - start over
        """
        while True:
            try:
                # Process current open positions
                self.process_open_positions()
                # Now process markets from the configured market source
                self.process_market_source()
                # Wait for the next spin before starting over
                self.wait_for_strategy_spin_period()
            except MarketClosedException:
                self.wait_for_next_market_opening()
            except NotSafeToTradeException:
                self.wait_for_strategy_spin_period()
            except StopIteration:
                self.wait_for_strategy_spin_period()
            except Exception as e:
                logging.error("Generic exception caught: {}".format(e))
                logging.debug(traceback.format_exc())
                logging.debug(sys.exc_info()[0])
                continue

    def process_open_positions(self):
        """
        Fetch open positions markets and run the strategy against them closing the
        trades if required
        """
        positions = self.broker.get_open_positions()
        # Do not run until we know the current open positions
        if positions is None:
            logging.warning(
                "Unable to fetch open positions! Will try again...")
            raise RuntimeError("Unable to fetch open positions")
        for epic in [
                item["market"]["epic"] for item in positions["positions"]
        ]:
            market = self.market_provider.get_market_from_epic(epic)
            self.process_market(market, positions)

    def process_market_source(self):
        """
        Process markets from the configured market source
        """
        while True:
            market = self.market_provider.next()
            positions = self.broker.get_open_positions()
            if positions is None:
                logging.warning(
                    "Unable to fetch open positions! Will try again...")
                raise RuntimeError("Unable to fetch open positions")
            self.process_market(market, positions)

    def process_market(self, market, open_positions):
        """Spin the strategy on all the markets"""
        self.safety_checks()
        logging.info("Processing {}".format(market.id))
        try:
            self.strategy.set_open_positions(open_positions)
            trade, limit, stop = self.strategy.run(market)
            self.process_trade(market, trade, limit, stop, open_positions)
        except Exception as e:
            logging.error("Strategy exception caught: {}".format(e))
            logging.debug(traceback.format_exc())
            logging.debug(sys.exc_info()[0])
            return

    def close_open_positions(self):
        """
        Closes all the open positions in the account
        """
        logging.info("Closing all the open positions...")
        if self.broker.close_all_positions():
            logging.info("All the posisions have been closed.")
        else:
            logging.error("Impossible to close all open positions, retry.")

    def wait_for_next_market_opening(self):
        """
        Sleep until the next market opening. Takes into account weekends
        and bank holidays in UK
        """
        seconds = Utils.get_seconds_to_market_opening(dt.datetime.now())
        logging.info("Market is closed! Wait for {0:.2f} hours...".format(
            seconds / 3600))
        time.sleep(seconds)

    def wait_for_strategy_spin_period(self):
        """
        Sleep for the amount of time configured in the active strategy between each spin
        """
        # Wait for next spin loop as configured in the strategy
        seconds = self.strategy.get_seconds_to_next_spin()
        logging.info(
            "Wait for {0:.2f} seconds before next spin".format(seconds))
        time.sleep(seconds)

    def safety_checks(self):
        """
        Perform some safety checks before running the strategy against the next market

        Return True if the trade can proceed, False otherwise
        """
        percent_used = self.broker.get_account_used_perc()
        if percent_used is None:
            logging.warning(
                "Stop trading because can't fetch percentage of account used")
            raise NotSafeToTradeException()
        if percent_used >= self.max_account_usable:
            logging.warning(
                "Stop trading because {}% of account is used".format(
                    str(percent_used)))
            raise NotSafeToTradeException()
        if not Utils.is_market_open(self.time_zone):
            logging.warning("Market is closed: stop processing")
            raise MarketClosedException()

    def process_trade(self, market, direction, limit, stop, open_positions):
        """
        Process a trade checking if it is a "close position" trade or a new trade
        """
        # Perform trade only if required
        if direction is not TradeDirection.NONE:
            if open_positions is not None:
                for item in open_positions["positions"]:
                    # If a same direction trade already exist, don't trade
                    if (item["market"]["epic"] == market.epic and
                            direction.name == item["position"]["direction"]):
                        logging.info(
                            "There is already an open position for this epic, skip trade"
                        )
                        return
                    # If a trade in opposite direction exist, close the position
                    elif (item["market"]["epic"] == market.epic
                          and direction.name != item["position"]["direction"]):
                        self.broker.close_position(item)
                        return
                self.broker.trade(market.epic, direction.name, limit, stop)
            else:
                logging.error(
                    "Unable to fetch open positions! Avoid trading this epic")
示例#25
0
class TradingBot:
    """
    Class that initialise and hold references of main components like the
    broker interface, the strategy or the epic_ids list
    """
    def __init__(self, time_provider=None, config_filepath=None):
        # Time manager
        self.time_provider = time_provider if time_provider else TimeProvider()
        # Set timezone
        set(pytz.all_timezones_set)

        # Load configuration
        self.config = Configuration.from_filepath(config_filepath)

        # Setup the global logger
        self.setup_logging()

        # Init trade services and create the broker interface
        # The Factory is used to create the services from the configuration file
        self.broker = Broker(BrokerFactory(self.config))

        # Create strategy from the factory class
        self.strategy = StrategyFactory(self.config,
                                        self.broker).make_from_configuration()

        # Create the market provider
        self.market_provider = MarketProvider(self.config, self.broker)

    def setup_logging(self):
        """
        Setup the global logging settings
        """
        # Clean logging handlers
        for handler in logging.root.handlers[:]:
            logging.root.removeHandler(handler)

        # Define the global logging settings
        debugLevel = (logging.DEBUG if self.config.is_logging_debug_enabled()
                      else logging.INFO)
        # If enabled define log file filename with current timestamp
        if self.config.is_logging_enabled():
            log_filename = self.config.get_log_filepath()
            time_str = dt.now().isoformat()
            time_suffix = time_str.replace(":", "_").replace(".", "_")
            log_filename = log_filename.replace("{timestamp}", time_suffix)
            os.makedirs(os.path.dirname(log_filename), exist_ok=True)
            logging.basicConfig(
                filename=log_filename,
                level=debugLevel,
                format="[%(asctime)s] %(levelname)s: %(message)s",
            )
        else:
            logging.basicConfig(
                level=debugLevel,
                format="[%(asctime)s] %(levelname)s: %(message)s")

    def start(self):
        """
        Starts the TradingBot main loop
        - process open positions
        - process markets from market source
        - wait for configured wait time
        - start over
        """
        while True:
            try:
                # Process current open positions
                self.process_open_positions()
                # Now process markets from the configured market source
                self.process_market_source()
                # Wait for the next spin before starting over
                self.time_provider.wait_for(TimeAmount.SECONDS,
                                            self.config.get_spin_interval())
            except MarketClosedException:
                logging.warning("Market is closed: stop processing")
                self.time_provider.wait_for(TimeAmount.NEXT_MARKET_OPENING)
            except NotSafeToTradeException:
                self.time_provider.wait_for(TimeAmount.SECONDS,
                                            self.config.get_spin_interval())
            except StopIteration:
                self.time_provider.wait_for(TimeAmount.SECONDS,
                                            self.config.get_spin_interval())
            except Exception as e:
                logging.error("Generic exception caught: {}".format(e))
                logging.error(traceback.format_exc())
                continue

    def process_open_positions(self):
        """
        Fetch open positions markets and run the strategy against them closing the
        trades if required
        """
        positions = self.broker.get_open_positions()
        # Do not run until we know the current open positions
        if positions is None:
            logging.warning(
                "Unable to fetch open positions! Will try again...")
            raise RuntimeError("Unable to fetch open positions")
        for epic in [item.epic for item in positions]:
            market = self.market_provider.get_market_from_epic(epic)
            self.process_market(market, positions)

    def process_market_source(self):
        """
        Process markets from the configured market source
        """
        while True:
            market = self.market_provider.next()
            positions = self.broker.get_open_positions()
            if positions is None:
                logging.warning(
                    "Unable to fetch open positions! Will try again...")
                raise RuntimeError("Unable to fetch open positions")
            self.process_market(market, positions)

    def process_market(self, market, open_positions):
        """Spin the strategy on all the markets"""
        self.safety_checks()
        logging.info("Processing {}".format(market.id))
        try:
            self.strategy.set_open_positions(open_positions)
            trade, limit, stop = self.strategy.run(market)
            self.process_trade(market, trade, limit, stop, open_positions)
        except Exception as e:
            logging.error("Strategy exception caught: {}".format(e))
            logging.error(traceback.format_exc())
            return

    def close_open_positions(self):
        """
        Closes all the open positions in the account
        """
        logging.info("Closing all the open positions...")
        if self.broker.close_all_positions():
            logging.info("All the posisions have been closed.")
        else:
            logging.error("Impossible to close all open positions, retry.")

    def safety_checks(self):
        """
        Perform some safety checks before running the strategy against the next market

        Raise exceptions if not safe to trade
        """
        percent_used = self.broker.get_account_used_perc()
        if percent_used is None:
            logging.warning(
                "Stop trading because can't fetch percentage of account used")
            raise NotSafeToTradeException()
        if percent_used >= self.config.get_max_account_usable():
            logging.warning(
                "Stop trading because {}% of account is used".format(
                    str(percent_used)))
            raise NotSafeToTradeException()
        if not self.time_provider.is_market_open(self.config.get_time_zone()):
            raise MarketClosedException()

    def process_trade(self, market, direction, limit, stop, open_positions):
        """
        Process a trade checking if it is a "close position" trade or a new trade
        """
        # Perform trade only if required
        if direction is not TradeDirection.NONE:
            if open_positions is not None:
                for item in open_positions["positions"]:
                    # If a same direction trade already exist, don't trade
                    if (item["market"]["epic"] == market.epic and
                            direction.name == item["position"]["direction"]):
                        logging.info(
                            "There is already an open position for this epic, skip trade"
                        )
                        return
                    # If a trade in opposite direction exist, close the position
                    elif (item["market"]["epic"] == market.epic
                          and direction.name != item["position"]["direction"]):
                        self.broker.close_position(item)
                        return
                self.broker.trade(market.epic, direction, limit, stop)
            else:
                logging.error(
                    "Unable to fetch open positions! Avoid trading this epic")

    def backtest(self, market_id, start_date, end_date, epic_id=None):
        """
        Backtest a market using the configured strategy
        """
        try:
            start = dt.strptime(start_date, "%Y-%m-%d")
            end = dt.strptime(end_date, "%Y-%m-%d")
        except ValueError as e:
            logging.error("Wrong date format! Must be YYYY-MM-DD")
            logging.debug(e)
            exit(1)

        bt = Backtester(self.broker, self.strategy)

        try:
            market = (self.market_provider.search_market(market_id)
                      if epic_id is None or epic_id is "" else
                      self.market_provider.get_market_from_epic(epic_id))
        except Exception as e:
            logging.error(e)
            exit(1)

        bt.start(market, start, end)
        bt.print_results()
    def test_run_strategy_with_two_news_for_one_stock(self):
        name_idx = 0
        datetime_idx = 1
        w52hi_parameter_dict = {
            'check_days': 5,
            'min_cnt': 3,
            'min_vol_dev_fact': 1.2,
            'within52w_high_fact': 0.98
        }
        parameter_dict = {
            'news_threshold': 0.7,
            'german_tagger': filepath + 'nltk_german_classifier_data.pickle'
        }

        labels = []
        for key, value in GlobalVariables.get_stock_data_labels_dict().items():
            labels.append(value)
        data = [('2016-09-30', 23.35, 23.91, 23.24, 23.8, 31000),
                ('2016-10-03', 23.68, 23.69, 23.39, 23.5, 31000),
                ('2016-10-04', 23.52, 23.64, 23.18, 23.28, 31000),
                ('2016-10-05', 23.28, 23.51, 23.27, 23.43, 31000),
                ('2016-10-06', 23.38, 23.56, 23.29, 23.48, 42000),
                ('2016-10-07', 23.58, 23.65, 23.37, 23.48, 43000),
                ('2016-10-10', 23.62, 23.88, 23.55, 23.77, 44000),
                ('2016-10-11', 23.62, 23.74, 23.01, 23.16, 45000),
                ('2016-10-12', 23.16, 23.8, 23.11, 23.18, 46000)]

        df = DataFrame.from_records(data, columns=labels)

        apple_stock_data_container = NewsDataContainerDecorator(
            StockDataContainer("Apple Inc.", "AAPL", ""), 0, 0,
            "ANALYSE-FLASH: Credit Suisse nimmt Apple mit 'Underperform' wieder auf"
        )
        apple_stock_data_container_2 = NewsDataContainerDecorator(
            StockDataContainer("Apple Inc.", "AAPL", ""), 0, 0,
            "ANALYSE-FLASH: Sparkasse hebt Apple auf 'Buy' und Ziel auf 97 Euro"
        )
        apple_stock_data_container.set_historical_stock_data(df)
        apple_stock_data_container_2.set_historical_stock_data(df)
        stock_data_container_list = [
            apple_stock_data_container, apple_stock_data_container_2
        ]

        stock_screener = StrategyFactory()
        news_strategy = stock_screener.prepare(
            "SimplePatternNewsStrategy",
            stock_data_container_list=stock_data_container_list,
            analysis_parameters=parameter_dict)

        news_strategy.run_strategy()
        self.assertEqual(
            "SELL",
            stock_data_container_list[0].get_recommendation_strategies()
            ["SimplePatternNewsStrategy"][name_idx])

        self.assertEqual(
            "BUY",
            stock_data_container_list[1].get_recommendation_strategies()
            ["SimplePatternNewsStrategy"][name_idx])

        # 52 wh strat ####################################
        w52_hi_strat = stock_screener.prepare(
            "W52HighTechnicalStrategy",
            stock_data_container_list=stock_data_container_list,
            analysis_parameters=w52hi_parameter_dict)
        w52_hi_strat.run_strategy()

        self.assertEqual(stock_data_container_list[0].get_stock_name(),
                         "Apple Inc.")
        self.assertEqual(
            "BUY",
            stock_data_container_list[0].get_recommendation_strategies()
            ["W52HighTechnicalStrategy"][name_idx])
        self.assertEqual(
            "BUY",
            stock_data_container_list[1].get_recommendation_strategies()
            ["W52HighTechnicalStrategy"][name_idx])

        dt = parser.parse(
            stock_data_container_list[0].get_recommendation_strategies()
            ["W52HighTechnicalStrategy"][datetime_idx])
        elapsed = datetime.now() - dt
        self.assertGreater(timedelta(seconds=0.1), elapsed)

        self.assertEqual(
            "SELL",
            stock_data_container_list[0].get_recommendation_strategies()
            ["SimplePatternNewsStrategy"][name_idx])

        self.assertEqual(
            "BUY",
            stock_data_container_list[1].get_recommendation_strategies()
            ["SimplePatternNewsStrategy"][name_idx])
    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)
示例#28
0
class BacktraderStrategyWrapper(bt.Strategy):
    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 __init__(self, **kwargs):
        """
        Init method to wrap the ASTA-Strategy to the bt.Strategy
        :param kwargs: Dict with parameters for testing, the Key "strategy_to_test" contains the strategy class to test.
        """

        # Keep a reference to the "close" line in the data[0] dataseries
        self.dataclose = self.datas[0].close
        self.datavol = self.datas[0].volume
        self.datahi = self.datas[0].high
        self.datalo = self.datas[0].low
        self.buy_price = 0

        # set the given values in self
        for key, value in kwargs.items():
            setattr(self, key, value)

        # To keep track of pending orders and buy price/commission
        self.order = None
        self.buyprice = None
        self.buycomm = None
        self.highest_high = 0  # max (self.datahi)
        self.buyCnt = 0

        self.stock_screener = StrategyFactory()

        # the parameter dict contains the strategy which is build with the string
        self.strategy_instance = self.stock_screener.prepare(
            self.strategy_to_test, **kwargs)

        # only one risk model can be used, the first risk model to be taken
        first_rm_key = list(self.risk_model.keys())[0]
        self.curr_risk_model = self.risk_model[first_rm_key]
        self.order_target_method = self._get_order_target(
            self.curr_risk_model['OrderTarget'])
        self.news_data_dict = {}

        # add the news text because backtrader does not support news
        # data from pandas do not have a name --> not add news
        for i, hist_data in enumerate(self.datas):
            dataname = hist_data._dataname
            if isinstance(dataname, str) and os.path.exists(dataname):
                news_data = pd.read_csv(dataname)
                self.news_data_dict.update({dataname: news_data})

    ###############
    def notify_order(self, order):
        date = self.data.datetime.datetime().date()

        if order.status == order.Accepted:
            self._log_order(date, order, "Accepted")

        if order.status == order.Completed:
            self._log_order(date, order, "Completed")

        if order.status == order.Canceled:
            self._log_order(date, order, "Canceled")

        if order.status == order.Rejected:
            self._log_order(date, order, "Rejected")

    def notify_trade(self, trade):
        date = self.data.datetime.datetime()
        if trade.isclosed:
            logger.info('---------  NOTIFY TRADE  ---------')
            logger.info(
                '   {}, Close Price: {}, Profit, Gross {}, Net {}'.format(
                    date, trade.price, trade.data._name, round(trade.pnl, 2),
                    round(trade.pnlcomm, 2)))
            logger.info('----------')

    ###########

    def next(self):
        """
        Method which is executed while running backtest.
        Must implement the real strategy.
        :return:
        """

        try:
            # TODO https://backtest-rookies.com/2017/08/22/backtrader-multiple-data-feeds-indicators/

            for i, hist_data in enumerate(self.datas):
                from datetime import datetime
                stock_data_container_list = []
                date_time = self.datetime.date()
                stock_name = hist_data._name

                self.log('Close: ' + str(hist_data.close[0]) + ", volume: " +
                         str(hist_data.volume[0]) + ', Datasource: ' +
                         str(stock_name))

                # TODO print anything to indicate a news in gui
                # TODO https://www.backtrader.com/docu/extending-a-datafeed.html
                # TODO ex: btind.SMA(self.data.pe, period=1, subplot=False) for data of classification

                convert_backtrader_to_asta_data(hist_data, self.news_data_dict,
                                                date_time,
                                                stock_data_container_list)
                # test only one strategy, first one --> [0]
                # TODO 11: result list wird nie zurückgesetzt --> immer mehr, [0] ist dann falsch
                result_list = self.strategy_instance.run_strategy(
                    stock_data_container_list)

                pos = self.getposition(hist_data).size
                # Check if we are in the market
                if not pos:
                    # TODO insert sell for short strategies too
                    # check if buy
                    try:
                        if len(result_list) > 0 and 'buy' in \
                                result_list[0].get_recommendation_strategies()[self.strategy_to_test][
                                    0].lower():
                            # test only first risk model --> [0]
                            rm_factory = RiskModelFactory()
                            first_rm_key = list(self.risk_model.keys())[0]
                            risk_model = self.risk_model[first_rm_key]
                            fsr = rm_factory.prepare(
                                first_rm_key,
                                stock_data_container_list=result_list,
                                parameter_dict=risk_model)
                            fsr.determine_risk()

                            # TODO checken ob da ned zwei stop order draus gemacht werden
                            # --> TODO order long - stop bearbeiten
                            # einstiegskurs nicht nach strategie sondern gleich

                            # buy the stock
                            self.buy_price = hist_data.close[0]
                            buy_ord = self.order_target_method(
                                data=hist_data,
                                target=self.curr_risk_model['TargetValue'])
                            buy_ord.addinfo(name="Long Market Entry")

                            # get the stop loss value to minimize risk
                            long_stop = result_list[0].get_stop_loss()
                            stop_size = buy_ord.size - abs(self.position.size)
                            self.sl_ord = self.sell(data=hist_data,
                                                    size=stop_size,
                                                    exectype=bt.Order.Stop,
                                                    price=long_stop)
                            self.sl_ord.addinfo(name='Long Stop Loss')
                    except Exception as e:
                        print(e)

                # sell order, if already have stocks
                elif len(result_list) > 0 and 'sell' in \
                        result_list[0].get_recommendation_strategies()[self.strategy_to_test][
                            0].lower():
                    self.sell_ord = self.sell(data=hist_data,
                                              exectype=bt.Order.Sell)
                    self.sell_ord.addinfo(name='Sell Order')

        except Exception as e:
            print(e)

    def _get_order_target(self, order_type_str):
        """
        Get the method of the backtrader order target.
        size -> amount of shares, contracts in the portfolio of a specific asset
        value -> value in monetary units of the asset in the portfolio
        percent -> percentage (from current portfolio) value of the asset in the current portfolio
        :param order_type_str: type or part of the type as string
        :return: target bounded method
        """
        order_target = None

        if order_type_str in "order_target_size":
            order_target = self.order_target_size
        elif order_type_str in "order_target_value":
            order_target = self.order_target_value
        elif order_type_str in "order_target_percent":
            order_target = self.order_target_percent
        else:
            raise NotImplementedError("Order target " + str(order_type_str) +
                                      " is not implemented!")

        return order_target

    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)))
示例#29
0
    def test_StockDataContainer_run_and_fill_with__W52HighTechnicalStrategy_BUY__and_SimplePatternNewsStrategy_BUY(
            self):
        w52hi_parameter_dict = {
            'check_days': 5,
            'min_cnt': 3,
            'min_vol_dev_fact': 1.2,
            'within52w_high_fact': 0.98
        }

        labels = []
        for key, value in GlobalVariables.get_stock_data_labels_dict().items():
            labels.append(value)
        data = [('2016-09-30', 23.35, 23.91, 23.24, 23.8, 31000),
                ('2016-10-03', 23.68, 23.69, 23.39, 23.5, 31000),
                ('2016-10-04', 23.52, 23.64, 23.18, 23.28, 31000),
                ('2016-10-05', 23.28, 23.51, 23.27, 23.43, 31000),
                ('2016-10-06', 23.38, 23.56, 23.29, 23.48, 42000),
                ('2016-10-07', 23.58, 23.65, 23.37, 23.48, 43000),
                ('2016-10-10', 23.62, 23.88, 23.55, 23.77, 44000),
                ('2016-10-11', 23.62, 23.74, 23.01, 23.16, 45000),
                ('2016-10-12', 23.16, 26, 23.11, 23.18, 46000)]

        df = DataFrame.from_records(data, columns=labels)
        stock_data_container = NewsDataContainerDecorator(
            StockDataContainer("Apple Inc.", "AAPL", ""), 0, 0,
            "ANALYSE-FLASH: Credit Suisse nimmt Apple mit 'Outperform' wieder auf, BUY"
        )
        stock_data_container.set_historical_stock_data(df)
        stock_data_container_list = [stock_data_container]
        ##################################################
        # 52 w strategy
        stock_screener = StrategyFactory()
        w52_hi_strat = stock_screener.prepare(
            "W52HighTechnicalStrategy",
            stock_data_container_list=stock_data_container_list,
            analysis_parameters=w52hi_parameter_dict)
        # results = w52_hi_strat.run_strategy()
        w52_hi_strat.run_strategy()
        self.assertGreater(len(stock_data_container_list), 0)
        self.assertEqual(
            "BUY",
            stock_data_container_list[0].get_recommendation_strategies()
            ["W52HighTechnicalStrategy"][0])

        dt = parser.parse(
            stock_data_container_list[0].get_recommendation_strategies()
            ["W52HighTechnicalStrategy"][1])
        elapsed = datetime.now() - dt
        self.assertGreater(timedelta(seconds=0.011), elapsed)
        # stock_data_container_list = results

        ##############################
        # SimplePatternNewsStrategy
        parameter_dict = {
            'news_threshold': 0.7,
            'german_tagger': filepath + 'nltk_german_classifier_data.pickle'
        }

        stock_screener = StrategyFactory()
        news_strategy = stock_screener.prepare(
            "SimplePatternNewsStrategy",
            stock_data_container_list=stock_data_container_list,
            analysis_parameters=parameter_dict)

        news_strategy.run_strategy()
        self.assertEqual(stock_data_container_list[0].get_stock_name(),
                         "Apple Inc.")
        self.assertEqual(
            "BUY",
            stock_data_container_list[0].get_recommendation_strategies()
            ["W52HighTechnicalStrategy"][0])
        self.assertEqual(
            "BUY",
            stock_data_container_list[0].get_recommendation_strategies()
            ["SimplePatternNewsStrategy"][0])
    def test_dump_and_load_other_parameter_to_file(self):
        global val, w, root
        root = Tk()
        top = ASTA_Framework(root)
        controller = MvcController.init(root, top)

        data_file_path = GlobalVariables.get_data_files_path()

        strat_param_file = data_file_path + '\\TestData\\ParameterFile_test_dump_and_load_strat_params.pickle'
        FileUtils.check_file_exists_and_delete(strat_param_file)

        strategy_parameter_dict = {
            'SimplePatternNewsStrategy': {
                'news_threshold': 0.7,
                'german_tagger':
                data_file_path + 'nltk_german_classifier_data.pickle',
                'data_readers': {
                    'TraderfoxNewsDataReader': {
                        'last_check_date_file':
                        data_file_path + 'TestData\\last_date_time.csv',
                        'german_tagger':
                        data_file_path + 'nltk_german_classifier_data.pickle',
                        'reload_data': True,
                        'ticker_needed': False
                    },
                    'HistoricalDataReader': {
                        'weeks_delta': 52,
                        'data_source': 'iex',
                        'reload_data': True,
                        'ticker_needed': False
                    }
                }
            },
            'W52HighTechnicalStrategy': {
                'check_days': 7,
                'min_cnt': 3,
                'min_vol_dev_fact': 1.2,
                'within52w_high_fact': 0.98,
                'data_readers': {
                    'HistoricalDataReader': {
                        'weeks_delta': 52,
                        'data_source': 'iex',
                        'reload_data': False,
                        'ticker_needed': True
                    }
                }
            }
        }
        stock_data_file = data_file_path + 'TestData\\stock_data_container_file.pickle'
        other_params = {
            'stock_data_container_file': stock_data_file,
            'dict_with_stock_pages_to_read': {
                'SP500': {
                    'websource_address':
                    "http://en.wikipedia.org/wiki/List_of_S%26P_500_companies",
                    'find_name': 'table',
                    'class_name': 'class',
                    'table_class': 'wikitable sortable',
                    'ticker_column_to_read': 0,
                    'name_column_to_read': 1,
                    'stock_exchange': 'en'
                }
            },
            'RiskModels': {
                'FixedSizeRiskModel': {
                    'OrderTarget': 'order_target_value',
                    'TargetValue': 2500
                }
            }
        }

        params = {
            'Strategies': strategy_parameter_dict,
            'OtherParameters': other_params
        }
        req_params = StrategyFactory.get_required_parameters_with_default_parameters(
        )
        controller.dump_analysis_parameters_to_file(strat_param_file, params,
                                                    req_params)

        controller.load_analysis_parameters_from_file(strat_param_file,
                                                      req_params)
        self.assertEqual(ast.literal_eval(params),
                         controller.model.analysis_parameters.get(),
                         req_params)