def kst_signal(fund: pd.DataFrame, **kwargs) -> list:
    """Know Sure Thing - Signal

    Also known as the "Summed Rate of Change" Oscillator

    Arguments:
        fund {pd.DataFrame} -- fund dataset

    Optional Args:
        periods {list} -- ROC periods (default: {[10, 15, 20, 30]})
        sma_intervals {list} -- sma intervals corresponding to the ROC periods
                                (default: {[10, 10, 10, 15]})
        plot_output {bool} -- (default: {True})
        name {str} -- (default: {''})
        views {str} -- (default: {''})
        p_bar {ProgressBar} -- (default: {None})

    Returns:
        list -- kst signal and its 9d sma signal line
    """
    periods = kwargs.get('periods', [10, 15, 20, 30])
    sma_intervals = kwargs.get('sma_intervals', [10, 10, 10, 15])
    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    views = kwargs.get('views', '')
    p_bar = kwargs.get('p_bar')

    increment = 0.7 / float(len(periods) * 3)
    signal = [0.0] * len(fund['Close'])

    for i, period in enumerate(periods):
        roc = roc_signal(fund, period)
        if p_bar:
            p_bar.uptick(increment=increment)

        sma = simple_moving_avg(roc, sma_intervals[i], data_type='list')
        if p_bar:
            p_bar.uptick(increment=increment)

        for j in range(len(signal)):
            signal[j] += float(i + 1) * sma[j]
        if p_bar:
            p_bar.uptick(increment=increment)

    signal_line = simple_moving_avg(signal, 9, data_type='list')
    if p_bar:
        p_bar.uptick(increment=0.1)

    name2 = INDEXES.get(name, name)
    title = f"{name2} - Know Sure Thing"

    if plot_output:
        dual_plotting(fund['Close'], [signal, signal_line],
                      'Price', 'KST', title=title)
    else:
        filename = os.path.join(name, views, f"kst_oscillator_{name}")
        dual_plotting(fund['Close'], [signal, signal_line], 'Price',
                      'KST', title=title, saveFig=True, filename=filename)

    return signal, signal_line
示例#2
0
def generate_macd_signal(fund: pd.DataFrame, **kwargs) -> dict:
    """Generate MACD Signal

    macd = ema(12) - ema(26)
    'signal' = macd(ema(9))

    Arguments:
        fund {pd.DataFrame} -- fund dataset

    Keyword Arguments:
        plotting {bool} -- (default: {True})
        name {str} -- (default: {''})
        view {str} -- directory of plots (default: {''})

    Returns:
        dict -- macd data object
    """
    plotting = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    view = kwargs.get('view')

    macd = dict()

    emaTw = exponential_moving_avg(fund, interval=12)
    emaTs = exponential_moving_avg(fund, interval=26)
    macd_val = []

    for i in range(len(emaTw)):
        if i < 26:
            macd_val.append(0.0)
        else:
            macd_val.append(emaTw[i] - emaTs[i])

    macd_sig = exponential_moving_avg(macd_val, interval=9, data_type='list')

    # Actual MACD vs. its signal line
    m_bar = []
    for i, sig in enumerate(macd_sig):
        m_bar.append(macd_val[i] - sig)

    macd['tabular'] = {'macd': macd_val, 'signal_line': macd_sig, 'bar': m_bar}

    x = dates_extractor_list(fund)
    name3 = INDEXES.get(name, name)
    name2 = name3 + ' - MACD'

    if plotting:
        bar_chart(m_bar, position=fund, x=x, title=name2)
    else:
        filename = os.path.join(name, view, f"macd_bar_{name}.png")
        bar_chart(m_bar,
                  position=fund,
                  x=x,
                  title=name2,
                  saveFig=True,
                  filename=filename)

    return macd
def slide_title_header(slide, fund: str, include_time=True, price_details=''):
    """Slide Title Header

    Generates a consistent title header for fund slides.

    Arguments:
        slide {pptx-slide} -- slide object
        fund {str} -- fund name

    Keyword Arguments:
        include_time {bool} -- will include time of pptx creation (default: {True})
        price_details {str} -- price content for latest period (default: {''})

    Returns:
        pptx-slide -- updated slide with title content
    """
    fund = INDEXES.get(fund, fund)

    left = Inches(0)  # Inches(3.86)
    top = Inches(0)
    width = height = Inches(0.5)
    txbox = slide.shapes.add_textbox(left, top, width, height)
    tf = txbox.text_frame

    p = tf.paragraphs[0]
    p.text = fund
    p.font.size = Pt(36)
    p.font.name = 'Arial'
    p.font.bold = True

    if include_time:
        p = tf.add_paragraph()
        p.font.size = Pt(14)
        p.font.bold = False
        p.font.name = 'Arial'
        p.text = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))

    if price_details != '':
        left = Inches(2)
        top = Inches(0.1)
        width = height = Inches(0.5)
        txbox = slide.shapes.add_textbox(left, top, width, height)
        tf = txbox.text_frame

        p = tf.paragraphs[0]
        p.text = fund
        p.font.size = Pt(24)
        p.font.name = 'Arial'
        p.font.bold = True
        p.text = price_details
        deets = price_details.split(' ')

        if '+' in deets[1]:
            p.font.color.rgb = color_to_RGB('green')
        else:
            p.font.color.rgb = color_to_RGB('red')

    return slide
示例#4
0
def cci_metrics(position: pd.DataFrame, cci: dict, **kwargs) -> list:

    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    view = kwargs.get('view', '')

    metrics = [0.0] * len(position['Close'])
    features = cci['signals']
    signals = cci['tabular']
    periods = cci['periods']

    for feat in features:
        if 'zero' in feat['value']:
            if feat['type'] == 'bullish':
                metrics[feat['index']] += 0.6
            else:
                metrics[feat['index']] -= 0.6

        elif '100' in feat['value']:
            if feat['type'] == 'bullish':
                metrics[feat['index']] += 1.0
            else:
                metrics[feat['index']] -= 1.0

    for period in signals:
        if period == str(periods['short']):
            point = 0.2
        elif period == str(periods['medium']):
            point = 0.2
        else:
            point = 0.2

        for i, value in enumerate(signals[period]):
            if value > 100.0:
                metrics[i] += point
            if value < 100.0:
                metrics[i] -= point

    metrics = exponential_moving_avg(metrics, 7, data_type='list')
    norm = normalize_signals([metrics])
    metrics = norm[0]

    name2 = INDEXES.get(name, name)
    title = f"{name2} - Commodity Channel Index Metrics"

    if plot_output:
        dual_plotting(position['Close'], metrics,
                      'Price', 'Metrics', title=title)

    else:
        filename = filename = os.path.join(
            name, view, f"commodity_metrics_{name}.png")
        dual_plotting(position['Close'], metrics, 'Price',
                      'Metrics', title=title, saveFig=True, filename=filename)

    return metrics
示例#5
0
def generate_momentum_signal(position: pd.DataFrame, **kwargs) -> list:
    """Generate Momentum Signal

    https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/cmo

    Arguments:
        position {pd.DataFrame} -- fund dataset

    Optional Args:
        interval {int} -- lookback period (default: {20})
        plot_output {bool} -- (default: {True})
        name {str} -- (default: {''})
        view {str} -- (default: {''})

    Returns:
        list -- momentum signal
    """
    interval = kwargs.get('interval', 20)
    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    view = kwargs.get('view', '')

    signal = []
    for i in range(interval - 1):
        signal.append(0.0)
    for i in range(interval - 1, len(position['Close'])):
        sum_up = 0.0
        sum_down = 0.0
        for j in range(i - (interval - 2), i):
            if position['Close'][j] > position['Close'][j - 1]:
                sum_up += position['Close'][j] - position['Close'][j - 1]
            else:
                sum_down += np.abs(position['Close'][j] -
                                   position['Close'][j - 1])
        cmo = 100.0 * (sum_up - sum_down) / (sum_up + sum_down)
        signal.append(cmo)

    name2 = INDEXES.get(name, name)
    if plot_output:
        dual_plotting(position['Close'],
                      signal,
                      'Price',
                      'CMO',
                      title=f'{name2} - (Chande) Momentum Oscillator')
    else:
        filename = os.path.join(name, view, f"momentum_oscillator_{name}.png")
        dual_plotting(position['Close'],
                      signal,
                      'Price',
                      'CMO',
                      title='(Chande) Momentum Oscillator',
                      filename=filename,
                      saveFig=True)

    return signal
示例#6
0
def get_atr_signal(fund: pd.DataFrame, **kwargs) -> list:
    """Get ATR Signal

    Arguments:
        fund {pd.DataFrame} -- fund dataset

    Optional Args:
        period {int} -- lookback period of atr signal (default: {14})
        plot_output {bool} -- (default: {True})
        name {str} -- (default: {''})
        views {str} -- (default: {''})
        out_suppress {bool} -- (default: {False})

    Returns:
        list -- atr signal
    """
    period = kwargs.get('period', 14)
    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    views = kwargs.get('views', '')
    out_suppress = kwargs.get('out_suppress', False)

    signal = [0.0] * len(fund['Close'])

    atr = [0.0]
    for i in range(1, len(fund['Close'])):
        trues = [
            fund['High'][i] - fund['Low'][i],
            abs(fund['High'][i] - fund['Close'][i - 1]),
            abs(fund['Low'][i] - fund['Close'][i - 1])
        ]
        _max = max(trues)
        atr.append(_max)

    for i in range(period - 1, len(fund['Close'])):
        atr_val = sum(atr[i - (period - 1):i + 1]) / float(period)
        signal[i] = atr_val

    if not out_suppress:
        name2 = INDEXES.get(name, name)
        title = f"{name2} - Average True Range"
        if plot_output:
            dual_plotting(fund['Close'], signal, 'Price', 'ATR', title=title)
        else:
            filename = os.path.join(name, views, f"atr_{name}.png")
            dual_plotting(fund['Close'],
                          signal,
                          'Price',
                          'ATR',
                          title=title,
                          saveFig=True,
                          filename=filename)

    return signal
