示例#1
0
def cluster_dates(cluster_list: list, fund: pd.DataFrame) -> list:
    """ Adds non-zero cluster values with date, price, and index """
    dates = []
    for i in range(len(cluster_list)):
        if cluster_list[i] != 0:
            dates.append([date_extractor(fund.index[i], _format='str'),
                          fund['Close'][i], cluster_list[i], i])
    return dates
def add_daterange(original: pd.DataFrame, extrema: dict,
                  num_feature_points: int) -> dict:
    """ Add Date Range

    Looks at index ranges of 'extrema' and adds actual dates from 'original' to 'extrema'

    Arguments:
        original {pd.DataFrame} -- fund dataset
        extrema {dict} -- extrema data object
        num_feature_points {int} -- selectable number of points to add dates

    Returns:
        dict -- extrema data object
    """
    for feat in extrema['features']:
        if feat:
            first_ind = feat['indexes'][0][0]
            last_ind = feat['indexes'][num_feature_points - 1][0]
            start = date_extractor(original.index[first_ind], _format='str')
            end = date_extractor(original.index[last_ind], _format='str')
            feat['daterange'] = start + ' : ' + end

    return extrema
示例#3
0
def period_strength(fund_name: str, tickers: dict, periods: list,
                    **kwargs) -> list:
    """Period Strength

    Try to provide ratio evaluations of 'fund' vs. market and sector. Update utilizes sectors.json
    file to pull information.

    Arguments:
        fund_name {str} -- 'MSFT', for example
        tickers {dict} -- entire downloaded data object
        periods {list} - list of lookback periods

    Optional Args:
        sector {str} -- name of sector, 'VGT' for Tech, for example (default: {''})
        sector_data {pd.DataFrame} -- data of sector (default: {None})

    Returns:
        list -- list of ratio data objects
    """
    sector = kwargs.get('sector', '')
    sector_data = kwargs.get('sector_data')

    ratio = []
    hasSP = False
    hasSector = False

    sp = get_SP500_df(tickers)
    if sp is not None:
        hasSP = True
    if sector != '':
        if sector_data is not None:
            sec = sector_data
            hasSector = True

    fund = tickers[fund_name]

    for period in periods:
        entry = {}

        entry['period'] = period
        entry['dates'] = date_extractor(fund.index[len(fund.index)-period], _format='str') + \
            " : " + \
            date_extractor(fund.index[len(fund.index)-1], _format='str')

        if hasSP:
            entry['sp500'] = {}

            sp_temp = list(sp['Adj Close'])
            sp_temp = sp_temp[len(sp_temp) - period:len(sp_temp) + 1]

            f_temp = list(fund['Adj Close'])
            f_temp = f_temp[len(f_temp) - period:len(f_temp) + 1]

            rat = normalized_ratio(f_temp, sp_temp, data_type='list')

            entry['sp500']['avg'] = np.round(np.mean(rat), 6)
            entry['sp500']['stdev'] = np.round(np.std(rat), 6)
            entry['sp500']['min'] = np.min(rat)
            entry['sp500']['max'] = np.max(rat)
            entry['sp500']['current'] = rat[-1]

        if hasSector:
            entry['sector'] = {}
            entry['sector']['name'] = sector

            sp_temp = list(sec['Adj Close'])
            sp_temp = sp_temp[len(sp_temp) - period:len(sp_temp) + 1]

            f_temp = list(fund['Adj Close'])
            f_temp = f_temp[len(f_temp) - period:len(f_temp) + 1]

            rat = normalized_ratio(f_temp, sp_temp, data_type='list')

            entry['sector']['avg'] = np.round(np.mean(rat), 6)
            entry['sector']['stdev'] = np.round(np.std(rat), 6)
            entry['sector']['min'] = np.min(rat)
            entry['sector']['max'] = np.max(rat)
            entry['sector']['current'] = rat[-1]

        ratio.append(entry)

    return ratio
