def test_read_price_metrics_with_exception(self):
        with patch.object(intrinio_data, 'get_daily_stock_close_prices',
                          return_value={
                "2020-06-09": 54.74
                          }), \
            patch.object(intrinio_data, 'get_sma_indicator',
                         return_value={
                "2020-06-09": 43.80299999999999
                             }), \
            patch.object(intrinio_data, 'get_macd_indicator',
                         return_value={
                "2020-06-09": {
                "macd_histogram": 9111766583116911,
                "macd_line": 2.085415403516656,
                "signal_line": 1.1742387452049647
                }
                             }):

            ticker_file_path = "%s/djia30.json" % constants.TICKER_DATA_DIR

            macd_strategy = MACDCrossoverStrategy(self.ticker_list,
                                                  date(2020, 6, 8), 0.0016, 12,
                                                  26, 9)

            with self.assertRaises(ValidationError):
                macd_strategy._read_price_metrics('AAPL')
    def test_analyze_security_3(self):
        '''
            Significant divergence. both MACD and Signal negative 
        '''

        macd_strategy = MACDCrossoverStrategy(self.ticker_list,
                                              date(2020, 6, 10), 0.0016, 12,
                                              26, 9)

        current_price = 100
        macd_line = -10
        signal_line = -9

        self.assertFalse(
            macd_strategy._analyze_security(current_price, macd_line,
                                            signal_line))
    def test_analyze_security_2(self):
        '''
            No significant divergence. Both MACD and histogram positive
        '''

        macd_strategy = MACDCrossoverStrategy(self.ticker_list,
                                              date(2020, 6, 10), 0.0016, 12,
                                              26, 9)

        current_price = 100
        macd_line = 10
        signal_line = 9.9

        self.assertTrue(
            macd_strategy._analyze_security(current_price, macd_line,
                                            signal_line))
    def test_analyze_security_7(self):
        '''
            No Significant divergence. MACD negative, Signal positive 
        '''

        macd_strategy = MACDCrossoverStrategy(self.ticker_list,
                                              date(2020, 6, 10), 0.0016, 12,
                                              26, 9)

        current_price = 100
        macd_line = -0.01
        signal_line = 0.01

        self.assertTrue(
            macd_strategy._analyze_security(current_price, macd_line,
                                            signal_line))
    def test_read_price_metrics(self):
        with patch.object(intrinio_data, 'get_daily_stock_close_prices',
                          return_value=self.price_dict), \
            patch.object(intrinio_data, 'get_sma_indicator',
                         return_value=self.sma_dict), \
            patch.object(intrinio_data, 'get_macd_indicator',
                         return_value=self.macd_dict):

            macd_strategy = MACDCrossoverStrategy(self.ticker_list,
                                                  date(2020, 6, 8), 0.0016, 12,
                                                  26, 9)

            (current_price, macd_line,
             signal_line) = macd_strategy._read_price_metrics('AAPL')

            self.assertEqual(current_price, 54.74)
            self.assertEqual(macd_line, 2.085415403516656)
            self.assertEqual(signal_line, 1.1742387452049647)