示例#7
0
def mov_avg_convergence_divergence(fund: pd.DataFrame, **kwargs) -> dict:
    """Moving Average Convergence Divergence (MACD)

    Arguments:
        fund {pd.DataFrame} -- fund historical data

    Optional Args:
        name {str} -- name of fund, primarily for plotting (default: {''})
        plot_output {bool} -- True to render plot in realtime (default: {True})
        progress_bar {ProgressBar} -- (default: {None})
        view {str} -- directory of plots (default: {''})

    Returns:
        dict -- contains all macd information in regarding macd
    """
    name = kwargs.get('name', '')
    plot_output = kwargs.get('plot_output', True)
    progress_bar = kwargs.get('progress_bar', None)
    view = kwargs.get('view', '')

    macd = generate_macd_signal(
        fund, plot_output=plot_output, name=name, view=view)
    if progress_bar is not None:
        progress_bar.uptick(increment=0.3)

    macd = get_macd_statistics(macd, progress_bar=progress_bar)

    macd = macd_metrics(fund, macd, p_bar=progress_bar,
                        name=name, plot_output=plot_output, view=view)

    macd_sig = macd['tabular']['macd']
    sig_line = macd['tabular']['signal_line']

    name3 = INDEXES.get(name, name)
    name2 = name3 + ' - MACD'
    if plot_output:
        dual_plotting(fund['Close'], [macd_sig, sig_line],
                      'Position Price', ['MACD', 'Signal Line'], title=name2)
        print_macd_statistics(macd)

    else:
        filename = os.path.join(name, view, f"macd_{name}.png")
        dual_plotting(fund['Close'], [macd_sig, sig_line], 'Position Price',
                      ['MACD', 'Signal Line'], title=name2, saveFig=True, filename=filename)

    if progress_bar is not None:
        progress_bar.uptick(increment=0.3)

    macd['type'] = 'oscillator'
    macd['signals'] = get_macd_features(macd, fund)
    macd['length_of_data'] = len(macd['tabular']['macd'])

    return macd
def kst_metrics(fund: pd.DataFrame, kst_dict: dict, **kwargs) -> dict:
    """KST Metrics

    Arguments:
        fund {pd.DataFrame} -- fund dataset
        kst_dict {dict} -- kst data object

    Optional Args:
        plot_output {bool} -- (default: {True})
        name {str} -- (default: {''})
        views {str} -- (default: {''})

    Returns:
        dict -- kst data object
    """
    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    views = kwargs.get('views', '')

    metrics = [0.0] * len(kst_dict['tabular']['signal'])

    for sig in kst_dict['signals']:
        if sig['type'] == 'bullish':
            multiply = 1.0
        else:
            multiply = -1.0

        if 'crossover' in sig['value']:
            metrics[sig['index']] += 0.2 * multiply

        if 'crossed' in sig['value']:
            metrics[sig['index']] += 1.0 * multiply

    metrics = exponential_moving_avg(metrics, 7, data_type='list')
    metrics = normalize_signals([metrics])[0]

    kst_dict['metrics'] = metrics

    name2 = INDEXES.get(name, name)
    title = f"{name2} - KST Metrics"

    if plot_output:
        dual_plotting(fund['Close'], kst_dict['metrics'],
                      'Price', 'Metrics', title=title)
    else:
        filename = os.path.join(name, views, f"kst_metrics_{name}")
        dual_plotting(fund['Close'], kst_dict['metrics'], 'Price',
                      'Metrics', title=title, saveFig=True, filename=filename)

    return kst_dict
示例#9
0
def generate_bear_bull_signal(position: pd.DataFrame, **kwargs) -> dict:
    """Generate Bear Bull Signal

    Arguments:
        position {pd.DataFrame} -- dataset

    Optional Args:
        interval {int} -- size of exponential moving average window (default: {13})
        plot_output {bool} -- (default: {True})
        name {str} -- (default: {''})
        p_bar {ProgressBar} -- (default: {None})

    Returns:
        dict -- [description]
    """
    interval = kwargs.get('interval', 13)
    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    p_bar = kwargs.get('p_bar')

    bb_signal = {'bulls': [], 'bears': []}
    ema = exponential_moving_avg(position, interval)

    for i, high in enumerate(position['High']):
        bb_signal['bulls'].append(high - ema[i])

    if p_bar is not None:
        p_bar.uptick(increment=0.1)

    for i, low in enumerate(position['Low']):
        bb_signal['bears'].append(low - ema[i])

    if p_bar is not None:
        p_bar.uptick(increment=0.1)

    x = dates_extractor_list(position)
    if plot_output:
        name3 = INDEXES.get(name, name)
        name2 = name3 + ' - Bull Power'
        bar_chart(bb_signal['bulls'], position=position, title=name2, x=x)
        name2 = name3 + ' - Bear Power'
        bar_chart(bb_signal['bears'], position=position, title=name2, x=x)

    return bb_signal
示例#10
0
def output_to_terminal(synopsis: dict, print_out=False, **kwargs):
    """Output to Terminal

    Mapping function to show fund information in terminal

    Arguments:
        synopsis {dict} -- synopsis object to output

    Keyword Arguments:
        print_out {bool} -- (default: {False})

    Optional Args:
        name {str} -- (default: {''})
    """
    name = kwargs.get('name', '')
    name2 = INDEXES.get(name, name)

    if print_out:
        for period in synopsis:

            if period not in EXEMPT_METRICS:
                print("\r\n")
                print(f"Time period: {period} for {name2}")
                print("")

                tabs = strings_to_tabs("Tabular:")
                tabs2 = strings_to_tabs("Current", style='percent')
                print(f"\r\nTabular:{tabs}Current{tabs2}Previous\r\n")

                for tab in synopsis[period]['tabular']:
                    custom_print(tab,
                                 synopsis[period]['tabular'][tab],
                                 prev=synopsis[period]['tabular_delta'][tab],
                                 thr=synopsis[period]['tabular_delta'][tab])

                tabs = strings_to_tabs("Metrics:")
                tabs2 = strings_to_tabs("Current", style='percent')
                print(f"\r\n\r\nMetrics:{tabs}Current{tabs2}Previous\r\n")

                for met in synopsis[period]['metrics']:
                    custom_print(met,
                                 synopsis[period]['metrics'][met],
                                 prev=synopsis[period]['metrics_delta'][met])
示例#11
0
def fund_pdf_pages(pdf, analysis: dict, **kwargs):
    """Fund PDF Pages

    Arguments:
        pdf {FPDF} -- pdf object
        analysis {dict} -- data run data set

    Optional Args:
        views {str} -- (default: {None})

    Returns:
        FPDF -- pdf object
    """
    views = kwargs.get('views')

    has_view = False
    if views is None:
        for fund in analysis:
            for period in analysis[fund]:
                views = period
                has_view = True
                break
            if has_view:
                break

    for fund in analysis:
        if fund != '_METRICS_':
            name = INDEXES.get(fund, fund)
            fund_data = analysis[fund]

            pdf.add_page()
            pdf = fund_title(pdf, name)
            pdf = fund_statistics(pdf, fund_data, sample_view=views)
            pdf = fund_volatility(pdf, fund_data)
            pdf = beta_rsq(pdf, fund_data)

            for period in fund_data['synopsis']:
                pdf = metrics_tables(pdf, fund_data, period)
                pdf = latest_signals(pdf, fund_data, period)

    return pdf
def feature_plotter(fund: pd.DataFrame, shapes: list, **kwargs):
    """Feature Plotter

    Plots a rectangle of where the feature was detected overlayed on the ticker signal.

    Arguments:
        fund {pd.DataFrame} -- fund dataset
        shapes {list} -- list of shape objects

    Optional Args:
        plot_output {bool} -- (default: {True})
        feature {str} -- to control content (default: {'head_and_shoulders'})
        name {str} -- name of fund (default: {''})
        view {str} -- period of viewing of dataset (default: {''})
    """
    plot_output = kwargs.get('plot_output', True)
    feature = kwargs.get('feature', 'head_and_shoulders')
    name = kwargs.get('name', '')
    view = kwargs.get('view', '')

    name2 = INDEXES.get(name, name)
    filename = name + f"/{view}" + f'/{feature}_{name}.png'
    title = f'{name2} Feature Detection: '

    if feature == 'head_and_shoulders':
        title += 'Head and Shoulders'
    elif feature == 'price_gaps':
        title += 'Price Gaps'

    saveFig = not plot_output

    shape_plotting(fund['Close'],
                   shapeXY=shapes,
                   feature=feature,
                   saveFig=saveFig,
                   title=title,
                   filename=filename)
def triple_exp_mov_average(fund: pd.DataFrame,
                           config=[9, 20, 50],
                           **kwargs) -> list:
    """Triple Exponential Moving Average

    Arguments:
        fund {pd.DataFrame} -- fund dataset

    Optional Args:
        plot_output {bool} -- (default: {True})
        name {str} -- (default: {str})
        view {str} -- file directory of plots (default: {''})
        p_bar {ProgressBar} -- (default: {None})

    Keyword Arguments:
        config {list} -- look back period (default: {[9, 13, 50]})

    Returns:
        list -- plots and signals
    """
    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    view = kwargs.get('view', '')
    p_bar = kwargs.get('progress_bar')
    out_suppress = kwargs.get('out_suppress', False)

    tema = dict()

    tshort = exponential_moving_avg(fund, config[0])
    if p_bar is not None:
        p_bar.uptick(increment=0.2)

    tmed = exponential_moving_avg(fund, config[1])
    if p_bar is not None:
        p_bar.uptick(increment=0.2)

    tlong = exponential_moving_avg(fund, config[2])
    if p_bar is not None:
        p_bar.uptick(increment=0.2)

    tema['tabular'] = {'short': tshort, 'medium': tmed, 'long': tlong}
    tema['short'] = {"period": config[0]}
    tema['medium'] = {"period": config[1]}
    tema['long'] = {"period": config[2]}

    tshort_x, tshort2 = adjust_signals(fund, tshort, offset=config[0])
    tmed_x, tmed2 = adjust_signals(fund, tmed, offset=config[1])
    tlong_x, tlong2 = adjust_signals(fund, tlong, offset=config[2])

    plot_short = {
        "plot": tshort2,
        "color": "blue",
        "legend": f"{config[0]}-day MA",
        "x": tshort_x
    }
    plot_med = {
        "plot": tmed2,
        "color": "orange",
        "legend": f"{config[1]}-day MA",
        "x": tmed_x
    }
    plot_long = {
        "plot": tlong2,
        "color": "black",
        "legend": f"{config[2]}-day MA",
        "x": tlong_x
    }

    mshort = []
    mmed = []
    mlong = []

    for i, close in enumerate(fund['Close']):
        mshort.append(np.round((close - tshort[i]) / tshort[i] * 100.0, 3))
        mmed.append(np.round((close - tmed[i]) / tmed[i] * 100.0, 3))
        mlong.append(np.round((close - tlong[i]) / tlong[i] * 100.0, 3))

    if p_bar is not None:
        p_bar.uptick(increment=0.2)

    tema['metrics'] = {
        f'{config[0]}-d': mshort,
        f'{config[1]}-d': mmed,
        f'{config[2]}-d': mlong
    }

    if not out_suppress:
        name3 = INDEXES.get(name, name)
        name2 = name3 + \
            ' - Exp Moving Averages [{}, {}, {}]'.format(
                config[0], config[1], config[2])
        # legend = ['Price', f'{config[0]}-EMA',
        #           f'{config[1]}-EMA', f'{config[2]}-EMA']

        # plots = [fund['Close'], tshort2, tmed2, tlong2]
        # x_vals = [fund.index, tshort_x, tmed_x, tlong_x]

        if plot_output:
            candlestick_plot(fund,
                             title=name2,
                             additional_plts=[plot_short, plot_med, plot_long])
            # generic_plotting(plots, x=x_vals,
            #                  legend=legend, title=name2)

        else:
            filename = os.path.join(name, view,
                                    f"exp_moving_averages_{name}.png")
            candlestick_plot(fund,
                             title=name2,
                             filename=filename,
                             saveFig=True,
                             additional_plts=[plot_short, plot_med, plot_long])
            # generic_plotting(plots, x=x_vals,
            #                  legend=legend, title=name2, saveFig=True, filename=filename)

    if p_bar is not None:
        p_bar.uptick(increment=0.2)

    tema['type'] = 'trend'
    tema['length_of_data'] = len(tema['tabular']['short'])
    tema['signals'] = find_crossovers(tema, fund)

    return tema
