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 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
Пример #3
0
def volatility_calculation(position: pd.DataFrame, **kwargs) -> list:
    """Volatility Calculation

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

    Optional Args:
        plot_output {bool} -- (default: {True})

    Returns:
        list -- volatility data as list of weighted standard deviations
    """
    plot_output = kwargs.get('plot_output', True)

    periods = [50, 100, 250, 500]
    stdevs = []

    for _ in range(len(periods)):
        std = [0.0] * len(position['Close'])
        stdevs.append(std)

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

    for i, period in enumerate(periods):
        for j in range(period, len(typical_price)):
            std = np.std(typical_price[j - (period):j]) * 2.0
            stdevs[i][j] = std

    std_correction = []
    for j in range(len(typical_price)):
        if j < periods[1]:
            s = stdevs[0][j]
        elif j < periods[2]:
            s = 0.7 * stdevs[1][j] + 0.3 * stdevs[0][j]
        elif j < periods[3]:
            s = 0.55 * stdevs[2][j] + \
                0.3 * stdevs[1][j] + 0.15 * stdevs[0][j]
        else:
            s = 0.4 * stdevs[3][j] + 0.3 * stdevs[2][j] + \
                0.2 * stdevs[1][j] + 0.1 * stdevs[0][j]
        std_correction.append(s)

    for i, price in enumerate(typical_price):
        std_correction[i] = std_correction[i] / price

    if plot_output:
        dual_plotting(position['Close'],
                      std_correction,
                      'Price',
                      'Volatility',
                      title='Standard Deviation Volatility')

    return std_correction
Пример #4
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
Пример #5
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
Пример #6
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
Пример #8
0
def compare_against_signal_line(signal: list, **kwargs) -> list:
    """Compare Against Signal Line

    Compare momentum oscillator signal vs. sma signal line

    Arguments:
        signal {list} -- momentum oscillator signal

    Optional Args:
        plot_output {bool} -- (default: {True})
        interval {int} -- lookback for simple moving average (default: {9})
        position {pd.DataFrame} -- fund dataset (default: {[]})

    Returns:
        list -- bear_bull oscillator signal
    """
    plot_output = kwargs.get('plot_output', True)
    interval = kwargs.get('interval', 9)
    position = kwargs.get('position', [])

    signal_line = simple_moving_avg(signal, interval, data_type='list')
    bear_bull = []
    for i in range(len(signal)):
        if signal[i] > signal_line[i]:
            bear_bull.append(1.0)
        elif signal[i] < signal_line[i]:
            bear_bull.append(-1.0)
        else:
            bear_bull.append(0.0)

    if plot_output and (len(position) > 0):
        dual_plotting(position['Close'],
                      bear_bull,
                      'Price',
                      'Bear_Bull',
                      title='Bear Bull')

    return bear_bull
