Tag Archives: Indicators

Article contains information about creating technical indicators

spacer
Trading

Fuzzy Logic for Indicators, part 2

Dmitry Blokhin Leave a comment

Ok, in the beginning we have to determine our goals and instruments.

We would draw our membership functions as lines in a subchart area. Our arithmetic average would be drawn as histogram and would be colored depending to absolute value of resulting function, from red to green. Also it’s good idea to draw our source indicators on chart in order to achieve the whole picture.

 

cAlgo Implementation

 

cAlgo is clean and simple but it lacks a few useful possibilities at this moment. One of them is inability to draw indicator lines on main chart and subchart at the same time, second one is the absence of multicolor histograms and third missed feature is an inability to use an already defined custom indicators. But we are able to overcome all these obstacles and complete our nice-looking indicator.

At first we’ll implement our source indicators. It is very simple at this moment because all that we need is two Moving Averages Envelopes and one Exponential Moving Average based on typical price so we’ll need a custom data series.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
using System;
using cAlgo.API;
using cAlgo.API.Indicators;
 
namespace cAlgo.Indicators
{
  [Indicator("Fuzzy Logic - Lines", IsOverlay = true)]
  public class FuzzyLogicLines : Indicator
  {
    [Parameter("MA Fast period", DefaultValue = 8)]
    public int fastPeriod { get; set; }
    [Parameter("MA Fast dev", DefaultValue = 0.08)]
    public double fastDev { get; set; }
    [Parameter("MA Slow period", DefaultValue = 32)]
    public int slowPeriod { get; set; }
    [Parameter("MA Slow dev", DefaultValue = 0.15)]
    public double slowDev { get; set; }
    [Parameter("Signal period", DefaultValue = 2)]
    public int signalPeriod { get; set; }
 
    [Output("FastUpperLine", Color = Colors.Red)]
    public IndicatorDataSeries FastUpperLine { get; set; }
    [Output("FastLowerLine", Color = Colors.Red)]
    public IndicatorDataSeries FastLowerLine { get; set; }
    [Output("SlowUpperLine", Color = Colors.Blue)]
    public IndicatorDataSeries SlowUpperLine { get; set; }
    [Output("SlowLowerLine", Color = Colors.Blue)]
    public IndicatorDataSeries SlowLowerLine { get; set; }
    [Output("Signal", Color = Colors.Yellow, Thickness = 2)]
    public IndicatorDataSeries Signal { get; set; }
 
    private IndicatorDataSeries priceTypical;
    private MovingAverage signalMA;
    private MovingAverage fastMA;
    private MovingAverage slowMA;
 
    protected override void Initialize()
    {
      // Initialize and create nested indicators
      priceTypical = CreateDataSeries();
      signalMA = Indicators.MovingAverage(priceTypical,
                                          signalPeriod,
                                          MovingAverageType.Exponential);
      fastMA = Indicators.MovingAverage(MarketSeries.Close,
                                        fastPeriod,
                                        MovingAverageType.Simple);
      slowMA = Indicators.MovingAverage(MarketSeries.Close,
                                        slowPeriod,
                                        MovingAverageType.Simple);
    }
 
    public override void Calculate(int index)
    {
      priceTypical[index] = (MarketSeries.High[index] +
                             MarketSeries.Low[index] +
                             MarketSeries.Close[index]) / 3;
      signalMA.Calculate(index);
 
      Signal[index] = signalMA.Result[index];
      FastUpperLine[index] = fastMA.Result[index] * (1 + fastDev / 100);
      FastLowerLine[index] = fastMA.Result[index] * (1 - fastDev / 100);
      SlowUpperLine[index] = slowMA.Result[index] * (1 + slowDev / 100);
      SlowLowerLine[index] = slowMA.Result[index] * (1 - slowDev / 100);
    }
  }
}

Then we left this indicator alone and start to write a second one, based on first’s code. This new indicator will use a subchart area with a vertical range from -1 to 1 and will show our membership functions and final colorful histogram. So if you’d like to see all initial conditions for our membership functions you simply add both indicators to chart. Of course they should use the same parameters.

We leave the parameters block untouched and replace output block with two lines and five histogram. Since we cannot change the color of specific bar of our histogram we would simply specify a value of only one histogram series. The remaining four series would have the NaN (“Not A Number”) value and wouldn’t be drawn on chart.

    [Output(Thickness = 2, Color = Colors.Red)]
    public IndicatorDataSeries SignalFast { get; set; }
    [Output(Thickness = 2, Color = Colors.Blue)]
    public IndicatorDataSeries SignalSlow { get; set; }
 
    [Output(IsHistogram = true, Thickness = 4, Color = Colors.Red)]
    public IndicatorDataSeries Signal1 { get; set; }
    [Output(IsHistogram = true, Thickness = 4, Color = Colors.DarkOrange)]
    public IndicatorDataSeries Signal2 { get; set; }
    [Output(IsHistogram = true, Thickness = 4, Color = Colors.Gold)]
    public IndicatorDataSeries Signal3 { get; set; }
    [Output(IsHistogram = true, Thickness = 4, Color = Colors.GreenYellow)]
    public IndicatorDataSeries Signal4 { get; set; }
    [Output(IsHistogram = true, Thickness = 4, Color = Colors.Lime)]
    public IndicatorDataSeries Signal5 { get; set; }