def triple_moving_average(fund: pd.DataFrame, **kwargs) -> dict:
    """Triple Moving Average

    3 simple moving averages of "config" length

    Arguments:
        fund {pd.DataFrame} -- fund historical data

    Optional Args:
        name {list} -- name of fund, primarily for plotting (default: {''})
        plot_output {bool} -- True to render plot in realtime (default: {True})
        config {list of ints} -- list of moving average time periods (default: {[12, 50, 200]})
        progress_bar {ProgressBar} -- (default: {None})
        view {str} -- directory of plots (default: {''})

    Returns:
        tma {dict} -- contains all ma information in "short", "medium", and "long" keys
    """
    name = kwargs.get('name', '')
    config = kwargs.get('config', [12, 50, 200])
    plot_output = kwargs.get('plot_output', True)
    out_suppress = kwargs.get('out_suppress', False)
    progress_bar = kwargs.get('progress_bar', None)
    view = kwargs.get('view', '')

    tshort = simple_moving_avg(fund, config[0])
    if progress_bar is not None:
        progress_bar.uptick(increment=0.2)

    tmed = simple_moving_avg(fund, config[1])
    if progress_bar is not None:
        progress_bar.uptick(increment=0.2)

    tlong = simple_moving_avg(fund, config[2])
    if progress_bar is not None:
        progress_bar.uptick(increment=0.2)

    mshort = []
    mmed = []
    mlong = []
    for i, close in enumerate(fund['Close']):
        mshort.append(np.round((close - tshort[i]) / tshort[i] * 100.0, 3))
        mmed.append(np.round((close - tmed[i]) / tmed[i] * 100.0, 3))
        mlong.append(np.round((close - tlong[i]) / tlong[i] * 100.0, 3))

    triple_exp_mov_average(fund,
                           config=[9, 21, 50],
                           plot_output=plot_output,
                           name=name,
                           view=view)

    tshort_x, tshort2 = adjust_signals(fund, tshort, offset=config[0])
    tmed_x, tmed2 = adjust_signals(fund, tmed, offset=config[1])
    tlong_x, tlong2 = adjust_signals(fund, tlong, offset=config[2])

    plot_short = {
        "plot": tshort2,
        "color": "blue",
        "legend": f"{config[0]}-day MA",
        "x": tshort_x
    }
    plot_med = {
        "plot": tmed2,
        "color": "orange",
        "legend": f"{config[1]}-day MA",
        "x": tmed_x
    }
    plot_long = {
        "plot": tlong2,
        "color": "black",
        "legend": f"{config[2]}-day MA",
        "x": tlong_x
    }

    if not out_suppress:
        name3 = INDEXES.get(name, name)
        name2 = name3 + \
            ' - Simple Moving Averages [{}, {}, {}]'.format(
                config[0], config[1], config[2])
        # legend = ['Price', f'{config[0]}-SMA',
        #           f'{config[1]}-SMA', f'{config[2]}-SMA']

        # plots = [fund['Close'], tshort2, tmed2, tlong2]
        # x_vals = [fund.index, tshort_x, tmed_x, tlong_x]

        if plot_output:
            candlestick_plot(fund,
                             title=name2,
                             additional_plts=[plot_short, plot_med, plot_long])
            # generic_plotting(plots, x=x_vals,
            #                  legend=legend, title=name2)

        else:
            filename = os.path.join(name, view,
                                    f"simple_moving_averages_{name}.png")
            candlestick_plot(fund,
                             title=name2,
                             filename=filename,
                             saveFig=True,
                             additional_plts=[plot_short, plot_med, plot_long])
            # generic_plotting(plots, x=x_vals,
            #                  legend=legend, title=name2, saveFig=True, filename=filename)

    tma = dict()
    tma['short'] = {'period': config[0]}
    tma['medium'] = {'period': config[1]}
    tma['long'] = {'period': config[2]}
    tma['tabular'] = {'short': tshort, 'medium': tmed, 'long': tlong}
    tma['metrics'] = {
        f'{config[0]}-d': mshort,
        f'{config[1]}-d': mmed,
        f'{config[2]}-d': mlong
    }

    if progress_bar is not None:
        progress_bar.uptick(increment=0.1)

    tma['type'] = 'trend'
    tma['length_of_data'] = len(tma['tabular']['short'])
    tma['signals'] = find_crossovers(tma, fund)

    return tma
def assemble_last_signals(meta_sub: dict,
                          fund: pd.DataFrame = None,
                          lookback: int = 10,
                          **kwargs) -> dict:
    """assemble_last signals

    Look through all indicators of lookback time and list them

    Arguments:
        meta_sub {dict} -- metadata subset "metadata[fund][view]"

    Keyword Arguments:
        lookback {int} -- number of trading periods into past to find signals (default: {5})
        fund {pd.DataFrame} -- fund dataset

    Optional Args:
        standalone {bool} -- if run as a function, fetch all metadata info (default: {False})
        print_out {bool} -- print in terminal (default: {False})
        name {str} -- (default: {''})
        pbar {ProgressBar} -- (default: {None})

    Returns:
        dict -- last signals data object
    """
    standalone = kwargs.get('standalone', False)
    print_out = kwargs.get('print_out', False)
    name = kwargs.get('name', '')
    pbar = kwargs.get('progress_bar')
    plot_output = kwargs.get('plot_output', True)

    metadata = []
    meta_keys = []
    name2 = INDEXES.get(name, name)

    if fund is not None:
        fund = fund['Close']

    if standalone:
        for key in meta_sub:
            if key not in EXEMPT_METRICS:
                metadata.append(meta_sub[key])
                meta_keys.append(key)
    else:
        metadata = [meta_sub]
        meta_keys.append('')

    increment = 1.0 / float(len(metadata))

    content = {"signals": [], "metrics": []}
    for a, sub in enumerate(metadata):
        content['signals'] = []

        for key in sub:
            if key in INDICATOR_NAMES:

                if SIGNAL_KEY in sub[key] and SIZE_KEY in sub[key]:
                    start_period = sub[key][SIZE_KEY] - lookback - 1

                    for signal in sub[key][SIGNAL_KEY]:
                        if signal['index'] >= start_period:
                            data = {
                                "type":
                                signal['type'],
                                "indicator":
                                key,
                                "value":
                                signal['value'],
                                "date":
                                signal['date'],
                                "days_ago":
                                (sub[key][SIZE_KEY] - 1 - signal['index'])
                            }
                            content["signals"].append(data)

                if METRICS_KEY in sub[key] and TYPE_KEY in sub[key]:
                    if sub[key][TYPE_KEY] == 'oscillator':
                        if len(content["metrics"]) == 0:
                            content["metrics"] = sub[key][METRICS_KEY]
                        else:
                            for i, met in enumerate(sub[key][METRICS_KEY]):
                                content["metrics"][i] += met

                    else:
                        for trend in sub[key][METRICS_KEY]:
                            if trend != 'metrics':

                                if len(content["metrics"]) == 0:
                                    content["metrics"] = [
                                        x / 10.0
                                        for x in sub[key][METRICS_KEY][trend]
                                    ]

                                else:
                                    for i, met in enumerate(
                                            sub[key][METRICS_KEY][trend]):
                                        content["metrics"][i] += met / 10.0

        content["signals"].sort(key=lambda x: x['days_ago'])

        if pbar is not None:
            pbar.uptick(increment=increment)

        if fund is None:
            fund = sub.get(STATS_KEY, {}).get('tabular')

        if print_out:
            content_printer(content, meta_keys[a], name=name2)

        if fund is not None:
            title = f"NATA Metrics - {name2}"
            upper = 0.3 * max(content["metrics"])
            upper = [upper] * len(content["metrics"])
            lower = 0.3 * min(content["metrics"])
            lower = [lower] * len(content["metrics"])

            if plot_output:
                dual_plotting(fund, [content["metrics"], upper, lower],
                              'Price',
                              'Metrics',
                              title=title)
            else:
                filename = os.path.join(name, meta_keys[a],
                                        f"overall_metrics_{name}.png")
                dual_plotting(fund, [content["metrics"], upper, lower],
                              'Price',
                              'Metrics',
                              title=title,
                              saveFig=True,
                              filename=filename)

    return content
