Creating functions, how do they work?

Questions about MultiCharts .NET and user contributed studies.
MidKnight
Posts: 343
Joined: 12 Aug 2012
Has thanked: 123 times
Been thanked: 56 times

Creating functions, how do they work?

Postby MidKnight » 15 Oct 2012

Hello,

I'm trying to create a function, and the generated template created by the editor has hooks for Create(), StartCalc(), and CalcBar() - no problem I can understand most of that......When I look at the MC.net supplied code in their indicators on how they are using functions, the caller simply makes a call to them within the indicators CalcBar() method...something like this:

Code: Select all

...
if (PublicFunctions.DoubleGreater(Bars.High[0], PublicFunctions.Highest(Bars.High, length, 1))){
...
And here is the template that MC.net created for my new function:

Code: Select all

public sealed class IsWithinTimeRange : FunctionSimple<System.Boolean>
{
public IsWithinTimeRange(CStudyControl _master) : base(_master) { }
public IsWithinTimeRange(CStudyControl _master, int _ds) : base(_master, _ds) { }

protected override void Create()
{
// create variable objects and function objects
}

protected override void StartCalc()
{
// assign inputs
}

protected override System.Boolean CalcBar()
{
// function logic
return default(System.Boolean);
}
}
So when I compare how MC.net uses their functions against the template code generated by MC.net, I don't understand the following:
1) In MC.net's example above, the object is never constructed, instead it almost looks as though it is static.

2) How do I assign inputs within the function provided template via StartCalc?

I'm really confused by this. Either there is magi happening in the background or I can't see how the builtin indicators using functions matches with the template that is generated. Yes, I could install the beta and get access to the source code but I never like running beta trading software ever. Often just ends up being a headache as it is beta for a reason.

Any insights are warmly received - thank you.

With kind regards,
MK

Zoli
Posts: 90
Joined: 12 Sep 2012
Has thanked: 24 times
Been thanked: 38 times

Re: Creating functions, how do they work?

Postby Zoli » 15 Oct 2012

Hi,

I am not sure I completely understand your questions, I am not even a good programmer LOL, but I have asked myself similar questions. I will post here the function I created, it does almost the same thing as the built in function called PivotHigh (PivotHighVS), but I really wanted to create my own to understand better all this. I will post the indicator that calls it as well.
Hope this helps a little bit.

Function code:

Code: Select all

using System;
using System.Drawing;
using System.Linq;


namespace PowerLanguage.Function
{
public class STPivotHigh : FunctionSimple<double>
{
public STPivotHigh(CStudyControl _master) : base(_master) { }
public STPivotHigh(CStudyControl _master, int _ds) : base(_master, _ds) { }
public int Strength { get; set; }
public double Price;
public bool PivotISHigh = false;

protected override Double CalcBar()
{
int length = Strength * 2;
if (Bars.CurrentBar >= length + 1)
for (int i = length; i >= 0; i--)
{
if ((Bars.High[Strength] >= Bars.High[i] && i != Strength + 1) || (Bars.High[Strength] > Bars.High[i] && i == Strength + 1))
{
if (i == 0)
{
PivotISHigh = true;
Price = Bars.High[Strength];
}
}
else
{
PivotISHigh = false;
break;
}
}
if (PivotISHigh == true) return Price;
else return 0;
}
}
}
Indicator code:

Code: Select all

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;

namespace PowerLanguage.Indicator
{
[SameAsSymbol(true)]

public class Test : IndicatorObject
{
public Test(object _ctx) : base(_ctx) { }
private STPivotHigh st_pivot_high;
private double result;
private IDrawObject plot1;

protected override void Create()
{
st_pivot_high = new STPivotHigh(this);
}

protected override void StartCalc()
{
st_pivot_high.Strength = 5;
}

protected override void CalcBar()
{
if (Bars.Status == EBarState.Close)
{
result = st_pivot_high.Value;
if (st_pivot_high.PivotISHigh == true)
plot1 = DrwArrow.Create(new ChartPoint(Bars.Time[st_pivot_high.Strength], st_pivot_high.Price), true);
}
}
}
}

MidKnight
Posts: 343
Joined: 12 Aug 2012
Has thanked: 123 times
Been thanked: 56 times

Re: Creating functions, how do they work?

Postby MidKnight » 15 Oct 2012

Thanks for the post Zoli. Yeah I could do that way, but because all the built-in functions do it a different way, I thought there might be some behind the scenes magic that is applied to the function type.

In an attempt to try and clarify my query. There is a mismatch between how the built-in functions and the generated template code when creating your own new function look. I am asking if functions should be designed to be called like the built-in code example I posted in my first post, or should they be created similar to how Zoli showed.

With kind regards,
MK

Zoli
Posts: 90
Joined: 12 Sep 2012
Has thanked: 24 times
Been thanked: 38 times

Re: Creating functions, how do they work?

Postby Zoli » 15 Oct 2012

Well I don't want to talk some nonsense so I will attach a screenshot with the beta version.
Attachments
publicfunctions.png
(156.88 KiB) Downloaded 2041 times

MidKnight
Posts: 343
Joined: 12 Aug 2012
Has thanked: 123 times
Been thanked: 56 times

Re: Creating functions, how do they work?

Postby MidKnight » 15 Oct 2012

Thanks for the post Zoli. Would you be generous enough to post a screenshot of a simple function such as:

Code: Select all

PublicFunctions.DoubleGreater(double lval, double rval)
This type of simple function is all I'm trying to create and want to be able to call it in the same clean fashion as the above. It just looks like a static function but I could be wrong about it and there may be some "voodoo" in the background that I don't know about.

With thanks,
MK

Zoli
Posts: 90
Joined: 12 Sep 2012
Has thanked: 24 times
Been thanked: 38 times

Re: Creating functions, how do they work?

Postby Zoli » 16 Oct 2012

Hi MK,

The DoubleGreater method is a public STATIC bool according to the .net help. It is a built in function so I don't seem to have access to it.
I am not sure whether you have the help for .net, if not, you can download it from here http://www.multicharts.com/downloads/Po ... ge.NET.chm
If you cannot read it in win7/win8 you have to right-click the file->properties->general tab and make sure you click Unblock at security.

User avatar
Henry MultiСharts
Posts: 9165
Joined: 25 Aug 2011
Has thanked: 1264 times
Been thanked: 2957 times

Re: Creating functions, how do they work?

Postby Henry MultiСharts » 16 Oct 2012

1) In MC.net's example above, the object is never constructed, instead it almost looks as though it is static.
There are two basic function types:

1) FunctionSeries<T> - basic class of series function. The feature of the series function is that its body is always calculated in the current execution context (on the current calculation bar) and that the function always keeps its previous values.

2) FunctionSimple<T> - basic class of simple function. The feature of the simple function is that it does not store any previous values. It is calculated every time in the execution context (calculated on the bar offset against the current bar for a specified number of bars)

By execution context a set of two attributes is understood:
• Calcualtion bar, i.e. BarsBack - offset against the current bar
• Number of data stream against which the offset is calculated.

Thus the body of the series function is calculated without offset on the current calculation bar, while simple function is calculated with the offset it is called.
(If SimplF, SeriaF – are examples of simple and series functions, then SimplF[5] call is the calculation of this function on the fifth bar back from the current bar.
SeriaF[5] call is the calculation on the current bar with extraction of the necessary offset value from the historical values collection).

The derived class must implement a method T FunctionObject<T>.CalcBar(); that should contain the body of the function.

The derived class can redefine the methods:
• void Create();
• void StartCalc();
• void Destroy();
In case of need:
• create examples of variable classes or other functions.
• set the entry parameters for the function in use.
• perform other actions to initialize and release resources.

Funtion calculation is done :
1) when calling IFunctionObject<T>.Value{get;} or ISeries<T>.this[int bars_ago]{get;} propertly
2) when calling T FunctionObject<T>.Call(); or T FunctionObject<T>.Call(int bars_ago); method
2) How do I assign inputs within the function provided template via StartCalc?
You can define the inputs by creating a public property, or through special methods that initialize internal variables by defined values.

MidKnight
Posts: 343
Joined: 12 Aug 2012
Has thanked: 123 times
Been thanked: 56 times

Re: Creating functions, how do they work?

Postby MidKnight » 13 Dec 2012

Hi Henry,

I've read this dozens of times and still do not understand what functions are doing. Why have you guys decided to make these so confusing instead of sticking to a traditional object orientated model without side effects?

Take this really simple code that is calling the AverageFC function. These screenshots will be showing the output from what should be a simple 1 bar moving average. The closing price should match the output from AverageFC.

Code: Select all

Create()
{...
m_average = new AverageFC(this);
...}

StartCalc()
{...
m_average.price = Bars.Close;
m_average.length = new Lambda<Int32>(delegate { return length; });
...}

CalcBar()
{...
plot1.Set(m_average[0]);
plot2.Set(m_average[0]);
...}
This will create errors. Screenshot one shows the result with plot2 commented out so the AverageFC() is only called once within my indicator CalcBar(), but as soon as you call it more than once you will get errors. This means you have to call it only once and store its result in a temporary variable. You are treating this like a function but using an object to do it and as a result, the code becomes less readable and harder to understand in anything sizable and non-trivial.

