示例#1
0
def generate_analysis(fund: pd.DataFrame, x_list: list, y_list: list,
                      len_list: list, color_list: list) -> list:
    """Generate Analysis

    Arguments:
        fund {pd.DataFrame} -- fund dataset
        x_list {list} -- list of x-value lists
        y_list {list} -- list of y-value lists
        len_list {list} -- list of trendline lengths
        color_list {list} -- list of colors, associated with each trendline

    Returns:
        list -- list of analysis data objects
    """
    analysis = []

    for i, x in enumerate(x_list):
        sub = {}
        sub['length'] = len(x)
        sub['color'] = color_list[i]

        reg = linregress(x[0:3], y=y_list[i][0:3])
        sub['slope'] = reg[0]
        sub['intercept'] = reg[1]

        sub['start'] = {}
        sub['start']['index'] = x[0]
        sub['start']['date'] = fund.index[x[0]].strftime("%Y-%m-%d")

        sub['end'] = {}
        sub['end']['index'] = x[len(x) - 1]
        sub['end']['date'] = fund.index[x[len(x) - 1]].strftime("%Y-%m-%d")

        sub['term'] = len_list[i]
        if sub['slope'] < 0:
            sub['type'] = 'bear'
        else:
            sub['type'] = 'bull'

        sub['x'] = {}
        sub['x']['by_date'] = dates_convert_from_index(fund, [x], to_str=True)
        sub['x']['by_index'] = x

        if sub['end']['index'] == len(fund['Close']) - 1:
            sub['current'] = True
        else:
            sub['current'] = False

        sub = attribute_analysis(fund, x, y_list[i], sub)

        analysis.append(sub)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    analysis['type'] = 'trend'

    return analysis