示例#16
0
def run_dev(script: list):
    """Run Development Script

    Script that is for implementing new content

    Arguments:
        script {list} -- dataset, funds, periods, config

    Returns:
        dict -- analysis object of fund data
    """
    dataset = script[0]
    funds = script[1]
    periods = script[2]
    config = script[3]

    # Start of automated process
    analysis = {}
    clock = start_clock()

    for fund_name in funds:

        if fund_name in SKIP_INDEXES:
            continue

        fund_print = INDEXES.get(fund_name, fund_name)
        print("")
        print(f"~~{fund_print}~~")
        create_sub_temp_dir(fund_name, sub_periods=config['period'])

        analysis[fund_name] = {}

        analysis[fund_name]['metadata'] = get_api_metadata(
            fund_name,
            max_close=max(dataset[periods[0]][fund_name]['Close']),
            data=dataset[periods[0]][fund_name])

        ###################### START OF PERIOD LOOPING #############################
        for i, period in enumerate(periods):
            fund_data = {}

            fund = dataset[period][fund_name]

            start = date_extractor(fund.index[0], _format='str')
            end = date_extractor(fund.index[-1], _format='str')
            fund_data['dates_covered'] = {'start': str(start), 'end': str(end)}
            fund_data['name'] = fund_name

            fund_print2 = fund_print + f" ({period}) "
            p = ProgressBar(config['process_steps'],
                            name=fund_print2,
                            offset=clock)
            p.start()

            fund_data['statistics'] = get_high_level_stats(fund)

            fund_data['clustered_osc'] = cluster_oscs(fund,
                                                      function='all',
                                                      filter_thresh=3,
                                                      name=fund_name,
                                                      plot_output=False,
                                                      progress_bar=p,
                                                      view=period)

            fund_data['full_stochastic'] = full_stochastic(fund,
                                                           name=fund_name,
                                                           plot_output=False,
                                                           out_suppress=False,
                                                           progress_bar=p,
                                                           view=period)

            fund_data['rsi'] = RSI(fund,
                                   name=fund_name,
                                   plot_output=False,
                                   out_suppress=False,
                                   progress_bar=p,
                                   view=period)

            fund_data['ultimate'] = ultimate_oscillator(fund,
                                                        name=fund_name,
                                                        plot_output=False,
                                                        out_suppress=False,
                                                        progress_bar=p,
                                                        view=period)

            fund_data['awesome'] = awesome_oscillator(fund,
                                                      name=fund_name,
                                                      plot_output=False,
                                                      progress_bar=p,
                                                      view=period)

            fund_data['momentum_oscillator'] = momentum_oscillator(
                fund,
                name=fund_name,
                plot_output=False,
                progress_bar=p,
                view=period)

            fund_data['on_balance_volume'] = on_balance_volume(
                fund,
                plot_output=False,
                name=fund_name,
                progress_bar=p,
                view=period)

            fund_data['simple_moving_average'] = triple_moving_average(
                fund,
                plot_output=False,
                name=fund_name,
                progress_bar=p,
                view=period)

            fund_data['exp_moving_average'] = triple_exp_mov_average(
                fund,
                plot_output=False,
                name=fund_name,
                progress_bar=p,
                view=period)

            fund_data['sma_swing_trade'] = moving_average_swing_trade(
                fund,
                plot_output=False,
                name=fund_name,
                progress_bar=p,
                view=period)

            fund_data['ema_swing_trade'] = moving_average_swing_trade(
                fund,
                function='ema',
                plot_output=False,
                name=fund_name,
                progress_bar=p,
                view=period)

            fund_data['hull_moving_average'] = hull_moving_average(
                fund,
                plot_output=False,
                name=fund_name,
                progress_bar=p,
                view=period)

            fund_data['macd'] = mov_avg_convergence_divergence(
                fund,
                plot_output=False,
                name=fund_name,
                progress_bar=p,
                view=period)

            fund_data['bear_bull_power'] = bear_bull_power(fund,
                                                           plot_output=False,
                                                           name=fund_name,
                                                           progress_bar=p,
                                                           view=period)

            fund_data['total_power'] = total_power(fund,
                                                   plot_output=False,
                                                   name=fund_name,
                                                   progress_bar=p,
                                                   view=period)

            fund_data['bollinger_bands'] = bollinger_bands(fund,
                                                           plot_output=False,
                                                           name=fund_name,
                                                           progress_bar=p,
                                                           view=period)

            fund_data['commodity_channels'] = commodity_channel_index(
                fund,
                plot_output=False,
                name=fund_name,
                progress_bar=p,
                view=period)

            fund_data['rate_of_change'] = rate_of_change_oscillator(
                fund,
                plot_output=False,
                name=fund_name,
                progress_bar=p,
                view=period)

            fund_data['know_sure_thing'] = know_sure_thing(fund,
                                                           plot_output=False,
                                                           name=fund_name,
                                                           progress_bar=p,
                                                           view=period)

            fund_data['average_true_range'] = average_true_range(
                fund,
                plot_output=False,
                name=fund_name,
                progress_bar=p,
                view=period)

            fund_data['adx'] = average_directional_index(
                fund,
                atr=fund_data['average_true_range']['tabular'],
                plot_output=False,
                name=fund_name,
                progress_bar=p,
                view=period)

            fund_data['parabolic_sar'] = parabolic_sar(
                fund,
                adx_tabular=fund_data['adx']['tabular'],
                plot_output=False,
                name=fund_name,
                progress_bar=p,
                view=period)

            fund_data['demand_index'] = demand_index(fund,
                                                     plot_output=False,
                                                     name=fund_name,
                                                     progress_bar=p,
                                                     view=period)

            if 'no_index' not in config['state']:
                strength, match_data = relative_strength(
                    fund_name,
                    full_data_dict=dataset[period],
                    config=config,
                    plot_output=False,
                    meta=analysis[fund_name]['metadata'],
                    progress_bar=p,
                    period=period,
                    interval=config['interval'][i],
                    view=period)
                fund_data['relative_strength'] = strength

                fund_data['statistics']['risk_ratios'] = risk_comparison(
                    fund,
                    dataset[period]['^GSPC'],
                    dataset[period]['^IRX'],
                    sector_data=match_data)
                p.uptick()

            # Support and Resistance Analysis
            fund_data['support_resistance'] = find_resistance_support_lines(
                fund,
                name=fund_name,
                plot_output=False,
                progress_bar=p,
                view=period)

            # Feature Detection Block
            fund_data['features'] = {}
            fund_data['features'][
                'head_shoulders'] = feature_detection_head_and_shoulders(
                    fund,
                    name=fund_name,
                    plot_output=False,
                    progress_bar=p,
                    view=period)

            fund_data['candlesticks'] = candlesticks(fund,
                                                     name=fund_name,
                                                     plot_output=False,
                                                     view=period,
                                                     progress_bar=p)

            fund_data['price_gaps'] = analyze_price_gaps(fund,
                                                         name=fund_name,
                                                         plot_output=False,
                                                         progress_bar=p,
                                                         view=period)

            # Get Trendlines
            fund_data['trendlines'] = get_trendlines(
                fund,
                name=fund_name,
                plot_output=False,
                progress_bar=p,
                view=period,
                meta=analysis[fund_name]['metadata'])

            # Various Fund-specific Metrics
            fund_data['futures'] = future_returns(fund, progress_bar=p)

            # Parse through indicators and pull out latest signals (must be last)
            fund_data['last_signals'] = assemble_last_signals(
                fund_data,
                fund=fund,
                name=fund_name,
                view=period,
                progress_bar=p,
                plot_output=False)

            p.end()

            analysis[fund_name][period] = fund_data

        analysis[fund_name]['synopsis'] = generate_synopsis(analysis,
                                                            name=fund_name)

    return analysis, clock
示例#17
0
def get_bollinger_signals(position: pd.DataFrame, period: int, stdev: float,
                          **kwargs) -> dict:
    """Get Bollinger Band Signals

    Arguments:
        position {pd.DataFrame} -- dataset
        period {int} -- time frame for moving average
        stdev {float} -- multiplier for band range

    Optional Args:
        plot_output {bool} -- (default: {True})
        filter_type {str} -- type of moving average (default: {'simple'})
        name {str} -- (default: {''})
        view {str} -- (default: {None})

    Returns:
        dict -- bollinger band data object
    """
    filter_type = kwargs.get('filter_type', 'simple')
    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    view = kwargs.get('view')

    typical_price = []
    for i, close in enumerate(position['Close']):
        typical_price.append(
            (close + position['Low'][i] + position['High'][i]) / 3.0)

    if filter_type == 'exponential':
        ma = exponential_moving_avg(typical_price, period, data_type='list')
    else:
        ma = simple_moving_avg(typical_price, period, data_type='list')

    upper = ma.copy()
    lower = ma.copy()
    std_list = [0.0] * len(ma)
    for i in range(period, len(ma)):
        std = np.std(typical_price[i - (period):i])
        std_list[i] = std
        upper[i] = ma[i] + (stdev * std)
        lower[i] = ma[i] - (stdev * std)

    signals = {'upper_band': upper, 'lower_band': lower, 'middle_band': ma}

    name3 = INDEXES.get(name, name)
    name2 = name3 + ' - Bollinger Bands'
    if plot_output:
        generic_plotting(
            [position['Close'], ma, upper, lower],
            title=name2,
            x=position.index,
            legend=['Price', 'Moving Avg', 'Upper Band', 'Lower Band'])

    else:
        filename = os.path.join(name, view, f"bollinger_bands_{name}.png")
        generic_plotting(
            [position['Close'], ma, upper, lower],
            title=name2,
            x=position.index,
            legend=['Price', 'Moving Avg', 'Upper Band', 'Lower Band'],
            saveFig=True,
            filename=filename)

    return signals
