Category Trend  Published on 04/07/2022

Finding Tops and Bottons on stock prices

Description

Below is a Python code that I created to identify tops and bottoms on price charts of stocks or any financial assets.
I also invented an extra indicator that calculates the angle between the last two tops and the angle between the last two bottoms, imagining that a straight line connects both.

price tops and bottoms with angle

I am using these indicators to operar opções binárias as we say in Brazil.

# Last tops:
# In the case of a window of 3, this value is i-1. In the case of a window of 5, it is i-2. In the case of a window of 7, it is i-3.
df['maximo'] = df['max'].rolling(window=9, center=True).max()
df['top'] = np.where(df['max']==df['maximo'], df['max'], np.nan)
df['top_1'] = np.nan
df['top_2'] = np.nan
df['top_3'] = np.nan
df['top_4'] = np.nan
df['top_5'] = np.nan
df['top_6'] = np.nan
df['top_7'] = np.nan
for i in range(4, df.shape[0]): # considering window = 9
    if df['top'][i-4]>0 and df['top_1'][i-1]!=df['top'][i-4]: # ignoring consecutive tops
        df['top_1'][i] = df['top'][i-4]
        df['top_2'][i] = df['top_1'][i-1]
        df['top_3'][i] = df['top_2'][i-1]
        df['top_4'][i] = df['top_3'][i-1]
        df['top_5'][i] = df['top_4'][i-1]
        df['top_6'][i] = df['top_5'][i-1]
        df['top_7'][i] = df['top_6'][i-1]
    else:
        df['top_1'][i] = df['top_1'][i-1]
        df['top_2'][i] = df['top_2'][i-1]
        df['top_3'][i] = df['top_3'][i-1]
        df['top_4'][i] = df['top_4'][i-1]
        df['top_5'][i] = df['top_5'][i-1]
        df['top_6'][i] = df['top_6'][i-1]
        df['top_7'][i] = df['top_7'][i-1]
        
# Last bottoms:
df['minimo'] = df['min'].rolling(window=9, center=True).min()
df['bottom'] = np.where(df['min']==df['minimo'], df['min'], np.nan)
df['bottom_1'] = np.nan
df['bottom_2'] = np.nan
df['bottom_3'] = np.nan
df['bottom_4'] = np.nan
df['bottom_5'] = np.nan
df['bottom_6'] = np.nan
df['bottom_7'] = np.nan
for i in range(4, df.shape[0]):
    if df['bottom'][i-4]>0 and df['bottom_1'][i-1]!=df['bottom'][i-4]:
        df['bottom_1'][i] = df['bottom'][i-4]
        df['bottom_2'][i] = df['bottom_1'][i-1]
        df['bottom_3'][i] = df['bottom_2'][i-1]
        df['bottom_4'][i] = df['bottom_3'][i-1]
        df['bottom_5'][i] = df['bottom_4'][i-1]
        df['bottom_6'][i] = df['bottom_5'][i-1]
        df['bottom_7'][i] = df['bottom_6'][i-1]
    else:
        df['bottom_1'][i] = df['bottom_1'][i-1]
        df['bottom_2'][i] = df['bottom_2'][i-1]
        df['bottom_3'][i] = df['bottom_3'][i-1]
        df['bottom_4'][i] = df['bottom_4'][i-1]
        df['bottom_5'][i] = df['bottom_5'][i-1]
        df['bottom_6'][i] = df['bottom_6'][i-1]
        df['bottom_7'][i] = df['bottom_7'][i-1]

# Counting the nº of candles before a new top:
df['count_tops'] = df.groupby((df['top_1'] != df['top_1'].shift(1)).cumsum()).cumcount()+1

df['AP1'] = np.nan # Angle between top_1 and top_2
df['AP2'] = np.nan
df['AP3'] = np.nan
df['AP4'] = np.nan
df['AP5'] = np.nan
df['AP6'] = np.nan

