コード例 #1
0
def run_screener_analysis(work_dict):
    """run_screener_analysis

    Celery wrapper for running without celery

    :param work_dict: task data
    """

    fn_name = 'run_screener_analysis'
    label = f'''{fn_name} - {work_dict.get(
        'label',
        '')}'''

    log.info(f'{label} - start')

    response = build_result.build_result(status=ae_consts.NOT_RUN,
                                         err=None,
                                         rec={})
    task_res = {}

    # allow running without celery
    if ae_consts.is_celery_disabled(work_dict=work_dict):
        work_dict['celery_disabled'] = True
        task_res = task_screener_analysis(work_dict)
        if task_res:
            response = task_res.get('result', task_res)
            if ae_consts.ev('DEBUG_RESULTS', '0') == '1':
                response_details = response
                try:
                    response_details = ae_consts.ppj(response)
                except Exception:
                    response_details = response

                log.info(f'{label} task result={response_details}')
        else:
            log.error(f'{label} celery was disabled but the task={response} '
                      'did not return anything')
        # end of if response
    else:
        task_res = task_screener_analysis.delay(work_dict=work_dict)
        rec = {'task_id': task_res}
        response = build_result.build_result(status=ae_consts.SUCCESS,
                                             err=None,
                                             rec=rec)
    # if celery enabled

    if response:
        if ae_consts.ev('DEBUG_RESULTS', '0') == '1':
            log.info(f'{label} - done '
                     f'status={ae_consts.get_status(response["status"])} '
                     f'err={response["err"]} rec={response["rec"]}')
        else:
            log.info(f'{label} - done '
                     f'status={ae_consts.get_status(response["status"])} '
                     f'err={response["err"]}')
    else:
        log.info(f'{label} - done no response')
    # end of if/else response

    return response
コード例 #2
0
def run_screener_analysis(work_dict):
    """run_screener_analysis

    Celery wrapper for running without celery

    :param work_dict: task data
    """

    fn_name = 'run_screener_analysis'
    label = '{} - {}'.format(fn_name, work_dict.get('label', ''))

    log.info('{} - start'.format(label))

    response = build_result.build_result(status=ae_consts.NOT_RUN,
                                         err=None,
                                         rec={})
    task_res = {}

    # allow running without celery
    if ae_consts.is_celery_disabled(work_dict=work_dict):
        work_dict['celery_disabled'] = True
        task_res = task_screener_analysis(work_dict)
        if task_res:
            response = task_res.get('result', task_res)
            if ae_consts.ev('DEBUG_RESULTS', '0') == '1':
                response_details = response
                try:
                    response_details = ae_consts.ppj(response)
                except Exception:
                    response_details = response

                log.info('{} task result={}'.format(label, response_details))
        else:
            log.error('{} celery was disabled but the task={} '
                      'did not return anything'.format(label, response))
        # end of if response
    else:
        task_res = task_screener_analysis.delay(work_dict=work_dict)
        rec = {'task_id': task_res}
        response = build_result.build_result(status=ae_consts.SUCCESS,
                                             err=None,
                                             rec=rec)
    # if celery enabled

    if response:
        if ae_consts.ev('DEBUG_RESULTS', '0') == '1':
            log.info('{} - done '
                     'status={} err={} rec={}'.format(
                         label, ae_consts.get_status(response['status']),
                         response['err'], response['rec']))
        else:
            log.info('{} - done '
                     'status={} err={}'.format(
                         label, ae_consts.get_status(response['status']),
                         response['err']))
    else:
        log.info('{} - done ' 'no response'.format(label))
    # end of if/else response

    return response
コード例 #3
0
def run_get_new_pricing_data(work_dict):
    """run_get_new_pricing_data

    Celery wrapper for running without celery

    :param work_dict: task data
    """

    label = work_dict.get('label', '')

    log.debug(f'run_get_new_pricing_data - {label} - start')

    response = build_result.build_result(status=ae_consts.NOT_RUN,
                                         err=None,
                                         rec={})
    task_res = {}

    # allow running without celery
    if ae_consts.is_celery_disabled(work_dict=work_dict):
        work_dict['celery_disabled'] = True
        task_res = get_new_pricing_data(work_dict)
        if task_res:
            response = task_res.get('result', task_res)
            if ae_consts.ev('DEBUG_RESULTS', '0') == '1':
                response_details = response
                try:
                    response_details = ae_consts.ppj(response)
                except Exception:
                    response_details = response

                log.debug(f'{label} task result={response_details}')
        else:
            log.error(f'{label} celery was disabled but the task={response} '
                      'did not return anything')
        # end of if response
    else:
        task_res = get_new_pricing_data.delay(work_dict=work_dict)
        rec = {'task_id': task_res}
        response = build_result.build_result(status=ae_consts.SUCCESS,
                                             err=None,
                                             rec=rec)
    # if celery enabled

    if response:
        status_str = ae_consts.get_status(response['status'])
        if ae_consts.ev('DEBUG_RESULTS', '0') == '1':
            log.debug(f'run_get_new_pricing_data - {label} - done '
                      f'status={status_str} '
                      f'err={response["err"]} '
                      f'rec={response["rec"]}')
        else:
            log.debug(f'run_get_new_pricing_data - {label} - done '
                      f'status={status_str} '
                      f'rec={response["rec"]}')
    else:
        log.debug(f'run_get_new_pricing_data - {label} - done ' 'no response')
    # end of if/else response

    return response
def run_publish_ticker_aggregate_from_s3(work_dict):
    """run_publish_ticker_aggregate_from_s3

    Celery wrapper for running without celery

    :param work_dict: task data
    """

    label = work_dict.get('label', '')

    log.info('run_publish_ticker_aggregate_from_s3 - {} - start'.format(label))

    response = build_result.build_result(status=NOT_RUN, err=None, rec={})
    task_res = {}

    # allow running without celery
    if is_celery_disabled(work_dict=work_dict):
        work_dict['celery_disabled'] = True
        task_res = publish_ticker_aggregate_from_s3(work_dict=work_dict)
        if task_res:
            response = task_res.get('result', task_res)
            if ev('DEBUG_RESULTS', '0') == '1':
                response_details = response
                try:
                    response_details = ppj(response)
                except Exception:
                    response_details = response
                log.info('{} task result={}'.format(label, response_details))
        else:
            log.error('{} celery was disabled but the task={} '
                      'did not return anything'.format(label, response))
        # end of if response
    else:
        task_res = publish_ticker_aggregate_from_s3.delay(work_dict=work_dict)
        rec = {'task_id': task_res}
        response = build_result.build_result(status=SUCCESS, err=None, rec=rec)
    # if celery enabled

    if response:
        if ev('DEBUG_RESULTS', '0') == '1':
            log.info('run_publish_ticker_aggregate_from_s3 - {} - done '
                     'status={} err={} rec={}'.format(
                         label, get_status(response['status']),
                         response['err'], response['rec']))
        else:
            log.info('run_publish_ticker_aggregate_from_s3 - {} - done '
                     'status={} err={}'.format(label,
                                               get_status(response['status']),
                                               response['err']))
    else:
        log.info('run_publish_ticker_aggregate_from_s3 - {} - done '
                 'no response'.format(label))
    # end of if/else response

    return response
コード例 #5
0
def mock_extract_news_from_redis_success(label, host, port, db, password, key,
                                         **kwargs):
    """mock_extract_news_from_redis_success

    :param label: test label
    :param address: test address
    :param db: test db
    :param key: test key
    :param kwargs: additional keyword args as a dictionary
    """
    sample_record = build_cache_ready_pricing_dataset(
        label=('{}.{}.{}.{}.{}.'
               'mock_extract_news_from_redis_success'.format(
                   label, host, port, db, key)))
    rec = {'data': sample_record['news']}
    res = build_result(status=SUCCESS, err=None, rec=rec)
    return res
コード例 #6
0
def mock_extract_news_from_redis_success(label, host, port, db, password, key,
                                         **kwargs):
    """mock_extract_news_from_redis_success

    :param label: test label
    :param address: test address
    :param db: test db
    :param key: test key
    :param kwargs: additional keyword args as a dictionary
    """
    sample_record = api_requests.build_cache_ready_pricing_dataset(
        label=(f'{label}.{host}.{port}.{db}.{key}.'
               'mock_extract_news_from_redis_success'))
    rec = {'data': sample_record['news']}
    res = build_result.build_result(status=ae_consts.SUCCESS,
                                    err=None,
                                    rec=rec)
    return res
コード例 #7
0
def plot_hloc_pricing(
        log_label,
        ticker,
        df,
        title,
        show_plot=True,
        dropna_for_all=True):
    """plot_hloc_pricing

    Plot the high, low, open and close columns together on a chart

    :param log_label: log identifier
    :param ticker: ticker
    :param df: initialized ``pandas.DataFrame``
    :param title: title for the chart
    :param show_plot: bool to show the plot
    :param dropna_for_all: optional - bool to toggle keep None's in
                           the plot ``df`` (default is drop them
                           for display purposes)
    """

    rec = {
        'ax': None,
        'fig': None
    }
    result = build_result.build_result(
        status=ae_consts.NOT_RUN,
        err=None,
        rec=rec)

    try:

        log.info(
            f'{log_label} - '
            'plot_hloc_pricing'
            ' - start')

        set_common_seaborn_fonts()

        fig, ax = plt.subplots(
            figsize=(15.0, 10.0))

        use_df = df
        if dropna_for_all:
            log.info(
                f'{log_label} - '
                'plot_hloc_pricing'
                ' - dropna_for_all')
            use_df = df.dropna(axis=0, how='any')
        # end of pre-plot dataframe scrubbing

        plt.plot(
            use_df['date'],
            use_df['high'],
            label='High',
            color=ae_consts.PLOT_COLORS['high'],
            alpha=0.4)
        plt.plot(
            use_df['date'],
            use_df['low'],
            label='Low',
            color=ae_consts.PLOT_COLORS['low'],
            alpha=0.4)
        plt.plot(
            use_df['date'],
            use_df['close'],
            label='Close',
            color=ae_consts.PLOT_COLORS['close'],
            alpha=0.4)
        plt.plot(
            use_df['date'],
            use_df['open'],
            label='Open',
            color=ae_consts.PLOT_COLORS['open'],
            alpha=0.4)

        xlabel = 'Dates'
        ylabel = 'Prices'

        plt.grid(True)
        plt.xlabel(xlabel)
        plt.ylabel(ylabel)

        # Build a date vs Close DataFrame
        start_date = str(use_df.iloc[0]['date'].strftime('%Y-%m-%d'))
        end_date = str(use_df.iloc[-1]['date'].strftime('%Y-%m-%d'))
        if not title:
            title = (
                f'{ticker} Pricing from: {start_date} to {end_date}')
        ax.set_title(title)

        # Build out the xtick chart by the dates
        ax.xaxis.grid(True, which='minor')

        legend_list = [
            'high',
            'low',
            'close',
            'open'
        ]

        fig.autofmt_xdate()
        show_with_entities(
            log_label=log_label,
            xlabel=xlabel,
            ylabel=ylabel,
            title=title,
            ax=ax,
            fig=fig,
            legend_list=legend_list,
            show_plot=show_plot)

        rec['ax'] = ax
        rec['fig'] = fig

        result = build_result.build_result(
            status=ae_consts.SUCCESS,
            err=None,
            rec=rec)

    except Exception as e:
        err = (
            f'failed plot_hloc_pricing with ex={e}')
        log.error(err)
        result = build_result.build_result(
            status=ae_consts.ERR,
            err=err,
            rec=rec)
    # end of try/ex

    send_final_log(
        log_label=log_label,
        fn_name='plot_hloc_pricing',
        result=result)

    return result
コード例 #8
0
def run_distributed_algorithm(self, algo_req):
    """run_distributed_algorithm

    Process a distributed Algorithm

    :param algo_req: dictionary for key/values for
        running an algorithm using Celery workers
    """

    label = algo_req.get('name', 'ae-algo')
    verbose = algo_req.get('verbose', False)
    debug = algo_req.get('debug', False)

    # please be careful logging prod passwords:
    if verbose or debug:
        log.info('task - {} - start ' 'algo_req={}'.format(label, algo_req))
    else:
        log.info('task - {} - start '.format(label))
    # end of start log

    rec = {}
    res = build_result.build_result(status=ae_consts.NOT_RUN,
                                    err=None,
                                    rec=rec)

    created_algo_object = None
    custom_algo_module = None
    new_algo_object = None
    use_custom_algo = False
    found_algo_module = True  # assume the BaseAlgo
    should_publish_extract_dataset = False
    should_publish_history_dataset = False
    should_publish_report_dataset = False

    ticker = algo_req.get('ticker', 'SPY')
    num_days_back = algo_req.get('num_days_back', 75)
    name = algo_req.get('name', 'ae-algo')
    algo_module_path = algo_req.get('mod_path', None)
    module_name = algo_req.get('module_name', 'BaseAlgo')
    custom_algo_module = algo_req.get('custom_algo_module', None)
    new_algo_object = algo_req.get('new_algo_object', None)
    use_custom_algo = algo_req.get('use_custom_algo', False)
    should_publish_extract_dataset = algo_req.get(
        'should_publish_extract_dataset', False)
    should_publish_history_dataset = algo_req.get(
        'should_publish_history_dataset', False)
    should_publish_report_dataset = algo_req.get(
        'should_publish_report_dataset', False)
    start_date = algo_req.get('start_date', None)
    end_date = algo_req.get('end_date', None)
    raise_on_err = algo_req.get('raise_on_err', False)

    report_config = algo_req.get('report_config', None)
    history_config = algo_req.get('history_config', None)
    extract_config = algo_req.get('extract_config', None)

    err = None
    if algo_module_path:
        found_algo_module = False
        module_name = algo_module_path.split('/')[-1]
        loader = importlib.machinery.SourceFileLoader(module_name,
                                                      algo_module_path)
        custom_algo_module = types.ModuleType(loader.name)
        loader.exec_module(custom_algo_module)
        use_custom_algo = True

        for member in inspect.getmembers(custom_algo_module):
            if module_name in str(member):
                found_algo_module = True
                break
        # for all members in this custom module file
    # if loading a custom algorithm module from a file on disk

    if not found_algo_module:
        err = ('{} - unable to find custom algorithm module={} '
               'module_path={}'.format(label, custom_algo_module,
                                       algo_module_path))
        if algo_module_path:
            err = (
                '{} - analysis_engine.work_tasks.run_distributed_algorithm '
                'was unable '
                'to find custom algorithm module={} with provided path to \n '
                'file: {} \n'
                '\n'
                'Please confirm '
                'that the class inherits from the BaseAlgo class like:\n'
                '\n'
                'import analysis_engine.algo\n'
                'class MyAlgo(analysis_engine.algo.BaseAlgo):\n '
                '\n'
                'If it is then please file an issue on github:\n '
                'https://github.com/AlgoTraders/stock-analysis-engine/'
                'issues/new \n\nFor now this error results in a shutdown'
                '\n'.format(label, custom_algo_module, algo_module_path))
        # if algo_module_path set

        log.error(err)
        res = build_result.build_result(status=ae_consts.ERR,
                                        err=err,
                                        rec=None)
        return get_task_results.get_task_results(work_dict=algo_req,
                                                 result=res)
    # if not found_algo_module

    use_start_date = start_date
    use_end_date = end_date
    if not use_end_date:
        end_date = datetime.datetime.utcnow()
        use_end_date = end_date.strftime(ae_consts.COMMON_TICK_DATE_FORMAT)
    if not use_start_date:
        start_date = end_date - datetime.timedelta(days=num_days_back)
        use_start_date = start_date.strftime(ae_consts.COMMON_TICK_DATE_FORMAT)
    dataset_publish_extract = algo_req.get('dataset_publish_extract', False)
    dataset_publish_history = algo_req.get('dataset_publish_history', False)
    dataset_publish_report = algo_req.get('dataset_publish_report', False)
    try:
        if use_custom_algo:
            log.info('inspecting {} for class {}'.format(
                custom_algo_module, module_name))
            use_class_member_object = None
            for member in inspect.getmembers(custom_algo_module):
                if module_name in str(member):
                    log.info('start {} with {}'.format(name, member[1]))
                    use_class_member_object = member
                    break
            # end of looking over the class definition but did not find it

            if use_class_member_object:
                new_algo_object = member[1](**algo_req)
            else:
                err = ('{} - did not find a derived '
                       'analysis_engine.algo.BaseAlgo '
                       'class in the module file={} '
                       'for ticker={} algo_name={}'.format(
                           label, algo_module_path, ticker, name))
                log.error(err)
                res = build_result.build_result(status=ae_consts.ERR,
                                                err=err,
                                                rec=None)
                return get_task_results.get_task_results(work_dict=algo_req,
                                                         result=res)
            # end of finding a valid algorithm object
        else:
            new_algo_object = ae_algo.BaseAlgo(**algo_req)
        # if using a custom module path or the BaseAlgo

        if new_algo_object:
            # heads up - logging this might have passwords in the algo_req
            # log.debug(
            #     '{} algorithm request: {}'.format(
            #         name,
            #         algo_req))
            log.info('{} - run ticker={} from {} to {}'.format(
                name, ticker, use_start_date, use_end_date))
            algo_res = run_algo.run_algo(algo=new_algo_object,
                                         raise_on_err=raise_on_err,
                                         **algo_req)
            created_algo_object = new_algo_object
            log.info('{} - run ticker={} from {} to {}'.format(
                name, ticker, use_start_date, use_end_date))
            if custom_algo_module:
                log.info(
                    '{} - done run_algo custom_algo_module={} module_name={} '
                    'ticker={} from {} to {}'.format(name, custom_algo_module,
                                                     module_name, ticker,
                                                     use_start_date,
                                                     use_end_date))
            else:
                log.info('{} - done run_algo BaseAlgo ticker={} from {} '
                         'to {}'.format(name, ticker, use_start_date,
                                        use_end_date))
        else:
            err = ('{} - missing a derived analysis_engine.algo.BaseAlgo '
                   'class in the module file={} for '
                   'ticker={} algo_name={}'.format(label, algo_module_path,
                                                   ticker, name))
            log.error(err)
            res = build_result.build_result(status=ae_consts.ERR,
                                            err=err,
                                            rec=None)
            return get_task_results.get_task_results(work_dict=algo_req,
                                                     result=res)
        # end of finding a valid algorithm object

        if not created_algo_object:
            err = ('{} - failed creating algorithm object - '
                   'ticker={} status={} error={}'
                   'algo name={} custom_algo_module={} module_name={} '
                   'from {} to {}'.format(
                       label, ticker,
                       ae_consts.get_status(status=algo_res['status']),
                       algo_res['err'], name, custom_algo_module, module_name,
                       use_start_date, use_end_date))
            res = build_result.build_result(status=ae_consts.ERR,
                                            err=err,
                                            rec=None)
            return get_task_results.get_task_results(work_dict=algo_req,
                                                     result=res)
        # end of stop early

        if should_publish_extract_dataset or dataset_publish_extract:
            s3_log = ''
            redis_log = ''
            file_log = ''
            use_log = 'publish'

            if (extract_config['redis_address'] and extract_config['redis_db']
                    and extract_config['redis_key']):
                redis_log = 'redis://{}@{}/{}'.format(
                    extract_config['redis_address'],
                    extract_config['redis_db'], extract_config['redis_key'])
                use_log += ' {}'.format(redis_log)
            else:
                extract_config['redis_enabled'] = False
            if (extract_config['s3_address'] and extract_config['s3_bucket']
                    and extract_config['s3_key']):
                s3_log = 's3://{}/{}/{}'.format(extract_config['s3_address'],
                                                extract_config['s3_bucket'],
                                                extract_config['s3_key'])
                use_log += ' {}'.format(s3_log)
            else:
                extract_config['s3_enabled'] = False
            if extract_config['output_file']:
                file_log = 'file:{}'.format(extract_config['output_file'])
                use_log += ' {}'.format(file_log)

            log.info('{} - publish - start ticker={} algorithm-ready {}'
                     ''.format(name, ticker, use_log))

            publish_status = created_algo_object.publish_input_dataset(
                **extract_config)
            if publish_status != ae_consts.SUCCESS:
                msg = ('failed to publish algorithm-ready datasets '
                       'with status {} attempted to {}'.format(
                           ae_consts.get_status(status=publish_status),
                           use_log))
                log.error(msg)
                res = build_result.build_result(status=ae_consts.ERR,
                                                err=err,
                                                rec=None)
                return get_task_results.get_task_results(work_dict=algo_req,
                                                         result=res)
            # end of stop early

            log.info('{} - publish - done ticker={} algorithm-ready {}'
                     ''.format(name, ticker, use_log))
        # if publish the algorithm-ready dataset

        if should_publish_history_dataset or dataset_publish_history:
            s3_log = ''
            redis_log = ''
            file_log = ''
            use_log = 'publish'

            if (history_config['redis_address'] and history_config['redis_db']
                    and history_config['redis_key']):
                redis_log = 'redis://{}@{}/{}'.format(
                    history_config['redis_address'],
                    history_config['redis_db'], history_config['redis_key'])
                use_log += ' {}'.format(redis_log)
            if (history_config['s3_address'] and history_config['s3_bucket']
                    and history_config['s3_key']):
                s3_log = 's3://{}/{}/{}'.format(history_config['s3_address'],
                                                history_config['s3_bucket'],
                                                history_config['s3_key'])
                use_log += ' {}'.format(s3_log)
            if history_config['output_file']:
                file_log = 'file:{}'.format(history_config['output_file'])
                use_log += ' {}'.format(file_log)

            log.info('{} - publish - start ticker={} trading history {}'
                     ''.format(name, ticker, use_log))

            publish_status = \
                created_algo_object.publish_trade_history_dataset(
                    **history_config)
            if publish_status != ae_consts.SUCCESS:
                msg = ('failed to publish trading history datasets '
                       'with status {} attempted to {}'.format(
                           ae_consts.get_status(status=publish_status),
                           use_log))
                log.error(msg)
                res = build_result.build_result(status=ae_consts.ERR,
                                                err=err,
                                                rec=None)
                return get_task_results.get_task_results(work_dict=algo_req,
                                                         result=res)
            # end of stop early

            log.info('{} - publish - done ticker={} trading history {}'
                     ''.format(name, ticker, use_log))
        # if publish an trading history dataset

        if should_publish_report_dataset or dataset_publish_report:
            s3_log = ''
            redis_log = ''
            file_log = ''
            use_log = 'publish'

            if (report_config['redis_address'] and report_config['redis_db']
                    and report_config['redis_key']):
                redis_log = 'redis://{}@{}/{}'.format(
                    report_config['redis_address'], report_config['redis_db'],
                    report_config['redis_key'])
                use_log += ' {}'.format(redis_log)
            if (report_config['s3_address'] and report_config['s3_bucket']
                    and report_config['s3_key']):
                s3_log = 's3://{}/{}/{}'.format(report_config['s3_address'],
                                                report_config['s3_bucket'],
                                                report_config['s3_key'])
                use_log += ' {}'.format(s3_log)
            if report_config['output_file']:
                file_log = ' file:{}'.format(report_config['output_file'])
                use_log += ' {}'.format(file_log)

            log.info('{} - publishing ticker={} trading performance report {}'
                     ''.format(name, ticker, use_log))

            publish_status = created_algo_object.publish_report_dataset(
                **report_config)
            if publish_status != ae_consts.SUCCESS:
                msg = ('failed to publish trading performance report datasets '
                       'with status {} attempted to {}'.format(
                           ae_consts.get_status(status=publish_status),
                           use_log))
                log.error(msg)
                res = build_result.build_result(status=ae_consts.ERR,
                                                err=err,
                                                rec=None)
                return get_task_results.get_task_results(work_dict=algo_req,
                                                         result=res)
            # end of stop early

            log.info(
                '{} - publish - done ticker={} trading performance report {}'
                ''.format(name, ticker, use_log))
        # if publish an trading performance report dataset

        log.info(
            '{} - done publishing datasets for ticker={} from {} to {}'.format(
                name, ticker, use_start_date, use_end_date))

        res = build_result.build_result(status=ae_consts.SUCCESS,
                                        err=None,
                                        rec=rec)

    except Exception as e:
        res = build_result.build_result(
            status=ae_consts.ERR,
            err=('failed - run_distributed_algorithm '
                 'dict={} with ex={}').format(algo_req, e),
            rec=rec)
        log.error('{} - {}'.format(label, res['err']))
    # end of try/ex

    log.info('task - run_distributed_algorithm done - '
             '{} - status={}'.format(label,
                                     ae_consts.get_status(res['status'])))

    return get_task_results.get_task_results(work_dict=algo_req, result=res)