示例#18
0
def relative_strength(primary_name: str, full_data_dict: dict,
                      **kwargs) -> list:
    """Relative Strength

    Compare a fund vs. market, sector, and/or other fund

    Arguments:
        primary_name {str} -- primary fund to compare against
        full_data_dict {dict} -- all retrieved funds by fund name

    Optional Args:
        secondary_fund_names {list} -- fund names to compare against (default: {[]})
        meta {dict} -- "metadata" from api calls (default: {None})
        config {dict} -- control config dictionary of software package (default: {None})
        sector {str} -- sector fund (if in full_data_dict) for comparison (default: {''})
        plot_output {bool} -- True to render plot in realtime (default: {True})
        progress_bar {ProgressBar} -- (default: {None})
        view {str} -- Directory of plots (default: {''})

    Returns:
        list -- dict containing all relative strength information, sector match data
    """
    secondary_fund_names = kwargs.get('secondary_fund_names', [])
    config = kwargs.get('config', None)
    sector = kwargs.get('sector', '')
    plot_output = kwargs.get('plot_output', True)
    progress_bar = kwargs.get('progress_bar', None)
    meta = kwargs.get('meta', None)
    sector_data = kwargs.get('sector_data', {})
    view = kwargs.get('view', '')

    period = kwargs.get('period', '2y')
    interval = kwargs.get('interval', '1d')

    sector_bench = None
    comp_funds = []
    comp_data = {}
    if meta is not None:
        match = meta.get('info', {}).get('sector')

        if match is not None:
            fund_len = {
                'length':
                len(full_data_dict[primary_name]['Close']),
                'start':
                full_data_dict[primary_name].index[0],
                'end':
                full_data_dict[primary_name].index[
                    len(full_data_dict[primary_name]['Close']) - 1],
                'dates':
                full_data_dict[primary_name].index
            }

            match_fund, match_data = api_sector_match(match,
                                                      config,
                                                      fund_len=fund_len,
                                                      period=period,
                                                      interval=interval)

            if match_fund is not None:
                comp_funds, comp_data = api_sector_funds(match_fund,
                                                         config,
                                                         fund_len=fund_len,
                                                         period=period,
                                                         interval=interval)

                if match_data is None:
                    match_data = full_data_dict
                sector = match_fund
                sector_data = match_data
                sector_bench = match_data[match_fund]

    if progress_bar is not None:
        progress_bar.uptick(increment=0.3)

    r_strength = dict()

    rat_sp = []
    rat_sector = []
    rat_secondaries = []
    secondary_names = []
    secondary_fund_names.extend(comp_funds)

    for key in comp_data:
        if sector_data.get(key) is None:
            sector_data[key] = comp_data[key]

    sp = get_SP500_df(full_data_dict)
    if sp is not None:
        rat_sp = normalized_ratio(full_data_dict[primary_name], sp)
    if progress_bar is not None:
        progress_bar.uptick(increment=0.1)

    if len(sector_data) > 0:
        rat_sector = normalized_ratio(full_data_dict[primary_name],
                                      sector_data[sector])
    if progress_bar is not None:
        progress_bar.uptick(increment=0.1)

    if len(secondary_fund_names) > 0:
        for sfund in secondary_fund_names:
            if full_data_dict.get(sfund) is not None:
                rat_secondaries.append(
                    normalized_ratio(full_data_dict[primary_name],
                                     full_data_dict[sfund]))
                secondary_names.append(sfund)

            elif sector_data.get(sfund) is not None:
                rat_secondaries.append(
                    normalized_ratio(full_data_dict[primary_name],
                                     sector_data[sfund]))
                secondary_names.append(sfund)

    if progress_bar is not None:
        progress_bar.uptick(increment=0.2)

    st = period_strength(primary_name,
                         full_data_dict,
                         config=config,
                         periods=[20, 50, 100],
                         sector=sector,
                         sector_data=sector_data.get(sector, None))

    r_strength['market'] = {'tabular': rat_sp, 'comparison': 'S&P500'}
    r_strength['sector'] = {'tabular': rat_sector, 'comparison': sector}
    r_strength['period'] = st
    r_strength['secondary'] = [{
        'tabular': second,
        'comparison': secondary_names[i]
    } for i, second in enumerate(rat_secondaries)]

    dates = dates_extractor_list(full_data_dict[list(
        full_data_dict.keys())[0]])
    if len(rat_sp) < len(dates):
        dates = dates[0:len(rat_sp)]

    output_data = []
    legend = []
    if len(rat_sp) > 0:
        output_data.append(rat_sp)
        legend.append("vs. S&P 500")

    if len(rat_sector) > 0:
        output_data.append(rat_sector)
        legend.append(f"vs. Sector ({sector})")

    if len(rat_secondaries) > 0:
        for i, rat in enumerate(rat_secondaries):
            output_data.append(rat)
            legend.append(f"vs. {secondary_names[i]}")

    r_strength['tabular'] = {}
    for i, out_data in enumerate(output_data):
        r_strength['tabular'][str(legend[i])] = out_data

    primary_name2 = INDEXES.get(primary_name, primary_name)
    title = f"Relative Strength of {primary_name2}"

    if progress_bar is not None:
        progress_bar.uptick(increment=0.1)

    if plot_output:
        generic_plotting(output_data,
                         x=dates,
                         title=title,
                         legend=legend,
                         ylabel='Difference Ratio')

    else:
        filename = os.path.join(primary_name, view,
                                f"relative_strength_{primary_name}.png")
        generic_plotting(output_data,
                         x=dates,
                         title=title,
                         saveFig=True,
                         filename=filename,
                         legend=legend,
                         ylabel='Difference Ratio')

    if progress_bar is not None:
        progress_bar.uptick(increment=0.2)

    return r_strength, sector_bench
def rate_of_change_oscillator(fund: pd.DataFrame,
                              periods: list = [10, 20, 40],
                              **kwargs) -> dict:
    """Rate of Change Oscillator

    Arguments:
        fund {pd.DataFrame} -- fund dataset

    Keyword Arguments:
        periods {list} -- lookback periods for ROC (default: {[10, 20, 40]})

    Optional Args:
        plot_output {bool} -- (default: {True})
        name {str} -- (default: {''})
        views {str} -- (default: {''})
        progress_bar {ProgressBar} -- (default: {None})

    Returns:
        dict -- roc data object
    """
    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    views = kwargs.get('views', '')
    p_bar = kwargs.get('progress_bar')

    roc = dict()

    tshort = roc_signal(fund, periods[0])
    if p_bar is not None:
        p_bar.uptick(increment=0.1)

    tmed = roc_signal(fund, periods[1])
    if p_bar is not None:
        p_bar.uptick(increment=0.1)

    tlong = roc_signal(fund, periods[2])
    if p_bar is not None:
        p_bar.uptick(increment=0.1)

    roc['tabular'] = {'short': tshort, 'medium': tmed, 'long': tlong}
    roc['short'] = periods[0]
    roc['medium'] = periods[1]
    roc['long'] = periods[2]

    tsx, ts2 = adjust_signals(fund, tshort, offset=periods[0])
    tmx, tm2 = adjust_signals(fund, tmed, offset=periods[1])
    tlx, tl2 = adjust_signals(fund, tlong, offset=periods[2])
    if p_bar is not None:
        p_bar.uptick(increment=0.2)

    name2 = INDEXES.get(name, name)
    title = f"{name2} - Rate of Change Oscillator"
    plots = [ts2, tm2, tl2]
    xs = [tsx, tmx, tlx]

    if plot_output:
        dual_plotting(fund['Close'], [tshort, tmed, tlong],
                      'Price',
                      'Rate of Change',
                      title=title,
                      legend=[
                          f'ROC-{periods[0]}', f'ROC-{periods[1]}',
                          f'ROC-{periods[2]}'
                      ])
        generic_plotting(plots,
                         x=xs,
                         title=title,
                         legend=[
                             f'ROC-{periods[0]}', f'ROC-{periods[1]}',
                             f'ROC-{periods[2]}'
                         ])

    else:
        filename = os.path.join(name, views, f"rate_of_change_{name}")
        dual_plotting(fund['Close'], [tshort, tmed, tlong],
                      'Price',
                      'Rate of Change',
                      title=title,
                      legend=[
                          f'ROC-{periods[0]}', f'ROC-{periods[1]}',
                          f'ROC-{periods[2]}'
                      ],
                      saveFig=True,
                      filename=filename)

    if p_bar is not None:
        p_bar.uptick(increment=0.1)

    roc = roc_metrics(fund,
                      roc,
                      plot_output=plot_output,
                      name=name,
                      views=views,
                      p_bar=p_bar)

    roc['length_of_data'] = len(roc['tabular']['short'])
    roc['type'] = 'oscillator'

    if p_bar is not None:
        p_bar.uptick(increment=0.1)

    return roc
def moving_average_swing_trade(fund: pd.DataFrame, **kwargs):
    """Triple Moving Average

    3 simple moving averages of "config" length

    Arguments:
        fund {pd.DataFrame} -- fund historical data

    Optional Args:
        function {str} -- type of filtering scheme (default: {'sma'})
        name {str} -- name of fund, primarily for plotting (default: {''})
        plot_output {bool} -- True to render plot in realtime (default: {True})
        config {list} -- list of moving average time periods (default: {[4, 9, 18]})
        progress_bar {ProgressBar} -- (default: {None})
        view {str} -- directory for plot (default: {''})

    Returns:
        mast {dict} -- contains all ma information in "short", "medium", "long", and "swing" keys
    """
    function = kwargs.get('function', 'sma')
    name = kwargs.get('name', '')
    plot_output = kwargs.get('plot_output', True)
    config = kwargs.get('config', [4, 9, 18])
    progress_bar = kwargs.get('progress_bar', None)
    view = kwargs.get('view', '')

    if plot_output:
        out_suppress = False
    else:
        out_suppress = True

    if function == 'sma':
        if config == []:
            tma = triple_moving_average(fund,
                                        plot_output=plot_output,
                                        name=name,
                                        out_suppress=out_suppress,
                                        view=view)
        else:
            tma = triple_moving_average(fund,
                                        config=config,
                                        plot_output=plot_output,
                                        name=name,
                                        out_suppress=out_suppress,
                                        view=view)
        sh = tma['tabular']['short']
        me = tma['tabular']['medium']
        ln = tma['tabular']['long']

    elif function == 'ema':
        if config == []:
            tma = triple_exp_mov_average(fund,
                                         plot_output=plot_output,
                                         name=name,
                                         out_suppress=out_suppress,
                                         view=view)
        else:
            tma = triple_exp_mov_average(fund,
                                         config=config,
                                         plot_output=plot_output,
                                         name=name,
                                         out_suppress=out_suppress,
                                         view=view)
        sh = tma['tabular']['short']
        me = tma['tabular']['medium']
        ln = tma['tabular']['long']

    else:
        return {}

    if progress_bar is not None:
        progress_bar.uptick(increment=0.4)

    mast = dict()
    mast['tabular'] = {}
    mast['tabular']['short'] = sh
    mast['tabular']['medium'] = me
    mast['tabular']['long'] = ln

    mast = generate_swing_signal(fund,
                                 mast,
                                 max_period=config[2],
                                 config=config)
    mast = swing_trade_metrics(fund, mast)

    swings = mast['metrics']

    if progress_bar is not None:
        progress_bar.uptick(increment=0.4)

    name3 = INDEXES.get(name, name)
    funct_name = function.upper()
    name2 = name3 + f' - Swing Trade {funct_name}s'
    legend = ['Price', 'Short-SMA', 'Medium-SMA', 'Long-SMA', 'Swing Signal']

    if plot_output:
        specialty_plotting([fund['Close'], sh, me, ln, swings],
                           alt_ax_index=[4],
                           legend=legend,
                           title=name2)
    else:
        filename = os.path.join(name, view,
                                f"swing_trades_{function}_{name}.png")
        specialty_plotting([fund['Close'], sh, me, ln, swings],
                           alt_ax_index=[4],
                           legend=['Swing Signal'],
                           title=name2,
                           saveFig=True,
                           filename=filename)

    if progress_bar is not None:
        progress_bar.uptick(increment=0.2)

    mast['type'] = 'oscillator'

    return mast