示例#3
0
def get_trendlines(fund: pd.DataFrame, **kwargs) -> dict:
    """Get Trendlines

    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})
        interval {list} -- list of windowed filter time periods (default: {[4, 8, 16, 32]})
        progress_bar {ProgressBar} -- (default: {None})
        sub_name {str} -- file extension within 'name' directory (default: {name})
        view {str} -- directory of plots (default: {''})
        meta {dict} -- 'metadata' object for fund (default: {None})
        out_suppress {bool} -- if True, skips plotting (default: {False})
        trend_window {list} -- line time windows (default: {[163, 91, 56, 27]})

    Returns:
        trends {dict} -- contains all trend lines determined by algorithm
    """
    name = kwargs.get('name', '')
    plot_output = kwargs.get('plot_output', True)
    interval = kwargs.get('interval', [4, 8, 16, 32])
    progress_bar = kwargs.get('progress_bar', None)
    sub_name = kwargs.get('sub_name', f"trendline_{name}")
    view = kwargs.get('view', '')
    meta = kwargs.get('meta')
    out_suppress = kwargs.get('out_suppress', False)
    trend_window = kwargs.get('trend_window', [163, 91, 56, 27])

    # Not ideal to ignore warnings, but these are handled already by scipy/numpy so... eh...
    warnings.filterwarnings("ignore", category=RuntimeWarning)

    trends = dict()

    mins_y = []
    mins_x = []
    maxes_y = []
    maxes_x = []
    all_x = []

    vq = 0.06
    if meta is not None:
        vol = meta.get('volatility', {}).get('VQ')
        if vol is not None:
            vq = vol / 100.0

    increment = 0.7 / (float(len(interval)) * 3)

    for i, period in enumerate(interval):
        ma_size = period

        # ma = windowed_ma_list(fund['Close'], interval=ma_size)
        weight_strength = 2.0 + (0.1 * float(i))
        ma = windowed_moving_avg(fund['Close'],
                                 interval=ma_size,
                                 weight_strength=weight_strength,
                                 data_type='list',
                                 filter_type='exponential')
        ex = find_filtered_local_extrema(ma)
        r = reconstruct_extrema(fund,
                                extrema=ex,
                                ma_size=ma_size,
                                ma_type='windowed')

        # Cleanse data sample for duplicates and errors
        r = remove_duplicates(r, method='point')

        for y in r['min']:
            if y[0] not in mins_x:
                mins_x.append(y[0])
                mins_y.append(y[1])
            if y[0] not in all_x:
                all_x.append(y[0])
        for y in r['max']:
            if y[0] not in maxes_x:
                maxes_x.append(y[0])
                maxes_y.append(y[1])
            if y[0] not in all_x:
                all_x.append(y[0])

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

    zipped_min = list(zip(mins_x, mins_y))
    zipped_min.sort(key=lambda x: x[0])
    mins_x = [x[0] for x in zipped_min]
    mins_y = [y[1] for y in zipped_min]

    zipped_max = list(zip(maxes_x, maxes_y))
    zipped_max.sort(key=lambda x: x[0])
    maxes_x = [x[0] for x in zipped_max]
    maxes_y = [y[1] for y in zipped_max]

    # mins_xd = [fund.index[x] for x in mins_x]
    # maxes_xd = [fund.index[x] for x in maxes_x]

    long_term = trend_window[0]
    intermediate_term = trend_window[1]
    short_term = trend_window[2]
    near_term = trend_window[3]

    X0, Y0 = get_lines_from_period(fund,
                                   [mins_x, mins_y, maxes_x, maxes_y, all_x],
                                   interval=long_term,
                                   vq=vq)
    X1, Y1 = get_lines_from_period(fund,
                                   [mins_x, mins_y, maxes_x, maxes_y, all_x],
                                   interval=intermediate_term,
                                   vq=vq)
    X2, Y2 = get_lines_from_period(fund,
                                   [mins_x, mins_y, maxes_x, maxes_y, all_x],
                                   interval=short_term,
                                   vq=vq)
    X3, Y3 = get_lines_from_period(fund,
                                   [mins_x, mins_y, maxes_x, maxes_y, all_x],
                                   interval=near_term,
                                   vq=vq)

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

    X = []
    Y = []
    C = []
    L = []

    for i, x in enumerate(X0):
        X.append(x)
        Y.append(Y0[i])
        C.append('blue')
        L.append('long')

    for i, x in enumerate(X1):
        X.append(x)
        Y.append(Y1[i])
        C.append('green')
        L.append('intermediate')

    for i, x in enumerate(X2):
        X.append(x)
        Y.append(Y2[i])
        C.append('orange')
        L.append('short')

    for i, x in enumerate(X3):
        X.append(x)
        Y.append(Y3[i])
        C.append('red')
        L.append('near')

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

    analysis_list = generate_analysis(fund,
                                      x_list=X,
                                      y_list=Y,
                                      len_list=L,
                                      color_list=C)

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

    X = dates_convert_from_index(fund, X)

    X.append(fund.index)
    Y.append(fund['Close'])
    C.append('black')

    name2 = INDEXES.get(name, name)

    if not out_suppress:
        try:
            title = f"{name2} Trend Lines for {near_term}, {short_term}, " + \
                f"{intermediate_term}, and {long_term} Periods"
            if plot_output:
                generic_plotting(Y, x=X, colors=C, title=title)
            else:
                filename = os.path.join(name, view, f"{sub_name}.png")
                generic_plotting(Y,
                                 x=X,
                                 colors=C,
                                 title=title,
                                 saveFig=True,
                                 filename=filename)

        except:
            print(
                f"{WARNING}Warning: plot failed to generate in trends.get_trendlines.{NORMAL}"
            )

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

    trends['trendlines'] = analysis_list

    current = []
    metrics = []

    for trend in analysis_list:
        if trend['current']:
            current.append(trend)
            met = {f"{trend.get('term')} term": trend.get('type')}
            met['periods'] = trend.get('length')
            metrics.append(met)

    trends['current'] = current
    trends['metrics'] = metrics
    trends['type'] = 'trend'

    return trends