:( :( :( :( :(
Attachments
2plot.png
(14.99 KiB) Downloaded 1983 times
1plot.png
(13.89 KiB) Downloaded 1969 times

User avatar
Henry MultiСharts
Posts: 9165
Joined: 25 Aug 2011
Has thanked: 1264 times
Been thanked: 2957 times

Re: Creating functions, how do they work?

Postby Henry MultiСharts » 14 Dec 2012

This will create errors. Screenshot one shows the result with plot2 commented out so the AverageFC() is only called once within my indicator CalcBar(), but as soon as you call it more than once you will get errors.
Hello MidKnight,

This issue has been already fixed in MultiCharts .Net 8.1 beta 1.Original bug report

User avatar
JoshM
Posts: 2195
Joined: 20 May 2011
Location: The Netherlands
Has thanked: 1544 times
Been thanked: 1565 times
Contact:

Re: Creating functions, how do they work?

Postby JoshM » 15 Dec 2012

(...)
Thanks for this explanation.

Henry (or any other C# expert), how would you program an indicator that uses the same function multiple times with different settings?

Say, for example, a "wave" indicator, which consists of multiple EMA lines. Working from the examples and my C# knowledge, I came up with this (which works correctly):

Code: Select all

namespace PowerLanguage.Indicator
{
public class TheWave : IndicatorObject
{
public TheWave(object _ctx):base(_ctx){}

private XAverage ema1, ema2, ema3, ema4, ema5, ema6, ema7, ema8, ema9, ema10,
ema11, ema12, ema13, ema14, ema15, ema16, ema17, ema18, ema19;

private VariableSeries<Double> ema_1, ema_2, ema_3, ema_4, ema_5, ema_6, ema_7,
ema_8, ema_9, ema_10, ema_11, ema_12, ema_13, ema_14, ema_15, ema_16, ema_17,
ema_18, ema_19;

protected override void Create()
{
ema1 = new XAverage(this);
ema2 = new XAverage(this);
ema3 = new XAverage(this);
ema4 = new XAverage(this);
ema5 = new XAverage(this);
ema6 = new XAverage(this);
ema7 = new XAverage(this);
ema8 = new XAverage(this);
ema9 = new XAverage(this);
ema10 = new XAverage(this);
ema11 = new XAverage(this);
ema12 = new XAverage(this);
ema13 = new XAverage(this);
ema14 = new XAverage(this);
ema15 = new XAverage(this);
ema16 = new XAverage(this);
ema17 = new XAverage(this);
ema18 = new XAverage(this);
ema19 = new XAverage(this);

ema_1 = new VariableSeries<Double>(this);
ema_2 = new VariableSeries<Double>(this);
ema_3 = new VariableSeries<Double>(this);
ema_4 = new VariableSeries<Double>(this);
ema_5 = new VariableSeries<Double>(this);
ema_6 = new VariableSeries<Double>(this);
ema_7 = new VariableSeries<Double>(this);
ema_8 = new VariableSeries<Double>(this);
ema_9 = new VariableSeries<Double>(this);
ema_10 = new VariableSeries<Double>(this);
ema_11 = new VariableSeries<Double>(this);
ema_12 = new VariableSeries<Double>(this);
ema_13 = new VariableSeries<Double>(this);
ema_14 = new VariableSeries<Double>(this);
ema_15 = new VariableSeries<Double>(this);
ema_16 = new VariableSeries<Double>(this);
ema_17 = new VariableSeries<Double>(this);
ema_18 = new VariableSeries<Double>(this);
ema_19 = new VariableSeries<Double>(this);
}

protected override void StartCalc()
{
...
}

protected override void CalcBar()
{
.....
}
}
But I'm wondering (just like MidKnight's confusion about treating functions as objects I suppose):
  • Doesn't this gives a lot of (unneeded) overhead with all those instances of XAverage()?

    Is this considered 'good programming practices' giving the MC .NET Function's framework?

User avatar
Henry MultiСharts
Posts: 9165
Joined: 25 Aug 2011
Has thanked: 1264 times
Been thanked: 2957 times

Re: Creating functions, how do they work?

Postby Henry MultiСharts » 21 Dec 2012

Henry (or any other C# expert), how would you program an indicator that uses the same function multiple times with different settings?
Hello JoshM,

That is not possible to use the same XAverage function with different variables because this function uses it's own previous value for calculation.

You can use a collection of functions and variables to achieve your goal:List<XAverage> and List<VariableSeries<Double>>


Return to “MultiCharts .NET”