コード例 #9
0
def task_screener_analysis(self, work_dict):
    """task_screener_analysis

    :param work_dict: task dictionary
    """

    label = work_dict.get('label', 'screener')

    log.info('{} - start'.format(label))

    rec = {}
    res = build_result.build_result(status=ae_consts.NOT_RUN,
                                    err=None,
                                    rec=rec)
    """
    Input - Set up dataset sources to collect
    """

    ticker = work_dict.get('ticker', None)
    org_tickers = work_dict.get('tickers', None)

    if not ticker and not org_tickers:
        res = build_result.build_result(status=ae_consts.ERR,
                                        err='missing ticker or tickers',
                                        rec=rec)

    tickers = []
    if not org_tickers:
        if ticker:
            tickers = [ticker]
    else:
        for t in org_tickers:
            upper_cased_ticker = str(t).upper()
            if upper_cased_ticker not in tickers:
                tickers.append(upper_cased_ticker)
        # build a unique ticker list
    # end of ensuring tickers is a unique list of
    # upper-cased ticker symbol strings

    # fetch from: 'all', 'iex' or 'yahoo'
    fetch_mode = work_dict.get('fetch_mode', os.getenv('FETCH_MODE', 'iex'))
    iex_datasets = work_dict.get(
        'iex_datasets',
        os.getenv('IEX_DATASETS_DEFAULT', ae_consts.IEX_DATASETS_DEFAULT))

    # if defined, these are task functions for
    # calling customiized determine Celery tasks
    determine_sells_callback = work_dict.get('determine_sells', None)
    determine_buys_callback = work_dict.get('determine_buys', None)

    try:

        log.info('{} fetch={} tickers={} '
                 'iex_datasets={} '
                 'sell_task={} '
                 'buy_task={}'.format(label, fetch_mode, tickers, iex_datasets,
                                      determine_sells_callback,
                                      determine_buys_callback))
        """
        Input - Set up required urls for building buckets
        """
        fv_urls = work_dict.get('urls', )

        if not fv_urls:
            res = build_result.build_result(
                status=ae_consts.ERR,
                err='missing required urls list of screeners',
                rec=rec)

        # stop if something errored out with the
        # celery helper for turning off celery to debug
        # without an engine running
        if res['err']:
            log.error('{} - tickers={} fetch={} iex_datasets={} '
                      'hit validation err={}'.format(label, tickers,
                                                     fetch_mode, iex_datasets,
                                                     res['err']))

            return get_task_results.get_task_results(work_dict=work_dict,
                                                     result=res)
        # end of input validation checks

        num_urls = len(fv_urls)
        log.info('{} - running urls={}'.format(label, fv_urls))

        fv_dfs = []
        for uidx, url in enumerate(fv_urls):
            log.info('{} - url={}/{} url={}'.format(label, uidx, num_urls,
                                                    url))
            fv_res = finviz_utils.fetch_tickers_from_screener(url=url)
            if fv_res['status'] == ae_consts.SUCCESS:
                fv_dfs.append(fv_res['rec']['data'])
                for ft_tick in fv_res['rec']['tickers']:
                    upper_ft_ticker = ft_tick.upper()
                    if upper_ft_ticker not in tickers:
                        tickers.append(upper_ft_ticker)
                # end of for all found tickers
            else:
                log.error('{} - failed url={}/{} url={}'.format(
                    label, uidx, num_urls, url))
            # if success vs log the error
        # end of urls to get pandas.DataFrame and unique tickers
        """
        Find tickers in screens
        """

        num_tickers = len(tickers)

        log.info('{} - fetching tickers={} from urls={}'.format(
            label, num_tickers, num_urls))
        """
        pull ticker data
        """

        fetch_recs = fetch_utils.fetch(tickers=tickers,
                                       fetch_mode=fetch_mode,
                                       iex_datasets=iex_datasets)

        if fetch_recs:
            rec = fetch_recs
            """
            Output - Where is data getting cached and archived?
            (this helps to retroactively evaluate trading performance)
            """

            res = build_result.build_result(status=ae_consts.SUCCESS,
                                            err=None,
                                            rec=rec)
        else:
            err = ('{} - tickers={} failed fetch={} '
                   'iex_datasets={}'.format(label, tickers, fetch_mode,
                                            iex_datasets))
            res = build_result.build_result(status=ae_consts.ERR,
                                            err=err,
                                            rec=rec)

        log.info('{} - done'.format(label))
    except Exception as e:
        err = ('{} - tickers={} fetch={} hit ex={} '.format(
            label, tickers, fetch_mode, e))
        log.error(err)
        res = build_result.build_result(status=ae_consts.ERR, err=err, rec=rec)
    # end of try/ex

    return get_task_results.get_task_results(work_dict=work_dict, result=res)
コード例 #10
0
def get_data_from_iex(work_dict):
    """get_data_from_iex

    Get data from IEX - this requires an account

    :param work_dict: request dictionary
    """
    label = 'get_data_from_iex'

    log.debug(f'task - {label} - start ' f'work_dict={work_dict}')

    rec = {'data': None, 'updated': None}
    res = {'status': ae_consts.NOT_RUN, 'err': None, 'rec': rec}

    ticker = None
    field = None
    ft_type = None

    try:

        ticker = work_dict.get('ticker', ae_consts.TICKER)
        field = work_dict.get('field', 'daily')
        ft_type = work_dict.get('ft_type', None)
        ft_str = str(ft_type).lower()
        label = work_dict.get('label', label)
        orient = work_dict.get('orient', 'records')
        backfill_date = work_dict.get('backfill_date', None)

        iex_req = None
        if ft_type == iex_consts.FETCH_DAILY or ft_str == 'daily':
            ft_type == iex_consts.FETCH_DAILY
            iex_req = api_requests.build_iex_fetch_daily_request(label=label)
        elif ft_type == iex_consts.FETCH_MINUTE or ft_str == 'minute':
            ft_type == iex_consts.FETCH_MINUTE
            iex_req = api_requests.build_iex_fetch_minute_request(label=label)
        elif ft_type == iex_consts.FETCH_QUOTE or ft_str == 'quote':
            ft_type == iex_consts.FETCH_QUOTE
            iex_req = api_requests.build_iex_fetch_quote_request(label=label)
        elif ft_type == iex_consts.FETCH_STATS or ft_str == 'stats':
            ft_type == iex_consts.FETCH_STATS
            iex_req = api_requests.build_iex_fetch_stats_request(label=label)
        elif ft_type == iex_consts.FETCH_PEERS or ft_str == 'peers':
            ft_type == iex_consts.FETCH_PEERS
            iex_req = api_requests.build_iex_fetch_peers_request(label=label)
        elif ft_type == iex_consts.FETCH_NEWS or ft_str == 'news':
            ft_type == iex_consts.FETCH_NEWS
            iex_req = api_requests.build_iex_fetch_news_request(label=label)
        elif ft_type == iex_consts.FETCH_FINANCIALS or ft_str == 'financials':
            ft_type == iex_consts.FETCH_FINANCIALS
            iex_req = api_requests.build_iex_fetch_financials_request(
                label=label)
        elif ft_type == iex_consts.FETCH_EARNINGS or ft_str == 'earnings':
            ft_type == iex_consts.FETCH_EARNINGS
            iex_req = api_requests.build_iex_fetch_earnings_request(
                label=label)
        elif ft_type == iex_consts.FETCH_DIVIDENDS or ft_str == 'dividends':
            ft_type == iex_consts.FETCH_DIVIDENDS
            iex_req = api_requests.build_iex_fetch_dividends_request(
                label=label)
        elif ft_type == iex_consts.FETCH_COMPANY or ft_str == 'company':
            ft_type == iex_consts.FETCH_COMPANY
            iex_req = api_requests.build_iex_fetch_company_request(label=label)
        else:
            log.error(f'{label} - unsupported ft_type={ft_type} '
                      f'ft_str={ft_str} ticker={ticker}')
            raise NotImplementedError
        # if supported fetch request type

        iex_req['ticker'] = ticker
        clone_keys = [
            'ticker', 's3_address', 's3_bucket', 's3_key', 'redis_address',
            'redis_db', 'redis_password', 'redis_key'
        ]

        for k in clone_keys:
            if k in iex_req:
                iex_req[k] = work_dict.get(k, f'{k}-missing-in-{label}')
        # end of cloning keys

        if not iex_req:
            err = (f'{label} - ticker={ticker} '
                   f'did not build an IEX request '
                   f'for work={work_dict}')
            log.error(err)
            res = build_result.build_result(status=ae_consts.ERR,
                                            err=err,
                                            rec=rec)
            return res
        else:
            log.debug(f'{label} - ticker={ticker} '
                      f'field={field} '
                      f'orient={orient} fetch')
        # if invalid iex request

        df = None
        try:
            if 'from' in work_dict:
                iex_req['from'] = datetime.datetime.strptime(
                    '%Y-%m-%d %H:%M:%S', work_dict['from'])
            if backfill_date:
                iex_req['backfill_date'] = backfill_date
                iex_req['redis_key'] = (f'{ticker}_{backfill_date}_{field}')
                iex_req['s3_key'] = (f'{ticker}_{backfill_date}_{field}')

            if os.getenv('SHOW_SUCCESS', '0') == '1':
                log.info(f'fetching IEX {field} req={iex_req}')
            else:
                log.debug(f'fetching IEX {field} req={iex_req}')

            df = iex_fetch_data.fetch_data(work_dict=iex_req,
                                           fetch_type=ft_type)
            rec['data'] = df.to_json(orient=orient, date_format='iso')
            rec['updated'] = datetime.datetime.utcnow().strftime(
                '%Y-%m-%d %H:%M:%S')
        except Exception as f:
            log.error(f'{label} - ticker={ticker} field={ft_type} '
                      f'failed fetch_data '
                      f'with ex={f}')
        # end of try/ex

        if ae_consts.ev('DEBUG_IEX_DATA', '0') == '1':
            log.debug(f'{label} ticker={ticker} '
                      f'field={field} data={rec["data"]} to_json')
        else:
            log.debug(f'{label} ticker={ticker} field={field} to_json')
        # end of if/else found data

        upload_and_cache_req = copy.deepcopy(iex_req)
        upload_and_cache_req['celery_disabled'] = True
        upload_and_cache_req['data'] = rec['data']
        if not upload_and_cache_req['data']:
            upload_and_cache_req['data'] = '{}'
        use_field = field
        if use_field == 'news':
            use_field = 'news1'
        if 'redis_key' in work_dict:
            rk = work_dict.get('redis_key', iex_req['redis_key'])
            if backfill_date:
                rk = f'{ticker}_{backfill_date}'
            upload_and_cache_req['redis_key'] = (f'{rk}_{use_field}')
        if 's3_key' in work_dict:
            sk = work_dict.get('s3_key', iex_req['s3_key'])
            if backfill_date:
                sk = f'{ticker}_{backfill_date}'
            upload_and_cache_req['s3_key'] = (f'{sk}_{use_field}')

        try:
            update_res = publisher.run_publish_pricing_update(
                work_dict=upload_and_cache_req)
            update_status = update_res.get('status', ae_consts.NOT_SET)
            log.debug(f'{label} publish update '
                      f'status={ae_consts.get_status(status=update_status)} '
                      f'data={update_res}')
        except Exception:
            err = (f'{label} - failed to upload iex '
                   f'data={upload_and_cache_req} to '
                   f'to s3_key={upload_and_cache_req["s3_key"]} '
                   f'and redis_key={upload_and_cache_req["redis_key"]}')
            log.error(err)
        # end of try/ex to upload and cache

        if not rec['data']:
            log.debug(f'{label} - ticker={ticker} no IEX data '
                      f'field={field} to publish')
        # end of if/else

        res = build_result.build_result(status=ae_consts.SUCCESS,
                                        err=None,
                                        rec=rec)

    except Exception as e:
        res = build_result.build_result(status=ae_consts.ERR,
                                        err=(f'failed - get_data_from_iex '
                                             f'dict={work_dict} with ex={e}'),
                                        rec=rec)
    # end of try/ex

    log.debug(f'task - get_data_from_iex done - '
              f'{label} - '
              f'status={ae_consts.get_status(res["status"])} '
              f'err={res["err"]}')

    return res
コード例 #11
0
def set_data_in_redis_key(label=None,
                          data=None,
                          client=None,
                          host=None,
                          port=None,
                          password=None,
                          db=None,
                          key=None,
                          expire=None,
                          px=None,
                          nx=False,
                          xx=False,
                          serializer='json',
                          encoding='utf-8'):
    """set_data_in_redis_key

    :param label: log tracking label
    :param data: data to set in redis
    :param client: initialized redis client
    :param host: not used yet - redis host
    :param port: not used yet - redis port
    :param password: not used yet - redis password
    :param db: not used yet - redis db
    :param key: not used yet - redis key
    :param expire: redis expire
    :param px: redis px
    :param nx: redis nx
    :param xx: redis xx
    :param serializer: not used yet - support for future
                       pickle objects in redis
    :param encoding: format of the encoded key in redis
    """

    data_str = None
    encoded_data = None

    rec = {}
    res = build_result.build_result(status=NOT_RUN, err=None, rec=rec)

    log_id = label if label else 'set-redis'

    try:
        log.debug('{} serializer={} encoding={} for key={}'.format(
            log_id, serializer, encoding, key))
        if serializer == 'json':
            data_str = json.dumps(data)
            encoded_data = data_str.encode(encoding)
        else:
            encoded_data = None
            err = ('{} unsupported serializer={} '
                   'encoding={} key={}'.format(log_id, serializer, encoding,
                                               key))
            log.error(err)
            res = build_result.build_result(status=ERR, err=err, rec=rec)
            return res
        # if supported serializer

        if encoded_data:
            if ev('DEBUG_REDIS', '0') == '1':
                log.debug('{} set - key={} data={}'.format(
                    log_id, key, encoded_data))

            use_client = client
            if not use_client:
                log.debug('{} set key={} new client={}:{}@{}'.format(
                    log_id, key, host, port, db))
                use_client = redis.Redis(host=host,
                                         port=port,
                                         password=password,
                                         db=db)
            else:
                log.debug('{} set key={} client'.format(log_id, key))
            # create Redis client if not set

            use_client.set(name=key,
                           value=encoded_data,
                           ex=expire,
                           px=px,
                           nx=nx,
                           xx=xx)
            res = build_result.build_result(status=SUCCESS, err=None, rec=rec)
            return res
        else:
            err = ('{} no data for key={}'.format(log_id, key))
            log.error(err)
            res = build_result.build_result(status=ERR, err=err, rec=rec)
            return res
        # end of if have data to set
    except Exception as e:
        err = ('{} failed - redis set from data={} encoded_data={} '
               'key={} ex={}'.format(log_id, data, encoded_data, key, e))
        log.error(err)
        res = build_result.build_result(status=ERR, err=err, rec=rec)
    # end of try/ex for setting redis data

    return res
コード例 #12
0
def run_distributed_algorithm(self, algo_req):
    """run_distributed_algorithm

    Process an Algorithm using a Celery task that is
    processed by a Celery worker

    :param algo_req: dictionary for key/values for
        running an algorithm using Celery workers
    """

    label = algo_req.get('name', 'ae-algo')
    verbose = algo_req.get('verbose_task', False)
    debug = algo_req.get('debug', False)

    # please be careful logging prod passwords:
    if debug:
        log.info(f'task - {label} - start algo_req={algo_req}')
    elif verbose:
        log.info(f'task - {label} - start ')
    # end of start log

    rec = {}
    res = build_result.build_result(status=ae_consts.NOT_RUN,
                                    err=None,
                                    rec=rec)

    created_algo_object = None
    custom_algo_module = None
    new_algo_object = None
    use_custom_algo = False
    found_algo_module = True  # assume the BaseAlgo
    should_publish_extract_dataset = False
    should_publish_history_dataset = False
    should_publish_report_dataset = False

    ticker = algo_req.get('ticker', 'SPY')
    num_days_back = algo_req.get('num_days_back', 75)
    name = algo_req.get('name', 'ae-algo')
    algo_module_path = algo_req.get('mod_path', None)
    module_name = algo_req.get('module_name', 'BaseAlgo')
    custom_algo_module = algo_req.get('custom_algo_module', None)
    new_algo_object = algo_req.get('new_algo_object', None)
    use_custom_algo = algo_req.get('use_custom_algo', False)
    should_publish_extract_dataset = algo_req.get(
        'should_publish_extract_dataset', False)
    should_publish_history_dataset = algo_req.get(
        'should_publish_history_dataset', False)
    should_publish_report_dataset = algo_req.get(
        'should_publish_report_dataset', False)
    start_date = algo_req.get('start_date', None)
    end_date = algo_req.get('end_date', None)
    raise_on_err = algo_req.get('raise_on_err', True)
    report_config = algo_req.get('report_config', None)
    history_config = algo_req.get('history_config', None)
    extract_config = algo_req.get('extract_config', None)

    err = None
    if algo_module_path:
        found_algo_module = False
        module_name = algo_module_path.split('/')[-1]
        loader = importlib.machinery.SourceFileLoader(module_name,
                                                      algo_module_path)
        custom_algo_module = types.ModuleType(loader.name)
        loader.exec_module(custom_algo_module)
        use_custom_algo = True

        for member in inspect.getmembers(custom_algo_module):
            if module_name in str(member):
                found_algo_module = True
                break
        # for all members in this custom module file
    # if loading a custom algorithm module from a file on disk

    if not found_algo_module:
        err = (f'{label} - unable to find custom algorithm '
               f'module={custom_algo_module} module_path={algo_module_path}')
        if algo_module_path:
            err = (
                f'{label} - analysis_engine.'
                'work_tasks.run_distributed_algorithm was unable '
                f'to find custom algorithm module={custom_algo_module} with '
                f'provided path to \n file: {algo_module_path} \n'
                '\n'
                'Please confirm '
                'that the class inherits from the BaseAlgo class like:\n'
                '\n'
                'import analysis_engine.algo\n'
                'class MyAlgo(analysis_engine.algo.BaseAlgo):\n '
                '\n'
                'If it is then please file an issue on github:\n '
                'https://github.com/AlgoTraders/stock-analysis-engine/'
                'issues/new \n\nFor now this error results in a shutdown'
                '\n')
        # if algo_module_path set

        log.error(err)
        res = build_result.build_result(status=ae_consts.ERR,
                                        err=err,
                                        rec=None)
        task_result = {
            'status': res['status'],
            'err': res['err'],
            'algo_req': algo_req,
            'rec': rec
        }
        return task_result
    # if not found_algo_module

    use_start_date = start_date
    use_end_date = end_date
    if not use_end_date:
        end_date = datetime.datetime.utcnow()
        use_end_date = end_date.strftime(ae_consts.COMMON_TICK_DATE_FORMAT)
    if not use_start_date:
        start_date = end_date - datetime.timedelta(days=num_days_back)
        use_start_date = start_date.strftime(ae_consts.COMMON_TICK_DATE_FORMAT)
    dataset_publish_extract = algo_req.get('dataset_publish_extract', False)
    dataset_publish_history = algo_req.get('dataset_publish_history', False)
    dataset_publish_report = algo_req.get('dataset_publish_report', False)
    try:
        if use_custom_algo:
            if verbose:
                log.info(
                    f'inspecting {custom_algo_module} for class {module_name}')
            use_class_member_object = None
            for member in inspect.getmembers(custom_algo_module):
                if module_name in str(member):
                    if verbose:
                        log.info(f'start {name} with {member[1]}')
                    use_class_member_object = member
                    break
            # end of looking over the class definition but did not find it

            if use_class_member_object:
                if algo_req.get('backtest', False):
                    new_algo_object = member[1](ticker=algo_req['ticker'],
                                                config_dict=algo_req)
                else:
                    new_algo_object = member[1](**algo_req)
            else:
                err = (f'{label} - did not find a derived '
                       'analysis_engine.algo.BaseAlgo '
                       f'class in the module file={algo_module_path} '
                       f'for ticker={ticker} algo_name={name}')
                log.error(err)
                res = build_result.build_result(status=ae_consts.ERR,
                                                err=err,
                                                rec=None)
                task_result = {
                    'status': res['status'],
                    'err': res['err'],
                    'algo_req': algo_req,
                    'rec': rec
                }
                return task_result
            # end of finding a valid algorithm object
        else:
            new_algo_object = ae_algo.BaseAlgo(**algo_req)
        # if using a custom module path or the BaseAlgo

        if new_algo_object:
            # heads up - logging this might have passwords in the algo_req
            # log.debug(f'{name} algorithm request: {algo_req}')
            if verbose:
                log.info(f'{name} - run START ticker={ticker} '
                         f'from {use_start_date} to {use_end_date}')
            if algo_req.get('backtest', False):
                algo_res = run_algo.run_algo(algo=new_algo_object,
                                             config_dict=algo_req)
                created_algo_object = new_algo_object
            else:
                algo_res = run_algo.run_algo(algo=new_algo_object, **algo_req)
                created_algo_object = new_algo_object

            if verbose:
                log.info(f'{name} - run DONE ticker={ticker} '
                         f'from {use_start_date} to {use_end_date}')
            if debug:
                if custom_algo_module:
                    log.info(f'{name} - done run_algo '
                             f'custom_algo_module={custom_algo_module} '
                             f'module_name={module_name} ticker={ticker} '
                             f'from {use_start_date} to {use_end_date}')
                else:
                    log.info(
                        f'{name} - done run_algo BaseAlgo ticker={ticker} '
                        f'from {use_start_date} to {use_end_date}')
        else:
            err = (
                f'{label} - missing a derived analysis_engine.algo.BaseAlgo '
                f'class in the module file={algo_module_path} for '
                f'ticker={ticker} algo_name={name}')
            log.error(err)
            res = build_result.build_result(status=ae_consts.ERR,
                                            err=err,
                                            rec=None)
            task_result = {
                'status': res['status'],
                'err': res['err'],
                'algo_req': algo_req,
                'rec': rec
            }
            return task_result
        # end of finding a valid algorithm object

        if not created_algo_object:
            err = (f'{label} - failed creating algorithm object - '
                   f'ticker={ticker} '
                   f'status={ae_consts.get_status(status=algo_res["status"])} '
                   f'error={algo_res["err"]} algo name={name} '
                   f'custom_algo_module={custom_algo_module} '
                   f'module_name={module_name} '
                   f'from {use_start_date} to {use_end_date}')
            res = build_result.build_result(status=ae_consts.ERR,
                                            err=err,
                                            rec=None)
            task_result = {
                'status': res['status'],
                'err': res['err'],
                'algo_req': algo_req,
                'rec': rec
            }
            return task_result
        # end of stop early

        if should_publish_extract_dataset or dataset_publish_extract:
            s3_log = ''
            redis_log = ''
            file_log = ''
            use_log = 'publish'

            if (extract_config['redis_address'] and extract_config['redis_db']
                    and extract_config['redis_key']):
                redis_log = (f'redis://{extract_config["redis_address"]}'
                             f'@{extract_config["redis_db"]}'
                             f'/{extract_config["redis_key"]}')
                use_log += f' {redis_log}'
            else:
                extract_config['redis_enabled'] = False
            if (extract_config['s3_address'] and extract_config['s3_bucket']
                    and extract_config['s3_key']):
                s3_log = (f's3://{extract_config["s3_address"]}'
                          f'/{extract_config["s3_bucket"]}'
                          f'/{extract_config["s3_key"]}')
                use_log += f' {s3_log}'
            else:
                extract_config['s3_enabled'] = False
            if extract_config['output_file']:
                file_log = f'file:{extract_config["output_file"]}'
                use_log += f' {file_log}'

            if verbose:
                log.info(f'{name} - publish - start ticker={ticker} '
                         f'algorithm-ready {use_log}')

            publish_status = created_algo_object.publish_input_dataset(
                **extract_config)
            if publish_status != ae_consts.SUCCESS:
                msg = ('failed to publish algorithm-ready datasets with '
                       f'status {ae_consts.get_status(status=publish_status)} '
                       f'attempted to {use_log}')
                log.error(msg)
                res = build_result.build_result(status=ae_consts.ERR,
                                                err=err,
                                                rec=None)
                task_result = {
                    'status': res['status'],
                    'err': res['err'],
                    'algo_req': algo_req,
                    'rec': rec
                }
                return task_result
            # end of stop early

            if verbose:
                log.info(f'{name} - publish - done ticker={ticker} '
                         f'algorithm-ready {use_log}')
        # if publish the algorithm-ready dataset

        if should_publish_history_dataset or dataset_publish_history:
            s3_log = ''
            redis_log = ''
            file_log = ''
            use_log = 'publish'

            if (history_config['redis_address'] and history_config['redis_db']
                    and history_config['redis_key']):
                redis_log = (f'redis://{history_config["redis_address"]}'
                             f'@{history_config["redis_db"]}'
                             f'/{history_config["redis_key"]}')
                use_log += f' {redis_log}'
            if (history_config['s3_address'] and history_config['s3_bucket']
                    and history_config['s3_key']):
                s3_log = (f's3://{history_config["s3_address"]}'
                          f'/{history_config["s3_bucket"]}'
                          f'/{history_config["s3_key"]}')
                use_log += f' {s3_log}'
            if history_config['output_file']:
                file_log = f'file:{history_config["output_file"]}'
                use_log += f' {file_log}'

            if verbose:
                log.info(f'{name} - publish - start ticker={ticker} trading '
                         f'history {use_log}')

            publish_status = \
                created_algo_object.publish_trade_history_dataset(
                    **history_config)
            if publish_status != ae_consts.SUCCESS:
                msg = ('failed to publish trading history datasets with '
                       f'status {ae_consts.get_status(status=publish_status)} '
                       f'attempted to {use_log}')
                log.error(msg)
                res = build_result.build_result(status=ae_consts.ERR,
                                                err=err,
                                                rec=None)
                task_result = {
                    'status': res['status'],
                    'err': res['err'],
                    'algo_req': algo_req,
                    'rec': rec
                }
                return task_result
            # end of stop early

            if verbose:
                log.info(f'{name} - publish - done ticker={ticker} trading '
                         f'history {use_log}')
        # if publish an trading history dataset

        if should_publish_report_dataset or dataset_publish_report:
            s3_log = ''
            redis_log = ''
            file_log = ''
            use_log = 'publish'

            if (report_config['redis_address'] and report_config['redis_db']
                    and report_config['redis_key']):
                redis_log = (f'redis://{report_config["redis_address"]}'
                             f'@{report_config["redis_db"]}'
                             f'/{report_config["redis_key"]}')
                use_log += f' {redis_log}'
            if (report_config['s3_address'] and report_config['s3_bucket']
                    and report_config['s3_key']):
                s3_log = (f's3://{report_config["s3_address"]}'
                          f'/{report_config["s3_bucket"]}'
                          f'/{report_config["s3_key"]}')
                use_log += f' {s3_log}'
            if report_config['output_file']:
                file_log = f' file:{report_config["output_file"]}'
                use_log += f' {file_log}'

            if verbose:
                log.info(
                    f'{name} - publishing ticker={ticker} trading performance '
                    f'report {use_log}')

            publish_status = created_algo_object.publish_report_dataset(
                **report_config)
            if publish_status != ae_consts.SUCCESS:
                msg = ('failed to publish trading performance '
                       'report datasets with '
                       f'status {ae_consts.get_status(status=publish_status)} '
                       f'attempted to {use_log}')
                log.error(msg)
                res = build_result.build_result(status=ae_consts.ERR,
                                                err=err,
                                                rec=None)
                task_result = {
                    'status': res['status'],
                    'err': res['err'],
                    'algo_req': algo_req,
                    'rec': rec
                }
                return task_result
            # end of stop early

            if verbose:
                log.info(f'{name} - publish - done ticker={ticker} trading '
                         f'performance report {use_log}')
        # if publish an trading performance report dataset

        if verbose:
            log.info(f'{name} - done publishing datasets for ticker={ticker} '
                     f'from {use_start_date} to {use_end_date}')

        rec['history_config'] = history_config
        rec['report_config'] = report_config

        res = build_result.build_result(status=ae_consts.SUCCESS,
                                        err=None,
                                        rec=rec)

    except Exception as e:
        res = build_result.build_result(
            status=ae_consts.ERR,
            err=('failed - run_distributed_algorithm '
                 f'dict={algo_req} with ex={e}'),
            rec=rec)
        if raise_on_err:
            raise e
        else:
            log.error(f'{label} - {res["err"]}')
    # end of try/ex

    if verbose:
        log.info('task - run_distributed_algorithm done - '
                 f'{label} - status={ae_consts.get_status(res["status"])}')

    task_result = {
        'status': res['status'],
        'err': res['err'],
        'algo_req': algo_req,
        'rec': rec
    }
    return task_result