示例#4
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
示例#5
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
示例#6
0
def determine_rsi_swing_rejection(position: pd.DataFrame, rsi_data: dict,
                                  **kwargs) -> dict:
    """ Find bullish / bearish and RSI indicators

    1. go beyond threshold
    2. go back within thresholds
    3. have local minima/maxima inside thresholds
    4. exceed max/min (bull/bear) of previous maxima/minima

    Arguments:
        position {pd.DataFrame} -- fund data
        rsi_signal {list} -- pure RSI signal
        rsi_data {dict} -- RSI data object

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

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

    thresholds = rsi_data['thresholds']
    rsi_signal = rsi_data['tabular']

    if thresholds is None:
        thresholds = dict()
        thresholds['oversold'] = [30.0] * len(position['Close'])
        thresholds['overbought'] = [70.0] * len(position['Close'])

    LOW_TH = thresholds['oversold']
    HIGH_TH = thresholds['overbought']

    rsi_data['bullish'] = []
    rsi_data['bearish'] = []
    indicator = []

    increment = 0.2 / float(len(rsi_signal))

    state = 0
    minima = 0.0
    maxima = 0.0
    for i in range(len(rsi_signal)):

        if (state == 0) and (rsi_signal[i] <= LOW_TH[i]):
            # Start of a bullish signal
            state = 1
            indicator.append(0.0)

        elif (state == 1) and (rsi_signal[i] > LOW_TH[i]):
            state = 2
            maxima = rsi_signal[i]
            indicator.append(0.0)

        elif (state == 2):
            if rsi_signal[i] >= maxima:
                if rsi_signal[i] >= HIGH_TH[i]:
                    state = 5
                else:
                    maxima = rsi_signal[i]
            else:
                minima = rsi_signal[i]
                state = 3
            indicator.append(0.0)

        elif (state == 3):
            if rsi_signal[i] <= LOW_TH[i]:
                # Failed attempted breakout
                state = 1
            elif rsi_signal[i] <= minima:
                minima = rsi_signal[i]
            else:
                state = 4
            indicator.append(0.0)

        elif (state == 4):
            if rsi_signal[i] > maxima:
                # Have found a bullish breakout!
                rsi_data['bullish'].append([
                    date_extractor(position.index[i], _format='str'),
                    position['Close'][i], i, "swing rejection"
                ])
                state = 0
                minima = 0.0
                maxima = 0.0
                indicator.append(1.0)
            else:
                if rsi_signal[i] <= LOW_TH[i]:
                    state = 1
                indicator.append(0.0)

        elif (state == 0) and (rsi_signal[i] >= HIGH_TH[i]):
            state = 5
            indicator.append(0.0)

        elif (state == 5) and (rsi_signal[i] < HIGH_TH[i]):
            state = 6
            minima = rsi_signal[i]
            indicator.append(0.0)

        elif (state == 6):
            if rsi_signal[i] <= minima:
                if rsi_signal[i] <= LOW_TH[i]:
                    state = 1
                else:
                    minima = rsi_signal[i]
            else:
                maxima = rsi_signal[i]
                state = 7
            indicator.append(0.0)

        elif (state == 7):
            if rsi_signal[i] >= HIGH_TH[i]:
                # Failed attempted breakout
                state = 5
            elif rsi_signal[i] >= maxima:
                maxima = rsi_signal[i]
            else:
                state = 8
            indicator.append(0.0)

        elif (state == 8):
            if rsi_signal[i] < minima:
                rsi_data['bearish'].append([
                    date_extractor(position.index[i], _format='str'),
                    position['Close'][i], i, "swing rejection"
                ])
                state = 0
                minima = 0.0
                maxima = 0.0
                indicator.append(-1.0)
            else:
                if rsi_signal[i] >= HIGH_TH[i]:
                    state = 5
                indicator.append(0.0)

        else:
            indicator.append(0.0)

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

    rsi_data['indicator'] = indicator

    return rsi_data
示例#7
0
def get_stoch_divergences(position: pd.DataFrame, full_stoch: dict,
                          **kwargs) -> dict:
    """Get Stoch Divergences

    Arguments:
        position {pd.DataFrame} -- dataset
        full_stoch {dict} -- stoch data object

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

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

    OVER_BOUGHT = 80.0
    OVER_SOLD = 20.0

    fast_k = full_stoch['tabular']['fast_k']
    state = 'n'

    # Look for divergences + fast_k at 50
    prices = [0.0, 0.0]
    s_vals = [0.0, 0.0]
    for i, fast in enumerate(fast_k):

        # Bearish divergences
        if (state == 'n') and fast >= OVER_BOUGHT:
            state = 'b1'
            s_vals[0] = fast

        elif state == 'b1':
            if fast < s_vals[0]:
                prices[0] = position['Close'][i]
                state = 'b2'
            else:
                s_vals[0] = fast

        elif state == 'b2':
            if fast < OVER_BOUGHT:
                state = 'b3'
                s_vals[1] = fast
            elif fast > s_vals[0]:
                s_vals[0] = fast
                state = 'b1'

        elif state == 'b3':
            if fast > s_vals[1]:
                state = 'b4'
                s_vals[1] = fast
            else:
                s_vals[1] = fast

        elif state == 'b4':
            if fast < s_vals[1]:
                prices[1] = position['Close'][i - 1]
                if (prices[0] < prices[1]) and (s_vals[0] > s_vals[1]):
                    full_stoch['bearish'].append([
                        date_extractor(position.index[i], _format='str'),
                        position['Close'][i - 1], i, "divergence"
                    ])
                    full_stoch['indicator'][i] += -1.5
                    state = 'n'
                else:
                    state = 'n'
            else:
                s_vals[1] = fast
                if s_vals[1] > s_vals[0]:
                    s_vals[0] = fast
                    state = 'b1'

        # Bullish divergences
        elif (state == 'n') and fast <= OVER_SOLD:
            state = 's1'
            s_vals[0] = fast

        elif state == 's1':
            if fast > s_vals[0]:
                prices[0] = position['Close'][i]
                state = 's2'
            else:
                s_vals[0] = fast

        elif state == 's2':
            if fast > OVER_SOLD:
                state = 's3'
                s_vals[1] = fast
            elif fast < s_vals[0]:
                s_vals[0] = fast
                state = 's1'

        elif state == 's3':
            if fast < s_vals[1]:
                state = 's4'
                s_vals[1] = fast
            else:
                s_vals[1] = fast

        elif state == 's4':
            if fast > s_vals[1]:
                prices[1] = position['Close'][i - 1]
                if (prices[0] > prices[1]) and (s_vals[0] < s_vals[1]):
                    full_stoch['bullish'].append([
                        date_extractor(position.index[i], _format='str'),
                        position['Close'][i - 1], i, "divergence"
                    ])
                    full_stoch['indicator'][i] += 1.5
                    state = 'n'
                else:
                    state = 'n'
            else:
                s_vals[1] = fast
                if s_vals[1] < s_vals[0]:
                    s_vals[0] = fast
                    state = 's1'

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

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

        if plot_output:
            dual_plotting(position['Close'],
                          full_stoch['indicator'],
                          'Position Price',
                          'Oscillator Signal',
                          title=name2)

        else:
            filename = os.path.join(name, view, f"stochastic_{name}.png")
            dual_plotting(position['Close'],
                          full_stoch['indicator'],
                          'Position Price',
                          'Stochastic Oscillator',
                          x_label='Trading Days',
                          title=name2,
                          saveFig=True,
                          filename=filename)

    return full_stoch