for i in range(4, df.shape[0]):
    if df['top_2'][i] != df['top_2'][i-1]: # when top_2 is updated
        df['AP1'][i] = (df['top_1'][i] - df['top_2'][i])/df['count_tops'][i-1] # find the angle between top_1 and top_2
        df['AP2'][i] = df['AP1'][i-1] # do the same for the others
        df['AP3'][i] = df['AP2'][i-1]
        df['AP4'][i] = df['AP3'][i-1]
        df['AP5'][i] = df['AP4'][i-1]
        df['AP6'][i] = df['AP5'][i-1]
    else:
        df['AP1'][i] = df['AP1'][i-1]
        df['AP2'][i] = df['AP2'][i-1]
        df['AP3'][i] = df['AP3'][i-1]
        df['AP4'][i] = df['AP4'][i-1]
        df['AP5'][i] = df['AP5'][i-1]
        df['AP6'][i] = df['AP6'][i-1]
        
# Same for bottoms:
df['count_bottoms'] = df.groupby((df['bottom_1'] != df['bottom_1'].shift(1)).cumsum()).cumcount()+1

df['AF1'] = np.nan
df['AF2'] = np.nan
df['AF3'] = np.nan
df['AF4'] = np.nan
df['AF5'] = np.nan
df['AF6'] = np.nan

for i in range(4, df.shape[0]):
    if df['bottom_2'][i] != df['bottom_2'][i-1]:
        df['AF1'][i] = (df['bottom_1'][i] - df['bottom_2'][i])/df['count_bottoms'][i-1]
        df['AF2'][i] = df['AF1'][i-1]
        df['AF3'][i] = df['AF2'][i-1]
        df['AF4'][i] = df['AF3'][i-1]
        df['AF5'][i] = df['AF4'][i-1]
        df['AF6'][i] = df['AF5'][i-1]
    else:
        df['AF1'][i] = df['AF1'][i-1]
        df['AF2'][i] = df['AF2'][i-1]
        df['AF3'][i] = df['AF3'][i-1]
        df['AF4'][i] = df['AF4'][i-1]
        df['AF5'][i] = df['AF5'][i-1]
        df['AF6'][i] = df['AF6'][i-1]

More concepts can be found here.


// -------------------------------------------------------------------------------------------------
//
//    This code is a cTrader Automate API example.
//    
//    All changes to this file might be lost on the next application update.
//    If you are going to modify this file please make a copy using the "Duplicate" command.
//
// -------------------------------------------------------------------------------------------------

using System;
using cAlgo.API;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AutoRescale = false, AccessRights = AccessRights.None)]
    public class SamplePriceChannels : Indicator
    {
        [Parameter(DefaultValue = 20)]
        public int Periods { get; set; }

        [Output("Upper", LineColor = "Pink")]
        public IndicatorDataSeries Upper { get; set; }

        [Output("Lower", LineColor = "Pink")]
        public IndicatorDataSeries Lower { get; set; }

        [Output("Center", LineColor = "Pink")]
        public IndicatorDataSeries Center { get; set; }

        public override void Calculate(int index)
        {
            double upper = double.MinValue;
            double lower = double.MaxValue;

            for (int i = index - Periods; i <= index - 1; i++)
            {
                upper = Math.Max(Bars.HighPrices[i], upper);
                lower = Math.Min(Bars.LowPrices[i], lower);
            }

            Upper[index] = upper;
            Lower[index] = lower;
            Center[index] = (upper + lower) / 2;
        }
    }
}


DO
dorivaltsu

Joined on 04.07.2022

  • Distribution: Free
  • Language: C#
  • Trading platform: cTrader Automate
  • File name: Sample Price Channels.algo
  • Rating: 2.5
  • Installs: 2178
  • Modified: 04/07/2022 20:24
Comments
Log in to add a comment.
GM
gmkenneyy · 2 years ago

int barSpan = 10;

Bars.HighPrices.Maximum(barSpan);

Bars.LowPrices.Minimum(barSpan);

will also do the job, no need to reinvent the wheel