コード例 #13
0
def get_data_from_td(work_dict):
    """get_data_from_td

    Get pricing data from Tradier

    :param work_dict: request dictionary
    """
    label = 'get_data_from_td'

    log.debug(f'task - {label} - start work_dict={work_dict}')

    rec = {'data': None, 'updated': None}
    res = {'status': ae_consts.NOT_RUN, 'err': None, 'rec': rec}

    ticker = None
    field = None
    ft_type = None

    try:

        ticker = work_dict.get('ticker', ae_consts.TICKER)
        field = work_dict.get('field', 'daily')
        ft_type = work_dict.get('ft_type', None)
        ft_str = str(ft_type).lower()
        label = work_dict.get('label', label)
        orient = work_dict.get('orient', 'records')

        td_req = None
        if ft_type == td_consts.FETCH_TD_CALLS or ft_str == 'tdcalls':
            ft_type == td_consts.FETCH_TD_CALLS
            td_req = api_requests.build_td_fetch_calls_request(label=label)
        elif ft_type == td_consts.FETCH_TD_PUTS or ft_str == 'tdputs':
            ft_type == td_consts.FETCH_TD_PUTS
            td_req = api_requests.build_td_fetch_puts_request(label=label)
        else:
            log.error(
                f'{label} - unsupported ft_type={ft_type} ft_str={ft_str} '
                f'ticker={ticker}')
            raise NotImplementedError
        # if supported fetch request type

        clone_keys = [
            'ticker', 's3_address', 's3_bucket', 's3_key', 'redis_address',
            'redis_db', 'redis_password', 'redis_key'
        ]

        for k in clone_keys:
            td_req[k] = work_dict.get(k, f'{k}-missing-in-{label}')
        # end of cloning keys

        if not td_req:
            err = (f'{label} - ticker={td_req["ticker"]} did not build a TD '
                   f'request for work={work_dict}')
            log.error(err)
            res = build_result.build_result(status=ae_consts.ERR,
                                            err=err,
                                            rec=rec)
            return res
        else:
            log.debug(f'{label} - ticker={td_req["ticker"]} field={field} '
                      f'orient={orient} fetch')
        # if invalid td request

        df = None
        try:
            if 'from' in work_dict:
                td_req['from'] = datetime.datetime.strptime(
                    '%Y-%m-%d %H:%M:%S', work_dict['from'])
            status_df, df = td_fetch_data.fetch_data(work_dict=td_req,
                                                     fetch_type=ft_type)

            if status_df == ae_consts.SUCCESS:
                rec['data'] = df.to_json(orient=orient)
                rec['updated'] = datetime.datetime.utcnow().strftime(
                    '%Y-%m-%d %H:%M:%S')
            elif status_df == ae_consts.EMPTY:
                res = build_result.build_result(
                    status=ae_consts.ERR,
                    err=(f'did not fetch any data'),
                    rec=rec)
                return res
            else:
                err = (f'{label} - ticker={td_req["ticker"]} '
                       f'td_fetch_data.fetch_data field={ft_type} '
                       'failed fetch_data')
                log.critical(err)
                res = build_result.build_result(status=ae_consts.ERR,
                                                err=err,
                                                rec=rec)
                return res
        except Exception as f:
            err = (f'{label} - ticker={td_req["ticker"]} field={ft_type} '
                   f'failed fetch_data with ex={f}')
            log.critical(err)
            res = build_result.build_result(status=ae_consts.ERR,
                                            err=err,
                                            rec=rec)
            return res
        # end of try/ex

        if ae_consts.ev('DEBUG_TD_DATA', '0') == '1':
            log.debug(f'{label} ticker={td_req["ticker"]} field={field} '
                      f'data={rec["data"]} to_json')
        else:
            log.debug(
                f'{label} ticker={td_req["ticker"]} field={field} to_json')
        # end of if/else found data

        upload_and_cache_req = copy.deepcopy(td_req)
        upload_and_cache_req['celery_disabled'] = True
        upload_and_cache_req['data'] = rec['data']
        if not upload_and_cache_req['data']:
            upload_and_cache_req['data'] = '{}'
        use_field = field
        if use_field == 'news':
            use_field = 'news1'
        if 'redis_key' in work_dict:
            upload_and_cache_req['redis_key'] = (f'''{work_dict.get(
                    'redis_key',
                    td_req['redis_key'])}_'''
                                                 f'{use_field}')
        if 's3_key' in work_dict:
            upload_and_cache_req['s3_key'] = (f'''{work_dict.get(
                    's3_key',
                    td_req['s3_key'])}_'''
                                              f'{use_field}')

        try:
            update_res = publisher.run_publish_pricing_update(
                work_dict=upload_and_cache_req)
            update_status = update_res.get('status', ae_consts.NOT_SET)
            log.debug(f'{label} publish update '
                      f'status={ae_consts.get_status(status=update_status)} '
                      f'data={update_res}')
        except Exception:
            err = (
                f'{label} - failed to upload td data={upload_and_cache_req} '
                f'to s3_key={upload_and_cache_req["s3_key"]} and '
                f'redis_key={upload_and_cache_req["redis_key"]}')
            log.error(err)
        # end of try/ex to upload and cache

        if not rec['data']:
            log.debug(f'{label} - ticker={td_req["ticker"]} no Tradier data '
                      f'field={field} to publish')
        # end of if/else

        res = build_result.build_result(status=ae_consts.SUCCESS,
                                        err=None,
                                        rec=rec)

    except Exception as e:
        res = build_result.build_result(status=ae_consts.ERR,
                                        err=('failed - get_data_from_td '
                                             f'dict={work_dict} with ex={e}'),
                                        rec=rec)
    # end of try/ex

    log.debug('task - get_data_from_td done - '
              f'{label} - status={ae_consts.get_status(res["status"])} '
              f'err={res["err"]}')

    return res
コード例 #14
0
def get_new_pricing_data(self, work_dict):
    """get_new_pricing_data

    Get Ticker information on:

    - prices - turn off with ``work_dict.get_pricing = False``
    - news - turn off with ``work_dict.get_news = False``
    - options - turn off with ``work_dict.get_options = False``

    :param work_dict: dictionary for key/values
    """

    label = 'get_new_pricing_data'

    log.debug(f'task - {label} - start ' f'work_dict={work_dict}')

    num_success = 0
    ticker = ae_consts.TICKER
    ticker_id = ae_consts.TICKER_ID
    rec = {
        'pricing': None,
        'options': None,
        'calls': None,
        'puts': None,
        'news': None,
        'daily': None,
        'minute': None,
        'quote': None,
        'stats': None,
        'peers': None,
        'iex_news': None,
        'financials': None,
        'earnings': None,
        'dividends': None,
        'company': None,
        'exp_date': None,
        'publish_pricing_update': None,
        'num_success': num_success,
        'date': ae_utils.utc_now_str(),
        'updated': None,
        'version': ae_consts.DATASET_COLLECTION_VERSION
    }
    res = {'status': ae_consts.NOT_RUN, 'err': None, 'rec': rec}

    try:
        ticker = work_dict.get('ticker', ticker)
        ticker_id = work_dict.get('ticker_id', ae_consts.TICKER_ID)
        s3_bucket = work_dict.get('s3_bucket', ae_consts.S3_BUCKET)
        s3_key = work_dict.get('s3_key', ae_consts.S3_KEY)
        redis_key = work_dict.get('redis_key', ae_consts.REDIS_KEY)
        exp_date = work_dict.get('exp_date', None)
        cur_date = ae_utils.last_close()
        cur_strike = work_dict.get('strike', None)
        contract_type = str(work_dict.get('contract', 'C')).upper()
        label = work_dict.get('label', label)
        iex_datasets = work_dict.get('iex_datasets',
                                     iex_consts.DEFAULT_FETCH_DATASETS)
        td_datasets = work_dict.get('td_datasets',
                                    td_consts.DEFAULT_FETCH_DATASETS_TD)
        fetch_mode = work_dict.get('fetch_mode', ae_consts.FETCH_MODE_ALL)
        iex_token = work_dict.get('iex_token', iex_consts.IEX_TOKEN)
        td_token = work_dict.get('td_token', td_consts.TD_TOKEN)
        str_fetch_mode = str(fetch_mode).lower()

        # control flags to deal with feed issues:
        get_iex_data = True
        get_td_data = True

        if (fetch_mode == ae_consts.FETCH_MODE_ALL
                or str_fetch_mode == 'initial'):
            get_iex_data = True
            get_td_data = True
            iex_datasets = ae_consts.IEX_INITIAL_DATASETS
        elif (fetch_mode == ae_consts.FETCH_MODE_ALL
              or str_fetch_mode == 'all'):
            get_iex_data = True
            get_td_data = True
            iex_datasets = ae_consts.IEX_DATASETS_DEFAULT
        elif (fetch_mode == ae_consts.FETCH_MODE_YHO
              or str_fetch_mode == 'yahoo'):
            get_iex_data = False
            get_td_data = False
        elif (fetch_mode == ae_consts.FETCH_MODE_IEX
              or str_fetch_mode == 'iex-all'):
            get_iex_data = True
            get_td_data = False
            iex_datasets = ae_consts.IEX_DATASETS_DEFAULT
        elif (fetch_mode == ae_consts.FETCH_MODE_IEX
              or str_fetch_mode == 'iex'):
            get_iex_data = True
            get_td_data = False
            iex_datasets = ae_consts.IEX_INTRADAY_DATASETS
        elif (fetch_mode == ae_consts.FETCH_MODE_INTRADAY
              or str_fetch_mode == 'intra'):
            get_iex_data = True
            get_td_data = True
            iex_datasets = ae_consts.IEX_INTRADAY_DATASETS
        elif (fetch_mode == ae_consts.FETCH_MODE_DAILY
              or str_fetch_mode == 'daily'):
            get_iex_data = True
            get_td_data = False
            iex_datasets = ae_consts.IEX_DAILY_DATASETS
        elif (fetch_mode == ae_consts.FETCH_MODE_WEEKLY
              or str_fetch_mode == 'weekly'):
            get_iex_data = True
            get_td_data = False
            iex_datasets = ae_consts.IEX_WEEKLY_DATASETS
        elif (fetch_mode == ae_consts.FETCH_MODE_TD or str_fetch_mode == 'td'):
            get_iex_data = False
            get_td_data = True
        else:
            get_iex_data = False
            get_td_data = False

            fetch_arr = str_fetch_mode.split(',')
            found_fetch = False
            iex_datasets = []
            for fetch_name in fetch_arr:
                if fetch_name not in iex_datasets:
                    if fetch_name == 'iex_min':
                        iex_datasets.append('minute')
                    elif fetch_name == 'iex_day':
                        iex_datasets.append('daily')
                    elif fetch_name == 'iex_quote':
                        iex_datasets.append('quote')
                    elif fetch_name == 'iex_stats':
                        iex_datasets.append('stats')
                    elif fetch_name == 'iex_peers':
                        iex_datasets.append('peers')
                    elif fetch_name == 'iex_news':
                        iex_datasets.append('news')
                    elif fetch_name == 'iex_fin':
                        iex_datasets.append('financials')
                    elif fetch_name == 'iex_earn':
                        iex_datasets.append('earnings')
                    elif fetch_name == 'iex_div':
                        iex_datasets.append('dividends')
                    elif fetch_name == 'iex_comp':
                        iex_datasets.append('company')
                    elif fetch_name == 'td':
                        get_td_data = True
                    else:
                        log.warn('unsupported IEX dataset ' f'{fetch_name}')
            found_fetch = (len(iex_datasets) != 0)
            if not found_fetch:
                log.error(f'{label} - unsupported '
                          f'fetch_mode={fetch_mode} value')
            else:
                get_iex_data = True
                log.debug(f'{label} - '
                          f'fetching={len(iex_datasets)} '
                          f'{iex_datasets} '
                          f'fetch_mode={fetch_mode}')
        # end of screening custom fetch_mode settings

        num_tokens = 0

        if get_iex_data:
            if not iex_token:
                log.warn(f'{label} - '
                         'please set a valid IEX Cloud Account token ('
                         'https://iexcloud.io/cloud-login/#/register'
                         ') to fetch data from IEX Cloud. It must be '
                         'set as an environment variable like: '
                         'export IEX_TOKEN=<token>')
                get_iex_data = False
            else:
                num_tokens += 1
        # sanity check - disable IEX fetch if the token is not set
        if get_td_data:
            missing_td_token = [
                'MISSING_TD_TOKEN', 'SETYOURTDTOKEN', 'SETYOURTRADIERTOKENHERE'
            ]
            if td_token in missing_td_token:
                log.warn(f'{label} - '
                         'please set a valid Tradier Account token ('
                         'https://developer.tradier.com/user/sign_up'
                         ') to fetch pricing data from Tradier. It must be '
                         'set as an environment variable like: '
                         'export TD_TOKEN=<token>')
                get_td_data = False
            else:
                num_tokens += 1
        # sanity check - disable Tradier fetch if the token is not set
        """
        as of Thursday, Jan. 3, 2019:
        https://developer.yahoo.com/yql/
        Important EOL Notice: As of Thursday, Jan. 3, 2019
        the YQL service at query.yahooapis.com will be retired
        """
        get_yahoo_data = False

        if (not get_iex_data and not get_td_data and not get_yahoo_data):
            err = None
            if num_tokens == 0:
                res['status'] = ae_consts.MISSING_TOKEN
                err = (f'Please set a valid IEX_TOKEN or TD_TOKEN '
                       f'environment variable')
            else:
                err = (f'Please set at least one supported datafeed from '
                       f'either: '
                       f'IEX Cloud (fetch -t TICKER -g iex) or '
                       f'Tradier (fetch -t TICKER -g td) '
                       f'for '
                       f'ticker={ticker} '
                       f'cur_date={cur_date} '
                       f'IEX enabled={get_iex_data} '
                       f'TD enabled={get_td_data} '
                       f'YHO enabled={get_yahoo_data}')
                res['status'] = ae_consts.ERR
                res['err'] = err
            return get_task_results.get_task_results(work_dict=work_dict,
                                                     result=res)
        # end of checking that there is at least 1 feed on

        if not exp_date:
            exp_date = opt_dates.option_expiration(date=exp_date)
        else:
            exp_date = datetime.datetime.strptime(exp_date, '%Y-%m-%d')

        rec['updated'] = cur_date.strftime('%Y-%m-%d %H:%M:%S')
        log.debug(f'{label} getting pricing for ticker={ticker} '
                  f'cur_date={cur_date} exp_date={exp_date} '
                  f'IEX={get_iex_data} '
                  f'TD={get_td_data} '
                  f'YHO={get_yahoo_data}')

        yahoo_rec = {
            'ticker': ticker,
            'pricing': None,
            'options': None,
            'calls': None,
            'puts': None,
            'news': None,
            'exp_date': None,
            'publish_pricing_update': None,
            'date': None,
            'updated': None
        }

        # disabled on 2019-01-03
        if get_yahoo_data:
            log.debug(f'{label} YHO ticker={ticker}')
            yahoo_res = yahoo_data.get_data_from_yahoo(work_dict=work_dict)
            status_str = ae_consts.get_status(status=yahoo_res['status'])
            if yahoo_res['status'] == ae_consts.SUCCESS:
                yahoo_rec = yahoo_res['rec']
                msg = (f'{label} YHO ticker={ticker} '
                       f'status={status_str} err={yahoo_res["err"]}')
                if ae_consts.ev('SHOW_SUCCESS', '0') == '1':
                    log.info(msg)
                else:
                    log.debug(msg)
                rec['pricing'] = yahoo_rec.get('pricing', '{}')
                rec['news'] = yahoo_rec.get('news', '{}')
                rec['options'] = yahoo_rec.get('options', '{}')
                rec['calls'] = rec['options'].get('calls',
                                                  ae_consts.EMPTY_DF_STR)
                rec['puts'] = rec['options'].get('puts',
                                                 ae_consts.EMPTY_DF_STR)
                num_success += 1
            else:
                log.error(f'{label} failed YHO ticker={ticker} '
                          f'status={status_str} err={yahoo_res["err"]}')
        # end of get from yahoo

        if get_iex_data:
            num_iex_ds = len(iex_datasets)
            log.debug(f'{label} IEX datasets={num_iex_ds}')
            for idx, ft_type in enumerate(iex_datasets):
                dataset_field = iex_consts.get_ft_str(ft_type=ft_type)

                log.debug(f'{label} IEX={idx}/{num_iex_ds} '
                          f'field={dataset_field} ticker={ticker}')
                iex_label = f'{label}-{dataset_field}'
                iex_req = copy.deepcopy(work_dict)
                iex_req['label'] = iex_label
                iex_req['ft_type'] = ft_type
                iex_req['field'] = dataset_field
                iex_req['ticker'] = ticker
                iex_res = iex_data.get_data_from_iex(work_dict=iex_req)

                status_str = (ae_consts.get_status(status=iex_res['status']))
                if iex_res['status'] == ae_consts.SUCCESS:
                    iex_rec = iex_res['rec']
                    msg = (f'{label} IEX ticker={ticker} '
                           f'field={dataset_field} '
                           f'status={status_str} '
                           f'err={iex_res["err"]}')
                    if ae_consts.ev('SHOW_SUCCESS', '0') == '1':
                        log.info(msg)
                    else:
                        log.debug(msg)
                    if dataset_field == 'news':
                        rec['iex_news'] = iex_rec['data']
                    else:
                        rec[dataset_field] = iex_rec['data']
                    num_success += 1
                else:
                    log.debug(f'{label} failed IEX ticker={ticker} '
                              f'field={dataset_field} '
                              f'status={status_str} err={iex_res["err"]}')
                # end of if/else succcess
            # end idx, ft_type in enumerate(iex_datasets):
        # end of if get_iex_data

        if get_td_data:
            num_td_ds = len(td_datasets)
            log.debug(f'{label} TD datasets={num_td_ds}')

            for idx, ft_type in enumerate(td_datasets):
                dataset_field = td_consts.get_ft_str_td(ft_type=ft_type)
                log.debug(f'{label} TD={idx}/{num_td_ds} '
                          f'field={dataset_field} ticker={ticker}')
                td_label = (f'{label}-{dataset_field}')
                td_req = copy.deepcopy(work_dict)
                td_req['label'] = td_label
                td_req['ft_type'] = ft_type
                td_req['field'] = dataset_field
                td_req['ticker'] = ticker
                td_res = td_data.get_data_from_td(work_dict=td_req)

                status_str = (ae_consts.get_status(status=td_res['status']))
                if td_res['status'] == ae_consts.SUCCESS:
                    td_rec = td_res['rec']
                    msg = (f'{label} TD ticker={ticker} '
                           f'field={dataset_field} '
                           f'status={status_str} '
                           f'err={td_res["err"]}')
                    if ae_consts.ev('SHOW_SUCCESS', '0') == '1':
                        log.info(msg)
                    else:
                        log.debug(msg)
                    if dataset_field == 'tdcalls':
                        rec['tdcalls'] = td_rec['data']
                    if dataset_field == 'tdputs':
                        rec['tdputs'] = td_rec['data']
                    else:
                        rec[dataset_field] = td_rec['data']
                    num_success += 1
                else:
                    log.critical(f'{label} failed TD ticker={ticker} '
                                 f'field={dataset_field} '
                                 f'status={status_str} err={td_res["err"]}')
                # end of if/else succcess
            # end idx, ft_type in enumerate(td_datasets):
        # end of if get_td_data

        rec['num_success'] = num_success

        update_req = {'data': rec}
        update_req['ticker'] = ticker
        update_req['ticker_id'] = ticker_id
        update_req['strike'] = cur_strike
        update_req['contract'] = contract_type
        update_req['s3_enabled'] = work_dict.get('s3_enabled',
                                                 ae_consts.ENABLED_S3_UPLOAD)
        update_req['redis_enabled'] = work_dict.get(
            'redis_enabled', ae_consts.ENABLED_REDIS_PUBLISH)
        update_req['s3_bucket'] = s3_bucket
        update_req['s3_key'] = s3_key
        update_req['s3_access_key'] = work_dict.get('s3_access_key',
                                                    ae_consts.S3_ACCESS_KEY)
        update_req['s3_secret_key'] = work_dict.get('s3_secret_key',
                                                    ae_consts.S3_SECRET_KEY)
        update_req['s3_region_name'] = work_dict.get('s3_region_name',
                                                     ae_consts.S3_REGION_NAME)
        update_req['s3_address'] = work_dict.get('s3_address',
                                                 ae_consts.S3_ADDRESS)
        update_req['s3_secure'] = work_dict.get('s3_secure',
                                                ae_consts.S3_SECURE)
        update_req['redis_key'] = redis_key
        update_req['redis_address'] = work_dict.get('redis_address',
                                                    ae_consts.REDIS_ADDRESS)
        update_req['redis_password'] = work_dict.get('redis_password',
                                                     ae_consts.REDIS_PASSWORD)
        update_req['redis_db'] = int(
            work_dict.get('redis_db', ae_consts.REDIS_DB))
        update_req['redis_expire'] = work_dict.get('redis_expire',
                                                   ae_consts.REDIS_EXPIRE)
        update_req['updated'] = rec['updated']
        update_req['label'] = label
        update_req['celery_disabled'] = True
        update_status = ae_consts.NOT_SET

        try:
            update_res = publisher.run_publish_pricing_update(
                work_dict=update_req)
            update_status = update_res.get('status', ae_consts.NOT_SET)
            status_str = ae_consts.get_status(status=update_status)
            if ae_consts.ev('DEBUG_RESULTS', '0') == '1':
                log.debug(f'{label} update_res '
                          f'status={status_str} '
                          f'data={ae_consts.ppj(update_res)}')
            else:
                log.debug(f'{label} run_publish_pricing_update '
                          f'status={status_str}')
            # end of if/else

            rec['publish_pricing_update'] = update_res
            res = build_result.build_result(status=ae_consts.SUCCESS,
                                            err=None,
                                            rec=rec)
        except Exception as f:
            err = (f'{label} publisher.run_publish_pricing_update failed '
                   f'with ex={f}')
            log.error(err)
            res = build_result.build_result(status=ae_consts.ERR,
                                            err=err,
                                            rec=rec)
        # end of trying to publish results to connected services

    except Exception as e:
        res = build_result.build_result(status=ae_consts.ERR,
                                        err=('failed - get_new_pricing_data '
                                             f'dict={work_dict} with ex={e}'),
                                        rec=rec)
        log.error(f'{label} - {res["err"]}')
    # end of try/ex

    if ae_consts.ev('DATASET_COLLECTION_SLACK_ALERTS', '0') == '1':
        env_name = 'DEV'
        if ae_consts.ev('PROD_SLACK_ALERTS', '1') == '1':
            env_name = 'PROD'
        done_msg = (f'Dataset collected ticker=*{ticker}* on '
                    f'env=*{env_name}* '
                    f'redis_key={redis_key} s3_key={s3_key} '
                    f'IEX={get_iex_data} '
                    f'TD={get_td_data} '
                    f'YHO={get_yahoo_data}')
        log.debug(f'{label} sending slack msg={done_msg}')
        if res['status'] == ae_consts.SUCCESS:
            slack_utils.post_success(msg=done_msg, block=False, jupyter=True)
        else:
            slack_utils.post_failure(msg=done_msg, block=False, jupyter=True)
        # end of if/else success
    # end of publishing to slack

    log.debug('task - get_new_pricing_data done - '
              f'{label} - status={ae_consts.get_status(res["status"])}')

    return get_task_results.get_task_results(work_dict=work_dict, result=res)
コード例 #15
0
def plot_dnn_fit_history(
        title,
        df,
        red,
        red_color=None,
        red_label=None,
        blue=None,
        blue_color=None,
        blue_label=None,
        green=None,
        green_color=None,
        green_label=None,
        orange=None,
        orange_color=None,
        orange_label=None,
        xlabel='Training Epochs',
        ylabel='Error Values',
        linestyle='-',
        width=9.0,
        height=9.0,
        date_format='%d\n%b',
        df_filter=None,
        start_date=None,
        footnote_text=None,
        footnote_xpos=0.70,
        footnote_ypos=0.01,
        footnote_color='#888888',
        footnote_fontsize=8,
        scale_y=False,
        show_plot=True,
        dropna_for_all=False,
        verbose=False,
        send_plots_to_slack=False):
    """plot_dnn_fit_history

    Plot a DNN's fit history using `Keras fit history object <https://ker
    as.io/visualization/#training-history-visualization>`__

    :param title: title of the plot
    :param df: dataset which is ``pandas.DataFrame``
    :param red: string - column name to plot in
        ``red_color`` (or default ``ae_consts.PLOT_COLORS[red]``)
        where the column is in the ``df`` and
        accessible with:``df[red]``
    :param red_color: hex color code to plot the data in the
        ``df[red]``  (default is ``ae_consts.PLOT_COLORS['red']``)
    :param red_label: optional - string for the label used
        to identify the ``red`` line in the legend
    :param blue: string - column name to plot in
        ``blue_color`` (or default ``ae_consts.PLOT_COLORS['blue']``)
        where the column is in the ``df`` and
        accessible with:``df[blue]``
    :param blue_color: hex color code to plot the data in the
        ``df[blue]``  (default is ``ae_consts.PLOT_COLORS['blue']``)
    :param blue_label: optional - string for the label used
        to identify the ``blue`` line in the legend
    :param green: string - column name to plot in
        ``green_color`` (or default ``ae_consts.PLOT_COLORS['darkgreen']``)
        where the column is in the ``df`` and
        accessible with:``df[green]``
    :param green_color: hex color code to plot the data in the
        ``df[green]``  (default is ``ae_consts.PLOT_COLORS['darkgreen']``)
    :param green_label: optional - string for the label used
        to identify the ``green`` line in the legend
    :param orange: string - column name to plot in
        ``orange_color`` (or default ``ae_consts.PLOT_COLORS['orange']``)
        where the column is in the ``df`` and
        accessible with:``df[orange]``
    :param orange_color: hex color code to plot the data in the
        ``df[orange]``  (default is ``ae_consts.PLOT_COLORS['orange']``)
    :param orange_label: optional - string for the label used
        to identify the ``orange`` line in the legend
    :param xlabel: x-axis label
    :param ylabel: y-axis label
    :param linestyle: style of the plot line
    :param width: float - width of the image
    :param height: float - height of the image
    :param date_format: string - format for dates
    :param df_filter: optional - initialized ``pandas.DataFrame`` query
        for reducing the ``df`` records before plotting. As an eaxmple
        ``df_filter=(df['close'] > 0.01)`` would find only records in
        the ``df`` with a ``close`` value greater than ``0.01``
    :param start_date: optional - string ``datetime``
        for plotting only from a date formatted as
        ``YYYY-MM-DD HH\\:MM\\:SS``
    :param footnote_text: optional - string footnote text
        (default is ``algotraders <DATE>``)
    :param footnote_xpos: optional - float for footnote position
        on the x-axies
        (default is ``0.75``)
    :param footnote_ypos: optional - float for footnote position
        on the y-axies
        (default is ``0.01``)
    :param footnote_color: optional - string hex color code for
        the footnote text
        (default is ``#888888``)
    :param footnote_fontsize: optional - float footnote font size
        (default is ``8``)
    :param scale_y: optional - bool to scale the y-axis with
        .. code-block:: python

            use_ax.set_ylim(
                [0, use_ax.get_ylim()[1] * 3])
    :param show_plot: bool to show the plot
    :param dropna_for_all: optional - bool to toggle keep None's in
        the plot ``df`` (default is drop them for display purposes)
    :param verbose: optional - bool to show logs for debugging
        a dataset
    :param send_plots_to_slack: optional - bool to send the dnn plot to slack
    """

    rec = {
        'ax1': None,
        'fig': None
    }
    result = build_result.build_result(
        status=ae_consts.NOT_RUN,
        err=None,
        rec=rec)

    if verbose:
        log.info(
            f'plot_dnn_fit_history - start')

    use_red = red_color
    use_blue = blue_color
    use_green = green_color
    use_orange = orange_color

    if not use_red:
        use_red = ae_consts.PLOT_COLORS['red']
    if not use_blue:
        use_blue = ae_consts.PLOT_COLORS['blue']
    if not use_green:
        use_green = ae_consts.PLOT_COLORS['darkgreen']
    if not use_orange:
        use_orange = ae_consts.PLOT_COLORS['orange']

    use_footnote = footnote_text
    if not use_footnote:
        use_footnote = f'''algotraders - {datetime.datetime.now().strftime(
            ae_consts.COMMON_TICK_DATE_FORMAT)}'''

    column_list = []
    all_plots = []
    if red:
        column_list.append(red)
        all_plots.append({
            'column': red,
            'color': use_red})
    if blue:
        column_list.append(blue)
        all_plots.append({
            'column': blue,
            'color': use_blue})
    if green:
        column_list.append(green)
        all_plots.append({
            'column': green,
            'color': use_green})
    if orange:
        column_list.append(orange)
        all_plots.append({
            'column': orange,
            'color': use_orange})

    use_df = df

    if hasattr(df_filter, 'to_json'):
        # Was seeing this warning below in Jupyter:
        # UserWarning: Boolean Series key
        # will be reindexed to match DataFrame index
        # use_df = use_df[df_filter][column_list]
        # now using:
        use_df = use_df.loc[df_filter, column_list]

    if verbose:
        log.info(
            f'plot_dnn_fit_history '
            f'filter df.index={len(use_df.index)} '
            f'column_list={column_list}')

    ae_charts.set_common_seaborn_fonts()

    hex_color = ae_consts.PLOT_COLORS['blue']
    fig, ax = plt.subplots(
        sharex=True,
        sharey=True,
        figsize=(
            width,
            height))

    all_axes = [
        ax
    ]
    num_plots = len(all_plots)
    for idx, node in enumerate(all_plots):
        column_name = node['column']
        hex_color = node['color']

        use_ax = ax

        if verbose:
            log.info(
                f'plot_dnn_fit_history - '
                f'{idx + 1}/{num_plots} - '
                f'{column_name} '
                f'in '
                f'{hex_color} - '
                f'ax={use_ax}')

        use_ax.plot(
            use_df[column_name],
            label=column_name,
            linestyle=linestyle,
            color=hex_color)
        # end if this is not the fist axis

    # end of for all plots

    lines = []
    for idx, cur_ax in enumerate(all_axes):
        ax_lines = cur_ax.get_lines()
        for line in ax_lines:
            label_name = str(line.get_label())
            use_label = label_name
            if idx == 0:
                if red_label:
                    use_label = red_label
            elif idx == 1:
                if blue_label:
                    use_label = blue_label
            elif idx == 2:
                use_label = label_name[-20:]
                if green_label:
                    use_label = green_label
            elif idx == 3:
                use_label = label_name[-20:]
                if orange_label:
                    use_label = orange_label
            else:
                if len(label_name) > 10:
                    use_label = label_name[-20:]
            # end of fixing the labels in the legend
            line.set_label(use_label)
            if line.get_label() not in lines:
                lines.append(line)
        rec[f'ax{idx + 1}'] = cur_ax
    # end of compiling a new-shortened legend while removing dupes

    for idx, cur_ax in enumerate(all_axes):
        if cur_ax:
            if cur_ax.get_legend():
                cur_ax.get_legend().remove()
    # end of removing all previous legends

    if verbose:
        log.info(
            f'legend lines={[l.get_label() for l in lines]}')
    # log what's going to be in the legend

    ax.legend(
        lines,
        [l.get_label() for l in lines],
        loc='best',
        shadow=True)

    fig.autofmt_xdate()

    plt.xlabel(xlabel)
    plt.ylabel(ylabel)

    ax.set_title(title)
    ae_charts.add_footnote(
        fig=fig,
        xpos=footnote_xpos,
        ypos=footnote_ypos,
        text=use_footnote,
        color=footnote_color,
        fontsize=footnote_fontsize)
    plt.tight_layout()

    if send_plots_to_slack:
        post_plot(plt, title=title)

    if show_plot:
        plt.show()
    else:
        plt.plot()

    rec['fig'] = fig

    result = build_result.build_result(
        status=ae_consts.SUCCESS,
        err=None,
        rec=rec)

    return result
コード例 #16
0
def plot_overlay_pricing_and_volume(
        log_label,
        ticker,
        df,
        xlabel=None,
        ylabel=None,
        high_color=ae_consts.PLOT_COLORS['high'],
        close_color=ae_consts.PLOT_COLORS['blue'],
        volume_color=ae_consts.PLOT_COLORS['green'],
        date_format=ae_consts.IEX_MINUTE_DATE_FORMAT,
        show_plot=True,
        dropna_for_all=True):
    """plot_overlay_pricing_and_volume

    Plot pricing (high, low, open, close) and volume as
    an overlay off the x-axis

    Here is a sample chart from the
    `Stock Analysis Jupyter Intro Notebook <https://github.com/Al
    goTraders/stock-analysis-engine/blob/master/co
    mpose/docker/notebooks/Stock-Analysis-Intro.ipynb>`__

    .. image:: https://i.imgur.com/pH368gy.png

    :param log_label: log identifier
    :param ticker: ticker name
    :param df: timeseries ``pandas.DateFrame``
    :param xlabel: x-axis label
    :param ylabel: y-axis label
    :param high_color: optional - high plot color
    :param close_color: optional - close plot color
    :param volume_color: optional - volume color
    :param data_format: optional - date format string this must
        be a valid value for the ``df['date']`` column
        that would work with:
        ``datetime.datetime.stftime(date_format)``
    :param show_plot: optional - bool to show the plot
    :param dropna_for_all: optional - bool to toggle keep None's in
        the plot ``df`` (default is drop them
        for display purposes)
    """

    rec = {
        'fig': None,
        'ax': None,
        'ax2': None
    }
    result = build_result.build_result(
        status=ae_consts.NOT_RUN,
        err=None,
        rec=rec)

    try:

        log.info(
            f'{log_label} - '
            'plot_overlay_pricing_and_volume'
            ' - start')

        set_common_seaborn_fonts()

        use_df = df
        if dropna_for_all:
            log.info(
                f'{log_label} - '
                'plot_overlay_pricing_and_volume'
                ' - dropna_for_all')
            use_df = df.dropna(axis=0, how='any')
        # end of pre-plot dataframe scrubbing

        fig, ax = plt.subplots(
            sharex=True,
            sharey=True,
            figsize=(15.0, 10.0))
        ax.plot(
            use_df['date'],
            use_df['close'],
            color=close_color)
        ax.plot(
            use_df['date'],
            use_df['high'],
            color=high_color)

        # use a second axis to display the
        # volume since it is in a different range
        # this will fill under the
        # volume's y values as well
        ax2 = ax.twinx()
        ax2.plot(
            use_df['date'],
            use_df['volume'],
            linestyle='-',
            color=volume_color,
            alpha=0.6)
        ax2.fill_between(
            use_df['date'].values,
            0,
            use_df['volume'].values,
            color=volume_color,
            alpha=0.5)
        # setup the second plot for volume
        ax2.set_ylim([0, ax2.get_ylim()[1] * 3])

        plt.grid(True)
        use_xlabel = xlabel
        use_ylabel = ylabel
        if not use_xlabel:
            xlabel = 'Minute Dates'
        if not use_ylabel:
            ylabel = f'{ticker} High and Close Prices'
        plt.xlabel(use_xlabel)
        plt.ylabel(use_ylabel)

        # Build a date vs Close DataFrame
        start_date = ''
        end_date = ''
        try:
            start_date = str(use_df.iloc[0]['date'].strftime(date_format))
            end_date = str(use_df.iloc[-1]['date'].strftime(date_format))
        except Exception:
            date_format = '%Y-%m-%d'
            start_date = str(use_df.iloc[0]['date'].strftime(date_format))
            end_date = str(use_df.iloc[-1]['date'].strftime(date_format))

        use_title = (
            f'{ticker} Pricing from: {start_date} to {end_date}')
        ax.set_title(use_title)

        # Merge in the second axis (volume) Legend
        handles, labels = plt.gca().get_legend_handles_labels()
        newLabels, newHandles = [], []
        for handle, label in zip(handles, labels):
            if label not in newLabels:
                newLabels.append(label)
                newHandles.append(handle)
        lines = ax.get_lines() + ax2.get_lines() + newHandles
        ax.legend(
            lines,
            [l.get_label() for l in lines],
            loc='best',
            shadow=True)

        # Build out the xtick chart by the dates
        ax.xaxis.grid(True, which='minor')
        ax.fmt_xdata = mdates.DateFormatter(date_format)
        ax.xaxis.set_major_formatter(ax.fmt_xdata)
        ax.xaxis.set_minor_formatter(ax.fmt_xdata)

        # turn off the grids on volume
        ax2.fmt_xdata = mdates.DateFormatter(date_format)
        ax2.xaxis.grid(False)
        ax2.yaxis.grid(False)
        ax2.yaxis.set_ticklabels([])

        fig.autofmt_xdate()

        show_with_entities(
            log_label=log_label,
            xlabel=xlabel,
            ylabel=ylabel,
            title=use_title,
            ax=ax,
            fig=fig,
            show_plot=show_plot)

        rec['fig'] = fig
        rec['ax'] = ax
        rec['ax2'] = ax2

        result = build_result.build_result(
            status=ae_consts.SUCCESS,
            err=None,
            rec=rec)

    except Exception as e:
        err = (
            'failed plot_overlay_pricing_and_volume '
            f'and volume with ex={e}')
        result = build_result.build_result(
            status=ae_consts.ERR,
            err=err,
            rec=rec)
    # end of try/ex

    send_final_log(
        log_label=log_label,
        fn_name='plot_overlay_pricing_and_volume',
        result=result)

    return result
コード例 #17
0
def get_data_from_iex(work_dict):
    """get_data_from_iex

    Get pricing from iex

    :param work_dict: request dictionary
    """
    label = 'get_data_from_iex'

    log.info('task - {} - start ' 'work_dict={}'.format(label, work_dict))

    rec = {'data': None, 'updated': None}
    res = {'status': ae_consts.NOT_RUN, 'err': None, 'rec': rec}

    ticker = None
    field = None
    ft_type = None

    try:

        ticker = work_dict.get('ticker', ae_consts.TICKER)
        field = work_dict.get('field', 'daily')
        ft_type = work_dict.get('ft_type', None)
        ft_str = str(ft_type).lower()
        label = work_dict.get('label', label)
        orient = work_dict.get('orient', 'records')

        iex_req = None
        if ft_type == iex_consts.FETCH_DAILY or ft_str == 'daily':
            ft_type == iex_consts.FETCH_DAILY
            iex_req = api_requests.build_iex_fetch_daily_request(label=label)
        elif ft_type == iex_consts.FETCH_MINUTE or ft_str == 'minute':
            ft_type == iex_consts.FETCH_MINUTE
            iex_req = api_requests.build_iex_fetch_minute_request(label=label)
        elif ft_type == iex_consts.FETCH_QUOTE or ft_str == 'quote':
            ft_type == iex_consts.FETCH_QUOTE
            iex_req = api_requests.build_iex_fetch_quote_request(label=label)
        elif ft_type == iex_consts.FETCH_STATS or ft_str == 'stats':
            ft_type == iex_consts.FETCH_STATS
            iex_req = api_requests.build_iex_fetch_stats_request(label=label)
        elif ft_type == iex_consts.FETCH_PEERS or ft_str == 'peers':
            ft_type == iex_consts.FETCH_PEERS
            iex_req = api_requests.build_iex_fetch_peers_request(label=label)
        elif ft_type == iex_consts.FETCH_NEWS or ft_str == 'news':
            ft_type == iex_consts.FETCH_NEWS
            iex_req = api_requests.build_iex_fetch_news_request(label=label)
        elif ft_type == iex_consts.FETCH_FINANCIALS or ft_str == 'financials':
            ft_type == iex_consts.FETCH_FINANCIALS
            iex_req = api_requests.build_iex_fetch_financials_request(
                label=label)
        elif ft_type == iex_consts.FETCH_EARNINGS or ft_str == 'earnings':
            ft_type == iex_consts.FETCH_EARNINGS
            iex_req = api_requests.build_iex_fetch_earnings_request(
                label=label)
        elif ft_type == iex_consts.FETCH_DIVIDENDS or ft_str == 'dividends':
            ft_type == iex_consts.FETCH_DIVIDENDS
            iex_req = api_requests.build_iex_fetch_dividends_request(
                label=label)
        elif ft_type == iex_consts.FETCH_COMPANY or ft_str == 'company':
            ft_type == iex_consts.FETCH_COMPANY
            iex_req = api_requests.build_iex_fetch_company_request(label=label)
        else:
            log.error('{} - unsupported ft_type={} ft_str={} ticker={}'.format(
                label, ft_type, ft_str, ticker))
            raise NotImplemented
        # if supported fetch request type

        clone_keys = [
            'ticker', 's3_address', 's3_bucket', 's3_key', 'redis_address',
            'redis_db', 'redis_password', 'redis_key'
        ]

        for k in clone_keys:
            iex_req[k] = work_dict.get(k, '{}-missing-in-{}'.format(k, label))
        # end of cloning keys

        if not iex_req:
            err = ('{} - ticker={} did not build an IEX request '
                   'for work={}'.format(label, iex_req['ticker'], work_dict))
            log.error(err)
            res = build_result.build_result(status=ae_consts.ERR,
                                            err=err,
                                            rec=rec)
            return res
        else:
            log.info('{} - ticker={} field={} '
                     'orient={} fetch'.format(label, iex_req['ticker'], field,
                                              orient))
        # if invalid iex request

        df = None
        try:
            if 'from' in work_dict:
                iex_req['from'] = datetime.datetime.strptime(
                    '%Y-%m-%d %H:%M:%S', work_dict['from'])
            df = iex_fetch_data.fetch_data(work_dict=iex_req,
                                           fetch_type=ft_type)
            rec['data'] = df.to_json(orient=orient, date_format='iso')
            rec['updated'] = datetime.datetime.utcnow().strftime(
                '%Y-%m-%d %H:%M:%S')
        except Exception as f:
            log.error('{} - ticker={} field={} failed fetch_data '
                      'with ex={}'.format(label, iex_req['ticker'], ft_type,
                                          f))
        # end of try/ex

        if ae_consts.ev('DEBUG_IEX_DATA', '0') == '1':
            log.info('{} ticker={} field={} data={} to_json'.format(
                label, iex_req['ticker'], field, rec['data']))
        else:
            log.info('{} ticker={} field={} to_json'.format(
                label, iex_req['ticker'], field))
        # end of if/else found data

        upload_and_cache_req = copy.deepcopy(iex_req)
        upload_and_cache_req['celery_disabled'] = True
        upload_and_cache_req['data'] = rec['data']
        if not upload_and_cache_req['data']:
            upload_and_cache_req['data'] = '{}'
        use_field = field
        if use_field == 'news':
            use_field = 'news1'
        if 'redis_key' in work_dict:
            upload_and_cache_req['redis_key'] = '{}_{}'.format(
                work_dict.get('redis_key', iex_req['redis_key']), use_field)
        if 's3_key' in work_dict:
            upload_and_cache_req['s3_key'] = '{}_{}'.format(
                work_dict.get('s3_key', iex_req['s3_key']), use_field)

        try:
            update_res = publisher.run_publish_pricing_update(
                work_dict=upload_and_cache_req)
            update_status = update_res.get('status', ae_consts.NOT_SET)
            log.info('{} publish update status={} data={}'.format(
                label, ae_consts.get_status(status=update_status), update_res))
        except Exception as f:
            err = ('{} - failed to upload iex data={} to '
                   'to s3_key={} and redis_key={}'.format(
                       label, upload_and_cache_req,
                       upload_and_cache_req['s3_key'],
                       upload_and_cache_req['redis_key']))
            log.error(err)
        # end of try/ex to upload and cache

        if not rec['data']:
            log.info('{} - ticker={} no IEX data field={} to publish'.format(
                label, iex_req['ticker'], field))
        # end of if/else

        res = build_result.build_result(status=ae_consts.SUCCESS,
                                        err=None,
                                        rec=rec)

    except Exception as e:
        res = build_result.build_result(status=ae_consts.ERR,
                                        err=('failed - get_data_from_iex '
                                             'dict={} with ex={}').format(
                                                 work_dict, e),
                                        rec=rec)
    # end of try/ex

    log.info('task - get_data_from_iex done - '
             '{} - status={} err={}'.format(
                 label, ae_consts.get_status(res['status']), res['err']))

    return res