def main():
    '''
        Main testing script
    '''
    try:

        ticker_list = TickerList.from_local_file("%s/djia30.json" %
                                                 (constants.APP_DATA_DIR))

        config = Configuration.try_from_s3(constants.STRATEGY_CONFIG_FILE_NAME,
                                           'sa')

        #macd_strategy = MACDCrossoverStrategy.from_configuration(config, 'sa')
        macd_strategy = MACDCrossoverStrategy(ticker_list, date(2020, 6, 16),
                                              0.0016, 12, 16, 9)
        macd_strategy.generate_recommendation()
        macd_strategy.display_results()
        '''
        #pd_strategy = PriceDispersionStrategy.from_configuration(config, 'sa')
        pd_strategy = PriceDispersionStrategy(
            ticker_list, '2020-06', date(2020, 5, 16), 3)
        pd_strategy.generate_recommendation()
        pd_strategy.display_results()
        '''

    except Exception as e:
        log.error("Could run script, because, %s" % (str(e)))
    def test_recommendation_set_dates(self):

        price_date = date(2020, 6, 8)
        with patch.object(intrinio_data, 'get_daily_stock_close_prices',
                          return_value=self.price_dict), \
            patch.object(intrinio_data, 'get_sma_indicator',
                         return_value=self.sma_dict), \
            patch.object(intrinio_data, 'get_macd_indicator',
                         return_value=self.macd_dict):

            strategy = MACDCrossoverStrategy(self.ticker_list, price_date,
                                             0.0016, 12, 26, 9)

            strategy.generate_recommendation()

            recommendation_set = strategy.recommendation_set

            self.assertEqual(recommendation_set.model['valid_from'],
                             str(date(2020, 6, 8)))
            self.assertEqual(recommendation_set.model['valid_to'],
                             str(date(2020, 6, 8)))
            self.assertEqual(recommendation_set.model['price_date'],
                             str(date(2020, 6, 8)))
    def test_from_configuration_valid(self):

        ticker_list = TickerList.from_local_file("%s/djia30.json" %
                                                 (constants.APP_DATA_DIR))

        price_date = date(2020, 6, 3)

        with patch.object(util, 'get_business_date',
                          return_value=price_date), \
            patch.object(TickerList, 'from_s3',
                         return_value=ticker_list):

            strategy = MACDCrossoverStrategy.from_configuration(
                Configuration.from_local_config(
                    constants.STRATEGY_CONFIG_FILE_NAME), 'sa')

            self.assertEqual(strategy.analysis_date, price_date)
def main():
    """
        Main Function for this script
    """

    description = """
                Executes a backtest for the MACD_CROSSOVER strategy given a ticker list,
                start date, end date and threshold, e.g. -0.02, used to determine the maximum
                allowed loss of a trade before a stop loss takes effect.
              """

    parser = argparse.ArgumentParser(description=description)
    parser.add_argument("-ticker_list",
                        help="Ticker List File",
                        type=str,
                        required=True)
    date_parser = lambda s: datetime.strptime(s, '%Y/%m/%d')
    parser.add_argument("-start_date",
                        help="Backtest start date (YYY/MM/DD)",
                        type=date_parser,
                        required=True)
    parser.add_argument("-end_date",
                        help="Backtest end date (YYYY/MM/DD)",
                        type=date_parser,
                        required=True)
    parser.add_argument("-stop_loss_theshold",
                        help="Stop Loss Threshold factor, e.g. -0.02 (-2%%)",
                        type=float,
                        required=True)

    args = parser.parse_args()

    ticker_file_name = args.ticker_list
    start_date = args.start_date
    end_date = args.end_date
    stop_loss_theshold = args.stop_loss_theshold

    log.info("Parameters:")
    log.info("Ticker File: %s" % ticker_file_name)
    log.info("Start Date: %s" % start_date)
    log.info("End Date: %s" % end_date)
    log.info("Stop Loss Threshold: %.2f" % stop_loss_theshold)

    log.info("")
    log.info("MACD Configuration:")
    log.info("Divergence Tolerance Factor: %f" % DIVERGENCE_FACTOR_THRESHOLD)
    log.info("Slow Period: %d" % SLOW_PERIOD)
    log.info("Fast Period: %d" % FAST_PERIOD)
    log.info("Signal Period: %d" % SIGNAL_PERIOD)

    log.info("")

    ticker_list = TickerList.from_local_file(
        "%s/%s" % (constants.TICKER_DATA_DIR, ticker_file_name))

    trade_dict = {
        'ticker': [],
        'buy_date': [],
        'buy_price': [],
        'sell_date': [],
        'sell_price': [],
        'trade_pnl_factor': [],
        'false_signal': []
    }

    try:
        date_list = get_business_date_list(start_date, end_date)
        init_portfolio_dict(ticker_list)

        for i in range(0, len(date_list) - 1):
            recommendation_date = date_list[i]
            trade_date = date_list[i + 1]

            strategy = MACDCrossoverStrategy(ticker_list, recommendation_date,
                                             DIVERGENCE_FACTOR_THRESHOLD,
                                             FAST_PERIOD, SLOW_PERIOD,
                                             SIGNAL_PERIOD)
            strategy.generate_recommendation()

            print("processing: %s" % recommendation_date, end="\r")

            unwound_positions = trade(trade_date, strategy.recommendation_set)

            for position in unwound_positions:
                (ticker, buy_date, sell_date, buy_price) = position

                sell_price = get_close_price(ticker, sell_date)
                pnl = ((sell_price / buy_price) - 1)
                false_signal = 0

                if (pnl < stop_loss_theshold):
                    sell_price = 'STOP_LOSS'
                    false_signal = 1
                    pnl = stop_loss_theshold

                if (pnl < 0):
                    false_signal = 1

                trade_dict['ticker'].append(ticker)
                trade_dict['buy_date'].append(buy_date)
                trade_dict['buy_price'].append(buy_price)
                trade_dict['sell_date'].append(str(sell_date))
                trade_dict['sell_price'].append(sell_price)
                trade_dict['trade_pnl_factor'].append(pnl)
                trade_dict['false_signal'].append(false_signal)

        trades_by_ticker = []
        for ticker in ticker_list.model['ticker_symbols']:
            trades_by_ticker.append(calculate_returns(ticker, trade_dict))
        trade_dataframe = pd.concat(trades_by_ticker)

        display_results(trade_dataframe)

    except Exception as e:
        log.error("Could run script, because, %s" % (str(e)))
        raise e