Пример #9
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
Пример #10
0
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
Пример #11
0
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
Пример #12
0
def bear_bull_feature_detection(bear_bull: dict, position: pd.DataFrame, **kwargs) -> dict:
    """Bear Bull Feature Detection

    Arguments:
        bear_bull {dict} -- bull bear data object
        position {pd.DataFrame} -- dataset

    Optional Args:
        interval {int} -- size of exponential moving average window (default: {13})
        bb_interval {list} -- list of sizes of bear and bull windows (default: {[4, 5, 6, 7, 8]})
        plot_output {bool} -- (default: {True})
        name {str} -- (default: {''})
        p_bar {ProgressBar} -- (default {None})
        view {str} -- (default: {''})

    Returns:
        dict -- [description]
    """
    interval = kwargs.get('interval', 13)
    bb_interval = kwargs.get('bb_interval', [4, 5, 6, 7, 8])
    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    p_bar = kwargs.get('p_bar')
    view = kwargs.get('view')

    # Determine the slope of the ema at given points
    ema = exponential_moving_avg(position, interval)

    ema_slopes = [0.0] * (interval-1)
    for i in range(interval-1, len(ema)):
        x = list(range(i-(interval-1), i))
        y = ema[i-(interval-1): i]
        reg = linregress(x, y=y)
        ema_slopes.append(reg[0])

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

    incr = 0.6 / float(len(bb_interval))

    state = [0.0] * len(ema)
    features = []

    for bb in bb_interval:
        # Determine the slope of the bear power signal at given points
        bear_slopes = [0.0] * (bb-1)
        for i in range(bb-1, len(ema)):
            x = list(range(i-(bb-1), i))
            y = bear_bull['tabular']['bears'][i-(bb-1): i]
            reg = linregress(x, y=y)
            bear_slopes.append(reg[0])

        # Determine the slope of the bull power signal at given points
        bull_slopes = [0.0] * (bb-1)
        for i in range(bb-1, len(ema)):
            x = list(range(i-(bb-1), i))
            y = bear_bull['tabular']['bulls'][i-(bb-1): i]
            reg = linregress(x, y=y)
            bull_slopes.append(reg[0])

        for i in range(1, len(ema)):
            data = None
            date = position.index[i].strftime("%Y-%m-%d")

            if ema_slopes[i] > 0.0:
                if bear_bull['tabular']['bears'][i] < 0.0:
                    if bear_slopes[i] > 0.0:
                        # Determine the basic (first 2 conditions) bullish state (+1)
                        state[i] += 1.0
                        if bear_bull['tabular']['bulls'][i] > bear_bull['tabular']['bulls'][i-1]:
                            state[i] += 0.5
                            if position['Close'][i] < position['Close'][i-1]:
                                # Need to find bullish divergence!
                                state[i] += 1.0
                                data = {
                                    "type": 'bullish',
                                    "value": f'bullish divergence: {bb}d interval',
                                    "index": i,
                                    "date": date
                                }

            if ema_slopes[i] < 0.0:
                if bear_bull['tabular']['bulls'][i] > 0.0:
                    if bull_slopes[i] < 0.0:
                        # Determine the basic (first 2 conditions) bearish state (+1)
                        state[i] += -1.0
                        if bear_bull['tabular']['bears'][i] < bear_bull['tabular']['bears'][i-1]:
                            state[i] += -0.5
                            if position['Close'][i] > position['Close'][i-1]:
                                # Need to find bearish divergence!
                                state[i] += -1.0
                                data = {
                                    "type": 'bearish',
                                    "value": f'bearish divergence: {bb}d interval',
                                    "index": i,
                                    "date": date
                                }

            if data is not None:
                features.append(data)

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

    bear_bull['signals'] = filter_features(features, plot_output=plot_output)
    bear_bull['length_of_data'] = len(bear_bull['tabular']['bears'])

    weights = [1.0, 0.75, 0.45, 0.1]

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

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

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

    title = 'Bear Bull Power Metrics'
    if plot_output:
        dual_plotting(position['Close'], state4, 'Price',
                      'Bear Bull Power', title=title)
    else:
        filename = os.path.join(name, view, f"bear_bull_power_{name}.png")
        dual_plotting(position['Close'], state4, 'Price', 'Metrics', title=title,
                      saveFig=True, filename=filename)

    bear_bull['metrics'] = state4

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

    return bear_bull