示例#8
0
def get_crossover_features(position: pd.DataFrame, full_stoch: dict,
                           **kwargs) -> dict:
    """Get Crossover Features

    Look for a %K cross over %d (fast) then cross inside the 80/20 bars.
    Look for a slow %K cross over slow %d then cross inside the 80/20 bars.

    Arguments:
        position {pd.DataFrame} -- dataset
        full_stoch {dict} -- full stochastic object

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

    Returns:
        dict -- full stochastic object
    """
    p_bar = kwargs.get('p_bar')

    OVER_BOUGHT = 80.0
    OVER_SOLD = 20.0

    fast_k = full_stoch['tabular']['fast_k']
    smooth_k = full_stoch['tabular']['smooth_k']
    d_sma = full_stoch['tabular']['slow_d']

    bearish = []
    bullish = []
    stochastic = [0.0] * (len(fast_k))
    state = 'n'

    # Look at crossovers and over-X positions of fast_k & smooth_k
    for i, fast in enumerate(fast_k):

        # Bearish / overbought signaling
        if (state == 'n') and (fast >= OVER_BOUGHT):
            state = 'b1'

        elif (state == 'b1'):
            if (fast >= OVER_BOUGHT):
                if (smooth_k[i] >= OVER_BOUGHT):
                    state = 'b2'
            else:
                state = 'n'

        elif (state == 'b2') and (fast < smooth_k[i]):
            state = 'b3'

        elif (state == 'b3'):
            if (fast < OVER_BOUGHT):
                bearish.append([
                    date_extractor(position.index[i], _format='str'),
                    position['Close'][i], i, "crossover: fast-k/smooth-k"
                ])
                stochastic[i] += -1.0
                state = 'n'

        # Bullish / oversold signaling
        elif (state == 'n') and (fast <= OVER_SOLD):
            state = 's1'

        elif (state == 's1'):
            if (fast <= OVER_SOLD):
                if (smooth_k[i] <= OVER_SOLD):
                    state = 's2'
            else:
                state = 'n'

        elif (state == 's2') and (fast > smooth_k[i]):
            state = 's3'

        elif (state == 's3'):
            if (fast > OVER_SOLD):
                bullish.append([
                    date_extractor(position.index[i], _format='str'),
                    position['Close'][i], i, "crossover: fast-k/smooth-k"
                ])
                stochastic[i] += 1.0
                state = 'n'

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

    # Look at crossovers and over-X positions of smooth_k & slow_d
    state = 'n'
    for i, slow in enumerate(smooth_k):

        # Bearish / overbought signaling
        if (state == 'n') and (slow >= OVER_BOUGHT):
            state = 'b1'

        elif (state == 'b1'):
            if (slow >= OVER_BOUGHT):
                if (d_sma[i] >= OVER_BOUGHT):
                    state = 'b2'
            else:
                state = 'n'

        elif (state == 'b2') and (slow < d_sma[i]):
            state = 'b3'

        elif (state == 'b3'):
            if (slow < OVER_BOUGHT):
                bearish.append([
                    date_extractor(position.index[i], _format='str'),
                    position['Close'][i], i, "crossover: smooth-k/slow-d"
                ])
                stochastic[i] += -1.0
                state = 'n'

        # Bullish / oversold signaling
        elif (state == 'n') and (slow <= OVER_SOLD):
            state = 's1'

        elif (state == 's1'):
            if (slow <= OVER_SOLD):
                if (d_sma[i] <= OVER_SOLD):
                    state = 's2'
            else:
                state = 'n'

        elif (state == 's2') and (slow > d_sma[i]):
            state = 's3'

        elif (state == 's3'):
            if (slow > OVER_SOLD):
                bullish.append([
                    date_extractor(position.index[i], _format='str'),
                    position['Close'][i], i, "crossover: smooth-k/slow-d"
                ])
                stochastic[i] += 1.0
                state = 'n'

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

    full_stoch['indicator'] = stochastic
    full_stoch['bullish'] = bullish
    full_stoch['bearish'] = bearish

    return full_stoch
