def notify_new_recommendation(recommendation_set: object, app_ns: str):
    '''
        Sends an SNS notification indicating that a new recommendation has been generated

        Parameters
        ----------
        recommendation_set: object
            the SecurityRecommendationSet object repr
        app_ns: str
            The application namespace supplied to the command line
            used to identify the appropriate CloudFormation exports
    '''

    recommnedation_month = parser.parse(recommendation_set.model['valid_to'])

    formatted_ticker_message = ""
    for security in recommendation_set.model['securities_set']:
        formatted_ticker_message += "Ticker Symbol: %s\n" % security[
            'ticker_symbol']

    sns_topic_arn = aws_service_wrapper.cf_read_export_value(
        constants.sns_app_notifications_topic_arn(app_ns))
    subject = "New Stock Recommendation Available"
    message = "A New Stock Recommendation is available for the month of %s\n" % recommnedation_month.strftime(
        "%B, %Y")
    message += "\n\n"
    message += formatted_ticker_message

    log.info("Publishing Recommendation set to SNS topic: %s" % sns_topic_arn)
    aws_service_wrapper.sns_publish_notification(sns_topic_arn, subject,
                                                 message)
def publish_current_returns(updated_portfolio: object, updated: bool, app_ns: str):
    '''
        publishes current returns as a SNS notifcation, given an updated portfolio
    '''

    sns_topic_arn = aws_service_wrapper.cf_read_export_value(
        constants.sns_app_notifications_topic_arn(app_ns))
    subject = "Portfolio Update - "

    if updated == True:
        subject = "Stock Advisor Update - New Portfolio was created"
    else:
        subject = "Stock Advisor Update - Portfolio Returns"

    creation_date = parser.parse(updated_portfolio.model['creation_date'])
    price_date = parser.parse(updated_portfolio.model['price_date'])

    message = "Portfolio was created on: %s\n" % datetime.strftime(
        creation_date.astimezone(get_localzone()), '%Y/%m/%d %I:%M %p (%Z)')
    message += "Price date is: %s\n\n" % datetime.strftime(
        price_date, '%Y/%m/%d')
    for security in updated_portfolio.model['current_portfolio']['securities']:
        message += "Symbol: %s\n" % security['ticker_symbol']
        message += "Purchase Price: %.2f\n" % security[
            'purchase_price']
        message += "Current Price: %.2f (%+d%%)\n" % (
            security['current_price'], round(security['current_returns'] * 100))
        message += "\n"

    log.info("Publishing portfolio update to SNS topic: %s" % sns_topic_arn)
    aws_service_wrapper.sns_publish_notification(
        sns_topic_arn, subject, message)
    def from_s3_bucket(cls, ticker_object_name: str, app_ns: str):
        '''
            Creates a TickerFile object instane based on an S3 bucket.
            The bucket is detrmined by looking at the system's ClouFormation
            exports.

            Parameters
            ----------
            ticker_object_name : str
                S3 object name
            app_ns : str
                Application namespace used to identify the appropriate
                CloudFormation exports
        '''

        s3_object_path = "%s/%s" % (constants.S3_TICKER_FILE_FOLDER_PREFIX,
                                    ticker_object_name)
        destination_path = "%s/%s" % (constants.APP_DATA_DIR,
                                      ticker_object_name)

        log.debug(
            "Reading S3 Data Bucket location from CloudFormation Exports")
        s3_data_bucket_name = aws_service_wrapper.cf_read_export_value(
            constants.s3_data_bucket_export_name(app_ns))

        util.create_dir(constants.APP_DATA_DIR)
        log.debug("Downloading s3://%s --> %s" %
                  (s3_object_path, destination_path))

        try:
            aws_service_wrapper.s3_download_object(s3_data_bucket_name,
                                                   s3_object_path,
                                                   destination_path)
        except AWSError as awe:
            if "(404)" in str(awe) and "Not Found" in str(awe):
                log.debug(
                    "File not found in S3. Looking for local alternatives")

                # Attempt to upload a local copy of the file if it exists
                local_ticker_path = '%s/%s' % (constants.TICKER_DATA_DIR,
                                               ticker_object_name)

                if os.path.isfile(local_ticker_path):
                    log.debug("Attempting to upload %s --> s3://%s/%s" %
                              (local_ticker_path, s3_data_bucket_name,
                               s3_object_path))
                    aws_service_wrapper.s3_upload_object(
                        local_ticker_path, s3_data_bucket_name, s3_object_path)

                    return cls.from_local_file(constants.TICKER_DATA_DIR,
                                               ticker_object_name)
                else:
                    log.debug("No local alternatives found")
                    raise awe
            else:
                raise awe

        return cls.from_local_file(constants.APP_DATA_DIR, ticker_object_name)
