Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Candle pattern 'Shooting Star' is not detected #647

Open
Tzion opened this issue May 7, 2024 · 5 comments
Open

Candle pattern 'Shooting Star' is not detected #647

Tzion opened this issue May 7, 2024 · 5 comments

Comments

@Tzion
Copy link

Tzion commented May 7, 2024

The pattern 'shooting star' is not detected on sample data (talib.CDLSHOOTINGSTAR)

Here is a test file to reproduce it - you can run it directly and see the plot printed to the screen.
The shooting star candle is the second from the end.

You can run this simple python file and see that there's no detection and the pattern on the chart:

import unittest
import talib
import numpy as np
import pandas as pd
import pandas_ta as pta

import mplfinance as mpf
import pandas as pd

def plot_candles_simple(candles):
    df = pd.DataFrame(candles)

    # Convert the index to a datetime index (required by mplfinance)
    if df.index.dtype != 'datetime64[ns]':
        df.index = pd.date_range(start=pd.Timestamp.today().strftime('%Y-%m-%d'), periods=len(df))

    mpf.plot(df, type='candle', style='charles', title='Candlestick Chart', ylabel='Price')

class TestgCandlesRegocnition(unittest.TestCase):

    def verify_pattern(self, pattern_func, candles, detection_idx=-1, force_chart=False, **pattern_func_args):
        open_prices = pd.Series(candles['open'])
        high_prices = pd.Series(candles['high'])
        low_prices = pd.Series(candles['low'])
        close_prices = pd.Series(candles['close'])
        pattern_detection = pattern_func(open_prices, high_prices, low_prices, close_prices, **pattern_func_args)
        last_candle_detection = pattern_detection.iloc[detection_idx] != 0

        if not last_candle_detection:
            plot_candles_simple(candles)
            self.fail("Pattern was not detected")
            print(pattern_detection)
        if force_chart:
            plot_candles_simple(candles)


    def test_shooting_star(self):
        candles = {
            'open': [8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 7.9, 8.2, 9.4, 9],
            'high': [8.8, 8.8, 8.8, 8.8, 8.8, 8.8, 8.8, 8.8, 9.0, 9.0, 11.9, 9.0],
            'low': [7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.8, 7.9, 9.2, 8.0],
            'close': [8.5, 8.7, 8.7, 8.7, 8.7, 8.7, 8.7, 8.7, 8.1, 9.0, 9.2, 8.0]
        }
        self.verify_pattern(talib.CDLSHOOTINGSTAR, candles, detection_idx=-2)

if __name__ == '__main__':
    unittest.main()

This is the chart:
image

I followed and made sure that the definition of my candles are correct according to the documentation in the C source code of the Shooting star pattern:

   /* Proceed with the calculation for the requested range.
    * Must have:
    * - small real body
    * - long upper shadow
    * - no, or very short, lower shadow
    * - gap up from prior real body
    * The meaning of "short", "very short" and "long" is specified with TA_SetCandleSettings;
    * outInteger is negative (-1 to -100): shooting star is always bearish;
    * the user should consider that a shooting star must appear in an uptrend, while this function does not consider it
    */
   outIdx = 0;

And I also made sure that the candles follows the default global definitions:

const TA_CandleSetting TA_CandleDefaultSettings[] = {
        /* real body is long when it's longer than the average of the 10 previous candles' real body */
        { TA_BodyLong, TA_RangeType_RealBody, 10, 1.0 },
        /* real body is very long when it's longer than 3 times the average of the 10 previous candles' real body */
        { TA_BodyVeryLong, TA_RangeType_RealBody, 10, 3.0 },
        /* real body is short when it's shorter than the average of the 10 previous candles' real bodies */
        { TA_BodyShort, TA_RangeType_RealBody, 10, 1.0 },
        /* real body is like doji's body when it's shorter than 10% the average of the 10 previous candles' high-low range */
        { TA_BodyDoji, TA_RangeType_HighLow, 10, 0.1 },
        /* shadow is long when it's longer than the real body */
        { TA_ShadowLong, TA_RangeType_RealBody, 0, 1.0 },
        /* shadow is very long when it's longer than 2 times the real body */
        { TA_ShadowVeryLong, TA_RangeType_RealBody, 0, 2.0 },
        /* shadow is short when it's shorter than half the average of the 10 previous candles' sum of shadows */
        { TA_ShadowShort, TA_RangeType_Shadows, 10, 1.0 },
        /* shadow is very short when it's shorter than 10% the average of the 10 previous candles' high-low range */
        { TA_ShadowVeryShort, TA_RangeType_HighLow, 10, 0.1 },
        /* when measuring distance between parts of candles or width of gaps */
        /* "near" means "<= 20% of the average of the 5 previous candles' high-low range" */
        { TA_Near, TA_RangeType_HighLow, 5, 0.2 },
        /* when measuring distance between parts of candles or width of gaps */
        /* "far" means ">= 60% of the average of the 5 previous candles' high-low range" */
        { TA_Far, TA_RangeType_HighLow, 5, 0.6 },
        /* when measuring distance between parts of candles or width of gaps */
        /* "equal" means "<= 5% of the average of the 5 previous candles' high-low range" */
        { TA_Equal, TA_RangeType_HighLow, 5, 0.05 }
    };
@mrjbq7
Copy link
Collaborator

mrjbq7 commented May 8, 2024

So you think the candle is defined in such a way that C code should trigger and it isn't? Or are you wondering if there is a definition issue where the example prices don't trigger and should?

@Tzion
Copy link
Author

Tzion commented May 8, 2024

I think that the C code doesn't trigger the pattern when it should - according to the pattern describe in the documentation

@Tzion
Copy link
Author

Tzion commented May 8, 2024

It is solved when I'm adding another candle from the left:

        candles = {
            'open': pd.Series([8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 7.9, 8.2, 9.4, 9.0]),
            'high': pd.Series([8.8, 8.8, 8.8, 8.8, 8.8, 8.8, 8.8, 8.8, 9.0, 9.0, 10.5, 9.0]),
            'low': pd.Series([7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.8, 7.9, 9.2, 8.0]),
            'close': pd.Series([8.5, 8.7, 8.7, 8.7, 8.7, 8.7, 8.7, 8.7, 8.1, 9.0, 9.2, 8.0])
        }

So the issue is about the definitions:
Instead of
average of the 10 previous candles'
in practice it's checking the average of the 11 previous candles'

How can I change the global candles settings (TA_CandleSetting) when using the python wrapper?

@mrjbq7
Copy link
Collaborator

mrjbq7 commented May 9, 2024

What do you need to change?

We currently expose that through a talib._ta_lib._ta_set_candle_settings function.

@Tzion
Copy link
Author

Tzion commented May 15, 2024

Thanks @mrjbq7

it is minor bug of off-by-one - the calculation should be over 10 candles and not 11.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants