rocketpoweryul / TradeTronic

1 stars 0 forks source link

DELL Sept-Dec 2023: Consolidation detection does not see excursion above the base #1

Closed rocketpoweryul closed 5 months ago

rocketpoweryul commented 5 months ago

Issue

Consolidation detection doesn't detect previous breakout.

Description

See image below. Detection logic doesn't see the excursion out of the base. This could be because no peaks occur during that excursion.

image

Root Cause

Detection logic isn't robust to excursions above a consolidation that do not create a peak, perhaps. This is still TBC.

Corrective Action

See future comments

rocketpoweryul commented 5 months ago

Discussion

The main issue seems to be that the peak at about 75$ is not being detected as a peak, only a swing high.

The alternative is to detect these excursions and disqualify the consolidation, however this does not solve the issue that this undetected peak could have been a new candidate for the left side of the consolidation.

The main logic at fault appears in filter_peaks function in the TATools module.

Detection of positive peaks is coded as such:

for i in range( 1, len(swing_highs) - 1 ):
    prev_swing_high_price = df.loc[swing_highs[i-1], 'High']
    curr_swing_high_price = df.loc[swing_highs[i  ], 'High']
    next_swing_high_price = df.loc[swing_highs[i+1], 'High']

# detect positive peak
if ( curr_swing_high_price > prev_swing_high_price ) and ( curr_swing_high_price > next_swing_high_price ):
    df.loc[swing_highs[i], 'Peak'] = 1

The undetected peak remains so because the next peak is higher. However it's quite clear it is a peak, and the information that can help us here is that the next swing low is lower than the previous swing high, which indicates a significant change in price direction, which is exactly what peak detection is for.

Note any mitigation likely needs to be inversely applied to detecting negative peaks.

Possible mitigation:

 # loop through swing highs, starting at the second occurrence and ending at 2nd last occurrence given the rules
    for i in range( 1, len(swing_highs) - 1 ):
        prev_swing_high_price = df.loc[swing_highs[i-1], 'High']
        curr_swing_high_price = df.loc[swing_highs[i  ], 'High']
        next_swing_high_price = df.loc[swing_highs[i+1], 'High']
        next_swing_low_price = df.loc[swing_lows[i+1], 'Low']

        # detect positive peak
        if ( curr_swing_high_price > prev_swing_high_price ) and \
           ( curr_swing_high_price > next_swing_high_price or prev_swing_high_price > next_swing_low_price):
            df.loc[swing_highs[i], 'Peak'] = 1

This code now checks that the next swing low undercuts the previous swing high.

Negative peak detection correction

Conversely, for troughs, or negative peaks, let's imagine the opposite scenario: image

Red arrows are peaks, hollow are swings.

The associated code is:

 # loop through swing lows, starting at the second occurrence and ending at 2nd last occurrence given the rules
    for i in range( 1, len(swing_lows) - 1 ):
        prev_swing_low_price  = df.loc[swing_lows[i-1], 'Low' ]
        curr_swing_low_price  = df.loc[swing_lows[i  ], 'Low' ]
        next_swing_low_price  = df.loc[swing_lows[i+1], 'Low' ]

        # detect negative peak
        if ( curr_swing_low_price < prev_swing_low_price ) and ( curr_swing_low_price < next_swing_low_price ):
            df.loc[swing_lows[i], 'Peak'] = -1

Corrected similarly to:

 # loop through swing lows, starting at the second occurrence and ending at 2nd last occurrence given the rules
    for i in range( 1, len(swing_lows) - 1 ):
        prev_swing_low_price  = df.loc[swing_lows[i-1], 'Low' ]
        curr_swing_low_price  = df.loc[swing_lows[i  ], 'Low' ]
        next_swing_low_price  = df.loc[swing_lows[i+1], 'Low' ]
        next_swing_high_price = df.loc[swing_highs[i+1], 'High']

        # detect negative peak
        if ( curr_swing_low_price < prev_swing_low_price ) and \
           ( curr_swing_low_price < next_swing_low_price or prev_swing_low_price < next_swing_high_price):
            df.loc[swing_lows[i], 'Peak'] = -1
rocketpoweryul commented 5 months ago

Solution works. Not exhaustively tested, though. image