RightEdge Forums
Main     Home          Members     Calendar     Who's On

Welcome Guest
        



Another indicator sample Expand / Collapse
Message
Posted 12/8/2006 06:35:31 Post #663
 

Lead DeveloperLead DeveloperLead DeveloperLead DeveloperLead DeveloperLead DeveloperLead DeveloperLead Developer
At the request of another member, I've decided to post the source code to another indicator to serve as an example.  This is our On Balance Volume code, slightly modified for clarity.

using System;
using System.Collections.Generic;
using System.Text;
using RightEdge.Common;

namespace MyIndicators
{
    [YYEIndicatorAttribute(System.Drawing.KnownColor.Crimson,
        YYEIndicatorAttribute.EIndicatorGroup.Volume,
        Name =
"OBV",
        Description =
"My On Balance Volume implementation",
        Id =
"Generate a unique ID here",
        DefaultDrawingPane =
"OBVPane",
        HelpText =
"Put some detailed text here if desired.")]
    [
Serializable]
   
public class MyOBV : IndicatorBase
    {
       
private double previousValue = 0.0;
       
private List<BarData> pBars = null;

        /// Constructs an On Balance Volume indicator instance.
        public MyOBV()
        {
           
pBars = new List<BarData>();
        }

        /// Calculates the values for an entire series.
       
public override List<double> CalcSeriesValues(IList<BarData> bars)
        {
            pBars =
new List<BarData>();
           
return base.CalcSeriesValues(bars);
        }

        /// Calculates the next value in the indicator series.
        public override double CalcNextValue(BarData bar)
        {
           
pBars.Add(bar);
            int pBarIndex = pBars.Count - 1;

            
if (pBarIndex == 0)
           
{
               
// This is our first non-empty bar
               
previousValue = double.NaN;
               
return double.NaN;
            }
           
else
           
{
               
double todaysClose = bar.Close;
               
double yesterdaysClose = pBars[pBarIndex - 1].Close;
               
double todaysVolume = bar.Volume;
               
if (double.IsNaN(previousValue))
                {
                    previousValue = todaysVolume;
                   
return todaysVolume;
                }
               
else
               
{
                   
double yesterdaysOBV = previousValue;
                   
if (todaysClose > yesterdaysClose)
                    {
                        previousValue = yesterdaysOBV + todaysVolume;
                       
return yesterdaysOBV + todaysVolume;
                    }
                   
else
                   
{
                        previousValue = yesterdaysOBV - todaysVolume;
                       
return yesterdaysOBV - todaysVolume;
                    }
                }
            }
        }
   
}
}

The meat is really in CalcNextValue().  This is called each time a new bar comes in, so we perform the calculation and return the value.

CalcSeriesValues() is used for optimizing an entire series of calculations.  In other words, many indicators can be calculated independently, while some rely on previously calculated values.  If you can store those previously calc'ed values instead of having to recalculate them everytime, you save a lot of cycles.  That's really what this function is for.  We don't need it in this case.

The attributes at the top of the class are used for the user interface and persistence.  We're specifying a default color of Crimson, we're asking RightEdge to place this in the "Volume" tree node in the indicator pane, it will show up as "OBV" in the indicator list.  Now the ID is important because this is what RightEdge uses to identify this indicator so that it can save and load it from a saved chart for example.  We typically generate a GUID as the ID.  You can generate this ID in Visual Studio if you're familiar with that tool, or use the one at http://www.guidgen.com.  DefaultDrawingPane proposes a default pane name to the user when they drag and drop this indicator.  HelpText is the text that is displayed when a user selects Indicator Information from the indicator pane.

Posted 12/10/2006 21:30:55 Post #729
 

Forum GuruForum GuruForum GuruForum GuruForum GuruForum GuruForum GuruForum Guru
Would it be possible to get an example in VB?
Posted 12/11/2006 08:34:13 Post #734
 

Lead DeveloperLead DeveloperLead DeveloperLead DeveloperLead DeveloperLead DeveloperLead DeveloperLead Developer
Sure.  Here's the code (I think my VB conversion is pretty close).  I've also attached the project file for your convenience.

Imports System
Imports System.Collections.Generic
Imports System.Text
Imports RightEdge.Common
Imports RightEdge.Indicators

Namespace MyIndicators

<YYEIndicatorAttribute(System.Drawing.KnownColor.Crimson, YYEIndicatorAttribute.EIndicatorGroup.Volatility, Author:="You", CompanyName:="", DefaultDrawingPane:="OBVPane", Description:="Your Indicator Description here", GroupName:="", HelpText:="Add help text that will be displayed in the RightEdge user interface here.", Id:="<Generate a unique ID here>", Name:="Your Indicator Name Here", Version:="0.1")> _