コード例 #18
0
def get_new_pricing_data(self, work_dict):
    """get_new_pricing_data

    Get Ticker information on:

    - prices - turn off with ``work_dict.get_pricing = False``
    - news - turn off with ``work_dict.get_news = False``
    - options - turn off with ``work_dict.get_options = False``

    :param work_dict: dictionary for key/values
    """

    label = 'get_new_pricing_data'

    log.info('task - {} - start ' 'work_dict={}'.format(label, work_dict))

    ticker = ae_consts.TICKER
    ticker_id = ae_consts.TICKER_ID
    rec = {
        'pricing': None,
        'options': None,
        'calls': None,
        'puts': None,
        'news': None,
        'daily': None,
        'minute': None,
        'quote': None,
        'stats': None,
        'peers': None,
        'iex_news': None,
        'financials': None,
        'earnings': None,
        'dividends': None,
        'company': None,
        'exp_date': None,
        'publish_pricing_update': None,
        'date': ae_utils.utc_now_str(),
        'updated': None,
        'version': ae_consts.DATASET_COLLECTION_VERSION
    }
    res = {'status': ae_consts.NOT_RUN, 'err': None, 'rec': rec}

    try:
        ticker = work_dict.get('ticker', ticker)
        ticker_id = work_dict.get('ticker_id', ae_consts.TICKER_ID)
        s3_bucket = work_dict.get('s3_bucket', ae_consts.S3_BUCKET)
        s3_key = work_dict.get('s3_key', ae_consts.S3_KEY)
        redis_key = work_dict.get('redis_key', ae_consts.REDIS_KEY)
        exp_date = work_dict.get('exp_date', None)
        cur_date = datetime.datetime.utcnow()
        cur_strike = work_dict.get('strike', None)
        contract_type = str(work_dict.get('contract', 'C')).upper()
        label = work_dict.get('label', label)
        iex_datasets = work_dict.get('iex_datasets',
                                     iex_consts.DEFAULT_FETCH_DATASETS)
        td_datasets = work_dict.get('td_datasets',
                                    td_consts.DEFAULT_FETCH_DATASETS_TD)
        fetch_mode = work_dict.get('fetch_mode', ae_consts.FETCH_MODE_ALL)

        # control flags to deal with feed issues:
        get_iex_data = True
        get_td_data = True

        if (fetch_mode == ae_consts.FETCH_MODE_ALL
                or str(fetch_mode).lower() == 'all'):
            get_iex_data = True
            get_td_data = True
        elif (fetch_mode == ae_consts.FETCH_MODE_YHO
              or str(fetch_mode).lower() == 'yahoo'):
            get_iex_data = False
            get_td_data = False
        elif (fetch_mode == ae_consts.FETCH_MODE_IEX
              or str(fetch_mode).lower() == 'iex'):
            get_iex_data = True
            get_td_data = False
        elif (fetch_mode == ae_consts.FETCH_MODE_TD
              or str(fetch_mode).lower() == 'td'):
            get_iex_data = False
            get_td_data = True
        else:
            log.debug('{} - unsupported fetch_mode={} value'.format(
                label, fetch_mode))
        """
        as of Thursday, Jan. 3, 2019:
        https://developer.yahoo.com/yql/
        Important EOL Notice: As of Thursday, Jan. 3, 2019
        the YQL service at query.yahooapis.com will be retired
        """
        get_yahoo_data = False

        if not exp_date:
            exp_date = opt_dates.option_expiration(date=exp_date)
        else:
            exp_date = datetime.datetime.strptime(exp_date, '%Y-%m-%d')

        rec['updated'] = cur_date.strftime('%Y-%m-%d %H:%M:%S')
        log.info('{} getting pricing for ticker={} '
                 'cur_date={} exp_date={} '
                 'yahoo={} iex={}'.format(label, ticker, cur_date, exp_date,
                                          get_yahoo_data, get_iex_data))

        yahoo_rec = {
            'ticker': ticker,
            'pricing': None,
            'options': None,
            'calls': None,
            'puts': None,
            'news': None,
            'exp_date': None,
            'publish_pricing_update': None,
            'date': None,
            'updated': None
        }

        # disabled on 2019-01-03
        if get_yahoo_data:
            log.info('{} yahoo ticker={}'.format(label, ticker))
            yahoo_res = yahoo_data.get_data_from_yahoo(work_dict=work_dict)
            if yahoo_res['status'] == ae_consts.SUCCESS:
                yahoo_rec = yahoo_res['rec']
                log.info('{} yahoo ticker={} '
                         'status={} err={}'.format(
                             label, ticker,
                             ae_consts.get_status(status=yahoo_res['status']),
                             yahoo_res['err']))
                rec['pricing'] = yahoo_rec.get('pricing', '{}')
                rec['news'] = yahoo_rec.get('news', '{}')
                rec['options'] = yahoo_rec.get('options', '{}')
                rec['calls'] = rec['options'].get('calls',
                                                  ae_consts.EMPTY_DF_STR)
                rec['puts'] = rec['options'].get('puts',
                                                 ae_consts.EMPTY_DF_STR)
            else:
                log.error('{} failed YAHOO ticker={} '
                          'status={} err={}'.format(
                              label, ticker,
                              ae_consts.get_status(status=yahoo_res['status']),
                              yahoo_res['err']))
        # end of get from yahoo

        if get_iex_data:
            num_iex_ds = len(iex_datasets)
            log.debug('{} iex datasets={}'.format(label, num_iex_ds))
            for idx, ft_type in enumerate(iex_datasets):
                dataset_field = iex_consts.get_ft_str(ft_type=ft_type)

                log.info('{} iex={}/{} field={} ticker={}'.format(
                    label, idx, num_iex_ds, dataset_field, ticker))
                iex_label = '{}-{}'.format(label, dataset_field)
                iex_req = copy.deepcopy(work_dict)
                iex_req['label'] = iex_label
                iex_req['ft_type'] = ft_type
                iex_req['field'] = dataset_field
                iex_req['ticker'] = ticker
                iex_res = iex_data.get_data_from_iex(work_dict=iex_req)

                if iex_res['status'] == ae_consts.SUCCESS:
                    iex_rec = iex_res['rec']
                    log.info(
                        '{} iex ticker={} field={} '
                        'status={} err={}'.format(
                            label, ticker, dataset_field,
                            ae_consts.get_status(status=iex_res['status']),
                            iex_res['err']))
                    if dataset_field == 'news':
                        rec['iex_news'] = iex_rec['data']
                    else:
                        rec[dataset_field] = iex_rec['data']
                else:
                    log.debug(
                        '{} failed IEX ticker={} field={} '
                        'status={} err={}'.format(
                            label, ticker, dataset_field,
                            ae_consts.get_status(status=iex_res['status']),
                            iex_res['err']))
                # end of if/else succcess
            # end idx, ft_type in enumerate(iex_datasets):
        # end of if get_iex_data

        if get_td_data:
            num_td_ds = len(td_datasets)
            log.debug('{} td datasets={}'.format(label, num_td_ds))
            for idx, ft_type in enumerate(td_datasets):
                dataset_field = td_consts.get_ft_str_td(ft_type=ft_type)

                log.info('{} td={}/{} field={} ticker={}'.format(
                    label, idx, num_td_ds, dataset_field, ticker))
                td_label = '{}-{}'.format(label, dataset_field)
                td_req = copy.deepcopy(work_dict)
                td_req['label'] = td_label
                td_req['ft_type'] = ft_type
                td_req['field'] = dataset_field
                td_req['ticker'] = ticker
                td_res = td_data.get_data_from_td(work_dict=td_req)

                if td_res['status'] == ae_consts.SUCCESS:
                    td_rec = td_res['rec']
                    log.info('{} td ticker={} field={} '
                             'status={} err={}'.format(
                                 label, ticker, dataset_field,
                                 ae_consts.get_status(status=td_res['status']),
                                 td_res['err']))
                    if dataset_field == 'tdcalls':
                        rec['tdcalls'] = td_rec['data']
                    if dataset_field == 'tdputs':
                        rec['tdputs'] = td_rec['data']
                    else:
                        rec[dataset_field] = td_rec['data']
                else:
                    log.critical(
                        '{} failed TD ticker={} field={} '
                        'status={} err={}'.format(
                            label, ticker, dataset_field,
                            ae_consts.get_status(status=td_res['status']),
                            td_res['err']))
                # end of if/else succcess
            # end idx, ft_type in enumerate(td_datasets):
        # end of if get_td_data

        update_req = {'data': rec}
        update_req['ticker'] = ticker
        update_req['ticker_id'] = ticker_id
        update_req['strike'] = cur_strike
        update_req['contract'] = contract_type
        update_req['s3_enabled'] = work_dict.get('s3_enabled',
                                                 ae_consts.ENABLED_S3_UPLOAD)
        update_req['redis_enabled'] = work_dict.get(
            'redis_enabled', ae_consts.ENABLED_REDIS_PUBLISH)
        update_req['s3_bucket'] = s3_bucket
        update_req['s3_key'] = s3_key
        update_req['s3_access_key'] = work_dict.get('s3_access_key',
                                                    ae_consts.S3_ACCESS_KEY)
        update_req['s3_secret_key'] = work_dict.get('s3_secret_key',
                                                    ae_consts.S3_SECRET_KEY)
        update_req['s3_region_name'] = work_dict.get('s3_region_name',
                                                     ae_consts.S3_REGION_NAME)
        update_req['s3_address'] = work_dict.get('s3_address',
                                                 ae_consts.S3_ADDRESS)
        update_req['s3_secure'] = work_dict.get('s3_secure',
                                                ae_consts.S3_SECURE)
        update_req['redis_key'] = redis_key
        update_req['redis_address'] = work_dict.get('redis_address',
                                                    ae_consts.REDIS_ADDRESS)
        update_req['redis_password'] = work_dict.get('redis_password',
                                                     ae_consts.REDIS_PASSWORD)
        update_req['redis_db'] = int(
            work_dict.get('redis_db', ae_consts.REDIS_DB))
        update_req['redis_expire'] = work_dict.get('redis_expire',
                                                   ae_consts.REDIS_EXPIRE)
        update_req['updated'] = rec['updated']
        update_req['label'] = label
        update_req['celery_disabled'] = True
        update_status = ae_consts.NOT_SET

        try:
            update_res = publisher.run_publish_pricing_update(
                work_dict=update_req)
            update_status = update_res.get('status', ae_consts.NOT_SET)
            if ae_consts.ev('DEBUG_RESULTS', '0') == '1':
                log.info('{} update_res status={} data={}'.format(
                    label, ae_consts.get_status(status=update_status),
                    ae_consts.ppj(update_res)))
            else:
                log.info('{} run_publish_pricing_update status={}'.format(
                    label, ae_consts.get_status(status=update_status)))
            # end of if/else

            rec['publish_pricing_update'] = update_res
            res = build_result.build_result(status=ae_consts.SUCCESS,
                                            err=None,
                                            rec=rec)
        except Exception as f:
            err = ('{} publisher.run_publish_pricing_update failed '
                   'with ex={}'.format(label, f))
            log.error(err)
            res = build_result.build_result(status=ae_consts.ERR,
                                            err=err,
                                            rec=rec)
        # end of trying to publish results to connected services

    except Exception as e:
        res = build_result.build_result(status=ae_consts.ERR,
                                        err=('failed - get_new_pricing_data '
                                             'dict={} with ex={}').format(
                                                 work_dict, e),
                                        rec=rec)
        log.error('{} - {}'.format(label, res['err']))
    # end of try/ex

    if ae_consts.ev('DATASET_COLLECTION_SLACK_ALERTS', '0') == '1':
        env_name = 'DEV'
        if ae_consts.ev('PROD_SLACK_ALERTS', '1') == '1':
            env_name = 'PROD'
        done_msg = ('Dataset collected ticker=*{}* on env=*{}* '
                    'redis_key={} s3_key={} iex={} yahoo={}'.format(
                        ticker, env_name, redis_key, s3_key, get_iex_data,
                        get_yahoo_data))
        log.debug('{} sending slack msg={}'.format(label, done_msg))
        if res['status'] == ae_consts.SUCCESS:
            slack_utils.post_success(msg=done_msg, block=False, jupyter=True)
        else:
            slack_utils.post_failure(msg=done_msg, block=False, jupyter=True)
        # end of if/else success
    # end of publishing to slack

    log.info('task - get_new_pricing_data done - '
             '{} - status={}'.format(label,
                                     ae_consts.get_status(res['status'])))

    return get_task_results.get_task_results(work_dict=work_dict, result=res)
コード例 #19
0
def fetch_tickers_from_screener(
        url,
        columns=DEFAULT_FINVIZ_COLUMNS,
        as_json=False,
        soup_selector='td.screener-body-table-nw',
        label='fz-screen-converter'):
    """fetch_tickers_from_screener

    Convert all the tickers on a FinViz screener
    url to a ``pandas.DataFrame``. Returns a dictionary
    with a ticker list and DataFrame or a json-serialized
    DataFrame in a string (by default ``as_json=False`` will
    return a ``pandas.DataFrame`` if the
    ``returned-dictionary['status'] == SUCCESS``

    Works with urls created on:

    https://finviz.com/screener.ashx

    .. code-block:: python

        import analysis_engine.finviz.fetch_api as fv

        url = (
            'https://finviz.com/screener.ashx?'
            'v=111&'
            'f=cap_midunder,exch_nyse,fa_div_o5,idx_sp500'
            '&ft=4')
        res = fv.fetch_tickers_from_screener(url=url)
        print(res)

    :param url: FinViz screener url
    :param columns: ordered header column as a list of strings
                    and corresponds to the header row from the
                    FinViz screener table
    :param soup_selector: ``bs4.BeautifulSoup.selector`` string
                          for pulling selected html data
                          (by default ``td.screener-body-table-nw``)
    :param as_json: FinViz screener url
    :param label: log tracking label string
    """

    rec = {
        'data': None,
        'created': get_last_close_str(),
        'tickers': []
    }
    res = req_utils.build_result(
        status=NOT_RUN,
        err=None,
        rec=rec)

    try:

        log.info(
            '{} fetching url={}'.format(
                label,
                url))

        response = requests.get(url)

        if response.status_code != requests.codes.ok:
            err = (
                '{} finviz returned non-ok HTTP (200) '
                'status_code={} with text={} for url={}'.format(
                    label,
                    response.status_code,
                    response.text,
                    url))
            log.error(err)
            return req_utils.build_result(
                status=ERR,
                err=err,
                rec=rec)
        # end of checking for a good HTTP response status code

        soup = bs4.BeautifulSoup(
            response.text,
            features='html.parser')
        selected = soup.select(soup_selector)

        log.debug(
            '{} found={} url={}'.format(
                label,
                len(selected),
                url))

        ticker_list = []
        rows = []
        use_columns = columns
        num_columns = len(use_columns)
        new_row = {}
        col_idx = 0

        for idx, node in enumerate(selected):

            if col_idx >= num_columns:
                col_idx = 0
            column_name = use_columns[col_idx]
            test_text = str(node.text).lower().strip()
            col_idx += 1

            if column_name != 'ignore' and (
                    test_text != 'save as portfolio'
                    and test_text != 'export'):

                cur_text = str(node.text).strip()

                if column_name == 'ticker':
                    ticker_list.append(cur_text)
                    new_row[column_name] = cur_text.upper()
                else:
                    new_row[column_name] = cur_text
                # end of filtering bad sections around table

                if len(new_row) >= num_columns:
                    log.debug(
                        '{} adding ticker={}'.format(
                            label,
                            new_row['ticker']))
                    rows.append(new_row)
                    new_row = {}
                    col_idx = 0
                # end of if valid row
            # end if column is valid
        # end of walking through all matched html data on the screener

        log.debug(
            '{} done convert url={} to tickers={} '
            'rows={}'.format(
                label,
                url,
                ticker_list,
                len(rows)))

        df = pd.DataFrame(
            rows)

        log.info(
            '{} fetch done - df={} from url={} with tickers={} '
            'rows={}'.format(
                label,
                len(df.index),
                url,
                ticker_list,
                len(rows)))

        rec['tickers'] = ticker_list
        rec['data'] = df

        res = req_utils.build_result(
            status=SUCCESS,
            err=None,
            rec=rec)

    except Exception as e:
        rec['tickers'] = []
        rec['data'] = None
        err = (
            '{} failed converting screen url={} to list '
            'with ex={}'.format(
                label,
                url,
                e))
        log.error(err)
        res = req_utils.build_result(
            status=EX,
            err=err,
            rec=rec)
    # end of try/ex

    return res
コード例 #20
0
def publish_from_s3_to_redis(self, work_dict):
    """publish_from_s3_to_redis

    Publish Ticker Data from S3 to Redis

    :param work_dict: dictionary for key/values
    """

    label = 'pub-s3-to-redis'

    log.info('task - {} - start ' 'work_dict={}'.format(label, work_dict))

    ticker = ae_consts.TICKER
    ticker_id = ae_consts.TICKER_ID
    rec = {
        'ticker': None,
        'ticker_id': None,
        's3_enabled': True,
        'redis_enabled': True,
        's3_bucket': None,
        's3_key': None,
        'redis_key': None,
        'updated': None
    }
    res = build_result.build_result(status=ae_consts.NOT_RUN,
                                    err=None,
                                    rec=rec)

    try:
        ticker = work_dict.get('ticker', ae_consts.TICKER)
        ticker_id = int(work_dict.get('ticker_id', ae_consts.TICKER_ID))

        if not ticker:
            res = build_result.build_result(status=ae_consts.ERR,
                                            err='missing ticker',
                                            rec=rec)
            return res

        s3_key = work_dict.get('s3_key', None)
        s3_bucket_name = work_dict.get('s3_bucket', 'pricing')
        redis_key = work_dict.get('redis_key', None)
        updated = work_dict.get('updated', None)
        serializer = work_dict.get('serializer', 'json')
        encoding = work_dict.get('encoding', 'utf-8')
        label = work_dict.get('label', label)

        enable_s3_read = True
        enable_redis_publish = True

        rec['ticker'] = ticker
        rec['ticker_id'] = ticker_id
        rec['s3_bucket'] = s3_bucket_name
        rec['s3_key'] = s3_key
        rec['redis_key'] = redis_key
        rec['updated'] = updated
        rec['s3_enabled'] = enable_s3_read
        rec['redis_enabled'] = enable_redis_publish

        data = None

        if enable_s3_read:

            log.info('{} parsing s3 values'.format(label))
            access_key = work_dict.get('s3_access_key',
                                       ae_consts.S3_ACCESS_KEY)
            secret_key = work_dict.get('s3_secret_key',
                                       ae_consts.S3_SECRET_KEY)
            region_name = work_dict.get('s3_region_name',
                                        ae_consts.S3_REGION_NAME)
            service_address = work_dict.get('s3_address', ae_consts.S3_ADDRESS)
            secure = work_dict.get('s3_secure', ae_consts.S3_SECURE) == '1'

            endpoint_url = 'http://{}'.format(service_address)
            if secure:
                endpoint_url = 'https://{}'.format(service_address)

            log.info('{} building s3 endpoint_url={} '
                     'region={}'.format(label, endpoint_url, region_name))

            s3 = boto3.resource(
                's3',
                endpoint_url=endpoint_url,
                aws_access_key_id=access_key,
                aws_secret_access_key=secret_key,
                region_name=region_name,
                config=boto3.session.Config(signature_version='s3v4'))

            try:
                log.info('{} checking bucket={} exists'.format(
                    label, s3_bucket_name))
                if s3.Bucket(s3_bucket_name) not in s3.buckets.all():
                    log.info('{} creating bucket={}'.format(
                        label, s3_bucket_name))
                    s3.create_bucket(Bucket=s3_bucket_name)
            except Exception as e:
                log.info('{} failed creating bucket={} '
                         'with ex={}'.format(label, s3_bucket_name, e))
            # end of try/ex for creating bucket

            try:
                log.info('{} reading to s3={}/{} '
                         'updated={}'.format(label, s3_bucket_name, s3_key,
                                             updated))
                data = s3_read_contents_from_key.s3_read_contents_from_key(
                    s3=s3,
                    s3_bucket_name=s3_bucket_name,
                    s3_key=s3_key,
                    encoding=encoding,
                    convert_as_json=True)

                initial_size_value = \
                    len(str(data)) / 1024000
                initial_size_str = ae_consts.to_f(initial_size_value)
                if ae_consts.ev('DEBUG_S3', '0') == '1':
                    log.info('{} read s3={}/{} data={}'.format(
                        label, s3_bucket_name, s3_key, ae_consts.ppj(data)))
                else:
                    log.info('{} read s3={}/{} data size={} MB'.format(
                        label, s3_bucket_name, s3_key, initial_size_str))
            except Exception as e:
                err = ('{} failed reading bucket={} '
                       'key={} ex={}').format(label, s3_bucket_name, s3_key, e)
                log.error(err)
                res = build_result.build_result(status=ae_consts.NOT_RUN,
                                                err=err,
                                                rec=rec)
            # end of try/ex for creating bucket
        else:
            log.info('{} SKIP S3 read bucket={} '
                     'key={}'.format(label, s3_bucket_name, s3_key))
        # end of if enable_s3_read

        if enable_redis_publish:
            redis_address = work_dict.get('redis_address',
                                          ae_consts.REDIS_ADDRESS)
            redis_key = work_dict.get('redis_key', ae_consts.REDIS_KEY)
            redis_password = work_dict.get('redis_password',
                                           ae_consts.REDIS_PASSWORD)
            redis_db = work_dict.get('redis_db', None)
            if not redis_db:
                redis_db = ae_consts.REDIS_DB
            redis_expire = None
            if 'redis_expire' in work_dict:
                redis_expire = work_dict.get('redis_expire',
                                             ae_consts.REDIS_EXPIRE)
            log.info('redis enabled address={}@{} '
                     'key={}'.format(redis_address, redis_db, redis_key))
            redis_host = redis_address.split(':')[0]
            redis_port = redis_address.split(':')[1]
            try:
                if ae_consts.ev('DEBUG_REDIS', '0') == '1':
                    log.info('{} publishing redis={}:{} '
                             'db={} key={} '
                             'updated={} expire={} '
                             'data={}'.format(label, redis_host, redis_port,
                                              redis_db, redis_key,
                                              updated, redis_expire,
                                              ae_consts.ppj(data)))
                else:
                    log.info('{} publishing redis={}:{} '
                             'db={} key={} '
                             'updated={} expire={}'.format(
                                 label, redis_host, redis_port, redis_db,
                                 redis_key, updated, redis_expire))
                # end of if/else

                rc = redis.Redis(host=redis_host,
                                 port=redis_port,
                                 password=redis_password,
                                 db=redis_db)

                redis_set_res = redis_set.set_data_in_redis_key(
                    label=label,
                    client=rc,
                    key=redis_key,
                    data=data,
                    serializer=serializer,
                    encoding=encoding,
                    expire=redis_expire,
                    px=None,
                    nx=False,
                    xx=False)

                log.info('{} redis_set status={} err={}'.format(
                    label, ae_consts.get_status(redis_set_res['status']),
                    redis_set_res['err']))

            except Exception as e:
                log.error('{} failed - redis publish to '
                          'key={} ex={}'.format(label, redis_key, e))
            # end of try/ex for creating bucket
        else:
            log.info('{} SKIP REDIS publish '
                     'key={}'.format(label, redis_key))
        # end of if enable_redis_publish

        res = build_result.build_result(status=ae_consts.SUCCESS,
                                        err=None,
                                        rec=rec)

    except Exception as e:
        res = build_result.build_result(
            status=ae_consts.ERR,
            err=('failed - publish_from_s3_to_redis '
                 'dict={} with ex={}').format(work_dict, e),
            rec=rec)
        log.error('{} - {}'.format(label, res['err']))
    # end of try/ex

    log.info('task - publish_from_s3_to_redis done - '
             '{} - status={}'.format(label,
                                     ae_consts.get_status(res['status'])))

    return get_task_results.get_task_results(work_dict=work_dict, result=res)