示例#21
0
def demand_index_metrics(fund: pd.DataFrame, dmx: dict, **kwargs) -> list:
    """Demand Index Metrics

    Arguments:
        fund {pd.DataFrame} -- fund dataset
        dmx {dict} -- demand index data object

    Optional Args:
        plot_output {bool} -- (default: {True})
        name {str} -- (default: {''})
        view {str} -- (default: {''})
        progress_bar {ProgressBar} -- (default: {None})

    Returns:
        list -- demand index data object
    """
    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    view = kwargs.get('view', '')
    pbar = kwargs.get('pbar')

    metrics = [0.0] * len(dmx['tabular'])

    weight_map = {
        "zero crossover": [1.2, 0.95, 0.6, 0.1],
        "dual-signal-line": [1.0, 0.85, 0.55, 0.1],
        "signal-line zone": [0.8, 0.65, 0.4, 0.1]
    }

    for sig in dmx['signals']:
        ind = sig['index']
        s = 1.0
        if sig['type'] == 'bearish':
            s = -1.0

        if 'dual-signal-line' in sig['value']:
            weights = weight_map['dual-signal-line']
        elif 'signal-line zone' in sig['value']:
            weights = weight_map['signal-line zone']
        else:
            weights = weight_map['zero crossover']
        
        metrics[ind] = s

        # Smooth the curves
        if ind - 1 >= 0:
            metrics[ind-1] += s * weights[1]
        if ind + 1 < len(metrics):
            metrics[ind+1] += s * weights[1]
        if ind - 2 >= 0:
            metrics[ind-2] += s * weights[2]
        if ind + 2 < len(metrics):
            metrics[ind+2] += s * weights[2]
        if ind - 3 >= 0:
            metrics[ind-3] += s * weights[3]
        if ind + 3 < len(metrics):
            metrics[ind+3] += s * weights[3]

    if pbar is not None:
        pbar.uptick(increment=0.1)

    metrics = exponential_moving_avg(metrics, 7, data_type='list')
    norm = normalize_signals([metrics])
    metrics = norm[0]

    if pbar is not None:
        pbar.uptick(increment=0.1)

    name2 = INDEXES.get(name, name)
    title = f"{name2} - Demand Index"
    if plot_output:
        dual_plotting(fund['Close'], metrics, 'Price', 'Demand Index Metrics')
    else:
        filename = os.path.join(name, view, f"di_metrics_{name}")
        dual_plotting(fund['Close'], metrics, 'Price', 'Demand Index Metrics',
                      title=title, saveFig=True, filename=filename)

    return metrics
示例#22
0
def generate_di_signal(fund: pd.DataFrame, **kwargs) -> list:
    """Generate Demand Index Signal

    Arguments:
        fund {pd.DataFrame} -- fund dataset

    Optional Args:
        plot_output {bool} -- (default: {True})
        name {str} -- (default: {''})
        view {str} -- (default: {''})
        progress_bar {ProgressBar} -- (default: {None})

    Returns:
        list -- demand index signal
    """
    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    view = kwargs.get('view', '')
    pbar = kwargs.get('pbar')

    signal = []

    # First, generate the "2d H-L volatility" signal.
    vol_hl = [0.0] * len(fund['Close'])
    for i in range(1, len(vol_hl)):
        high = max([fund['High'][i], fund['High'][i-1]])
        low = min([fund['Low'][i], fund['Low'][i-1]])
        vol_hl[i] = high - low

    if pbar is not None:
        pbar.uptick(increment=0.05)

    vol_av = simple_moving_avg(vol_hl, 10, data_type='list')
    if pbar is not None:
        pbar.uptick(increment=0.05)

    # Calculate the constant 'K'.
    const_K = [0.0] * len(vol_av)
    for i, vol in enumerate(vol_av):
        if vol == 0.0:
            const_K[i] = 0.0
        else:
            const_K[i] = 3.0 * fund['Close'][i] / vol

    if pbar is not None:
        pbar.uptick(increment=0.05)

    # Calculate daily percent change of open-close.
    percent = [0.0] * len(vol_av)
    for i, ope in enumerate(fund['Open']):
        percent[i] = (fund['Close'][i] - ope) / ope * const_K[i]

    if pbar is not None:
        pbar.uptick(increment=0.05)

    # Calculate BP and SP, so we can get DI = BP/SP | SP/BP
    B_P = []
    S_P = []
    for i, vol in enumerate(fund['Volume']):
        if percent[i] == 0.0:
            B_P.append(0.0)
            S_P.append(0.0)
        elif percent[i] > 0.0:
            B_P.append(vol)
            S_P.append(vol / percent[i])
        else:
            B_P.append(vol / percent[i])
            S_P.append(vol)

    if pbar is not None:
        pbar.uptick(increment=0.05)

    for i, bpx in enumerate(B_P):
        if abs(bpx) > abs(S_P[i]):
            signal.append(S_P[i] / bpx)
        else:
            if abs(bpx) == 0.0 and abs(S_P[i]) == 0.0:
                signal.append(0.0)
            else:
                signal.append(bpx / S_P[i])

    if pbar is not None:
        pbar.uptick(increment=0.1)

    signal = exponential_moving_avg(signal, 10, data_type='list')
    if pbar is not None:
        pbar.uptick(increment=0.05)

    name2 = INDEXES.get(name, name)
    title = f"{name2} - Demand Index"
    if plot_output:
        dual_plotting(fund['Close'], signal, 'Price',
                      'Demand Index', title=title)
    else:
        filename = os.path.join(name, view, f"demand_index_{name}")
        dual_plotting(fund['Close'], signal, 'Price', 'Demand Index',
                      title=title, saveFig=True, filename=filename)

    if pbar is not None:
        pbar.uptick(increment=0.1)

    return signal
def find_resistance_support_lines(data: pd.DataFrame, **kwargs) -> dict:
    """Find Resistance / Support Lines

    Arguments:
        data {pd.DataFrame} -- fund historical data

    Optional Args:
        name {str} -- name of fund, primarily for plotting (default: {''})
        plot_output {bool} -- True to render plot in realtime (default: {True})
        timeframes {list} -- time windows for feature discovery (default: {[13, 21, 34, 55]})
        progress_bar {ProgressBar} -- (default: {None})
        view {str} -- directory of plots (default: {''})

    Returns:
        dict -- contains all trendline information
    """
    name = kwargs.get('name', '')
    plot_output = kwargs.get('plot_output', True)
    timeframes = kwargs.get('timeframes', [13, 21, 34, 55])
    progress_bar = kwargs.get('progress_bar', None)
    view = kwargs.get('view', '')

    resist_support_lines = {}
    resist_support_lines['support'] = {}
    resist_support_lines['resistance'] = {}

    increment = 0.5 / (float(len(timeframes)))

    support = {}
    resistance = {}
    for time in timeframes:
        support[str(time)] = {}
        x, y = find_points(data, line_type='support',
                           timeframe=time, filter_type='windowed')
        support[str(time)]['x'] = x
        support[str(time)]['y'] = y
        sorted_support = sort_and_group(support)
        resist_support_lines['support'][str(
            time)] = cluster_notables(sorted_support, data)

        resistance[str(time)] = {}
        x2, y2 = find_points(data, line_type='resistance', timeframe=time)
        resistance[str(time)]['x'] = x2
        resistance[str(time)]['y'] = y2
        sorted_resistance = sort_and_group(resistance)
        resist_support_lines['resistance'][str(
            time)] = cluster_notables(sorted_resistance, data)

        if progress_bar is not None:
            progress_bar.uptick(increment=increment)

    Xs, Ys, Xr, Yr = get_plot_content(
        data, resist_support_lines, selected_timeframe=str(timeframes[len(timeframes)-1]))

    if progress_bar is not None:
        progress_bar.uptick(increment=0.2)

    Xc, Yc = res_sup_unions(Yr, Xr, Ys, Xs)
    # Odd list behavior when no res/sup lines drawn on appends, so if-else to fix
    if len(Yc) > 0:
        Xp = Xc.copy()
        Xp2 = dates_convert_from_index(data, Xp)
        Yp = Yc.copy()
        Xp2.append(data.index)
        Yp.append(remove_dates_from_close(data))
    else:
        Xp2 = data.index
        Yp = [remove_dates_from_close(data)]
    c = colorize_plots(len(Yp), primary_plot_index=len(Yp)-1)

    if progress_bar is not None:
        progress_bar.uptick(increment=0.1)

    name2 = INDEXES.get(name, name)
    if plot_output:
        generic_plotting(Yp, x=Xp2, colors=c,
                         title=f'{name2} Major Resistance & Support')
    else:
        filename = f"{name}/{view}/resist_support_{name}.png"
        generic_plotting(
            Yp, x=Xp2, colors=c, title=f'{name2} Major Resistance & Support', saveFig=True, filename=filename)

    if progress_bar is not None:
        progress_bar.uptick(increment=0.1)

    analysis = detailed_analysis([Yr, Ys, Yc], data, key_args={'Colors': c})
    if progress_bar is not None:
        progress_bar.uptick(increment=0.1)

    analysis['type'] = 'trend'

    return analysis
