rocketpoweryul / TradeTronic

1 stars 0 forks source link

Measure performance of stock against index #8

Closed rocketpoweryul closed 6 months ago

rocketpoweryul commented 6 months ago

Relative Strength Line and RSL New High Feature

Create a function that measures IBD style Relative Strength Line, which is computed as:

RSL = Symbol.Close / Index.Close

For plotting IBD style it will require some formatting or use of multiple y-axes so they can both show on the same chart pane.

Work scope:

rocketpoweryul commented 6 months ago

References:

rocketpoweryul commented 6 months ago

Corrective Action

Proposed function for determining RSL and new highs:

def add_relative_strength_line(df, index="S&P500", new_high_bars=69):
    # Ensure df.index is a DatetimeIndex for proper diff calculation
    if not isinstance(df.index, pd.DatetimeIndex):
        raise TypeError("Index of df must be a pandas DatetimeIndex.")

    # Determine period of input stock data in df
    date_diff = df.index.to_series().diff().dt.days
    min_date_diff = date_diff.min()

    # Map minimum date difference to interval
    if min_date_diff == 1:
        interval = 'D'
    elif min_date_diff == 7:
        interval = 'W'
    elif min_date_diff >= 30:
        interval = 'M'
    else:
        raise ValueError("Invalid frequency: {}. Please choose daily (1 day), weekly (7 days), or monthly (30+ days).".format(min_date_diff))

    # Get the index symbol based on the input
    index_symbol_map = {"S&P500": "$SPX", "NASDAQ": "$COMP", "DJIA": "$DJI"}
    index_symbol = index_symbol_map.get(index)
    if index_symbol is None:
        raise ValueError("Invalid index specified: '{}'. Please choose from S&P500, NASDAQ, or DJIA.".format(index))

    # Fetch OHLCV data for the index
    index_df = fetch_OHLCV(symbol=index_symbol, numbars=len(df), interval=interval)

    # Update the dataframe with RSL and RSL new high data
    df['RSL'] = df['Close'] / index_df['Close']
    # Calculate new highs over the specified period using a rolling window
    df['RSL_NH'] = df['RSL'] > df['RSL'].rolling(window=new_high_bars, min_periods=new_high_bars).max().shift(1)

    return df
rocketpoweryul commented 6 months ago

This was added to Launch_GUI function at line 165. This plots the RS Line, such that it is about 20% under the last low price:

# Handling RSL scaling to ensure it is 10% below the last Low value on the last bar
    if 'RSL' in df.columns and df['RSL'].notna().any():
        last_low = df['Low'].iloc[-1]
        last_rsl = df['RSL'].iloc[-1]
        desired_rsl_position = last_low * 0.8
        rsl_scale_factor = desired_rsl_position / last_rsl
        scaled_rsl = df['RSL'] * rsl_scale_factor
        p.line(df.index, scaled_rsl, line_width=1, color='blue', legend_label='RSL')
rocketpoweryul commented 6 months ago

This was added starting at line 174 of Launch_GUI

# Plotting dots at RSL New Highs using scatter, with color conditional on Consol_Detected
    if 'RSL_NH' in df.columns and df['RSL_NH'].any():
        # Extract indices and values where RSL_NH is true
        nh_indices = df.index[df['RSL_NH']].tolist()
        nh_values = scaled_rsl[df['RSL_NH']]

        # Determine color based on Consol_Detected
        colors = ['cyan' if consol else 'lightblue' for consol in df.loc[df['RSL_NH'], 'Consol_Detected']]

        size = [10 if consol else 7 for consol in df.loc[df['RSL_NH'], 'Consol_Detected']]

        nh_source = ColumnDataSource(data={
            'x': nh_indices,
            'y': nh_values,
            'color': colors,  # Adding a color field to the data source
            'size': size
        })
        p.scatter('x', 'y', size='size', color='color', alpha=0.8, source=nh_source)  # Use the color field for the color property

Seem to work as intended so far, so closing the issue. image

Note, that RSL New Highs while consolidating are shown in a larger circles in cyan, while the RSL New Highs not during a consolidation are light blue and smaller.