<Serializable()> _

<SeriesInputAttribute(Name:="Input", Order:=1, Value:=BarElement.Close)> _

Public Class MyRightEdgeIndicator
   
Inherits SeriesCalculatorBaseWithValues

   
Private periods As Integer = 20
   
Private shift As Double = 5
   
Private sma As SMA = Nothing
   
Private validCount As Integer = 0

   
Public Sub New(ByVal periods As Integer, ByVal shift As Double)
       MyBase.New(1)
      
Me.periods = periods
      
Me.shift = shift
       sma =
New SMA(periods)
   
End Sub

    Protected Overloads Overrides Function CalcNewValue(ByVal index As Integer) As Double
       
System.Math.Min(System.Threading.Interlocked.Increment(validCount), validCount - 1)
       
If validCount < periods Then
           
Return Double.NaN
       
End If

        Dim price As Double = inputs(0)(index)
       
Return price - (sma(index) * (shift / 100))
    End Function

   
Protected Overloads Overrides Sub Reset()
        validCount = 0
   
End Sub

   
Public Overloads Overrides Sub NewBar()
        sma.NewBar()
       
MyBase.NewBar()
   
End Sub

   
Public Overloads Overrides Sub NewSeries(ByVal count As Integer)
        sma.NewSeries(count)
       
MyBase.NewSeries(count)
   
End Sub

    Public Overloads Overrides Sub SetInputs(ByVal ParamArray newInputs As ISeries())
        sma.SetInputs(newInputs)
       
MyBase.SetInputs(newInputs)
    End Sub
End Class
End
Namespace



  Post Attachments 
MyIndicatorVB.zip (215 views, 218.31 KB)
Posted 12/11/2006 18:19:04 Post #744
 

Forum GuruForum GuruForum GuruForum GuruForum GuruForum GuruForum GuruForum Guru
Thanks for that.

Just one question for now. How would I add a signal line to that moving average? Can I do it through code, or do I have to manually add two SMA's to the chart?

Posted 12/11/2006 18:25:03 Post #745
 

Lead DeveloperLead DeveloperLead DeveloperLead DeveloperLead DeveloperLead DeveloperLead DeveloperLead Developer
There's only one series per indicator.  So you'd have to build another indicator that calculates the signal line, or you can do it through the user interface.  In other words, you would be your indicator and for the series line, "chain" this indicator to an SMA.  There's a good example of this using the MACD and a MACD signal line here:

http://www.rightedgesystems.com/forums/FindPost575.aspx

BigBerner (12/11/2006)
Thanks for that.

Just one question for now. How would I add a signal line to that moving average? Can I do it through code, or do I have to manually add two SMA's to the chart?

Posted 12/11/2006 19:10:10 Post #747
 

Forum GuruForum GuruForum GuruForum GuruForum GuruForum GuruForum GuruForum Guru
OK thanks.

One more question. I don't really understand the line of code Dim price as Double = inputs(0)(index). Can you explain the inputs(0)(index) part - I can't see where they are coming from.

Posted 12/11/2006 19:38:16 Post #749
 

Lead DeveloperLead DeveloperLead DeveloperLead DeveloperLead DeveloperLead DeveloperLead DeveloperLead Developer
Sure, the inputs come from the SeriesCalculatorBase class.  This is the core of what allows indicators to be chained.  Since this indicator is derived from SeriesCalculatorBaseWithValues, which is derived from SeriesCalculatorBase, the inputs variable is populated for you.  This gives you the input parameter.  In cases where you can have multiple inputs, this array would hold those values.

Here's some of the relevant documentation.

http://www.rightedgesystems.com/documentation/developerguide/RightEdge.Common.SeriesCalculatorBaseMembers.html

Note, if you want a really simple indicator that takes one input and doesn't need to support chaining with another indicator (in other words, will always take a piece of bar data), derive from IndicatorBase.

Keep firing off the questions as they come up.  I know getting your head around the various classes is a bit of a task at first.  Hopefully you'll find that they make life easy.

« Prev Topic | Next Topic »


Reading This Topic Expand / Collapse
Active Users: 0 (0 guests, 0 members, 0 anonymous members)
No members currently viewing this topic.
Forum Moderators: billb, young, dplaisted

Permissions Expand / Collapse

All times are GMT -5:00, Time now is 6:04am

2005-2007 © RightEdge Systems