def get_ao_signal(position: pd.DataFrame, **kwargs) -> list:
    """Get Awesome Oscillator Signal

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

    Optional Args:
        short_period {int} -- moving average period (default: {5})
        long_period {int} -- moving average period (default: {34})
        filter_style {str} -- moving average type, 'sma' or 'ema' (default: {'sma'})
        plot_output {bool} -- True plots in realtime (default: {True})
        p_bar {ProgressBar} -- (default: {None})
        name {str} -- name of fund (default: {''})

    Returns:
        list -- awesome signal
    """
    short_period = kwargs.get('short_period', 5)
    long_period = kwargs.get('long_period', 34)
    filter_style = kwargs.get('filter_style', 'sma')
    plot_output = kwargs.get('plot_output', True)
    p_bar = kwargs.get('progress_bar')
    name = kwargs.get('name', '')
    view = kwargs.get('view')

    signal = []
    mid_points = []
    for i, high in enumerate(position['High']):
        mid = (high + position['Low'][i]) / 2
        mid_points.append(mid)

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

    if filter_style == 'sma':
        short_signal = simple_moving_avg(mid_points,
                                         short_period,
                                         data_type='list')
        long_signal = simple_moving_avg(mid_points,
                                        long_period,
                                        data_type='list')

    elif filter_style == 'ema':
        short_signal = exponential_moving_avg(mid_points,
                                              short_period,
                                              data_type='list')
        long_signal = exponential_moving_avg(mid_points,
                                             long_period,
                                             data_type='list')

    else:
        short_signal = []
        long_signal = []

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

    for i in range(long_period):
        signal.append(0.0)
    for i in range(long_period, len(long_signal)):
        diff = short_signal[i] - long_signal[i]
        signal.append(diff)

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

    med_term = simple_moving_avg(signal, 14, data_type='list')
    long_term = simple_moving_avg(signal, long_period, data_type='list')

    signal, med_term, long_term = normalize_signals(
        [signal, med_term, long_term])

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

    triggers = ao_signal_trigger(signal, med_term, long_term)

    x = dates_extractor_list(position)
    name3 = INDEXES.get(name, name)
    name2 = name3 + ' - Awesome Oscillator'

    if plot_output:
        dual_plotting([signal, med_term, long_term], position['Close'],
                      ['Awesome', 'Medium', 'Long'], 'Price')
        dual_plotting([signal, triggers], position['Close'],
                      ['Awesome', 'Triggers'], 'Price')
        bar_chart(signal, position=position, x=x, title=name2, bar_delta=True)
    else:
        filename = os.path.join(name, view, f"awesome_bar_{name}")
        bar_chart(signal,
                  position=position,
                  x=x,
                  saveFig=True,
                  filename=filename,
                  title=name2,
                  bar_delta=True)

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

    return signal
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
Пример #15
0
def momentum_metrics(position: pd.DataFrame, mo_dict: dict, **kwargs) -> dict:
    """Momentum Oscillator Metrics 

    Combination of pure oscillator signal + weighted features

    Arguments:
        position {pd.DataFrame} -- fund
        mo_dict {dict} -- momentum oscillator dict

    Optional Args:
        plot_output {bool} -- plots in real time if True (default: {True})
        name {str} -- name of fund (default: {''})
        progress_bar {ProgressBar} -- (default: {None})
        view {str} -- (default: {''})

    Returns:
        dict -- mo_dict w/ updated keys and data
    """
    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    period_change = kwargs.get('period_change', 5)
    view = kwargs.get('view', '')

    weights = [1.3, 0.85, 0.55, 0.1]

    # Convert features to a "tabular" array
    tot_len = len(position['Close'])
    metrics = [0.0] * tot_len
    mo_features = mo_dict['signals']
    signal = mo_dict['tabular']

    for feat in mo_features:
        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]

    norm_signal = normalize_signals([signal])[0]

    metrics4 = []
    changes = []
    for i, met in enumerate(metrics):
        metrics4.append(met + norm_signal[i])

    min_ = np.abs(min(metrics4)) + 1.0
    for _ in range(period_change):
        changes.append(0.0)
    for i in range(period_change, len(metrics4)):
        c = (((metrics4[i] + min_) /
              (metrics4[i - period_change] + min_)) - 1.0) * 100.0
        changes.append(c)

    mo_dict['metrics'] = metrics4
    mo_dict['changes'] = changes

    title = '(Chande) Momentum Oscillator Metrics'
    if plot_output:
        dual_plotting(position['Close'],
                      metrics4,
                      'Price',
                      'Metrics',
                      title=title)
    else:
        filename = os.path.join(name, view, f"momentum_metrics_{name}.png")
        dual_plotting(position['Close'],
                      metrics4,
                      'Price',
                      'Metrics',
                      title=title,
                      saveFig=True,
                      filename=filename)

    return mo_dict