def main():
    """
        Main function for this script
    """
    try:
        app_ns = parse_params()

        log.info("Parameters:")
        log.info("Application Namespace: %s" % app_ns)

        business_date = util.get_business_date(
            constants.BUSINESS_DATE_DAYS_LOOKBACK, constants.BUSINESS_DATE_CUTOVER_TIME)
        log.info("Business Date is: %s" % business_date)

        # test all connectivity upfront, so if there any issues
        # the problem becomes more apparent
        connector_test.test_aws_connectivity()
        connector_test.test_intrinio_connectivity()

        log.info('Loading Strategy Configuration "%s" from S3' %
                 constants.STRATEGY_CONFIG_FILE_NAME)
        configuration = Configuration.try_from_s3(
            constants.STRATEGY_CONFIG_FILE_NAME, app_ns)

        log.info("Initalizing Trading Strategies")
        strategies = [
            PriceDispersionStrategy.from_configuration(configuration, app_ns),
            MACDCrossoverStrategy.from_configuration(configuration, app_ns)
        ]

        notification_list = []
        for strategy in strategies:
            recommendation_set = None
            try:
                log.info("Executing %s strategy" % strategy.STRATEGY_NAME)
                recommendation_set = SecurityRecommendationSet.from_s3(
                    app_ns, strategy.S3_RECOMMENDATION_SET_OBJECT_NAME)
            except AWSError as awe:
                if not awe.resource_not_found():
                    raise awe
                log.info("No recommendation set was found in S3.")

            if recommendation_set == None  \
                    or not recommendation_set.is_current(business_date):

                strategy.generate_recommendation()
                strategy.display_results()

                recommendation_set = strategy.recommendation_set

                recommendation_set.save_to_s3(
                    app_ns, strategy.S3_RECOMMENDATION_SET_OBJECT_NAME)

                notification_list.append(recommendation_set)
            else:
                log.info(
                    "Recommendation set is still valid. There is nothing to do")

        recommendation_svc.notify_new_recommendation(
            notification_list, app_ns)
    except Exception as e:
        stack_trace = traceback.format_exc()
        log.error("Could run script, because: %s" % (str(e)))
        log.error(stack_trace)
 def test_from_configuration_invalid(self):
     with patch('support.constants.CONFIG_FILE_PATH',
                "./test/config-unittest-bad/"):
         bad_config = Configuration.from_local_config("bad-test-config.ini")
         with self.assertRaises(ValidationError):
             MACDCrossoverStrategy.from_configuration(bad_config, 'sa')