コード例 #21
0
def prepare_pricing_dataset(
        self,
        work_dict):
    """prepare_pricing_dataset

    Prepare dataset for analysis. Supports loading dataset from
    s3 if not found in redis. Outputs prepared artifact as a csv
    to s3 and redis.

    :param work_dict: dictionary for key/values
    """

    label = 'prepare'

    log.info(
        'task - {} - start '
        'work_dict={}'.format(
            label,
            work_dict))

    initial_data = None

    ticker = ae_consts.TICKER
    ticker_id = ae_consts.TICKER_ID
    rec = {
        'ticker': None,
        'ticker_id': None,
        's3_enabled': True,
        'redis_enabled': True,
        's3_bucket': None,
        's3_key': None,
        'redis_key': None,
        'prepared_s3_key': None,
        'prepared_s3_bucket': None,
        'prepared_redis_key': None,
        'prepared_data': None,
        'prepared_size': None,
        'initial_data': None,
        'initial_size': None,
        'ignore_columns': None,
        'updated': None
    }
    res = build_result.build_result(
        status=ae_consts.NOT_RUN,
        err=None,
        rec=rec)

    try:
        ticker = work_dict.get(
            'ticker',
            ae_consts.TICKER)
        ticker_id = int(work_dict.get(
            'ticker_id',
            ae_consts.TICKER_ID))

        if not ticker:
            res = build_result.build_result(
                status=ae_consts.ERR,
                err='missing ticker',
                rec=rec)
            return res

        label = work_dict.get(
            'label',
            label)
        s3_key = work_dict.get(
            's3_key',
            None)
        s3_bucket_name = work_dict.get(
            's3_bucket',
            'pricing')
        s3_access_key = work_dict.get(
            's3_access_key',
            ae_consts.S3_ACCESS_KEY)
        s3_secret_key = work_dict.get(
            's3_secret_key',
            ae_consts.S3_SECRET_KEY)
        s3_region_name = work_dict.get(
            's3_region_name',
            ae_consts.S3_REGION_NAME)
        s3_address = work_dict.get(
            's3_address',
            ae_consts.S3_ADDRESS)
        s3_secure = work_dict.get(
            's3_secure',
            ae_consts.S3_SECURE) == '1'
        redis_address = work_dict.get(
            'redis_address',
            ae_consts.REDIS_ADDRESS)
        redis_key = work_dict.get(
            'redis_key',
            ae_consts.REDIS_KEY)
        redis_password = work_dict.get(
            'redis_password',
            ae_consts.REDIS_PASSWORD)
        redis_db = work_dict.get(
            'redis_db',
            None)
        if not redis_db:
            redis_db = ae_consts.REDIS_DB
        redis_expire = None
        if 'redis_expire' in work_dict:
            redis_expire = work_dict.get(
                'redis_expire',
                ae_consts.REDIS_EXPIRE)
        updated = work_dict.get(
            'updated',
            datetime.datetime.utcnow().strftime(
                '%Y_%m_%d_%H_%M_%S'))
        prepared_s3_key = work_dict.get(
            'prepared_s3_key',
            '{}_{}.csv'.format(
                ticker,
                updated))
        prepared_s3_bucket = work_dict.get(
            'prepared_s3_bucket',
            'prepared')
        prepared_redis_key = work_dict.get(
            'prepared_redis_key',
            'prepared')
        ignore_columns = work_dict.get(
            'ignore_columns',
            None)
        log.info(
            '{} redis enabled address={}@{} '
            'key={} prepare_s3={}:{} prepare_redis={} '
            'ignore_columns={}'.format(
                label,
                redis_address,
                redis_db,
                redis_key,
                prepared_s3_bucket,
                prepared_s3_key,
                prepared_redis_key,
                ignore_columns))
        redis_host = redis_address.split(':')[0]
        redis_port = redis_address.split(':')[1]

        enable_s3 = True
        enable_redis_publish = True

        rec['ticker'] = ticker
        rec['ticker_id'] = ticker_id
        rec['s3_bucket'] = s3_bucket_name
        rec['s3_key'] = s3_key
        rec['redis_key'] = redis_key
        rec['prepared_s3_key'] = prepared_s3_key
        rec['prepared_s3_bucket'] = prepared_s3_bucket
        rec['prepared_redis_key'] = prepared_redis_key
        rec['updated'] = updated
        rec['s3_enabled'] = enable_s3
        rec['redis_enabled'] = enable_redis_publish

        try:
            log.info(
                '{} connecting redis={}:{} '
                'db={} key={} '
                'updated={} expire={}'.format(
                    label,
                    redis_host,
                    redis_port,
                    redis_db,
                    redis_key,
                    updated,
                    redis_expire))
            rc = redis.Redis(
                host=redis_host,
                port=redis_port,
                password=redis_password,
                db=redis_db)
        except Exception as e:
            err = (
                '{} failed - redis connection to address={}@{} '
                'key={} ex={}'.format(
                    label,
                    redis_address,
                    redis_key,
                    redis_db,
                    e))
            res = build_result.build_result(
                status=ae_consts.ERR,
                err=err,
                rec=rec)
            return res
        # end of try/ex for connecting to redis

        initial_data_res = redis_get.get_data_from_redis_key(
            label=label,
            client=rc,
            key=redis_key)

        log.info(
            '{} get redis key={} status={} err={}'.format(
                label,
                redis_key,
                ae_consts.get_status(initial_data_res['status']),
                initial_data_res['err']))

        initial_data = initial_data_res['rec'].get(
            'data',
            None)

        if enable_s3 and not initial_data:

            log.info(
                '{} failed to find redis_key={} trying s3 '
                'from s3_key={} s3_bucket={} s3_address={}'.format(
                    label,
                    redis_key,
                    s3_key,
                    s3_bucket_name,
                    s3_address))

            get_from_s3_req = \
                api_requests.build_publish_from_s3_to_redis_request()

            get_from_s3_req['s3_enabled'] = enable_s3
            get_from_s3_req['s3_access_key'] = s3_access_key
            get_from_s3_req['s3_secret_key'] = s3_secret_key
            get_from_s3_req['s3_region_name'] = s3_region_name
            get_from_s3_req['s3_address'] = s3_address
            get_from_s3_req['s3_secure'] = s3_secure
            get_from_s3_req['s3_key'] = s3_key
            get_from_s3_req['s3_bucket'] = s3_bucket_name
            get_from_s3_req['redis_key'] = redis_key
            get_from_s3_req['label'] = (
                '{}-run_publish_from_s3_to_redis'.format(
                    label))

            log.info(
                '{} load from s3={} to '
                'redis={}'.format(
                    label,
                    s3_key,
                    redis_key))

            try:
                # run in synchronous mode:
                get_from_s3_req['celery_disabled'] = True
                task_res = s3_to_redis.run_publish_from_s3_to_redis(
                    get_from_s3_req)
                if task_res.get(
                        'status',
                        ae_consts.ERR) == ae_consts.SUCCESS:
                    log.info(
                        '{} loaded s3={}:{} '
                        'to redis={} retrying'.format(
                            label,
                            s3_bucket_name,
                            s3_key,
                            redis_key))
                    initial_data_res = redis_get.get_data_from_redis_key(
                        label=label,
                        client=rc,
                        key=redis_key)

                    log.info(
                        '{} get redis try=2 key={} status={} err={}'.format(
                            label,
                            redis_key,
                            ae_consts.get_status(initial_data_res['status']),
                            initial_data_res['err']))

                    initial_data = initial_data_res['rec'].get(
                        'data',
                        None)
                else:
                    err = (
                        '{} ERR failed loading from bucket={} '
                        's3_key={} to redis_key={} with res={}'.format(
                            label,
                            s3_bucket_name,
                            s3_key,
                            redis_key,
                            task_res))
                    log.error(err)
                    res = build_result.build_result(
                        status=ae_consts.ERR,
                        err=err,
                        rec=rec)
                    return res
            except Exception as e:
                err = (
                    '{} extract from s3 and publish to redis failed loading '
                    'data from bucket={} in '
                    's3_key={} with publish to redis_key={} '
                    'with ex={}'.format(
                        label,
                        s3_bucket_name,
                        s3_key,
                        redis_key,
                        e))
                log.error(err)
                res = build_result.build_result(
                    status=ae_consts.ERR,
                    err=err,
                    rec=rec)
                return res
            # end of try/ex for publishing from s3->redis
        # end of if enable_s3

        if not initial_data:
            err = (
                '{} did not find any data to prepare in redis_key={} or '
                's3_key={} in bucket={}'.format(
                    label,
                    redis_key,
                    s3_key,
                    s3_bucket_name))
            log.error(err)
            res = build_result.build_result(
                status=ae_consts.ERR,
                err=err,
                rec=rec)
            return res

        initial_data_num_chars = len(str(initial_data))
        initial_size_value = None
        initial_size_str = None
        if initial_data_num_chars < ae_consts.PREPARE_DATA_MIN_SIZE:
            err = (
                '{} not enough data={} in redis_key={} or '
                's3_key={} in bucket={}'.format(
                    label,
                    initial_data_num_chars,
                    redis_key,
                    s3_key,
                    s3_bucket_name))
            log.error(err)
            res = build_result.build_result(
                status=ae_consts.ERR,
                err=err,
                rec=rec)
            return res
        else:
            initial_size_value = initial_data_num_chars / 1024000
            initial_size_str = ae_consts.to_f(initial_size_value)
            if ae_consts.ev('DEBUG_PREPARE', '0') == '1':
                log.info(
                    '{} initial - redis_key={} data={}'.format(
                        label,
                        redis_key,
                        str(initial_data)))
            else:
                log.info(
                    '{} initial - redis_key={} data size={} MB'.format(
                        label,
                        redis_key,
                        initial_size_str))
        # end of trying to get initial_data

        rec['initial_data'] = initial_data
        rec['initial_size'] = initial_data_num_chars

        prepare_data = None

        try:
            if ae_consts.ev('DEBUG_PREPARE', '0') == '1':
                log.info(
                    '{} data={} - flatten - {} MB from '
                    'redis_key={}'.format(
                        label,
                        ae_consts.ppj(initial_data),
                        initial_size_str,
                        redis_key))
            else:
                log.info(
                    '{} flatten - {} MB from '
                    'redis_key={}'.format(
                        label,
                        initial_size_str,
                        redis_key))
            prepare_data = dict_to_csv.flatten_dict(
                data=initial_data)
        except Exception as e:
            prepare_data = None
            err = (
                '{} flatten - convert to csv failed with ex={} '
                'redis_key={}'.format(
                    label,
                    e,
                    redis_key))
            log.error(err)
            res = build_result.build_result(
                status=ae_consts.ERR,
                err=err,
                rec=rec)
            return res
        # end of try/ex

        if not prepare_data:
            err = (
                '{} flatten - did not return any data from redis_key={} '
                'or s3_key={} in bucket={}'.format(
                    label,
                    redis_key,
                    s3_key,
                    s3_bucket_name))
            log.error(err)
            res = build_result.build_result(
                status=ae_consts.ERR,
                err=err,
                rec=rec)
            return res
        # end of prepare_data

        prepare_data_num_chars = len(str(prepare_data))
        prepare_size_value = None

        if prepare_data_num_chars < ae_consts.PREPARE_DATA_MIN_SIZE:
            err = (
                '{} prepare - there is not enough data={} in redis_key={}'
                ''.format(
                    label,
                    prepare_data_num_chars,
                    redis_key))
            log.error(err)
            res = build_result.build_result(
                status=ae_consts.ERR,
                err=err,
                rec=rec)
            return res
        else:
            prepare_size_value = prepare_data_num_chars / 1024000
            prepare_size_str = ae_consts.to_f(prepare_size_value)
            if ae_consts.ev('DEBUG_PREPARE', '0') == '1':
                log.info(
                    '{} data={} - prepare - redis_key={}'.format(
                        label,
                        redis_key,
                        ae_consts.ppj(prepare_data)))
            else:
                log.info(
                    '{} prepare - redis_key={} data size={} MB'.format(
                        label,
                        redis_key,
                        prepare_size_str))
        # end of trying to the size of the prepared data

        rec['prepared_data'] = prepare_data
        rec['prepared_size'] = prepare_data_num_chars

        res = build_result.build_result(
            status=ae_consts.SUCCESS,
            err=None,
            rec=rec)

        rc = None

    except Exception as e:
        res = build_result.build_result(
            status=ae_consts.ERR,
            err=(
                'failed - prepare_pricing_dataset '
                'dict={} with ex={}').format(
                    work_dict,
                    e),
            rec=rec)
        log.error(
            '{} - {}'.format(
                label,
                res['err']))
    # end of try/ex

    log.info(
        'task - prepare_pricing_dataset done - '
        '{} - status={}'.format(
            label,
            ae_consts.get_status(res['status'])))

    return get_task_results.get_task_results(
        work_dict=work_dict,
        result=res)
コード例 #22
0
def plot_df(
        log_label,
        title,
        column_list,
        df,
        xcol='date',
        xlabel='Date',
        ylabel='Pricing',
        linestyle='-',
        color='blue',
        show_plot=True,
        dropna_for_all=True):
    """plot_df
    :param log_label: log identifier
    :param title: title of the plot
    :param column_list: list of columns in the df to show
    :param df: initialized ``pandas.DataFrame``
    :param xcol: x-axis column in the initialized ``pandas.DataFrame``
    :param xlabel: x-axis label
    :param ylabel: y-axis label
    :param linestyle: style of the plot line
    :param color: color to use
    :param show_plot: bool to show the plot
    :param dropna_for_all: optional - bool to toggle keep None's in
                           the plot ``df`` (default is drop them
                           for display purposes)
    """

    rec = {
        'ax': None,
        'fig': None
    }
    result = build_result.build_result(
        status=ae_consts.NOT_RUN,
        err=None,
        rec=rec)

    try:

        log.info(
            f'{log_label} - '
            'plot_df'
            ' - start')

        use_df = df
        if dropna_for_all:
            log.info(
                f'{log_label} - '
                'plot_df'
                ' - dropna_for_all')
            use_df = df.dropna(axis=0, how='any')
        # end of pre-plot dataframe scrubbing

        set_common_seaborn_fonts()

        hex_color = ae_consts.PLOT_COLORS['blue']
        fig, ax = plt.subplots(figsize=(15.0, 10.0))

        if linestyle == '-':
            use_df[column_list].plot(
                x=xcol,
                linestyle=linestyle,
                ax=ax,
                color=hex_color,
                rot=0)
        else:
            use_df[column_list].plot(
                kind='bar',
                x=xcol,
                ax=ax,
                color=hex_color,
                rot=0)

        if 'date' in str(xcol).lower():
            # plot the column
            min_date = use_df.iloc[0][xcol]
            max_date = use_df.iloc[-1][xcol]

            # give a bit of space at each end of the plot - aesthetics
            span = max_date - min_date
            extra = int(span.days * 0.03) * datetime.timedelta(days=1)
            ax.set_xlim([min_date - extra, max_date + extra])

            # format the x tick marks
            ax.xaxis.set_minor_formatter(mdates.DateFormatter('%b\n%Y'))
            ax.xaxis.set_major_locator(plt.NullLocator())
            ax.xaxis.set_minor_locator(
                mdates.MonthLocator(
                    bymonthday=1,
                    interval=1))

            # grid, legend and yLabel
            ax.xaxis.grid(True, which='minor')

        # end of date formatting

        show_with_entities(
            log_label=log_label,
            xlabel=xlabel,
            ylabel=ylabel,
            title=title,
            ax=ax,
            fig=fig,
            show_plot=show_plot)

        rec['ax'] = ax
        rec['fig'] = fig

        result = build_result.build_result(
            status=ae_consts.SUCCESS,
            err=None,
            rec=rec)

    except Exception as e:
        err = (
            f'failed plot_df title={title} with ex={e}')
        result = build_result.build_result(
            status=ae_consts.ERR,
            err=err,
            rec=rec)
    # end of try/ex

    send_final_log(
        log_label=log_label,
        fn_name='plot_df',
        result=result)

    return result
コード例 #23
0
def run_algo(
        ticker=None,
        tickers=None,
        algo=None,  # optional derived ``analysis_engine.algo.Algo`` instance
        balance=None,  # float starting base capital
        commission=None,  # float for single trade commission for buy or sell
        start_date=None,  # string YYYY-MM-DD HH:MM:SS
        end_date=None,  # string YYYY-MM-DD HH:MM:SS
        datasets=None,  # string list of identifiers
        num_owned_dict=None,  # not supported
        cache_freq='daily',  # 'minute' not supported
        auto_fill=True,
        load_config=None,
        report_config=None,
        history_config=None,
        extract_config=None,
        use_key=None,
        extract_mode='all',
        iex_datasets=None,
        redis_enabled=True,
        redis_address=None,
        redis_db=None,
        redis_password=None,
        redis_expire=None,
        redis_key=None,
        s3_enabled=True,
        s3_address=None,
        s3_bucket=None,
        s3_access_key=None,
        s3_secret_key=None,
        s3_region_name=None,
        s3_secure=False,
        s3_key=None,
        celery_disabled=True,
        broker_url=None,
        result_backend=None,
        label=None,
        name=None,
        timeseries=None,
        trade_strategy=None,
        verbose=False,
        publish_to_slack=True,
        publish_to_s3=True,
        publish_to_redis=True,
        extract_datasets=None,
        config_file=None,
        config_dict=None,
        version=1,
        raise_on_err=True,
        **kwargs):
    """run_algo

    Run an algorithm with steps:

        1) Extract redis keys between dates
        2) Compile a data pipeline dictionary (call it ``data``)
        3) Call algorithm's ``myalgo.handle_data(data=data)``

    .. note:: If no ``algo`` is set, the
        ``analysis_engine.algo.BaseAlgo`` algorithm
        is used.

    .. note:: Please ensure Redis and Minio are running
        before trying to extract tickers

    **Stock tickers to extract**

    :param ticker: single stock ticker/symbol/ETF to extract
    :param tickers: optional - list of tickers to extract
    :param use_key: optional - extract historical key from Redis

    **Algo Configuration**

    :param algo: derived instance of ``analysis_engine.algo.Algo`` object
    :param balance: optional - float balance parameter
        can also be set on the ``algo`` object if not
        set on the args
    :param commission: float for single trade commission for
        buy or sell. can also be set on the ``algo`` objet
    :param start_date: string ``YYYY-MM-DD_HH:MM:SS`` cache value
    :param end_date: string ``YYYY-MM-DD_HH:MM:SS`` cache value
    :param dataset_types: list of strings that are ``iex`` or ``yahoo``
        datasets that are cached.
    :param cache_freq: optional - depending on if you are running data feeds
        on a ``daily`` cron (default) vs every ``minute`` (or faster)
    :param num_owned_dict: not supported yet
    :param auto_fill: optional - boolean for auto filling
        buy/sell orders for backtesting (default is
        ``True``)
    :param trading_calendar: ``trading_calendar.TradingCalendar``
        object, by default ``analysis_engine.calendars.
        always_open.AlwaysOpen`` trading calendar
        # TradingCalendar by ``TFSExchangeCalendar``
    :param config_file: path to a json file
        containing custom algorithm object
        member values (like indicator configuration and
        predict future date units ahead for a backtest)
    :param config_dict: optional - dictionary that
        can be passed to derived class implementations
        of: ``def load_from_config(config_dict=config_dict)``

    **Timeseries**

    :param timeseries: optional - string to
        set ``day`` or ``minute`` backtesting
        or live trading
        (default is ``minute``)

    **Trading Strategy**

    :param trade_strategy: optional - string to
        set the type of ``Trading Strategy``
        for backtesting or live trading
        (default is ``count``)

    **Algorithm Dataset Loading, Extracting, Reporting
    and Trading History arguments**

    :param load_config: optional - dictionary
        for setting member variables to load an
        agorithm-ready dataset from
        a file, s3 or redis
    :param report_config: optional - dictionary
        for setting member variables to publish
        an algo ``trading performance report`` to s3,
        redis, a file or slack
    :param history_config: optional - dictionary
        for setting member variables to publish
        an algo ``trade history`` to s3, redis, a file
        or slack
    :param extract_config: optional - dictionary
        for setting member variables to publish
        an algo ``trading performance report`` to s3,
        redis, a file or slack

    **(Optional) Data sources, datafeeds and datasets to gather**

    :param iex_datasets: list of strings for gathering specific `IEX
        datasets <https://iexcloud.io/>`__
        which are set as consts: ``analysis_engine.iex.consts.FETCH_*``.

    **(Optional) Redis connectivity arguments**

    :param redis_enabled: bool - toggle for auto-caching all
        datasets in Redis
        (default is ``True``)
    :param redis_address: Redis connection string
        format is ``host:port``
        (default is ``localhost:6379``)
    :param redis_db: Redis db to use
        (default is ``0``)
    :param redis_password: optional - Redis password
        (default is ``None``)
    :param redis_expire: optional - Redis expire value
        (default is ``None``)
    :param redis_key: optional - redis key not used
        (default is ``None``)

    **(Optional) Minio (S3) connectivity arguments**

    :param s3_enabled: bool - toggle for auto-archiving on Minio (S3)
        (default is ``True``)
    :param s3_address: Minio S3 connection string
        format ``host:port``
        (default is ``localhost:9000``)
    :param s3_bucket: S3 Bucket for storing the artifacts
        (default is ``dev``) which should be viewable on a browser:
        http://localhost:9000/minio/dev/
    :param s3_access_key: S3 Access key
        (default is ``trexaccesskey``)
    :param s3_secret_key: S3 Secret key
        (default is ``trex123321``)
    :param s3_region_name: S3 region name
        (default is ``us-east-1``)
    :param s3_secure: Transmit using tls encryption
        (default is ``False``)
    :param s3_key: optional s3 key not used
        (default is ``None``)

    **(Optional) Celery worker broker connectivity arguments**

    :param celery_disabled: bool - toggle synchronous mode or publish
        to an engine connected to the `Celery broker and backend
        <https://github.com/celery/celery#transports-and-backends>`__
        (default is ``True`` - synchronous mode without an engine
        or need for a broker or backend for Celery)
    :param broker_url: Celery broker url
        (default is ``redis://0.0.0.0:6379/13``)
    :param result_backend: Celery backend url
        (default is ``redis://0.0.0.0:6379/14``)
    :param label: tracking log label
    :param publish_to_slack: optional - boolean for
        publishing to slack (coming soon)
    :param publish_to_s3: optional - boolean for
        publishing to s3 (coming soon)
    :param publish_to_redis: optional - boolean for
        publishing to redis (coming soon)

    **(Optional) Debugging**

    :param verbose: bool - show extract warnings
        and other debug logging (default is False)
    :param raise_on_err: optional - boolean for
        unittests and developing algorithms with the
        ``analysis_engine.run_algo.run_algo`` helper.
        When set to ``True`` exceptions will
        are raised to the calling functions

    :param kwargs: keyword arguments dictionary
    """

    # dictionary structure with a list sorted on: ascending dates
    # algo_data_req[ticker][list][dataset] = pd.DataFrame
    algo_data_req = {}
    extract_requests = []
    return_algo = False  # return created algo objects for use by caller
    rec = {}
    msg = None

    use_tickers = tickers
    use_balance = balance
    use_commission = commission

    if ticker:
        use_tickers = [ticker]
    else:
        if not use_tickers:
            use_tickers = []

    # if these are not set as args, but the algo object
    # has them, use them instead:
    if algo:
        if len(use_tickers) == 0:
            use_tickers = algo.get_tickers()
        if not use_balance:
            use_balance = algo.get_balance()
        if not use_commission:
            use_commission = algo.get_commission()

    default_iex_datasets = [
        'daily', 'minute', 'quote', 'stats', 'peers', 'news', 'financials',
        'earnings', 'dividends', 'company'
    ]

    if not iex_datasets:
        iex_datasets = default_iex_datasets

    if redis_enabled:
        if not redis_address:
            redis_address = os.getenv('REDIS_ADDRESS', 'localhost:6379')
        if not redis_password:
            redis_password = os.getenv('REDIS_PASSWORD', None)
        if not redis_db:
            redis_db = int(os.getenv('REDIS_DB', '0'))
        if not redis_expire:
            redis_expire = os.getenv('REDIS_EXPIRE', None)
    if s3_enabled:
        if not s3_address:
            s3_address = os.getenv('S3_ADDRESS', 'localhost:9000')
        if not s3_access_key:
            s3_access_key = os.getenv('AWS_ACCESS_KEY_ID', 'trexaccesskey')
        if not s3_secret_key:
            s3_secret_key = os.getenv('AWS_SECRET_ACCESS_KEY', 'trex123321')
        if not s3_region_name:
            s3_region_name = os.getenv('AWS_DEFAULT_REGION', 'us-east-1')
        if not s3_secure:
            s3_secure = os.getenv('S3_SECURE', '0') == '1'
        if not s3_bucket:
            s3_bucket = os.getenv('S3_BUCKET', 'dev')
    if not broker_url:
        broker_url = os.getenv('WORKER_BROKER_URL', 'redis://0.0.0.0:6379/11')
    if not result_backend:
        result_backend = os.getenv('WORKER_BACKEND_URL',
                                   'redis://0.0.0.0:6379/12')

    if not label:
        label = 'run-algo'

    num_tickers = len(use_tickers)
    last_close_str = ae_utils.get_last_close_str()

    if iex_datasets:
        if verbose:
            log.info(f'{label} - tickers={num_tickers} '
                     f'iex={json.dumps(iex_datasets)}')
    else:
        if verbose:
            log.info(f'{label} - tickers={num_tickers}')

    ticker_key = use_key
    if not ticker_key:
        ticker_key = f'{ticker}_{last_close_str}'

    if not algo:
        algo = base_algo.BaseAlgo(ticker=None,
                                  tickers=use_tickers,
                                  balance=use_balance,
                                  commission=use_commission,
                                  config_dict=config_dict,
                                  name=label,
                                  auto_fill=auto_fill,
                                  timeseries=timeseries,
                                  trade_strategy=trade_strategy,
                                  publish_to_slack=publish_to_slack,
                                  publish_to_s3=publish_to_s3,
                                  publish_to_redis=publish_to_redis,
                                  raise_on_err=raise_on_err)
        return_algo = True
        # the algo object is stored
        # in the result at: res['rec']['algo']

    if not algo:
        msg = f'{label} - missing algo object'
        log.error(msg)
        return build_result.build_result(status=ae_consts.EMPTY,
                                         err=msg,
                                         rec=rec)

    if raise_on_err:
        log.debug(f'{label} - enabling algo exception raises')
        algo.raise_on_err = True

    indicator_datasets = algo.get_indicator_datasets()
    if len(indicator_datasets) == 0:
        indicator_datasets = ae_consts.BACKUP_DATASETS
        log.info(f'using all datasets={indicator_datasets}')

    verbose_extract = False
    if config_dict:
        verbose_extract = config_dict.get('verbose_extract', False)

    common_vals = {}
    common_vals['base_key'] = ticker_key
    common_vals['celery_disabled'] = celery_disabled
    common_vals['ticker'] = ticker
    common_vals['label'] = label
    common_vals['iex_datasets'] = iex_datasets
    common_vals['s3_enabled'] = s3_enabled
    common_vals['s3_bucket'] = s3_bucket
    common_vals['s3_address'] = s3_address
    common_vals['s3_secure'] = s3_secure
    common_vals['s3_region_name'] = s3_region_name
    common_vals['s3_access_key'] = s3_access_key
    common_vals['s3_secret_key'] = s3_secret_key
    common_vals['s3_key'] = ticker_key
    common_vals['redis_enabled'] = redis_enabled
    common_vals['redis_address'] = redis_address
    common_vals['redis_password'] = redis_password
    common_vals['redis_db'] = redis_db
    common_vals['redis_key'] = ticker_key
    common_vals['redis_expire'] = redis_expire

    use_start_date_str = start_date
    use_end_date_str = end_date
    last_close_date = ae_utils.last_close()
    end_date_val = None

    cache_freq_fmt = ae_consts.COMMON_TICK_DATE_FORMAT

    if not use_end_date_str:
        use_end_date_str = last_close_date.strftime(cache_freq_fmt)

    end_date_val = ae_utils.get_date_from_str(date_str=use_end_date_str,
                                              fmt=cache_freq_fmt)
    start_date_val = None

    if not use_start_date_str:
        start_date_val = end_date_val - datetime.timedelta(days=60)
        use_start_date_str = start_date_val.strftime(cache_freq_fmt)
    else:
        start_date_val = datetime.datetime.strptime(
            use_start_date_str, ae_consts.COMMON_TICK_DATE_FORMAT)

    total_dates = (end_date_val - start_date_val).days

    if end_date_val < start_date_val:
        msg = (
            f'{label} - invalid dates - start_date={start_date_val} is after '
            f'end_date={end_date_val}')
        raise Exception(msg)

    if verbose:
        log.info(f'{label} - days={total_dates} '
                 f'start={use_start_date_str} '
                 f'end={use_end_date_str} '
                 f'datasets={indicator_datasets}')

    for ticker in use_tickers:
        req = algo_utils.build_algo_request(ticker=ticker,
                                            use_key=use_key,
                                            start_date=use_start_date_str,
                                            end_date=use_end_date_str,
                                            datasets=datasets,
                                            balance=use_balance,
                                            cache_freq=cache_freq,
                                            timeseries=timeseries,
                                            trade_strategy=trade_strategy,
                                            label=label)
        ticker_key = f'{ticker}_{last_close_str}'
        common_vals['ticker'] = ticker
        common_vals['base_key'] = ticker_key
        common_vals['redis_key'] = ticker_key
        common_vals['s3_key'] = ticker_key

        for date_key in req['extract_datasets']:
            date_req = api_requests.get_ds_dict(ticker=ticker,
                                                base_key=date_key,
                                                ds_id=label,
                                                service_dict=common_vals)
            node_date_key = date_key.replace(f'{ticker}_', '')
            extract_requests.append({
                'id': date_key,
                'ticker': ticker,
                'date_key': date_key,
                'date': node_date_key,
                'req': date_req
            })
    # end of for all ticker in use_tickers

    first_extract_date = None
    last_extract_date = None
    total_extract_requests = len(extract_requests)
    cur_idx = 1
    for idx, extract_node in enumerate(extract_requests):

        extract_ticker = extract_node['ticker']
        extract_date = extract_node['date']
        ds_node_id = extract_node['id']

        if not first_extract_date:
            first_extract_date = extract_date
        last_extract_date = extract_date
        perc_progress = ae_consts.get_percent_done(
            progress=cur_idx, total=total_extract_requests)
        percent_label = (f'{label} '
                         f'ticker={extract_ticker} '
                         f'date={extract_date} '
                         f'{perc_progress} '
                         f'{idx}/{total_extract_requests} '
                         f'{indicator_datasets}')
        if verbose:
            log.info(f'extracting - {percent_label}')

        ticker_bt_data = build_ds_node.build_dataset_node(
            ticker=extract_ticker,
            date=extract_date,
            service_dict=common_vals,
            datasets=indicator_datasets,
            log_label=label,
            verbose=verbose_extract)

        if ticker not in algo_data_req:
            algo_data_req[ticker] = []

        algo_data_req[ticker].append({
            'id': ds_node_id,  # id is currently the cache key in redis
            'date': extract_date,  # used to confirm dates in asc order
            'data': ticker_bt_data
        })

        if verbose:
            log.info(f'extract - {percent_label} '
                     f'dataset={len(algo_data_req[ticker])}')
        cur_idx += 1
    # end of for service_dict in extract_requests

    # this could be a separate celery task
    status = ae_consts.NOT_RUN
    if len(algo_data_req) == 0:
        msg = (f'{label} - nothing to test - no data found for '
               f'tickers={use_tickers} '
               f'between {first_extract_date} and {last_extract_date}')
        log.info(msg)
        return build_result.build_result(status=ae_consts.EMPTY,
                                         err=msg,
                                         rec=rec)

    # this could be a separate celery task
    try:
        if verbose:
            log.info(f'handle_data START - {percent_label} from '
                     f'{first_extract_date} to {last_extract_date}')
        algo.handle_data(data=algo_data_req)
        if verbose:
            log.info(f'handle_data END - {percent_label} from '
                     f'{first_extract_date} to {last_extract_date}')
    except Exception as e:
        a_name = algo.get_name()
        a_debug_msg = algo.get_debug_msg()
        if not a_debug_msg:
            a_debug_msg = 'debug message not set'
        a_config_dict = ae_consts.ppj(algo.config_dict)
        msg = (f'{percent_label} - algo={a_name} '
               f'encountered exception in handle_data tickers={use_tickers} '
               f'from {first_extract_date} to {last_extract_date} ex={e} '
               f'and failed during operation: {a_debug_msg}')
        if raise_on_err:
            if algo:
                try:
                    ind_obj = \
                        algo.get_indicator_process_last_indicator()
                    if ind_obj:
                        ind_obj_path = ind_obj.get_path_to_module()
                        ind_obj_config = ae_consts.ppj(ind_obj.get_config())
                        found_error_hint = False
                        if hasattr(ind_obj.use_df, 'to_json'):
                            if len(ind_obj.use_df.index) == 0:
                                log.critical(
                                    f'indicator failure report for '
                                    f'last module: '
                                    f'{ind_obj_path} '
                                    f'indicator={ind_obj.get_name()} '
                                    f'config={ind_obj_config} '
                                    f'dataset={ind_obj.use_df.head(5)} '
                                    f'name_of_dataset={ind_obj.uses_data}')
                                log.critical(
                                    '--------------------------------------'
                                    '--------------------------------------')
                                log.critical('Please check if this indicator: '
                                             f'{ind_obj_path} '
                                             'supports Empty Dataframes')
                                log.critical(
                                    '--------------------------------------'
                                    '--------------------------------------')
                                found_error_hint = True
                        # indicator error hints

                        if not found_error_hint:
                            log.critical(
                                f'indicator failure report for last module: '
                                f'{ind_obj_path} '
                                f'indicator={ind_obj.get_name()} '
                                f'config={ind_obj_config} '
                                f'dataset={ind_obj.use_df.head(5)} '
                                f'name_of_dataset={ind_obj.uses_data}')
                except Exception as f:
                    log.critical(f'failed to pull indicator processor '
                                 f'last indicator for debugging '
                                 f'from ex={e} with parsing ex={f}')
                # end of ignoring non-supported ways of creating
                # indicator processors
            log.error(msg)
            log.error(f'algo failure report: '
                      f'algo={a_name} handle_data() '
                      f'config={a_config_dict} ')
            log.critical(f'algo failed during operation: {a_debug_msg}')
            raise e
        else:
            log.error(msg)
            return build_result.build_result(status=ae_consts.ERR,
                                             err=msg,
                                             rec=rec)
    # end of try/ex

    # this could be a separate celery task
    try:
        if verbose:
            log.info(f'get_result START - {percent_label} from '
                     f'{first_extract_date} to {last_extract_date}')
        rec = algo.get_result()
        status = ae_consts.SUCCESS
        if verbose:
            log.info(f'get_result END - {percent_label} from '
                     f'{first_extract_date} to {last_extract_date}')
    except Exception as e:
        msg = (
            f'{percent_label} - algo={algo.get_name()} encountered exception '
            f'in get_result tickers={use_tickers} from '
            f'{first_extract_date} to {last_extract_date} ex={e}')
        if raise_on_err:
            if algo:
                log.error(f'algo={algo.get_name()} failed in get_result with '
                          f'debug_msg={algo.get_debug_msg()}')
            log.error(msg)
            raise e
        else:
            log.error(msg)
            return build_result.build_result(status=ae_consts.ERR,
                                             err=msg,
                                             rec=rec)
    # end of try/ex

    if return_algo:
        rec['algo'] = algo

    return build_result.build_result(status=status, err=msg, rec=rec)