Пример #16
0
def swing_trade_metrics(position: pd.DataFrame, swings: dict, **kwargs) -> dict:
    """Swing Trade Metrics

    Arguments:
        position {pd.DataFrame} -- fund dataset
        swings {dict} -- hull data object

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

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

    weights = [1.0, 0.55, 0.25, 0.1]

    # Convert features to a "tabular" array
    tot_len = len(position['Close'])
    metrics = [0.0] * tot_len

    for i, val in enumerate(swings['tabular']['swing']):

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

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

    norm_signal = normalize_signals([metrics])[0]
    metrics = simple_moving_avg(norm_signal, 7, data_type='list')
    swings['metrics'] = {'metrics': metrics}

    tshort = swings['tabular']['short']
    tmed = swings['tabular']['medium']
    tlong = swings['tabular']['long']

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

    for i, close in enumerate(position['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))

    shp = swings['short']['period']
    mdp = swings['medium']['period']
    lgp = swings['long']['period']

    swings['metrics'][f'{shp}-d'] = mshort
    swings['metrics'][f'{mdp}-d'] = mmed
    swings['metrics'][f'{lgp}-d'] = mlong

    name3 = INDEXES.get(name, name)
    name2 = name3 + ' - Hull Moving Average Metrics'

    if plot_output:
        dual_plotting(position['Close'], swings['metrics']['metrics'],
                      'Price', 'Metrics', title='Hull Moving Average Metrics')
    else:
        filename2 = os.path.join(name, view, f"hull_metrics_{name}.png")
        dual_plotting(position['Close'], swings['metrics']['metrics'],
                      'Price', 'Metrics', title=name2, saveFig=True, filename=filename2)

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

    return swings
Пример #17
0
def rsi_divergence(position: pd.DataFrame, rsi_data: dict, **kwargs) -> dict:
    """RSI Divergence:

    1. Cross outside threshold at Price A
    2. Cross inside threshold
    3. Cross outside threshold at Price B
    4. Exit [inside] threshold, where Price B is more extreme than A

    Arguments:
        position {pd.DataFrame} -- dataset
        rsi_data {dict} -- rsi data object

    Optional Args:
        plot_output {bool} -- (default: {True})
        p_bar {ProgressBar} -- (default: {None})

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

    signal = rsi_data['tabular']
    ovb_th = rsi_data['thresholds']['overbought']
    ovs_th = rsi_data['thresholds']['oversold']

    divs = [0.0] * len(signal)

    state = 'n'
    maxima = 0.0
    minima = 0.0
    prices = [0.0, 0.0]
    rsi_vals = [0.0, 0.0]
    for i, sig in enumerate(signal):

        # Start with bullish divergence
        if (state == 'n') and (sig <= ovs_th[i]):
            state = 'u1'
            rsi_vals[0] = sig

        elif state == 'u1':
            if sig <= rsi_vals[0]:
                rsi_vals[0] = sig
                prices[0] = position['Close'][i]
            else:
                state = 'u2'
                maxima = sig

        elif state == 'u2':
            if sig >= maxima:
                if sig >= ovb_th[i]:
                    state = 'e1'
                    rsi_vals[0] = sig
                else:
                    maxima = sig
            else:
                state = 'u3'
                rsi_vals[1] = sig

        elif state == 'u3':
            if sig <= rsi_vals[1]:
                prices[1] = position['Close'][i]
                rsi_vals[1] = sig
            else:
                if rsi_vals[1] <= ovs_th[i]:
                    if (prices[1] < prices[0]) and (rsi_vals[0] < rsi_vals[1]):
                        # Bullish divergence!
                        divs[i] = 1.0
                        rsi_data['bullish'].append([
                            date_extractor(position.index[i], _format='str'),
                            position['Close'][i], i, "divergence"
                        ])
                        state = 'n'
                    else:
                        state = 'n'
                else:
                    state = 'n'

        # Start with bearish divergence
        elif (state == 'n') and (sig >= ovb_th[i]):
            state = 'e1'
            rsi_vals[0] = sig

        elif state == 'e1':
            if sig >= rsi_vals[0]:
                rsi_vals[0] = sig
                prices[0] = position['Close'][i]
            else:
                state = 'e2'
                minima = sig

        elif state == 'e2':
            if sig <= minima:
                if sig <= ovs_th[i]:
                    state = 'u1'
                    rsi_vals[0] = sig
                else:
                    minima = sig
            else:
                state = 'e3'
                rsi_vals[1] = sig

        elif state == 'e3':
            if sig >= rsi_vals[1]:
                prices[1] = position['Close'][i]
                rsi_vals[1] = sig
            else:
                if rsi_vals[1] >= ovb_th[i]:
                    if (prices[1] > prices[0]) and (rsi_vals[0] > rsi_vals[1]):
                        # Bearish divergence!
                        divs[i] = -1.0
                        rsi_data['bearish'].append([
                            date_extractor(position.index[i], _format='str'),
                            position['Close'][i], i, "divergence"
                        ])
                        state = 'n'
                    else:
                        state = 'n'
                else:
                    state = 'n'

    rsi_data['divergence'] = divs

    if plot_output:
        dual_plotting(position['Close'], divs, 'Price', 'RSI', title='Divs')

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

    return rsi_data
Пример #18
0
def RSI(position: pd.DataFrame, **kwargs) -> dict:
    """Relative Strength Indicator

    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})
        period {int} -- size of RSI indicator (default: {14})
        out_suppress {bool} -- output plot/prints are suppressed (default: {True})
        progress_bar {ProgressBar} -- (default: {None})
        overbought {float} -- threshold to trigger overbought/sell condition (default: {70.0})
        oversold {float} -- threshold to trigger oversold/buy condition (default: {30.0})
        auto_trend {bool} -- True calculates basic trend, applies to thresholds (default: {True})
        view {str} -- (default: {''})
        trendlines {bool} -- (default: {False})

    Returns:
        dict -- contains all rsi information
    """
    name = kwargs.get('name', '')
    plot_output = kwargs.get('plot_output', True)
    period = kwargs.get('period', 14)
    out_suppress = kwargs.get('out_suppress', True)
    progress_bar = kwargs.get('progress_bar', None)
    overbought = kwargs.get('overbought', 70.0)
    oversold = kwargs.get('oversold', 30.0)
    auto_trend = kwargs.get('auto_trend', True)
    view = kwargs.get('view', '')
    trendlines = kwargs.get('trendlines', False)

    rsi_data = dict()

    rsi = generate_rsi_signal(position, period=period, p_bar=progress_bar)
    rsi_data['tabular'] = rsi

    slope_trend = []
    if auto_trend:
        slope_trend = autotrend(position['Close'],
                                periods=[period * 3, period * 5.5, period * 8],
                                weights=[0.45, 0.33, 0.22],
                                normalize=True)

    over_thresholds = over_threshold_lists(overbought,
                                           oversold,
                                           len(position['Close']),
                                           slope_list=slope_trend)
    if progress_bar is not None:
        progress_bar.uptick(increment=0.1)

    rsi_data['thresholds'] = over_thresholds

    # Determine indicators, swing rejection and divergences
    rsi_data = determine_rsi_swing_rejection(position,
                                             rsi_data,
                                             p_bar=progress_bar)

    rsi_data = rsi_divergence(position,
                              rsi_data,
                              plot_output=plot_output,
                              p_bar=progress_bar)

    # Determine metrics, primarily using both indicators
    rsi_data = rsi_metrics(position, rsi_data, p_bar=progress_bar)

    main_plots = [
        rsi, over_thresholds['overbought'], over_thresholds['oversold']
    ]

    if not out_suppress:
        name3 = INDEXES.get(name, name)
        name2 = name3 + ' - RSI'

        if plot_output:
            dual_plotting(position['Close'],
                          main_plots,
                          'Position Price',
                          'RSI',
                          title=name2)
            dual_plotting(position['Close'],
                          rsi_data['metrics'],
                          'Position Price',
                          'RSI Indicators',
                          title=name2)

        else:
            filename1 = os.path.join(name, view, f"RSI_standard_{name}.png")
            filename2 = os.path.join(name, view, f"RSI_indicator_{name}.png")
            dual_plotting(position['Close'],
                          main_plots,
                          'Position Price',
                          'RSI',
                          title=name2,
                          saveFig=True,
                          filename=filename1)
            dual_plotting(position['Close'],
                          rsi_data['metrics'],
                          'Position Price',
                          'RSI Metrics',
                          title=name2,
                          saveFig=True,
                          filename=filename2)

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

    if trendlines:
        end = len(rsi)
        rsi_trend = rsi[end - 100:end]
        get_trendlines_regression(rsi_trend, plot_output=True, indicator='RSI')

    rsi_data['type'] = 'oscillator'
    rsi_data['length_of_data'] = len(rsi)
    rsi_data['signals'] = rsi_signals(rsi_data['bullish'], rsi_data['bearish'])

    return rsi_data
Пример #19
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
def composite_index(data: dict,
                    sectors: list,
                    progress_bar=None,
                    plot_output=True) -> list:
    """Composite Index

    Arguments:
        data {dict} -- data
        sectors {list} -- list of sectors

    Keyword Arguments:
        progress_bar {ProgressBar} -- (default: {None})
        plot_output {bool} -- (default: {True})

    Returns:
        list -- correlation vector
    """
    composite = []
    for tick in sectors:
        cluster = cluster_oscs(data[tick],
                               plot_output=False,
                               function='market',
                               wma=False,
                               progress_bar=progress_bar)

        graph = cluster['tabular']
        composite.append(graph)

    composite2 = []
    for i in range(len(composite[0])):
        s = 0.0
        for j in range(len(composite)):
            s += float(composite[j][i])

        composite2.append(s)

    progress_bar.uptick()

    composite2 = windowed_moving_avg(composite2, 3, data_type='list')

    max_ = np.max(np.abs(composite2))
    composite2 = [x / max_ for x in composite2]
    progress_bar.uptick()

    if plot_output:
        dual_plotting(data['^GSPC']['Close'],
                      composite2,
                      y1_label='S&P500',
                      y2_label='MCI',
                      title='Market Composite Index')
    else:
        dual_plotting(data['^GSPC']['Close'],
                      composite2,
                      y1_label='S&P500',
                      y2_label='MCI',
                      title='Market Composite Index',
                      saveFig=True,
                      filename='MCI.png')

    progress_bar.uptick()
    return composite2