示例#9
0
def find_ult_osc_features(position: pd.DataFrame, ultimate: dict,
                          **kwargs) -> list:
    """Find Ultimate Oscilator Features 

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

    Optional Args:
        thresh_low {int} -- oversold signal threshold (default: {30})
        thresh_high {int} -- overbought signal threshold (default: {70})
        p_bar {ProgressBar} -- (default: {None})

    Returns:
        dict -- ultimate osc data object
    """
    p_bar = kwargs.get('p_bar')
    LOW_TH = kwargs.get('thresh_low', 30)
    HIGH_TH = kwargs.get('thresh_high', 70)

    ult_osc = ultimate['tabular']

    trigger = []
    marker_val = 0.0
    marker_ind = 0

    for i, close in enumerate(position['Close']):

        # Find bullish signal
        if ult_osc[i] < LOW_TH:
            ult1 = ult_osc[i]
            marker_val = close
            marker_ind = i
            lows = lower_low(position['Close'], marker_val, marker_ind)

            if len(lows) != 0:
                ult2 = ult_osc[lows[-1][1]]

                if ult2 > ult1:
                    start_ind = lows[-1][1]
                    interval = np.max(ult_osc[i:start_ind + 1])
                    start_ind = bull_bear_th(ult_osc,
                                             start_ind,
                                             interval,
                                             bull_bear='bull')

                    if start_ind is not None:
                        trigger.append([
                            "BULLISH",
                            date_extractor(position.index[start_ind],
                                           _format='str'),
                            position['Close'][start_ind], start_ind,
                            "divergence (original)"
                        ])

        # Find bearish signal
        if ult_osc[i] > HIGH_TH:
            ult1 = ult_osc[i]
            marker_val = position['Close'][i]
            marker_ind = i
            highs = higher_high(position['Close'], marker_val, marker_ind)

            if len(highs) != 0:
                ult2 = ult_osc[highs[-1][1]]

                if ult2 < ult1:
                    start_ind = highs[-1][1]
                    interval = np.min(ult_osc[i:start_ind + 1])
                    start_ind = bull_bear_th(ult_osc,
                                             start_ind,
                                             interval,
                                             bull_bear='bear')

                    if start_ind is not None:
                        trigger.append([
                            "BEARISH",
                            date_extractor(position.index[start_ind],
                                           _format='str'),
                            position['Close'][start_ind], start_ind,
                            "divergence (original)"
                        ])

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

    state = 'n'
    prices = [0.0, 0.0]
    ults = [0.0, 0.0, 0.0]

    for i, ult in enumerate(ult_osc):

        # Find bullish divergence and breakout
        if (state == 'n') and (ult <= LOW_TH):
            state = 'u1'
            ults[0] = ult

        elif state == 'u1':
            if ult < ults[0]:
                ults[0] = ult
            else:
                prices[0] = position['Close'][i - 1]
                state = 'u2'

        elif (state == 'u2') and (ult > LOW_TH):
            state = 'u3'
            ults[1] = ult

        elif state == 'u3':
            if ult > ults[1]:
                ults[1] = ult
            else:
                # we think we've found a divergent high
                state = 'u4'
                ults[2] = ult

        elif state == 'u4':
            if ults[2] >= ult:
                ults[2] = ult
            else:
                # We think we've found the bullish 2nd low
                prices[1] = position['Close'][i - 1]
                state == 'u5'

        elif state == 'u5':
            if ult > ults[1]:
                if prices[0] > prices[1]:
                    # Bullish breakout!
                    trigger.append([
                        "BULLISH",
                        date_extractor(position.index[start_ind],
                                       _format='str'),
                        position['Close'][start_ind], start_ind, "divergence"
                    ])
                    state = 'n'
                else:
                    # False breakout, see if this is the new max:
                    state = 'u3'
                    ults[1] = ult

            elif ult < ults[2]:
                # There may have been a false signal
                ults[2] = ult
                state = 'u4'

        # Find bullish divergence and breakout
        if (state == 'n') and (ult >= HIGH_TH):
            state = 'e1'
            ults[0] = ult

        elif state == 'e1':
            if ult > ults[0]:
                ults[0] = ult
            else:
                prices[0] = position['Close'][i - 1]
                state = 'e2'

        elif (state == 'e2') and (ult < HIGH_TH):
            state = 'e3'
            ults[1] = ult

        elif state == 'e3':
            if ult < ults[1]:
                ults[1] = ult
            else:
                # we think we've found a divergent low
                state = 'e4'
                ults[2] = ult

        elif state == 'e4':
            if ults[2] <= ult:
                ults[2] = ult
            else:
                # We think we've found the bullish 2nd high
                prices[1] = position['Close'][i - 1]
                state == 'e5'

        elif state == 'e5':
            if ult < ults[1]:
                if prices[0] < prices[1]:
                    # Bullish breakout!
                    trigger.append([
                        "BEARISH",
                        date_extractor(position.index[start_ind],
                                       _format='str'),
                        position['Close'][start_ind], start_ind, "divergence"
                    ])
                    state = 'n'
                else:
                    # False breakout, see if this is the new max:
                    state = 'e3'
                    ults[1] = ult

            elif ult > ults[2]:
                # There may have been a false signal
                ults[2] = ult
                state = 'e4'

        elif ult >= HIGH_TH:
            state = 'e1'
            ults[0] = ult

        elif ult <= LOW_TH:
            state = 'u1'
            ults[0] = ult

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

    ultimate['indicator'] = trigger

    return ultimate