コード例 #24
0
def dist_plot(
        log_label,
        df,
        width=10.0,
        height=10.0,
        title='Distribution Plot',
        style='default',
        xlabel='',
        ylabel='',
        show_plot=True,
        dropna_for_all=True):
    """dist_plot

    Show a distribution plot for the passed in dataframe: ``df``

    :param log_label: log identifier
    :param df: initialized ``pandas.DataFrame``
    :param width: width of figure
    :param height: height of figure
    :param style: style to use
    :param xlabel: x-axis label
    :param ylabel: y-axis label
    :param show_plot: bool to show plot or not
    :param dropna_for_all: optional - bool to toggle keep None's in
                           the plot ``df`` (default is drop them
                           for display purposes)
    """

    rec = {}
    result = build_result.build_result(
        status=ae_consts.NOT_RUN,
        err=None,
        rec=rec)

    try:

        log.info(
            f'{log_label} - '
            'dist_plot'
            ' - start')

        set_common_seaborn_fonts()

        fig, ax = plt.subplots(
            figsize=(width, height))

        if style == 'default':
            sns.set_context('poster')
            sns.axes_style('darkgrid')

        use_df = df
        if dropna_for_all:
            log.info(
                f'{log_label} - '
                'dist_plot'
                ' - dropna_for_all')
            use_df = df.dropna(axis=0, how='any')
        # end of pre-plot dataframe scrubbing

        sns.distplot(
            use_df,
            color=ae_consts.PLOT_COLORS['blue'],
            ax=ax)

        if xlabel != '':
            ax.set_xlabel(xlabel)
        if ylabel != '':
            ax.set_ylabel(ylabel)

        plt.tight_layout()
        plt.subplots_adjust(top=0.9)
        fig.suptitle(title)

        show_with_entities(
            log_label=log_label,
            xlabel=xlabel,
            ylabel=ylabel,
            title=title,
            ax=ax,
            fig=fig,
            show_plot=show_plot)

        rec['ax'] = ax
        rec['fig'] = fig

        result = build_result.build_result(
            status=ae_consts.SUCCESS,
            err=None,
            rec=rec)

    except Exception as e:
        err = (
            f'failed dist_plot title={title} with ex={e}')
        log.error(err)
        result = build_result.build_result(
            status=ae_consts.ERR,
            err=err,
            rec=rec)
    # end of try/ex

    send_final_log(
        log_label=log_label,
        fn_name='dist_plot',
        result=result)

    return result
コード例 #25
0
def publish_ticker_aggregate_from_s3(self, work_dict):
    """publish_ticker_aggregate_from_s3

    Publish Aggregated Ticker Data from S3 to Redis

    :param work_dict: dictionary for key/values
    """

    label = 'pub-tic-agg-s3-to-redis'

    log.info(f'task - {label} - start work_dict={work_dict}')

    ticker = ae_consts.TICKER
    ticker_id = ae_consts.TICKER_ID
    rec = {
        'ticker': None,
        'ticker_id': None,
        's3_read_enabled': True,
        's3_upload_enabled': True,
        'redis_enabled': True,
        's3_bucket': None,
        's3_compiled_bucket': None,
        's3_key': None,
        'redis_key': None,
        'updated': None
    }
    res = build_result.build_result(status=ae_consts.NOT_RUN,
                                    err=None,
                                    rec=rec)

    try:
        ticker = work_dict.get('ticker', ae_consts.TICKER)
        ticker_id = int(work_dict.get('ticker_id', ae_consts.TICKER_ID))

        if not ticker:
            res = build_result.build_result(status=ae_consts.ERR,
                                            err='missing ticker',
                                            rec=rec)
            return res

        label = work_dict.get('label', label)
        s3_key = work_dict.get('s3_key', None)
        s3_bucket_name = work_dict.get('s3_bucket', 'pricing')
        s3_compiled_bucket_name = work_dict.get('s3_compiled_bucket',
                                                'compileddatasets')
        redis_key = work_dict.get('redis_key', None)
        updated = work_dict.get('updated', None)
        enable_s3_upload = work_dict.get('s3_upload_enabled',
                                         ae_consts.ENABLED_S3_UPLOAD)
        enable_redis_publish = work_dict.get('redis_enabled',
                                             ae_consts.ENABLED_REDIS_PUBLISH)
        serializer = work_dict.get('serializer', 'json')
        encoding = work_dict.get('encoding', 'utf-8')

        enable_s3_read = True

        rec['ticker'] = ticker
        rec['ticker_id'] = ticker_id
        rec['s3_bucket'] = s3_bucket_name
        rec['s3_compiled_bucket'] = s3_compiled_bucket_name
        rec['s3_key'] = s3_key
        rec['redis_key'] = redis_key
        rec['updated'] = updated
        rec['s3_read_enabled'] = enable_s3_read
        rec['s3_upload_enabled'] = enable_s3_upload
        rec['redis_enabled'] = enable_redis_publish

        if enable_s3_read:
            log.info(f'{label} parsing s3 values')
            access_key = work_dict.get('s3_access_key',
                                       ae_consts.S3_ACCESS_KEY)
            secret_key = work_dict.get('s3_secret_key',
                                       ae_consts.S3_SECRET_KEY)
            region_name = work_dict.get('s3_region_name',
                                        ae_consts.S3_REGION_NAME)
            service_address = work_dict.get('s3_address', ae_consts.S3_ADDRESS)
            secure = work_dict.get('s3_secure', ae_consts.S3_SECURE) == '1'

            endpoint_url = f'http{"s" if secure else ""}://{service_address}'

            log.info(f'{label} building s3 endpoint_url={endpoint_url} '
                     f'region={region_name}')

            s3 = boto3.resource(
                's3',
                endpoint_url=endpoint_url,
                aws_access_key_id=access_key,
                aws_secret_access_key=secret_key,
                region_name=region_name,
                config=boto3.session.Config(signature_version='s3v4'))

            try:
                log.info(f'{label} checking bucket={s3_bucket_name} exists')
                if s3.Bucket(s3_bucket_name) not in s3.buckets.all():
                    log.info(f'{label} creating bucket={s3_bucket_name}')
                    s3.create_bucket(Bucket=s3_bucket_name)
            except Exception as e:
                log.info(f'{label} failed creating bucket={s3_bucket_name} '
                         f'with ex={e}')
            # end of try/ex for creating bucket

            try:
                log.info(f'{label} checking bucket={s3_bucket_name} keys')
                date_keys = []
                keys = []
                # {TICKER}_YYYY-DD-MM regex
                reg = r'^.*_\d{4}-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])$'
                for bucket in s3.buckets.all():
                    for key in bucket.objects.all():
                        if (ticker.lower() in key.key.lower()
                                and bool(re.compile(reg).search(key.key))):
                            keys.append(key.key)
                            date_keys.append(key.key.split(f'{ticker}_')[1])
            except Exception as e:
                log.info(f'{label} failed to get bucket={s3_bucket_name} '
                         f'keys with ex={e}')
            # end of try/ex for getting bucket keys

            if keys:
                data = []
                for idx, key in enumerate(keys):
                    try:
                        log.info(
                            f'{label} reading to s3={s3_bucket_name}/{key} '
                            f'updated={updated}')
                        loop_data = s3_read_contents_from_key.\
                            s3_read_contents_from_key(
                                s3=s3,
                                s3_bucket_name=s3_bucket_name,
                                s3_key=key,
                                encoding=encoding,
                                convert_as_json=True)

                        initial_size_value = \
                            len(str(loop_data)) / 1024000
                        initial_size_str = ae_consts.to_f(initial_size_value)
                        if ae_consts.ev('DEBUG_S3', '0') == '1':
                            log.info(f'{label} read s3={s3_bucket_name}/{key} '
                                     f'data={ae_consts.ppj(loop_data)}')
                        else:
                            log.info(
                                f'{label} read s3={s3_bucket_name}/{key} data '
                                f'size={initial_size_str} MB')
                        data.append({f'{date_keys[idx]}': loop_data})
                    except Exception as e:
                        err = (
                            f'{label} failed reading bucket={s3_bucket_name} '
                            f'key={key} ex={e}')
                        log.error(err)
                        res = build_result.build_result(
                            status=ae_consts.NOT_RUN, err=err, rec=rec)
                    # end of try/ex for creating bucket
            else:
                log.info(f'{label} No keys found in S3 '
                         f'bucket={s3_bucket_name} for ticker={ticker}')
        else:
            log.info(f'{label} SKIP S3 read bucket={s3_bucket_name} '
                     f'ticker={ticker}')
        # end of if enable_s3_read

        if data and enable_s3_upload:
            try:
                log.info(f'{label} checking bucket={s3_compiled_bucket_name} '
                         'exists')
                if s3.Bucket(s3_compiled_bucket_name) not in s3.buckets.all():
                    log.info(
                        f'{label} creating bucket={s3_compiled_bucket_name}')
                    s3.create_bucket(Bucket=s3_compiled_bucket_name)
            except Exception as e:
                log.info(f'{label} failed creating '
                         f'bucket={s3_compiled_bucket_name} with ex={e}')
            # end of try/ex for creating bucket

            try:
                cmpr_data = zlib.compress(json.dumps(data).encode(encoding), 9)

                if ae_consts.ev('DEBUG_S3', '0') == '1':
                    log.info(
                        f'{label} uploading to '
                        f's3={s3_compiled_bucket_name}/{s3_key} '
                        f'data={ae_consts.ppj(loop_data)} updated={updated}')
                else:
                    sizes = {
                        'MB': 1024000,
                        'GB': 1024000000,
                        'TB': 1024000000000,
                        'PB': 1024000000000000
                    }
                    initial_size_value = len(str(data))
                    org_data_size = 'MB'
                    for key in sizes.keys():
                        size = float(initial_size_value) / float(sizes[key])
                        if size > 1024:
                            continue
                        org_data_size = key
                        initial_size_value = size
                        break
                    initial_size_str = ae_consts.to_f(initial_size_value)

                    cmpr_data_size_value = len(cmpr_data)
                    cmpr_data_size = 'MB'
                    for key in sizes.keys():
                        size = float(cmpr_data_size_value) / float(sizes[key])
                        if size > 1024:
                            continue
                        cmpr_data_size = key
                        cmpr_data_size_value = size
                        break
                    cmpr_size_str = ae_consts.to_f(cmpr_data_size_value)
                    log.info(
                        f'{label} uploading to '
                        f's3={s3_compiled_bucket_name}/{s3_key} data '
                        f'original_size={initial_size_str} {org_data_size} '
                        f'compressed_size={cmpr_size_str} {cmpr_data_size} '
                        f'updated={updated}')
                s3.Bucket(s3_compiled_bucket_name).put_object(Key=s3_key,
                                                              Body=cmpr_data)
            except Exception as e:
                log.error(f'{label} failed '
                          f'uploading bucket={s3_compiled_bucket_name} '
                          f'key={s3_key} ex={e}')
            # end of try/ex for creating bucket
        else:
            log.info(
                f'{label} SKIP S3 upload bucket={s3_bucket_name} key={s3_key}')
        # end of if enable_s3_upload

        if data and enable_redis_publish:
            redis_address = work_dict.get('redis_address',
                                          ae_consts.REDIS_ADDRESS)
            redis_key = work_dict.get('redis_key', ae_consts.REDIS_KEY)
            redis_password = work_dict.get('redis_password',
                                           ae_consts.REDIS_PASSWORD)
            redis_db = work_dict.get('redis_db', None)
            if not redis_db:
                redis_db = ae_consts.REDIS_DB
            redis_expire = None
            if 'redis_expire' in work_dict:
                redis_expire = work_dict.get('redis_expire',
                                             ae_consts.REDIS_EXPIRE)
            log.info(f'redis enabled address={redis_address}@{redis_db} '
                     f'key={redis_key}')
            redis_host = redis_address.split(':')[0]
            redis_port = redis_address.split(':')[1]
            try:
                if ae_consts.ev('DEBUG_REDIS', '0') == '1':
                    log.info(
                        f'{label} publishing redis={redis_host}:{redis_port} '
                        f'db={redis_db} key={redis_key} updated={updated} '
                        f'expire={redis_expire} data={ae_consts.ppj(data)}')
                else:
                    log.info(
                        f'{label} publishing redis={redis_host}:{redis_port} '
                        f'db={redis_db} key={redis_key} '
                        f'updated={updated} expire={redis_expire}')
                # end of if/else

                rc = redis.Redis(host=redis_host,
                                 port=redis_port,
                                 password=redis_password,
                                 db=redis_db)

                redis_set_res = redis_set.set_data_in_redis_key(
                    label=label,
                    client=rc,
                    key=redis_key,
                    data=data,
                    serializer=serializer,
                    encoding=encoding,
                    expire=redis_expire,
                    px=None,
                    nx=False,
                    xx=False)

                log.info(
                    f'{label} redis_set '
                    f'status={ae_consts.get_status(redis_set_res["status"])} '
                    f'err={redis_set_res["err"]}')

            except Exception as e:
                log.error(f'{label} failed - redis publish to '
                          f'key={redis_key} ex={e}')
            # end of try/ex for creating bucket
        else:
            log.info(f'{label} SKIP REDIS publish key={redis_key}')
        # end of if enable_redis_publish

        res = build_result.build_result(status=ae_consts.SUCCESS,
                                        err=None,
                                        rec=rec)

    except Exception as e:
        res = build_result.build_result(
            status=ae_consts.ERR,
            err=(f'failed - publish_from_s3 dict={work_dict} with ex={e}'),
            rec=rec)
        log.error(f'{label} - {res["err"]}')
    # end of try/ex

    log.info('task - publish_from_s3 done - '
             f'{label} - status={ae_consts.get_status(res["status"])}')

    return get_task_results.get_task_results(work_dict=work_dict, result=res)
コード例 #26
0
def get_data_from_redis_key(label=None,
                            client=None,
                            host=None,
                            port=None,
                            password=None,
                            db=None,
                            key=None,
                            expire=None,
                            serializer='json',
                            encoding='utf-8'):
    """get_data_from_redis_key

    :param label: log tracking label
    :param client: initialized redis client
    :param host: not used yet - redis host
    :param port: not used yet - redis port
    :param password: not used yet - redis password
    :param db: not used yet - redis db
    :param key: not used yet - redis key
    :param expire: not used yet - redis expire
    :param serializer: not used yet - support for future
                       pickle objects in redis
    :param encoding: format of the encoded key in redis
    """

    decoded_data = None
    data = None

    rec = {'data': data}
    res = build_result.build_result(status=NOT_RUN, err=None, rec=rec)

    log_id = label if label else 'get-data'

    try:

        use_client = client
        if not use_client:
            log.debug('{} get key={} new client={}:{}@{}'.format(
                log_id, key, host, port, db))
            use_client = redis.Redis(host=host,
                                     port=port,
                                     password=password,
                                     db=db)
        else:
            log.debug('{} get key={} client'.format(log_id, key))
        # create Redis client if not set

        # https://redis-py.readthedocs.io/en/latest/index.html#redis.StrictRedis.get  # noqa
        raw_data = use_client.get(name=key)

        if raw_data:
            log.debug('{} decoding key={} encoding={}'.format(
                log_id, key, encoding))
            decoded_data = raw_data.decode(encoding)

            log.debug('{} deserial key={} serializer={}'.format(
                log_id, key, serializer))

            if serializer == 'json':
                data = json.loads(decoded_data)
            elif serializer == 'df':
                data = decoded_data
            else:
                data = decoded_data

            if data:
                if ev('DEBUG_REDIS', '0') == '1':
                    log.info('{} - found key={} data={}'.format(
                        log_id, key, ppj(data)))
                else:
                    log.debug('{} - found key={}'.format(log_id, key))
            # log snippet - if data

            rec['data'] = data

            return build_result.build_result(status=SUCCESS, err=None, rec=rec)
        else:
            log.debug('{} no data key={}'.format(log_id, key))
            return build_result.build_result(status=SUCCESS, err=None, rec=rec)
    except Exception as e:
        err = ('{} failed - redis get from decoded={} data={} '
               'key={} ex={}'.format(log_id, decoded_data, data, key, e))
        log.error(err)
        res = build_result.build_result(status=ERR, err=err, rec=rec)
    # end of try/ex for getting redis data

    return res
コード例 #27
0
def publish_pricing_update(
        self,
        work_dict):
    """publish_pricing_update

    Publish Ticker Data to S3 and Redis

    - prices - turn off with ``work_dict.get_pricing = False``
    - news - turn off with ``work_dict.get_news = False``
    - options - turn off with ``work_dict.get_options = False``

    :param work_dict: dictionary for key/values
    """

    label = 'publish_pricing'

    log.info(
        'task - {} - start'.format(
            label))

    ticker = TICKER
    ticker_id = TICKER_ID
    rec = {
        'ticker': None,
        'ticker_id': None,
        's3_enabled': False,
        'redis_enabled': False,
        's3_bucket': None,
        's3_key': None,
        'redis_key': None,
        'updated': None
    }
    res = build_result.build_result(
        status=NOT_RUN,
        err=None,
        rec=rec)

    try:
        ticker = work_dict.get(
            'ticker',
            TICKER)
        ticker_id = int(work_dict.get(
            'ticker_id',
            TICKER_ID))

        if not ticker:
            res = build_result.build_result(
                status=ERR,
                err='missing ticker',
                rec=rec)
            return res

        label = work_dict.get(
            'label',
            label)
        s3_key = work_dict.get(
            's3_key',
            None)
        s3_bucket_name = work_dict.get(
            's3_bucket',
            'pricing')
        redis_key = work_dict.get(
            'redis_key',
            None)
        data = work_dict.get(
            'data',
            None)
        updated = work_dict.get(
            'updated',
            None)
        enable_s3_upload = work_dict.get(
            's3_enabled',
            ENABLED_S3_UPLOAD)
        enable_redis_publish = work_dict.get(
            'redis_enabled',
            ENABLED_REDIS_PUBLISH)
        serializer = work_dict.get(
            'serializer',
            'json')
        encoding = work_dict.get(
            'encoding',
            'utf-8')

        rec['ticker'] = ticker
        rec['ticker_id'] = ticker_id
        rec['s3_bucket'] = s3_bucket_name
        rec['s3_key'] = s3_key
        rec['redis_key'] = redis_key
        rec['updated'] = updated
        rec['s3_enabled'] = enable_s3_upload
        rec['redis_enabled'] = enable_redis_publish

        if enable_s3_upload:
            access_key = work_dict.get(
                's3_access_key',
                S3_ACCESS_KEY)
            secret_key = work_dict.get(
                's3_secret_key',
                S3_SECRET_KEY)
            region_name = work_dict.get(
                's3_region_name',
                S3_REGION_NAME)
            service_address = work_dict.get(
                's3_address',
                S3_ADDRESS)
            secure = work_dict.get(
                's3_secure',
                S3_SECURE) == '1'

            endpoint_url = 'http://{}'.format(
                service_address)
            if secure:
                endpoint_url = 'https://{}'.format(
                    service_address)

            log.info(
                '{} building s3 endpoint_url={} '
                'region={}'.format(
                    label,
                    endpoint_url,
                    region_name))

            s3 = boto3.resource(
                's3',
                endpoint_url=endpoint_url,
                aws_access_key_id=access_key,
                aws_secret_access_key=secret_key,
                region_name=region_name,
                config=boto3.session.Config(
                    signature_version='s3v4')
            )

            try:
                log.info(
                    '{} checking bucket={} exists'.format(
                        label,
                        s3_bucket_name))
                if s3.Bucket(s3_bucket_name) not in s3.buckets.all():
                    log.info(
                        '{} creating bucket={}'.format(
                            label,
                            s3_bucket_name))
                    s3.create_bucket(
                        Bucket=s3_bucket_name)
            except Exception as e:
                log.info(
                    '{} failed creating bucket={} '
                    'with ex={}'.format(
                        label,
                        s3_bucket_name,
                        e))
            # end of try/ex for creating bucket

            try:
                log.info(
                    '{} uploading to s3={}/{} '
                    'updated={}'.format(
                        label,
                        s3_bucket_name,
                        s3_key,
                        updated))
                s3.Bucket(s3_bucket_name).put_object(
                    Key=s3_key,
                    Body=json.dumps(data).encode(encoding))
            except Exception as e:
                log.error(
                    '{} failed uploading bucket={} '
                    'key={} ex={}'.format(
                        label,
                        s3_bucket_name,
                        s3_key,
                        e))
            # end of try/ex for creating bucket
        else:
            log.info(
                '{} SKIP S3 upload bucket={} '
                'key={}'.format(
                    label,
                    s3_bucket_name,
                    s3_key))
        # end of if enable_s3_upload

        if enable_redis_publish:
            redis_address = work_dict.get(
                'redis_address',
                REDIS_ADDRESS)
            redis_key = work_dict.get(
                'redis_key',
                REDIS_KEY)
            redis_password = work_dict.get(
                'redis_password',
                REDIS_PASSWORD)
            redis_db = work_dict.get(
                'redis_db',
                REDIS_DB)
            redis_expire = None
            if 'redis_expire' in work_dict:
                redis_expire = work_dict.get(
                    'redis_expire',
                    REDIS_EXPIRE)
            log.info(
                'redis enabled address={}@{} '
                'key={}'.format(
                    redis_address,
                    redis_db,
                    redis_key))
            redis_host = None
            redis_port = None
            try:
                redis_host = redis_address.split(':')[0]
                redis_port = redis_address.split(':')[1]
            except Exception as c:
                err = (
                    '{} failed parsing redis_address={} '
                    'with ex={} '
                    'please set one with the format: '
                    '<hostname>:<port>'.format(
                        label,
                        redis_address,
                        c))
                log.critical(err)
                res = build_result.build_result(
                    status=ERR,
                    err=err,
                    rec=rec)
                return res
            # end of checking that redis_address is valid

            try:
                log.info(
                    '{} publishing redis={}:{} '
                    'db={} key={} '
                    'updated={} expire={}'.format(
                        label,
                        redis_host,
                        redis_port,
                        redis_db,
                        redis_key,
                        updated,
                        redis_expire))

                rc = redis.Redis(
                    host=redis_host,
                    port=redis_port,
                    password=redis_password,
                    db=redis_db)

                redis_set_res = redis_set.set_data_in_redis_key(
                    label=label,
                    client=rc,
                    key=redis_key,
                    data=data,
                    serializer=serializer,
                    encoding=encoding,
                    expire=redis_expire,
                    px=None,
                    nx=False,
                    xx=False)

                log.info(
                    '{} redis_set status={} err={}'.format(
                        label,
                        get_status(redis_set_res['status']),
                        redis_set_res['err']))

            except Exception as e:
                log.error(
                    '{} failed - redis publish to '
                    'key={} ex={}'.format(
                        label,
                        redis_key,
                        e))
            # end of try/ex for creating bucket
        else:
            log.info(
                '{} SKIP REDIS publish '
                'key={}'.format(
                    label,
                    redis_key))
        # end of if enable_redis_publish

        res = build_result.build_result(
            status=SUCCESS,
            err=None,
            rec=rec)

    except Exception as e:
        res = build_result.build_result(
            status=ERR,
            err=(
                'failed - publish_pricing_update '
                'dict={} with ex={}').format(
                    work_dict,
                    e),
            rec=rec)
        log.error(
            '{} - {}'.format(
                label,
                res['err']))
    # end of try/ex

    log.info(
        'task - publish_pricing_update done - '
        '{} - status={}'.format(
            label,
            get_status(res['status'])))

    return analysis_engine.get_task_results.get_task_results(
        work_dict=work_dict,
        result=res)