Пример #21
0
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
def composite_correlation(data: dict,
                          sectors: list,
                          progress_bar=None,
                          plot_output=True) -> dict:
    """Composite Correlation

    Betas and r-squared for 2 time periods for each sector (full, 1/2 time); plot of r-squared
    vs. S&P500 for last 50 or 100 days for each sector.

    Arguments:
        data {dict} -- data object
        sectors {list} -- list of sectors

    Keyword Arguments:
        progress_bar {ProgressBar} -- (default: {None})
        plot_output {bool} -- (default: {True})

    Returns:
        dict -- correlation dictionary
    """
    DIVISOR = 5
    correlations = {}

    if '^GSPC' in data.keys():
        tot_len = len(data['^GSPC']['Close'])
        start_pt = int(np.floor(tot_len / DIVISOR))

        if start_pt > 100:
            start_pt = 100

        corrs = {}
        dates = data['^GSPC'].index[start_pt:tot_len]
        net_correlation = [0.0] * (tot_len - start_pt)

        DIVISOR = 10.0
        increment = float(len(sectors)) / (float(tot_len - start_pt) /
                                           DIVISOR * float(len(sectors)))

        counter = 0
        for sector in sectors:
            correlations[sector] = simple_beta_rsq(
                data[sector],
                data['^GSPC'],
                recent_period=[int(np.round(tot_len / 2, 0)), tot_len])

            corrs[sector] = []
            for i in range(start_pt, tot_len):

                _, rsqd = beta_comparison_list(
                    data[sector]['Close'][i - start_pt:i],
                    data['^GSPC']['Close'][i - start_pt:i])

                corrs[sector].append(rsqd)
                net_correlation[i - start_pt] += rsqd

                counter += 1
                if counter == DIVISOR:
                    progress_bar.uptick(increment=increment)
                    counter = 0

        plots = [corrs[x] for x in corrs.keys()]
        legend = [x for x in corrs.keys()]

        generic_plotting(plots,
                         x=dates,
                         title='MCI Correlations',
                         legend=legend,
                         saveFig=(not plot_output),
                         filename='MCI_correlations.png')

        progress_bar.uptick()

        max_ = np.max(net_correlation)
        net_correlation = [x / max_ for x in net_correlation]

        legend = ['Net Correlation', 'S&P500']
        dual_plotting(net_correlation,
                      data['^GSPC']['Close'][start_pt:tot_len],
                      x=dates,
                      y1_label=legend[0],
                      y2_label=legend[1],
                      title='MCI Net Correlation',
                      saveFig=(not plot_output),
                      filename='MCI_net_correlation.png')

        progress_bar.uptick()

    return correlations
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
def awesome_metrics(position: pd.DataFrame, ao_dict: dict, **kwargs) -> dict:
    """Awesome Oscillator Metrics 

    Combination of pure oscillator signal + weighted trigger signals

    Arguments:
        position {pd.DataFrame} -- fund
        ao_dict {dict} -- awesome oscillator dictionary

    Optional Args:
        plot_output {bool} -- plots in real time if True (default: {True})
        name {str} -- name of fund (default: {''})
        progress_bar {ProgressBar} -- (default: {None})

    Returns:
        dict -- ao_dict w/ updated keys and data
    """
    plot_output = kwargs.get('plot_output', True)
    name = kwargs.get('name', '')
    p_bar = kwargs.get('progress_bar')
    period_change = kwargs.get('period_change', 5)
    view = kwargs.get('view')

    weights = [1.0, 0.85, 0.5, 0.05]

    # Convert features to a "tabular" array
    tot_len = len(position['Close'])
    metrics = [0.0] * tot_len
    plus_minus = ao_dict.get('pm', {}).get('pm_data')
    indexes = ao_dict.get('pm', {}).get('indexes', [])

    for i, ind in enumerate(indexes):
        metrics[ind] += float(plus_minus[i])

        # Smooth the curves
        if ind - 1 >= 0:
            metrics[ind - 1] += float(plus_minus[i]) * weights[1]
        if ind + 1 < tot_len:
            metrics[ind + 1] += float(plus_minus[i]) * weights[1]
        if ind - 2 >= 0:
            metrics[ind - 2] += float(plus_minus[i]) * weights[2]
        if ind + 2 < tot_len:
            metrics[ind + 2] += float(plus_minus[i]) * weights[2]
        if ind - 3 >= 0:
            metrics[ind - 3] += float(plus_minus[i]) * weights[3]
        if ind + 3 < tot_len:
            metrics[ind + 3] += float(plus_minus[i]) * weights[3]

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

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

    ao_signal = ao_dict['tabular']

    metrics4 = []
    for i, met in enumerate(metrics3):
        metrics4.append(met + ao_signal[i])

    changes = []
    min_ = 1.0 - min(metrics4)
    for _ in range(period_change):
        changes.append(0.0)
    for i in range(period_change, len(metrics4)):
        c = (((metrics4[i] + min_) /
              (metrics4[i - period_change] + min_)) - min_) * 100.0
        changes.append(c)

    ao_dict['metrics'] = metrics4
    ao_dict['changes'] = changes

    title = 'Awesome Oscillator Metrics'
    if plot_output:
        dual_plotting(position['Close'],
                      metrics4,
                      'Price',
                      'Metrics',
                      title=title)
    else:
        filename = os.path.join(name, view, f"awesome_metrics_{name}.png")
        dual_plotting(position['Close'],
                      metrics4,
                      'Price',
                      'Metrics',
                      title=title,
                      saveFig=True,
                      filename=filename)

    ao_dict.pop('pm')

    return ao_dict
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 composite_index(data: dict,
                    sectors: list,
                    index_dict: dict,
                    plot_output=True,
                    bond_type='Treasury',
                    index_type='BND',
                    **kwargs):
    """Composite Index

    Arguments:
        data {dict} -- Data of composites
        sectors {list} -- sector list
        index_dict {dict} -- data pulled from sectors.json file (can be None)

    Keyword Arguments:
        plot_output {bool} -- (default: {True})
        bond_type {str} -- (default: {'Treasury'})
        index_type {str} -- (default: {'BND'})

    Optional Args:
        clock {uint64_t} -- timekeeping for prog_bar (default: {None})

    Returns:
        list -- composite signal, plots, dates
    """
    clock = kwargs.get('clock')

    progress = len(sectors) + 2
    p = ProgressBar(
        progress, name=f'{bond_type} Bond Composite Index', offset=clock)
    p.start()

    composite = []
    for tick in sectors:
        if tick != index_type:
            cluster = cluster_oscs(
                data[tick], plot_output=False, function='market', wma=False)
            graph = cluster['tabular']
            p.uptick()
            composite.append(graph)

    composite2 = []
    for i in range(len(composite[0])):
        s = 0.0
        for j in range(len(composite)):
            s += float(composite[j][i])

        composite2.append(s)
    p.uptick()

    composite2 = windowed_moving_avg(composite2, 3, data_type='list')
    max_ = np.max(np.abs(composite2))
    composite2 = [x / max_ for x in composite2]

    key = list(data.keys())[0]
    data_to_plot = bond_type_index_generator(
        data, index_dict, bond_type=bond_type)
    dates = dates_extractor_list(data[key])

    if plot_output:
        dual_plotting(data_to_plot, composite2, y1_label=index_type,
                      y2_label='BCI', title=f'{bond_type} Bond Composite Index')
    else:
        dual_plotting(data_to_plot, composite2,
                      y1_label=index_type, y2_label='BCI',
                      title=f'{bond_type} Bond Composite Index', x=dates,
                      saveFig=True, filename=f'{bond_type}_BCI.png')
    p.uptick()

    return composite2, data_to_plot, dates