Now let’s duplicate our first indicator’s calculations. But we need values only for current bar, so we can replace IndicatorDataSeries objects with simple double-precision variables.

    private IndicatorDataSeries priceTypical;
    private MovingAverage signalMA;
    private MovingAverage fastMA;
    private MovingAverage slowMA;
 
    // We can't draw this lines on non-overlay chart, 
    // so we don't need IndicatorDataSeries variables
    private double FastUpperLine;
    private double FastLowerLine;
    private double SlowUpperLine;
    private double SlowLowerLine;
 
    private double SignalLine;
    private double SignalResult;
    private double AbsResult;
 
    protected override void Initialize()
    {
      // Initialize and create nested indicators
      priceTypical = CreateDataSeries();
      signalMA = Indicators.MovingAverage(priceTypical,
                                          signalPeriod,
                                          MovingAverageType.Exponential);
      fastMA = Indicators.MovingAverage(MarketSeries.Close,
                                        fastPeriod,
                                        MovingAverageType.Simple);
      slowMA = Indicators.MovingAverage(MarketSeries.Close,
                                        slowPeriod,
                                        MovingAverageType.Simple);
    }

Also we need our membership function. It’s very simple because we’ve formalized it earlier.

    private double Fuzzy(double testVal, double upLine, double lowLine)
    {
      double F = 0;
      if (testVal > upLine) F = 1;          // 100% uptrend
      if (testVal <= upLine && testVal >= lowLine) {
        F = (1 - 2*(upLine-testVal)/(upLine-lowLine));
      }
      if (testVal < lowLine) F = -1;        // 100% downtrend
      return F;       
    }

And now it is time to our Calculate() function. We can duplicate it from our first indicator, changing result variables. Then we calculate two our membership function and final function. Last thing to implement is our nice colored histogram. As I’ve wrote before we simply compute only one of our five histogram bars leaving others undefined.

    public override void Calculate(int index)
    {
      priceTypical[index] = (MarketSeries.High[index] +
                             MarketSeries.Low[index] +
                             MarketSeries.Close[index]) / 3;
      signalMA.Calculate(index);
 
      SignalLine = signalMA.Result[index];
      FastUpperLine = fastMA.Result[index] * (1 + fastDev / 100);
      FastLowerLine = fastMA.Result[index] * (1 - fastDev / 100);
      SlowUpperLine = slowMA.Result[index] * (1 + slowDev / 100);
      SlowLowerLine = slowMA.Result[index] * (1 - slowDev / 100);
 
      SignalFast[index] = Fuzzy(SignalLine, FastUpperLine, FastLowerLine);
      SignalSlow[index] = Fuzzy(SignalLine, SlowUpperLine, SlowLowerLine);
      SignalResult = (SignalFast[index] + SignalSlow[index]) / 2;
      AbsResult = Math.Abs(SignalResult);
 
      if (AbsResult > 0.0 && AbsResult <= 0.2) Signal1[index] = SignalResult;
      if (AbsResult > 0.2 && AbsResult <= 0.4) Signal2[index] = SignalResult;
      if (AbsResult > 0.4 && AbsResult <= 0.6) Signal3[index] = SignalResult;
      if (AbsResult > 0.6 && AbsResult <= 0.8) Signal4[index] = SignalResult;
      if (AbsResult > 0.8 && AbsResult <= 1.0) Signal5[index] = SignalResult;
    }

So let’s compile both indicators and put them on one chart. As a result, we’ll see something like this:

spacer

cAlgoIndicators
spacer
Trading

Fuzzy Logic for Indicators, part 1

Dmitry Blokhin 2 Comments

Since Charles Babbage’s invention of the first computer we know our electronic friends use simple binary logic based on “true/false” system. It’s quite enough for mathematical calculations and most financial indicators, but when we try to construct a complex indicator or a robot based on our human experience we may encounter a problem. How to tell a computer such simple human terms like “slightly more…”, “too fast…”, “practically nothing…”?

However, it’s possible with fuzzy logic theory, or rather “membership functions”. Let’s define a membership function to describe a human term “hot coffee”.