def cluster_oscs(position: pd.DataFrame, **kwargs):
    """
    2-3-5-8 multiplier comparing several different osc lengths

    Arguments:
        position {pd.DataFrame} -- list of y-value datasets to be plotted (multiple)

    Optional Args:
        name {str} -- name of fund, primarily for plotting (default: {''})
        plot_output {bool} -- True to render plot in realtime (default: {True})
        function {str} -- type of oscillator (default: {'full_stochastic'}) 
                                (others: ultimate, rsi, all, market)
        wma {bool} -- output signal is filtered by windowed moving average (default: {True})
        progress_bar {ProgressBar} -- (default: {None})
        view {str} -- file directory of plots (default: {''})

    Returns:
        list -- dict of all clustered oscillator info, list of clustered osc signal
    """
    name = kwargs.get('name', '')
    plot_output = kwargs.get('plot_output', True)
    function = kwargs.get('function', 'full_stochastic')
    wma = kwargs.get('wma', True)
    prog_bar = kwargs.get('progress_bar', None)
    view = kwargs.get('view', '')

    cluster_oscs = {}

    clusters = generate_cluster(position, function, p_bar=prog_bar)
    cluster_oscs['tabular'] = clusters
    cluster_oscs['length_of_data'] = len(clusters)

    #clusters_filtered = cluster_filtering(clusters, filter_thresh)
    clusters_wma = exponential_moving_avg(clusters,
                                          interval=3,
                                          data_type='list')
    if prog_bar is not None:
        prog_bar.uptick(increment=0.1)

    dates = cluster_dates(clusters_wma, position)
    if prog_bar is not None:
        prog_bar.uptick(increment=0.1)

    signals = clustered_signals(dates)
    if prog_bar is not None:
        prog_bar.uptick(increment=0.1)

    cluster_oscs['clustered type'] = function
    cluster_oscs[function] = dates
    cluster_oscs['signals'] = signals

    cluster_oscs = clustered_metrics(position,
                                     cluster_oscs,
                                     plot_output=plot_output,
                                     name=name,
                                     view=view)

    name3 = INDEXES.get(name, name)
    name2 = name3 + ' - Clustering: ' + function
    if plot_output:
        dual_plotting(position['Close'],
                      clusters,
                      'Position Price',
                      'Clustered Oscillator',
                      x_label='Trading Days',
                      title=name2)

    else:
        filename = os.path.join(name, view, f"clustering_{name}_{function}")
        dual_plotting(y1=position['Close'],
                      y2=clusters,
                      y1_label='Price',
                      y2_label='Clustered Oscillator',
                      x_label='Trading Days',
                      title=name2,
                      saveFig=True,
                      filename=filename)

    if prog_bar is not None:
        prog_bar.uptick(increment=0.2)

    if wma:
        cluster_oscs['tabular'] = clusters_wma

    cluster_oscs['type'] = 'oscillator'

    return cluster_oscs
def roc_metrics(fund: pd.DataFrame, roc_dict: dict, **kwargs) -> dict:
    """Rate of Change Metrics

    Arguments:
        fund {pd.DataFrame} -- fund dataset
        roc_dict {dict} -- roc data object

    Optional Args:
        plot_output {bool} -- (default: {True})
        name {str} -- (default: {''})
        views {str} -- (default: {''})
        p_bar {ProgressBar} -- (default: {None})

    Returns:
        dict -- roc data object
    """
    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    views = kwargs.get('views', '')
    p_bar = kwargs.get('p_bar')

    MAP_TABULAR = {'short': 0.65, 'medium': 1.0, 'long': 0.4}

    roc_dict['metrics'] = [0.0] * len(fund['Close'])
    roc_dict['signals'] = []

    # Look at zero crossovers first
    roc_dict = roc_zero_crossovers(fund, roc_dict, MAP_TABULAR)
    if p_bar is not None:
        p_bar.uptick(increment=0.1)

    roc_dict = roc_over_threshold_crossovers(fund, roc_dict, MAP_TABULAR)
    if p_bar is not None:
        p_bar.uptick(increment=0.1)

    roc_dict['metrics'] = exponential_moving_avg(roc_dict['metrics'],
                                                 7,
                                                 data_type='list')

    roc_dict['metrics'] = normalize_signals([roc_dict['metrics']])[0]
    if p_bar is not None:
        p_bar.uptick(increment=0.1)

    name2 = INDEXES.get(name, name)
    title = f"{name2} - Rate of Change Metrics"

    if plot_output:
        dual_plotting(fund['Close'],
                      roc_dict['metrics'],
                      'Price',
                      'ROC Metrics',
                      title=title)
    else:
        filename = os.path.join(name, views, f"roc_metrics_{name}")
        dual_plotting(fund['Close'],
                      roc_dict['metrics'],
                      'Price',
                      'ROC Metrics',
                      title=title,
                      saveFig=True,
                      filename=filename)

    return roc_dict
def clustered_metrics(position: pd.DataFrame, cluster_oscs: dict,
                      **kwargs) -> dict:
    """Clustered Metrics

    Arguments:
        position {pd.DataFrame} -- dataset
        cluster_oscs {dict} -- clustered osc data object

    Optional Args:
        plot_output {bool} -- (default: {True})
        name {str} -- (default: {''})
        view {str} -- file directory of plots (default: {''})

    Returns:
        dict -- clustered osc data object
    """
    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    view = kwargs.get('view')

    ults = cluster_oscs['tabular']

    # Take indicator set: weight, filter, normalize
    weights = [1.0, 0.85, 0.55, 0.1]
    state2 = [0.0] * len(ults)

    for ind, s in enumerate(ults):
        if s != 0.0:
            state2[ind] += s

            # Smooth the curves
            if ind - 1 >= 0:
                state2[ind - 1] += s * weights[1]
            if ind + 1 < len(ults):
                state2[ind + 1] += s * weights[1]
            if ind - 2 >= 0:
                state2[ind - 2] += s * weights[2]
            if ind + 2 < len(ults):
                state2[ind + 2] += s * weights[2]
            if ind - 3 >= 0:
                state2[ind - 3] += s * weights[3]
            if ind + 3 < len(ults):
                state2[ind + 3] += s * weights[3]

    metrics = exponential_moving_avg(state2, 7, data_type='list')
    norm = normalize_signals([metrics])
    metrics = norm[0]

    cluster_oscs['metrics'] = metrics

    name3 = INDEXES.get(name, name)
    name2 = name3 + " - Clustered Oscillator Metrics"
    if plot_output:
        dual_plotting(position['Close'],
                      metrics,
                      'Price',
                      'Metrics',
                      title=name2)
    else:
        filename = os.path.join(name, view,
                                f"clustered_osc_metrics_{name}.png")
        dual_plotting(position['Close'],
                      metrics,
                      'Price',
                      'Metrics',
                      title=name2,
                      filename=filename,
                      saveFig=True)

    return cluster_oscs
def generate_obv_content(fund: pd.DataFrame, **kwargs) -> dict:
    """Generate On Balance Signal Content

    Arguments:
        fund {pd.DataFrame}

    Optional Args:
        plot_output {bool} -- (default: {True})
        filter_factor {float} -- threshold divisor (x/filter_factor) for "significant" OBVs
                                (default: {2.5})
        sma_interval {int} -- interval for simple moving average (default: {20})
        name {str} -- (default: {''})
        progress_bar {ProgressBar} -- (default: {None})
        view {'str'} -- period (default: {None})

    Returns:
        dict -- obv data object
    """
    plot_output = kwargs.get('plot_output', True)
    filter_factor = kwargs.get('filter_factor', 2.5)
    sma_interval = kwargs.get('sma_interval', 20)
    name = kwargs.get('name', '')
    progress_bar = kwargs.get('progress_bar')
    view = kwargs.get('view')

    obv_dict = dict()

    obv = generate_obv_signal(fund)
    obv_dict['obv'] = obv

    if progress_bar is not None:
        progress_bar.uptick(increment=0.125)

    ofilter, features = obv_feature_detection(obv,
                                              fund,
                                              sma_interval=sma_interval,
                                              filter_factor=filter_factor,
                                              progress_bar=progress_bar,
                                              plot_output=plot_output)

    obv_dict['tabular'] = ofilter
    obv_dict['signals'] = features

    if progress_bar is not None:
        progress_bar.uptick(increment=0.125)

    volume = []
    volume.append(fund['Volume'][0])
    for i in range(1, len(fund['Volume'])):
        if fund['Close'][i] - fund['Close'][i - 1] < 0:
            volume.append(-1.0 * fund['Volume'][i])
        else:
            volume.append(fund['Volume'][i])

    x = dates_extractor_list(fund)
    name3 = INDEXES.get(name, name)
    name2 = name3 + ' - On Balance Volume (OBV)'
    name4 = name3 + ' - Significant OBV Changes'
    name5 = name3 + ' - Volume'

    if plot_output:
        dual_plotting(fund['Close'],
                      obv,
                      x=x,
                      y1_label='Position Price',
                      y2_label='On Balance Volume',
                      x_label='Trading Days',
                      title=name2,
                      subplot=True)
        dual_plotting(fund['Close'],
                      ofilter,
                      x=x,
                      y1_label='Position Price',
                      y2_label='OBV-DIFF',
                      x_label='Trading Days',
                      title=name4,
                      subplot=True)
        bar_chart(volume, x=x, position=fund, title=name5, all_positive=True)

    else:
        filename = os.path.join(name, view, f"obv_diff_{name}.png")
        filename2 = os.path.join(name, view, f"obv_standard_{name}.png")
        filename3 = os.path.join(name, view, f"volume_{name}.png")

        bar_chart(volume,
                  x=x,
                  position=fund,
                  title=name5,
                  saveFig=True,
                  filename=filename3,
                  all_positive=True)
        bar_chart(ofilter,
                  x=x,
                  position=fund,
                  title=name4,
                  saveFig=True,
                  filename=filename)
        dual_plotting(fund['Close'],
                      obv,
                      x=x,
                      y1_label='Position Price',
                      y2_label='On Balance Volume',
                      x_label='Trading Days',
                      title=name2,
                      saveFig=True,
                      filename=filename2)

    if progress_bar is not None:
        progress_bar.uptick(increment=0.125)

    obv_dict['length_of_data'] = len(obv_dict['tabular'])

    return obv_dict