Пример #27
0
def get_correlation(data: dict, sectors: list, **kwargs) -> dict:
    """Get Correlation

    Arguments:
        data {dict} -- downloaded data
        sectors {list} -- sector list

    Optional Arguments:
        plot_output {bool} -- (default: {True})
        clock {uint64_t} -- time for prog_bar (default: {None})

    Returns:
        dict -- object with correlations
    """
    plot_output = kwargs.get('plot_output', True)
    clock = kwargs.get('clock')

    PERIOD_LENGTH = [100, 50, 25]
    corr_data = dict()

    if '^GSPC' in data.keys():
        tot_len = len(data['^GSPC']['Close'])
        start_pt = max(PERIOD_LENGTH)

        tot_count = (tot_len - start_pt) * 11 * len(PERIOD_LENGTH)
        if tot_count < 25000:
            divisor = 50
        else:
            divisor = 250
        pbar_count = np.ceil(tot_count / float(divisor))

        progress_bar = ProgressBar(pbar_count,
                                   name="Correlation Composite Index",
                                   offset=clock)
        progress_bar.start()

        corrs = {}
        dates = data['^GSPC'].index[start_pt:tot_len]
        net_correlation = []
        legend = []
        counter = 0

        for period in PERIOD_LENGTH:
            nc = [0.0] * (tot_len - start_pt)

            for sector in sectors:
                corrs[sector] = []

                for i in range(start_pt, tot_len):
                    _, rsqd = beta_comparison_list(
                        data[sector]['Close'][i - period:i],
                        data['^GSPC']['Close'][i - period:i])
                    corrs[sector].append(rsqd)
                    nc[i - start_pt] += rsqd
                    counter += 1

                    if counter == divisor:
                        progress_bar.uptick()
                        counter = 0

            net_correlation.append(nc.copy())
            legend.append('Corr-' + str(period))

        norm_corr = []
        for nc_period in net_correlation:
            max_ = np.max(nc_period)
            norm = [x / max_ for x in nc_period]
            norm_corr.append(norm)

        net_correlation = norm_corr.copy()

        dual_plotting(net_correlation,
                      data['^GSPC']['Close'][start_pt:tot_len],
                      x=dates,
                      y1_label=legend,
                      y2_label='S&P500',
                      title='CCI Net Correlation',
                      saveFig=(not plot_output),
                      filename='CCI_net_correlation.png')

        str_dates = []
        for date in dates:
            str_dates.append(date.strftime("%Y-%m-%d"))

        corr_data['tabular'] = {}
        for i, nc_period in enumerate(net_correlation):
            corr_data[legend[i]] = {}
            corr_data[legend[i]]['data'] = nc_period.copy()
            corr_data[legend[i]]['date'] = str_dates.copy()
            corr_data['tabular'][legend[i]] = nc_period.copy()

        corr_data['tabular']['date'] = str_dates.copy()
        progress_bar.end()

    return corr_data
Пример #28
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
Пример #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 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