예제 #4
0
    def try_from_s3(cls, config_filename: str, app_ns: str):
        '''
            Downloads a configuration file from S3 given the supplied file (object) name
            and application namespace used to read cloudformation exports.

            If the file does not exist use the local one and upload it to S3
        '''
        try:
            s3_data_bucket_name = aws_service_wrapper.cf_read_export_value(
                constants.s3_data_bucket_export_name(app_ns))

            s3_object_name = "%s/%s" % (constants.S3_CONFIG_OLDER_PREFIX,
                                        config_filename)

            dest_filename = "%s.s3download" % config_filename
            dest_path = "%s%s" % (constants.CONFIG_FILE_PATH, dest_filename)

            log.info("Downloading Configuration File: s3://%s/%s --> %s" %
                     (s3_data_bucket_name, s3_object_name, dest_path))
            aws_service_wrapper.s3_download_object(s3_data_bucket_name,
                                                   s3_object_name, dest_path)

            return cls.from_local_config(dest_filename)
        except AWSError as awe:
            if awe.resource_not_found():
                log.debug(
                    "Configuration not found in S3. Looking for local alternatives"
                )

                # Attempt to upload a local copy of the configuration if it
                # exists
                local_configuration_path = "%s%s" % (
                    constants.CONFIG_FILE_PATH, config_filename)

                if os.path.isfile(local_configuration_path):
                    log.debug("Attempting to upload %s --> s3://%s/%s" %
                              (local_configuration_path, s3_data_bucket_name,
                               s3_object_name))
                    aws_service_wrapper.s3_upload_object(
                        local_configuration_path, s3_data_bucket_name,
                        s3_object_name)

                    return cls.from_local_config(config_filename)
                else:
                    log.debug("No local alternatives found")
                    raise awe
            else:
                raise awe
예제 #5
0
    def from_s3(cls, app_ns: str, s3_object_name: str):
        '''
            loads the model from S3 using preconfigured object names
        '''

        util.create_dir(constants.APP_DATA_DIR)

        s3_data_bucket_name = aws_service_wrapper.cf_read_export_value(
            constants.s3_data_bucket_export_name(app_ns))
        s3_object_path = "%s/%s" % (cls.model_s3_folder_prefix, s3_object_name)
        dest_path = "%s/%s" % (constants.APP_DATA_DIR, s3_object_name)

        log.info(
            "Downloading %s: s3://%s/%s --> %s" %
            (cls.model_name, s3_data_bucket_name, s3_object_path, dest_path))
        aws_service_wrapper.s3_download_object(s3_data_bucket_name,
                                               s3_object_path, dest_path)

        return cls.from_local_file(dest_path)
    def try_from_s3(cls, app_ns: str, ticker_file_name: str):
        '''
            Override for BaseModel.from_s3

            loads the model from S3. If one is not found look for a local alternative
            and upload it to the same bucket. This is done to eliminate the need to
            pre-populate S3 with any data when the application is first installed.
        '''

        try:
            return cls.from_s3(app_ns, ticker_file_name)
        except AWSError as awe:
            if awe.resource_not_found():
                log.debug(
                    "File not found in S3. Looking for local alternatives")

                s3_object_path = "%s/%s" % (cls.model_s3_folder_prefix,
                                            ticker_file_name)

                log.debug(
                    "Reading S3 Data Bucket location from CloudFormation Exports"
                )
                s3_data_bucket_name = aws_service_wrapper.cf_read_export_value(
                    constants.s3_data_bucket_export_name(app_ns))

                # Attempt to upload a local copy of the file if it exists
                local_ticker_path = '%s/%s' % (constants.TICKER_DATA_DIR,
                                               ticker_file_name)

                if os.path.isfile(local_ticker_path):
                    log.debug("Attempting to upload %s --> s3://%s/%s" %
                              (local_ticker_path, s3_data_bucket_name,
                               s3_object_path))

                    aws_service_wrapper.s3_upload_object(
                        local_ticker_path, s3_data_bucket_name, s3_object_path)

                    return cls.from_local_file(local_ticker_path)
                else:
                    log.debug("No local alternatives found")
                    raise awe
            else:
                raise awe
예제 #7
0
    def save_to_s3(self, app_ns: str):
        '''
            Uploads the model to S3

            Parameters
            ----------
            app_ns : str
                The application namespace supplied to the command line
                used to identify the appropriate CloudFormation exports
        '''

        self.validate_model()

        s3_data_bucket_name = aws_service_wrapper.cf_read_export_value(
            constants.s3_data_bucket_export_name(app_ns))
        object_name = "%s/%s" % (self.model_s3_folder_prefix,
                                 self.model_s3_object_name)

        log.info("Uploading %s to S3: s3://%s/%s" %
                 (self.model_name, s3_data_bucket_name, object_name))
        aws_service_wrapper.s3_upload_ascii_string(
            util.format_dict(self.model), s3_data_bucket_name, object_name)
def notify_new_recommendation(notification_list: list, app_ns: str):
    '''
        Sends an SNS notification indicating that a new recommendation has been generated

        Parameters
        ----------
        notification_list: list
            List of new SecurityRecommendationSet objects that require notifications
        app_ns: str
            The application namespace supplied to the command line
            used to identify the appropriate CloudFormation exports
    '''
    if notification_list == None or len(notification_list) == 0:
        return

    message = ""
    sns_topic_arn = aws_service_wrapper.cf_read_export_value(
        constants.sns_app_notifications_topic_arn(app_ns))
    subject = "New Stock Recommendation Available"

    for recommendation_set in notification_list:
        formatted_ticker_message = ""

        for security in recommendation_set.model['securities_set']:
            formatted_ticker_message += "Ticker Symbol: %s\n" % security[
                'ticker_symbol']

        message += "A New Stock Recommendation is available for the following trading strategy %s\n" % recommendation_set.model[
            'strategy_name']
        message += "\n"
        message += formatted_ticker_message

        message += "\n\n"

    log.info("Publishing Recommendation set to SNS topic: %s" % sns_topic_arn)
    aws_service_wrapper.sns_publish_notification(sns_topic_arn, subject,
                                                 message)