示例#28
0
def adx_metrics(fund: pd.DataFrame, adx: dict, **kwargs) -> dict:
    """ADX Metricx

    Arguments:
        fund {pd.DataFrame} -- fund dataset
        adx {dict} -- adx data object

    Optional Args:
        plot_output {bool} -- (default: {True})
        name {str} -- (default: {''})
        view {str} -- (default: {''})
        pbar {ProgressBar} -- (default: {None})

    Returns:
        dict -- adx data object
    """
    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    view = kwargs.get('view', '')
    pbar = kwargs.get('pbar')

    adx['metrics'] = [0.0] * len(fund['Close'])
    adx['signals'] = []

    auto = autotrend(fund['Close'], periods=[14])

    no_trend = adx['tabular']['no_trend'][0]
    strong_trend = adx['tabular']['strong_trend'][0]
    over_trend = adx['tabular']['high_trend'][0]

    signal = adx['tabular']['adx']
    for i in range(1, len(signal)):
        data = None
        date = fund.index[i].strftime("%Y-%m-%d")

        trend = 0.0
        state = 'none'
        if auto[i] > 0.0:
            trend = 1.0
            state = 'bull'
        elif auto[i] < 0.0:
            trend = -1.0
            state = 'bear'

        if signal[i - 1] < no_trend and signal[i] > no_trend:
            adx['metrics'][i] += 1.0 * trend
            if state != 'none':
                data = {
                    "type": state,
                    "value": '20-crossover: trend start',
                    "index": i,
                    "date": date
                }

        if signal[i - 1] < strong_trend and signal[i] > strong_trend:
            adx['metrics'][i] += 0.6 * trend
            if state != 'none':
                data = {
                    "type": state,
                    "value": '25-crossover: STRONG trend',
                    "index": i,
                    "date": date
                }

        if signal[i] > strong_trend:
            adx['metrics'][i] += 0.2 * trend

        if signal[i - 1] > over_trend and signal[i] < over_trend:
            adx['metrics'][i] += -1.0 * trend
            if state != 'none':
                if state == 'bull':
                    state = 'bear'
                else:
                    state = 'bull'
                data = {
                    "type": state,
                    "value": '40-crossunder: weakening trend',
                    "index": i,
                    "date": date
                }

        if signal[i - 1] > no_trend and signal[i] < no_trend:
            adx['metrics'][i] += 0.0
            if state != 'none':
                if state == 'bull':
                    state = 'bear'
                else:
                    state = 'bull'
                data = {
                    "type": state,
                    "value": '20-crossunder: WEAK/NO trend',
                    "index": i,
                    "date": date
                }

        if data is not None:
            adx['signals'].append(data)

    if pbar is not None:
        pbar.uptick(increment=0.1)

    metrics = exponential_moving_avg(adx['metrics'], 7, data_type='list')
    if pbar is not None:
        pbar.uptick(increment=0.1)

    adx['metrics'] = normalize_signals([metrics])[0]

    name2 = INDEXES.get(name, name)
    title = f"{name2} - ADX Metrics"

    if plot_output:
        dual_plotting(fund['Close'],
                      adx['metrics'],
                      'Price',
                      'Metrics',
                      title=title)
    else:
        filename = os.path.join(name, view, f"adx_metrics_{name}.png")
        dual_plotting(fund['Close'],
                      adx['metrics'],
                      'Price',
                      'Metrics',
                      title=title,
                      saveFig=True,
                      filename=filename)

    if pbar is not None:
        pbar.uptick(increment=0.2)

    return adx
示例#29
0
def bollinger_metrics(position: pd.DataFrame, bol_bands: dict,
                      **kwargs) -> dict:
    """Bollinger Metrics

    Arguments:
        position {pd.DataFrame} -- dataset of fund
        bol_bands {dict} -- bollinger band data object

    Optional Args:
        period {int} -- look back period for Stdev (default: {20})
        plot_output {bool} -- (default: {True})
        name {str} -- (default: {''})
        view {str} -- (default: {''})

    Returns:
        dict -- bollinger band data object
    """
    period = kwargs.get('period', 20)
    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    view = kwargs.get('view')

    weights = [1.0, 0.6, 0.25, 0.0]
    tot_len = len(position['Close'])

    metrics = [0.0] * tot_len
    for feat in bol_bands['indicators']:
        ind = feat['index']
        if feat['type'] == 'bullish':
            val = 1.0
        else:
            val = -1.0

        metrics[ind] += val * weights[0]

        # Smooth the curves
        if ind - 1 >= 0:
            metrics[ind - 1] += val * weights[1]
        if ind + 1 < tot_len:
            metrics[ind + 1] += val * weights[1]
        if ind - 2 >= 0:
            metrics[ind - 2] += val * weights[2]
        if ind + 2 < tot_len:
            metrics[ind + 2] += val * weights[2]
        if ind - 3 >= 0:
            metrics[ind - 3] += val * weights[3]
        if ind + 3 < tot_len:
            metrics[ind + 3] += val * weights[3]

    close = position['Close']
    bb = bol_bands['tabular']
    for i in range(period, len(close)):
        s_range = bb['middle_band'][i] - bb['lower_band'][i]
        if metrics[i] <= 0.6 and metrics[i] >= -0.6:
            c = close[i] - bb['middle_band'][i]
            c = np.round(c / s_range, 4)
            metrics[i] = c

    metrics = exponential_moving_avg(metrics, 7, data_type='list')
    norm_signal = normalize_signals([metrics])[0]

    bol_bands['metrics'] = norm_signal

    name3 = INDEXES.get(name, name)
    name2 = name3 + f" - Bollinger Band Metrics"
    if plot_output:
        dual_plotting(position['Close'],
                      norm_signal,
                      'Price',
                      'Indicators',
                      title=name2)
    else:
        filename = os.path.join(name, view,
                                f"bollinger_band_metrics_{name}.png")
        # filename = name + f"/{view}" + f"/bollinger_band_metrics_{name}.png"
        dual_plotting(position['Close'],
                      norm_signal,
                      'Price',
                      'Metrics',
                      title=name2,
                      saveFig=True,
                      filename=filename)

    return bol_bands
示例#30
0
def get_adx_signal(fund: pd.DataFrame, atr: list, **kwargs) -> dict:
    """Get ADX Signal

    Arguments:
        fund {pd.DataFrame} -- fund dataset
        atr {list} -- atr signal

    Optional Args:
        interval {int} -- lookback period (default: {14})
        adx_default {float} -- default adx signal value before calculations appear
                                (default: {20.0})
        no_trend_value {float} -- threshold of ADX where signal is deemed to not have a trend
                                    (default: {20.0})
        strong_trend_value {float} -- threshold of ADX where signal is deemed to have a strong trend
                                        (default: {25.0})
        high_trend_value {float} -- threshold of ADX where signal drops below as trend weakens
                                        (default: {40.0})
        plot_output {bool} -- (default: {True})
        name {str} -- (default: {''})
        view {str} -- (default: {''})
        pbar {ProgressBar} -- (default: {None})

    Returns:
        dict -- tabular adx and DI signals
    """
    interval = kwargs.get('interval', 14)
    ADX_DEFAULT = kwargs.get('adx_default', 20.0)
    NO_TREND = kwargs.get('no_trend_value', 20.0)
    STRONG_TREND = kwargs.get('strong_trend_value', 25.0)
    HIGH_TREND = kwargs.get('high_trend_value', 40.0)

    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    view = kwargs.get('view', '')
    pbar = kwargs.get('pbar')

    signal = dict()

    # Calculate the directional movement signals
    dmp = [0.0] * len(fund['Close'])
    dmn = [0.0] * len(fund['Close'])
    for i in range(1, len(fund['Close'])):
        dmp[i] = fund['High'][i] - fund['High'][i - 1]
        dmn[i] = fund['Low'][i - 1] - fund['Low'][i]

        if dmp[i] > dmn[i]:
            dmn[i] = 0.0
        else:
            dmp[i] = 0.0
        if dmp[i] < 0.0:
            dmp[i] = 0.0
        if dmn[i] < 0.0:
            dmn[i] = 0.0

    if pbar is not None:
        pbar.uptick(increment=0.1)

    # Calculate the dm signals, di signals, dx signal with 'interval' averages
    dma_p = [0.0] * len(fund['Close'])
    dma_n = [0.0] * len(fund['Close'])
    di_p = [0.0] * len(fund['Close'])
    di_n = [0.0] * len(fund['Close'])
    dx_signal = [0.0] * len(fund['Close'])

    dma_p[interval - 1] = sum(dmp[0:interval])
    dma_n[interval - 1] = sum(dmn[0:interval])
    for i in range(interval, len(fund['Close'])):
        dma_p[i] = dma_p[i - 1] - (dma_p[i - 1] / float(interval)) + dmp[i]
        dma_n[i] = dma_n[i - 1] - (dma_n[i - 1] / float(interval)) + dmn[i]

        di_p[i] = dma_p[i] / atr[i] * 100.0
        di_n[i] = dma_n[i] / atr[i] * 100.0

        dx_signal[i] = abs(di_p[i] - di_n[i]) / (di_p[i] + di_n[i]) * 100.0

    if pbar is not None:
        pbar.uptick(increment=0.3)

    # Finally, calculate the adx signal as an 'interval' average of dx
    adx_signal = [ADX_DEFAULT] * len(fund['Close'])
    adx_signal[interval - 1] = sum(dx_signal[0:interval]) / float(interval)
    for i in range(interval, len(adx_signal)):
        adx_signal[i] = (
            (adx_signal[i - 1] * 13) + dx_signal[i]) / float(interval)

    if pbar is not None:
        pbar.uptick(increment=0.1)

    signal['di_+'] = di_p
    signal['di_-'] = di_n
    signal['adx'] = adx_signal
    signal['high_trend'] = [HIGH_TREND] * len(adx_signal)
    signal['no_trend'] = [NO_TREND] * len(adx_signal)
    signal['strong_trend'] = [STRONG_TREND] * len(adx_signal)

    plots = [
        signal['no_trend'], signal['high_trend'], signal['strong_trend'],
        signal['adx']
    ]

    name2 = INDEXES.get(name, name)
    title = f"{name2} - Average Directional Index (ADX)"

    if plot_output:
        dual_plotting(fund['Close'],
                      plots,
                      'Price',
                      ['No Trend', 'Over Trend', 'Strong Trend', 'ADX'],
                      title=title)
    else:
        filename = os.path.join(name, view, f"adx_tabular_{name}.png")
        dual_plotting(fund['Close'],
                      plots,
                      'Price',
                      ['No Trend', 'Over Trend', 'Strong Trend', 'ADX'],
                      title=title,
                      saveFig=True,
                      filename=filename)

    if pbar is not None:
        pbar.uptick(increment=0.1)

    return signal