Initially, we should consider the temperature from 0 to 100 degrees Celsius due to the fact that at the temperatures below 0 coffee turns to ice and above 100 – steam. Obviously a cup of coffee with the temperature of 20 degrees cannot be referred to as “hot” (and our membership function “Hot Coffee” equals 0), while coffee with the temperature over 70 is clearly “hot” and our membership function equals 1. As for values, that exist between these two extremes, the situation is contraversial. The cup of coffee with the temperature of 55 degrees would be “hot” for one person and “not too hot” for another. This is the “fuzziness”.

Nevertheless we can imagine some form of our membership function – it is “monotonically increasing”.

spacer

Therefore our function may be expressed by the following analytical equation:

spacer

Membership function

The main purpose of any technical indicator, one way or another, is the definition of the market condition at any given moment (flat, uptrend or downtrend) as well as the generation of signals to enter new position or exit it. How can membership function help us to do it? Easy enough.

Firstly we need to define the boundary conditions. Let’s identify “100% uptrend” as intersection of short EMA (with period of 2) built on typical price (H+L+C)/3 with upper band of the Moving Averages Envelope built with period of 8 and 0.08 deviation and “100% downtrend” as intersection with lower band. We assume “flat” in all other situations. For better results let’s add another envelope with parameters 32 and 0.15. That’s how it looks on the chart:

spacer

As a result we have two identical membership functions. Since the signal indicator would look more informative on the subchart with typical range from -1 to 1, then signal to buy and signal to sell occur when both functions are equal to 1 and -1 respectively. So our membership function looks like the following:

spacer

And it can be expressed with the following analytical equation:

spacer

where “a” and “b” are upper and lower envelope bands respectively, and “x” is an EMA(2) value. Finally, we’ve got our aggregate function for indicator from arithmetic average of two membership functions, i.e. F(x) = [ f1(x) + f2(x) ] / 2.

I’ll continue with programming this indicator in the next part of this article.

cAlgoIndicators
spacer
Trading

Moving Averages Envelope

Dmitry Blokhin Leave a comment

Moving Average Envelopes are percentage-based envelopes set above and below a moving average. The moving average, which forms the base for this indicator, can be a simple or exponential moving average. Each envelope is then set the same percentage above or below the moving average. This creates parallel bands that follow price action. With a moving average as the base, Moving Average Envelopes can be used as a trend following indicator. However, this indicator is not limited to just trend following. The envelopes can also be used to identify overbought and oversold levels when the trend is relatively flat.

Indicators based on channels, bands and envelopes are designed to encompass most price action. Therefore, moves above or below the envelopes warrant attention. Trends often start with strong moves in one direction or another. A surge above the upper envelope shows extraordinary strength, while a plunge below the lower envelope shows extraordinary weakness. Such strong moves can signal the end of one trend and the beginning of another.

With a moving average as its foundation, Moving Average Envelopes are a natural trend following indicator. As with moving averages, the envelopes will lag price action. The direction of the moving average dictates the direction of the channel. In general, a downtrend is present when the channel moves lower, while an uptrend exists when the channel moves higher. The trend is flat when the channel moves sideways.

Sometimes a strong trend does not take hold after an envelope break and prices move into a trading range. Such trading ranges are marked by a relatively flat moving average. The envelopes can then be used to identify overbought and oversold levels for trading purposes. A move above the upper envelope denotes an overbought situation, while a move below the lower envelope marks an oversold condition.

spacer

Calculation:

Upper Band = MA(Close, n * [1 + k]
Lower Band = MA(Close, n) * [1 - k]

Where:

  • MA— chosen Moving Average (Simple or Exponential);
  • n — averaging period;
  • k — the percentage value of shifting from the average.

Implementation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using System;
using cAlgo.API;
using cAlgo.API.Indicators;
 
namespace cAlgo.Indicators
{
  [Indicator(IsOverlay = true)] // Drawing on main chart area
  public class Envelopes : Indicator
  {
    [Parameter("Data Series")]
    public DataSeries SourceSeries { get; set; }
    [Parameter("MA Period";, DefaultValue = 14)
    public int MAPeriod { get; set; }
    [Parameter("MA Type";, DefaultValue = MovingAverageType.Simple)]
    public MovingAverageType MAType { get; set; }
    [Parameter("Shift (percentage)", DefaultValue = 0.1)]
    public double Deviation { get; set; }
 
    [Output("Upper Band", Color=Colors:Red)]
    public IndicatorDataSeries UpperBand { get; set; }
    [Output("Lower Band", Color=Colors:Blue)]
    public IndicatorDataSeries LowerBand { get; set; }
 
    private MovingAverage ma;
 
    protected override void Initialize()
    {
      ma = Indicators.MovingAverage(SourceSeries, MAPeriod, MAType);
    }
 
    public override void Calculate(int index)
    {
      UpperBand[index] = ma.Result[index] * (1 + Deviation/100);
      LowerBand[index] = ma.Result[index] * (1 - Deviation/100);
    }
  }
}
cAlgoIndicators