コード例 #28
0
def plot_trading_history(title,
                         df,
                         red,
                         red_color=None,
                         red_label=None,
                         blue=None,
                         blue_color=None,
                         blue_label=None,
                         green=None,
                         green_color=None,
                         green_label=None,
                         orange=None,
                         orange_color=None,
                         orange_label=None,
                         date_col='date',
                         xlabel='Date',
                         ylabel='Algo Values',
                         linestyle='-',
                         width=15.0,
                         height=15.0,
                         date_format='%d\n%b',
                         df_filter=None,
                         start_date=None,
                         footnote_text=None,
                         footnote_xpos=0.70,
                         footnote_ypos=0.01,
                         footnote_color='#888888',
                         footnote_fontsize=8,
                         scale_y=False,
                         show_plot=True,
                         dropna_for_all=False,
                         verbose=False):
    """plot_trading_history

    Plot columns up to 4 lines from the ``Trading History`` dataset

    :param title: title of the plot
    :param df: dataset which is ``pandas.DataFrame``
    :param red: string - column name to plot in
        ``red_color`` (or default ``ae_consts.PLOT_COLORS[red]``)
        where the column is in the ``df`` and
        accessible with:``df[red]``
    :param red_color: hex color code to plot the data in the
        ``df[red]``  (default is ``ae_consts.PLOT_COLORS['red']``)
    :param red_label: optional - string for the label used
        to identify the ``red`` line in the legend
    :param blue: string - column name to plot in
        ``blue_color`` (or default ``ae_consts.PLOT_COLORS['blue']``)
        where the column is in the ``df`` and
        accessible with:``df[blue]``
    :param blue_color: hex color code to plot the data in the
        ``df[blue]``  (default is ``ae_consts.PLOT_COLORS['blue']``)
    :param blue_label: optional - string for the label used
        to identify the ``blue`` line in the legend
    :param green: string - column name to plot in
        ``green_color`` (or default ``ae_consts.PLOT_COLORS['darkgreen']``)
        where the column is in the ``df`` and
        accessible with:``df[green]``
    :param green_color: hex color code to plot the data in the
        ``df[green]``  (default is ``ae_consts.PLOT_COLORS['darkgreen']``)
    :param green_label: optional - string for the label used
        to identify the ``green`` line in the legend
    :param orange: string - column name to plot in
        ``orange_color`` (or default ``ae_consts.PLOT_COLORS['orange']``)
        where the column is in the ``df`` and
        accessible with:``df[orange]``
    :param orange_color: hex color code to plot the data in the
        ``df[orange]``  (default is ``ae_consts.PLOT_COLORS['orange']``)
    :param orange_label: optional - string for the label used
        to identify the ``orange`` line in the legend
    :param date_col: string - date column name
        (default is ``date``)
    :param xlabel: x-axis label
    :param ylabel: y-axis label
    :param linestyle: style of the plot line
    :param width: float - width of the image
    :param height: float - height of the image
    :param date_format: string - format for dates
    :param df_filter: optional - initialized ``pandas.DataFrame`` query
        for reducing the ``df`` records before plotting. As an eaxmple
        ``df_filter=(df['close'] > 0.01)`` would find only records in
        the ``df`` with a ``close`` value greater than ``0.01``
    :param start_date: optional - string ``datetime``
        for plotting only from a date formatted as
        ``YYYY-MM-DD HH\:MM\:SS``
    :param footnote_text: optional - string footnote text
        (default is ``algotraders <DATE>``)
    :param footnote_xpos: optional - float for footnote position
        on the x-axies
        (default is ``0.75``)
    :param footnote_ypos: optional - float for footnote position
        on the y-axies
        (default is ``0.01``)
    :param footnote_color: optional - string hex color code for
        the footnote text
        (default is ``#888888``)
    :param footnote_fontsize: optional - float footnote font size
        (default is ``8``)
    :param scale_y: optional - bool to scale the y-axis with
        .. code-block:: python

            use_ax.set_ylim(
                [0, use_ax.get_ylim()[1] * 3])
    :param show_plot: bool to show the plot
    :param dropna_for_all: optional - bool to toggle keep None's in
        the plot ``df`` (default is drop them for display purposes)
    :param verbose: optional - bool to show logs for debugging
        a dataset
    """

    rec = {'ax1': None, 'ax2': None, 'ax3': None, 'ax4': None, 'fig': None}
    result = build_result.build_result(status=ae_consts.NOT_RUN,
                                       err=None,
                                       rec=rec)

    if verbose:
        log.info('plot_trading_history - start')

    use_red = red_color
    use_blue = blue_color
    use_green = green_color
    use_orange = orange_color

    if not use_red:
        use_red = ae_consts.PLOT_COLORS['red']
    if not use_blue:
        use_blue = ae_consts.PLOT_COLORS['blue']
    if not use_green:
        use_green = ae_consts.PLOT_COLORS['darkgreen']
    if not use_orange:
        use_orange = ae_consts.PLOT_COLORS['orange']

    use_footnote = footnote_text
    if not use_footnote:
        use_footnote = ('algotraders - {}'.format(
            datetime.datetime.now().strftime(
                ae_consts.COMMON_TICK_DATE_FORMAT)))

    column_list = [date_col]
    all_plots = []
    if red:
        column_list.append(red)
        all_plots.append({'column': red, 'color': use_red})
    if blue:
        column_list.append(blue)
        all_plots.append({'column': blue, 'color': use_blue})
    if green:
        column_list.append(green)
        all_plots.append({'column': green, 'color': use_green})
    if orange:
        column_list.append(orange)
        all_plots.append({'column': orange, 'color': use_orange})

    use_df = df
    if start_date:
        start_date_value = datetime.datetime.strptime(
            start_date, ae_consts.COMMON_TICK_DATE_FORMAT)
        use_df = df[(df[date_col] >= start_date_value)][column_list]
    # end of filtering by start date

    if verbose:
        log.info(
            'plot_history_df start_date={} df.index={} column_list={}'.format(
                start_date, len(use_df.index), column_list))

    if hasattr(df_filter, 'to_json'):
        # Was seeing this warning below in Jupyter:
        # UserWarning: Boolean Series key
        # will be reindexed to match DataFrame index
        # use_df = use_df[df_filter][column_list]
        # now using:
        use_df = use_df.loc[df_filter, column_list]

    if verbose:
        log.info('plot_history_df filter df.index={} column_list={}'.format(
            start_date, len(use_df.index), column_list))

    if dropna_for_all:
        use_df = use_df.dropna(axis=0, how='any')
        if verbose:
            log.info('plot_history_df dropna_for_all')
    # end of pre-plot dataframe scrubbing

    ae_charts.set_common_seaborn_fonts()

    hex_color = ae_consts.PLOT_COLORS['blue']
    fig, ax = plt.subplots(sharex=True, sharey=True, figsize=(width, height))

    # Convert matplotlib date numbers to strings for dates to
    # avoid dealing with weekend date gaps in plots
    date_strings, date_labels = \
        ae_utils.get_trade_open_xticks_from_date_col(
            use_df[date_col])
    """
    hit the slice warning with this approach before
    and one trying df[date_col] = df[date_col].dt.strftime

    SettingWithCopyWarning
    Try using .loc[row_indexer,col_indexer] = value instead

    use_df[date_col].replace(
        use_df[date_col].dt.strftime(
            ae_consts.COMMON_TICK_DATE_FORMAT),
        inplace=True)
    trying this:
    https://stackoverflow.com/questions/19738169/
    convert-column-of-date-objects-in-pandas-dataframe-to-strings
    """
    use_df[date_col] = use_df[date_col].apply(
        lambda x: x.strftime(ae_consts.COMMON_TICK_DATE_FORMAT))

    all_axes = []
    num_plots = len(all_plots)
    for idx, node in enumerate(all_plots):
        column_name = node['column']
        hex_color = node['color']

        use_ax = ax
        if idx > 0:
            use_ax = ax.twinx()

        if verbose:
            log.info('plot_history_df - {}/{} - {} in {} - ax={}'.format(
                (idx + 1), num_plots, column_name, hex_color, use_ax))

        all_axes.append(use_ax)
        use_ax.plot(use_df[date_col],
                    use_df[column_name],
                    linestyle=linestyle,
                    color=hex_color)
        if idx > 0:
            if scale_y:
                use_ax.set_ylim([0, use_ax.get_ylim()[1] * 3])
            use_ax.yaxis.set_ticklabels([])
            use_ax.yaxis.set_ticks([])
            use_ax.xaxis.grid(False)
            use_ax.yaxis.grid(False)
        # end if this is not the fist axis

        use_ax.set_xticks(date_strings)
        use_ax.set_xticklabels(date_labels, rotation=45, ha='right')
    # end of for all plots

    lines = []
    for idx, cur_ax in enumerate(all_axes):
        ax_lines = cur_ax.get_lines()
        for line in ax_lines:
            label_name = str(line.get_label())
            use_label = label_name
            if idx == 0:
                if red_label:
                    use_label = red_label
            elif idx == 1:
                if blue_label:
                    use_label = blue_label
            elif idx == 2:
                use_label = label_name[-20:]
                if green_label:
                    use_label = green_label
            elif idx == 3:
                use_label = label_name[-20:]
                if orange_label:
                    use_label = orange_label
            else:
                if len(label_name) > 10:
                    use_label = label_name[-20:]
            # end of fixing the labels in the legend
            line.set_label(use_label)
            if line.get_label() not in lines:
                lines.append(line)
        rec['ax{}'.format(idx + 1)] = cur_ax
    # end of compiling a new-shortened legend while removing dupes

    for idx, cur_ax in enumerate(all_axes):
        if cur_ax:
            if cur_ax.get_legend():
                cur_ax.get_legend().remove()
    # end of removing all previous legends

    if verbose:
        log.info('legend lines={}'.format([l.get_label() for l in lines]))
    # log what's going to be in the legend

    ax.legend(lines, [l.get_label() for l in lines], loc='best', shadow=True)

    fig.autofmt_xdate()

    plt.xlabel(xlabel)
    plt.ylabel(ylabel)

    ax.set_title(title)
    ae_charts.add_footnote(fig=fig,
                           xpos=footnote_xpos,
                           ypos=footnote_ypos,
                           text=use_footnote,
                           color=footnote_color,
                           fontsize=footnote_fontsize)
    plt.tight_layout()

    plt.show()
    if show_plot:
        plt.show()
    else:
        plt.plot()

    rec['fig'] = fig

    result = build_result.build_result(status=ae_consts.SUCCESS,
                                       err=None,
                                       rec=rec)

    return result
コード例 #29
0
def build_df_from_redis(label=None,
                        client=None,
                        address=None,
                        host=None,
                        port=None,
                        password=None,
                        db=None,
                        key=None,
                        expire=None,
                        serializer='json',
                        encoding='utf-8',
                        orient='records'):
    """build_df_from_redis

    :param label: log tracking label
    :param client: initialized redis client
    :param address: redis address: <host:port>
    :param host: redis host
    :param port: redis port
    :param password: redis password
    :param db: redis db
    :param key: redis key
    :param expire: not used yet - redis expire
    :param serializer: support for future
                       pickle objects in redis
    :param encoding: format of the encoded key in redis
    :param orient: use the same orient value as
                   the ``to_json(orient='records')`` used
                   to deserialize the DataFrame correctly.
    """

    data = None
    valid_df = False
    df = None

    rec = {'valid_df': valid_df, 'data': data}
    res = build_result.build_result(status=NOT_RUN, err=None, rec=rec)

    log_id = label if label else 'build-df'

    try:
        log.debug('{} calling get redis key={}'.format(log_id, key))

        use_host = host
        use_port = port
        if not use_host and not use_port:
            if address:
                use_host = address.split(':')[0]
                use_port = int(address.split(':')[1])

        use_client = client
        if not use_client:
            log.debug('{} connecting to redis={}:{}@{}'.format(
                log_id, use_host, use_port, db))
            use_client = redis.Redis(host=use_host,
                                     port=use_port,
                                     password=password,
                                     db=db)

        redis_res = redis_get.get_data_from_redis_key(label=log_id,
                                                      client=use_client,
                                                      host=use_host,
                                                      port=use_port,
                                                      password=password,
                                                      db=db,
                                                      key=key,
                                                      expire=expire,
                                                      serializer='json',
                                                      encoding=encoding)

        valid_df = False
        if redis_res['status'] == SUCCESS:
            data = redis_res['rec'].get('data', None)
            if data:
                if ev('DEBUG_REDIS', '0') == '1':
                    log.info('{} - found key={} data={}'.format(
                        log_id, key, ppj(data)))
                else:
                    log.debug('{} - loading df from key={}'.format(
                        log_id, key))
                    df = pd.read_json(data, orient='records')
                    valid_df = True
            else:
                log.debug('{} key={} no data'.format(log_id, key))
            # if data

            rec['data'] = df
            rec['valid_df'] = valid_df

            res = build_result.build_result(status=SUCCESS, err=None, rec=rec)
            return res
        else:
            log.debug('{} no data key={}'.format(log_id, key))
            res = build_result.build_result(status=SUCCESS, err=None, rec=rec)
            return res
    except Exception as e:
        err = ('{} failed - build_df_from_redis data={} '
               'key={} ex={}'.format(log_id, (data == '0'), key, e))
        log.error(err)
        res = build_result.build_result(status=ERR, err=err, rec=rec)
    # end of try/ex for getting redis data

    return res
コード例 #30
0
def get_data_from_yahoo(work_dict):
    """get_data_from_yahoo

    Get data from yahoo

    :param work_dict: request dictionary
    """
    label = 'get_data_from_yahoo'

    log.info('task - {} - start ' 'work_dict={}'.format(label, work_dict))

    num_news_rec = 0
    num_option_calls = 0
    num_option_puts = 0
    cur_high = -1
    cur_low = -1
    cur_open = -1
    cur_close = -1
    cur_volume = -1

    rec = {
        'pricing': None,
        'options': None,
        'calls': None,
        'puts': None,
        'news': None,
        'exp_date': None,
        'publish_pricing_update': None,
        'date': None,
        'updated': None
    }
    res = {'status': NOT_RUN, 'err': None, 'rec': rec}

    try:

        ticker = work_dict.get('ticker', TICKER)
        exp_date = work_dict.get('exp_date', None)
        cur_strike = work_dict.get('strike', None)
        contract_type = str(work_dict.get('contract', 'C')).upper()
        get_pricing = work_dict.get('get_pricing', True)
        get_news = work_dict.get('get_news', True)
        get_options = work_dict.get('get_options', True)
        orient = work_dict.get('orient', 'records')
        label = work_dict.get('label', label)

        ticker_results = pinance.Pinance(ticker)
        num_news_rec = 0

        use_date = exp_date
        if not exp_date:
            exp_date = opt_dates.option_expiration(date=exp_date)
            use_date = exp_date.strftime('%Y-%m-%d')
        """
        Debug control flags

        Quickly turn specific fetches off:

        get_news = False
        get_pricing = False
        get_options = False

        """
        if get_pricing:
            log.info('{} getting ticker={} pricing'.format(label, ticker))
            ticker_results.get_quotes()
            if ticker_results.quotes_data:
                pricing_dict = ticker_results.quotes_data

                cur_high = pricing_dict.get('regularMarketDayHigh', None)
                cur_low = pricing_dict.get('regularMarketDayLow', None)
                cur_open = pricing_dict.get('regularMarketOpen', None)
                cur_close = pricing_dict.get('regularMarketPreviousClose',
                                             None)
                cur_volume = pricing_dict.get('regularMarketVolume', None)
                pricing_dict['high'] = cur_high
                pricing_dict['low'] = cur_low
                pricing_dict['open'] = cur_open
                pricing_dict['close'] = cur_close
                pricing_dict['volume'] = cur_volume
                pricing_dict['date'] = get_last_close_str()
                if 'regularMarketTime' in pricing_dict:
                    pricing_dict['market_time'] = \
                        datetime.datetime.fromtimestamp(
                            pricing_dict['regularMarketTime']).strftime(
                                COMMON_TICK_DATE_FORMAT)
                if 'postMarketTime' in pricing_dict:
                    pricing_dict['post_market_time'] = \
                        datetime.datetime.fromtimestamp(
                            pricing_dict['postMarketTime']).strftime(
                                COMMON_TICK_DATE_FORMAT)

                log.info('{} ticker={} converting pricing to '
                         'df orient={}'.format(label, ticker, orient))

                try:
                    rec['pricing'] = pricing_dict
                except Exception as f:
                    rec['pricing'] = '{}'
                    log.info('{} ticker={} failed converting pricing '
                             'data={} to df ex={}'.format(
                                 label, ticker, ppj(pricing_dict), f))
                # try/ex

                log.info('{} ticker={} done converting pricing to '
                         'df orient={}'.format(label, ticker, orient))

            else:
                log.error('{} ticker={} missing quotes_data={}'.format(
                    label, ticker, ticker_results.quotes_data))
            # end of if ticker_results.quotes_data

            log.info('{} ticker={} close={} vol={}'.format(
                label, ticker, cur_close, cur_volume))
        else:
            log.info('{} skip - getting ticker={} pricing'.format(
                label, ticker, get_pricing))
        # if get_pricing

        if get_news:
            log.info('{} getting ticker={} news'.format(label, ticker))
            ticker_results.get_news()
            if ticker_results.news_data:
                news_list = None
                try:
                    news_list = ticker_results.news_data
                    log.info('{} ticker={} converting news to '
                             'df orient={}'.format(label, ticker, orient))

                    num_news_rec = len(news_list)

                    rec['news'] = news_list
                except Exception as f:
                    rec['news'] = '{}'
                    log.info('{} ticker={} failed converting news '
                             'data={} to df ex={}'.format(
                                 label, ticker, news_list, f))
                # try/ex

                log.info('{} ticker={} done converting news to '
                         'df orient={}'.format(label, ticker, orient))
            else:
                log.info('{} ticker={} Yahoo NO news={}'.format(
                    label, ticker, ticker_results.news_data))
            # end of if ticker_results.news_data
        else:
            log.info('{} skip - getting ticker={} news'.format(label, ticker))
        # end if get_news

        if get_options:

            get_all_strikes = True
            if get_all_strikes:
                cur_strike = None
            else:
                if cur_close:
                    cur_strike = int(cur_close)
                if not cur_strike:
                    cur_strike = 287

            log.info('{} ticker={} num_news={} get options close={} '
                     'exp_date={} contract={} strike={}'.format(
                         label, ticker, num_news_rec, cur_close, use_date,
                         contract_type, cur_strike))

            options_dict = \
                yahoo_get_pricing.get_options(
                    ticker=ticker,
                    exp_date_str=use_date,
                    contract_type=contract_type,
                    strike=cur_strike)

            rec['options'] = '{}'

            try:
                log.info('{} ticker={} converting options to '
                         'df orient={}'.format(label, ticker, orient))

                num_option_calls = options_dict.get('num_calls', None)
                num_option_puts = options_dict.get('num_puts', None)
                rec['options'] = {
                    'exp_date': options_dict.get('exp_date', None),
                    'calls': options_dict.get('calls', None),
                    'puts': options_dict.get('puts', None),
                    'num_calls': num_option_calls,
                    'num_puts': num_option_puts
                }
                rec['calls'] = rec['options'].get('calls', EMPTY_DF_STR)
                rec['puts'] = rec['options'].get('puts', EMPTY_DF_STR)
            except Exception as f:
                rec['options'] = '{}'
                log.info('{} ticker={} failed converting options '
                         'data={} to df ex={}'.format(label, ticker,
                                                      options_dict, f))
            # try/ex

            log.info('{} ticker={} done converting options to '
                     'df orient={} num_calls={} num_puts={}'.format(
                         label, ticker, orient, num_option_calls,
                         num_option_puts))

        else:
            log.info('{} skip - getting ticker={} options'.format(
                label, ticker))
        # end of if get_options

        log.info('{} yahoo pricing for ticker={} close={} '
                 'num_calls={} num_puts={} news={}'.format(
                     label, ticker, cur_close, num_option_calls,
                     num_option_puts, num_news_rec))

        fields_to_upload = ['pricing', 'options', 'calls', 'puts', 'news']

        for field_name in fields_to_upload:
            upload_and_cache_req = copy.deepcopy(work_dict)
            upload_and_cache_req['celery_disabled'] = True
            upload_and_cache_req['data'] = rec[field_name]
            if not upload_and_cache_req['data']:
                upload_and_cache_req['data'] = '{}'

            if 'redis_key' in work_dict:
                upload_and_cache_req['redis_key'] = '{}_{}'.format(
                    work_dict.get('redis_key',
                                  '{}_{}'.format(ticker, field_name)),
                    field_name)
            if 's3_key' in work_dict:
                upload_and_cache_req['s3_key'] = '{}_{}'.format(
                    work_dict.get('s3_key', '{}_{}'.format(ticker,
                                                           field_name)),
                    field_name)
            try:
                update_res = publisher.run_publish_pricing_update(
                    work_dict=upload_and_cache_req)
                update_status = update_res.get('status', NOT_SET)
                log.info('{} publish update status={} data={}'.format(
                    label, get_status(status=update_status), update_res))
            except Exception as f:
                err = ('{} - failed to upload YAHOO data={} to '
                       'to s3_key={} and redis_key={}'.format(
                           label, upload_and_cache_req,
                           upload_and_cache_req['s3_key'],
                           upload_and_cache_req['redis_key']))
                log.error(err)
            # end of try/ex to upload and cache
            if not rec[field_name]:
                log.debug('{} - ticker={} no data from YAHOO for '
                          'field_name={}'.format(label, ticker, field_name))
        # end of for all fields

        res = build_result.build_result(status=SUCCESS, err=None, rec=rec)
    except Exception as e:
        res = build_result.build_result(status=ERR,
                                        err=('failed - get_data_from_yahoo '
                                             'dict={} with ex={}').format(
                                                 work_dict, e),
                                        rec=rec)
        log.error('{} - {}'.format(label, res['err']))
    # end of try/ex

    log.info('task - get_data_from_yahoo done - '
             '{} - status={}'.format(label, get_status(res['status'])))

    return res