Listing MultiCharts.NET API Issues

Questions about MultiCharts .NET and user contributed studies.
User avatar
orad
Posts: 121
Joined: 14 Nov 2012
Has thanked: 50 times
Been thanked: 20 times

Listing MultiCharts.NET API Issues

Postby orad » 02 Feb 2015

Just because I like MultiCharts.NET, and I want it to be the best trading platform I use, I'm creating this thread to list any minor issues and inconsistencies that I notice in the MC.NET API. This is going to be a follow up of .NET APIs do not follow the C# Conventions. I understand that some things cannot be changed easily after the API is released, but still I would prefer if a new release has breaking changes because of fixing these than a backwards-compatible release with continued inconsistencies in .NET guidelines. Again, many of these are minor and just naming conventions but they add up. So here we go and I will try to add more stuff here as I find them. If you have any inputs too on this please add them here.

Thanks,
orad
Last edited by orad on 02 Feb 2015, edited 3 times in total.

User avatar
orad
Posts: 121
Joined: 14 Nov 2012
Has thanked: 50 times
Been thanked: 20 times

Re: Listing MultiCharts.NET API Issues

Postby orad » 02 Feb 2015

Starting with C# templates. These are modified templates that follow C# naming conventions better (also attached).

Function.cs.template

Code: Select all

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

namespace PowerLanguage.Function
{
public sealed class __CLASS_NAME__ : __BASE_TYPE_NAME__<__FUNC_TYPE__>
{
public __CLASS_NAME__(CStudyControl master) : base(master) { }
public __CLASS_NAME__(CStudyControl master, int dataStream) : base(master, dataStream) { }

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

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

protected override __FUNC_TYPE__ CalcBar()
{
// function logic
return default(__FUNC_TYPE__);
}

}
}
Indicator.cs.template

Code: Select all

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

namespace PowerLanguage.Indicator
{
public class __CLASS_NAME__ : IndicatorObject
{
public __CLASS_NAME__(object ctx) : base(ctx) { }

private IPlotObject _plot1;

protected override void Create()
{
// create variable objects, function objects, plot objects, etc.
_plot1 = AddPlot(new PlotAttributes("", EPlotShapes.Line, Color.Red));
}

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

protected override void CalcBar()
{
// indicator logic
_plot1.Set(Bars.Close[0]);
}

}
}
Strategy.cs.template

Code: Select all

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

namespace PowerLanguage.Strategy
{
public class __CLASS_NAME__ : SignalObject
{
public __CLASS_NAME__(object ctx) : base(ctx) { }

private IOrderMarket _buyOrder;

protected override void Create()
{
// create variable objects, function objects, order objects, etc.
_buyOrder = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.Default, EOrderAction.Buy));
}

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

protected override void CalcBar()
{
// strategy logic
_buyOrder.Send();
}

}
}

Things to notice:
  • - C# source code file extensions of .cs are not capitalized.
  • - In code blocks, open brace opens on next line.
  • - Constructor parameter names (and method parameters in general) do not start with underscore (ctx, master, ...).
  • - Parameter names are preferably not abbreviated (dataStream instead of ds) and not python style (like data_stream)... currently we have all variations in the API.
  • - private fields are camel cased and start with underscore (_buyOrder instead of buy_order, or m_buyOrder, etc)
  • - Namespaces are not nested (i.e. namespace PowerLanguage.Function { } instead of namespace PowerLanguage {namespace Function { }})
  • - Bonus: (not a .NET convention but something I follow) empty line after last code block in the class, and always one new line at the end of the file.
Things that I could not change in the template:
  • - Don't end class names with Object (e.g. IndicatorObject, SignalObject, etc.)
    - Don't use hungarian notation (e.g. SOrderParameters, EOrderAction, EPlotShapes)
Attachments
Templates.zip
(1.35 KiB) Downloaded 194 times

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

Re: Listing MultiCharts.NET API Issues

Postby JoshM » 02 Feb 2015

I agree with this topic, its content, and the need for it. But aren't something also a matter of personal preference? For example,
- private fields are camel cased and start with underscore (_buyOrder instead of buy_order, or m_buyOrder, etc)
Is advised against by Microsoft's General Naming Conventions, stating that:
DO NOT use underscores, hyphens, or any other nonalphanumeric characters.
The same goes for the .NET Framework Design Guidelines (source):
Do not use a prefix for member variables (_, m_, s_, etc.). If you want to distinguish between local and member variables you should use “this.” in C# and “Me.” in VB.NET.
That being said, I agree with all the other points you make. However, I'd also warn against getting your hopes up -- even MultiCharts PowerLanguage standard functions, indicators, and strategies are sloppy coded. And that platform has been around long enough to have that corrected by now.

Personally, I don't think it's a good idea to change all the style that has been used (like Hungarian notation) since that will be code- and documentation-breaking. I think learning MultiCharts .NET is a challenge already for new users. But if the code is changed such that all previous topics, code examples, and the pdf manual don't compile anymore, the drawback of that is much greater than the benefit (nicer code).

User avatar
orad
Posts: 121
Joined: 14 Nov 2012
Has thanked: 50 times
Been thanked: 20 times

Re: Listing MultiCharts.NET API Issues

Postby orad » 02 Feb 2015

Hi JoshM,

I would be happy even if only future code follows .NET conventions and I can live with existing API for the most part. One reason I opened this thread is because MC is working on new Auto Trading and Backtesting Engine for MultiCharts 9.1 that will come with a new API. So hopefully this can help there.

About private fields, you are right. I'm fine with going with the documented naming conventions and use this.buyOrder. I gave my suggestions based on the conventions we followed in the teams that I worked with (including few teams at Microsoft). I've noticed that in the case of (only) private fields people find the 'this.' prefix to create long statements sometimes that make it less readable, especially if used in mathematical expressions (which we will be dealing with very much in our trading code), so they use underscore instead. Another reason is to avoid a public member and a private member that only differ in casing (e.g. private buyOrder field and public BuyOrder property). This is the only thing that I've seen large teams may not agree on Microsoft guidelines. Again, I'm okay with either this.buyOrder or _buyOrder, or even this._buyOrder but not buy_order, m_buyOrder or m_buy_order etc.
Personally, I don't think it's a good idea to change all the style that has been used (like Hungarian notation) since that will be code- and documentation-breaking.
Agreed. This will be particularly of less importance in C# 6.0, because it will allow you to omit class names when calling static members. For example, you can say Line instaed of EPlotShapes.Line.
Last edited by orad on 08 Feb 2015, edited 2 times in total.

User avatar
orad
Posts: 121
Joined: 14 Nov 2012
Has thanked: 50 times
Been thanked: 20 times

Re: Listing MultiCharts.NET API Issues

Postby orad » 02 Feb 2015

Methods names should have a verb: GetCurrentEntries() instead of CurrentEntries()

If it makes sense, make it a getter property. For example when viewing object in Visual Studio debugger, it does not show the object's methods but it shows its properties. If it makes sense that the value of the member to be displayed in the debugger's Quick View then make it a getter property. If you want to indicate that calling this member will trigger some extra calculation or work for it to be evaluated then keep it as a method with a proper verb prefix.

Boolean properties should start with "Is" (even if item is plural):
- LastBarInChart should be IsLastBarInChart
- LastBarInSession should be IsLastBarInSession

This would be especially helpful in if statements...

Code: Select all

if (this.IsLastBarInChart)
{
//...
}
Last edited by orad on 09 Feb 2015, edited 6 times in total.

User avatar
orad
Posts: 121
Joined: 14 Nov 2012
Has thanked: 50 times
Been thanked: 20 times

Re: Listing MultiCharts.NET API Issues

Postby orad » 03 Feb 2015

MouseClickArgs is defined as:

Code: Select all

public struct MouseClickArgs
{
public Keys keys;
public MouseButtons buttons;
public ChartPoint point;
public int data_number;
public int bar_number;
}
Recommended interface would be:

Code: Select all

public struct MouseClickArgs
{
public Keys Keys {get; set}
public MouseButtons Buttons {get; set}
public ChartPoint Point {get; set}
public int DataNumber {get; set}
public int BarNumber {get; set}
}
Things to note:
  • - Typically all fields should be non-public, if it is public then make it an automatic property. Compiler does optimizations on it, so there is zero to insignificant performance penalty in using automatic properties vs. fields. Also pretty much all C# static analyzers (such as Resharper) will complain when they see public fields.
    - No python style names (like data_number), instead use Pascal cased (DataNumber)
    - This could be a class instead of struct, if using any .NET EventArgs type as reference. For example see MouseEventArgs
    - To be fully according to .NET event guidelines it should also inherit System.EventArgs
Last edited by orad on 08 Feb 2015, edited 1 time in total.

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

Re: Listing MultiCharts.NET API Issues

Postby JoshM » 07 Feb 2015

Thanks Orad for taking the time to document these things. They are currently outside the area of my competence and experience, but I do see the need for fixing these issues.

The suggestions certainly would make the code easier to understand and more 'pretty' (as in, in line with how the code elements normally look). I hope the ideas that can be implemented without breaking existing code are implemented.

User avatar
orad
Posts: 121
Joined: 14 Nov 2012
Has thanked: 50 times
Been thanked: 20 times

Re: Listing MultiCharts.NET API Issues

Postby orad » 10 Feb 2015

The PlotAttributes class has 6 constructors:
  • public PlotAttributes(string name, EPlotShapes type, Color fgColor, Color bgColor, int width, EPlotStyle style, bool showLastPriceMarker)

    public PlotAttributes(string name, EPlotShapes type, Color fgColor, Color bgColor, int width, int style, bool showLastPriceMarker)
    // --> this constructor is totally redundant. 'style' should use the enum type EPlotStyle. what if user enters 1000?

    public PlotAttributes(string name, EPlotShapes type, Color fgColor)

    public PlotAttributes(string name, int plotNum)
    // --> in this constructor plotNum specifies color? This is not documented and is not intuitive either.

    public PlotAttributes(string name)

    public PlotAttributes(int plotNum)
All this clutter could be reduced to a single constructor using Optional Arguments, like the following:

Code: Select all

public PlotAttributes(
string name = null,
EPlotShapes type = EPlotShapes.Line,
Color fgColor = new Color(),
Color bgColor = new Color(),
int width = 1,
EPlotStyle style = EPlotStyle.Solid,
bool showLastPriceMarker = true,
PlotAlignment alignment = PlotAlignment.Center)
{
if (String.IsNullOrWhiteSpace(name))
{
name = generateName(); // "Plot 1", "Plot 2", ...
}
if (fgColor.IsEmpty)
{
fgColor = generateColor(); // rotate between Red, Blue, Cyan, Yellow, Magenta, Green, ...
}
if (bgColor.IsEmpty)
{
bgColor = Color.Black;
}

// initialize members...
}
UPDATE

An easier API would be, instead of the following syntax:

Code: Select all

this.plot1 = AddPlot(new PlotAttributes( ... ));
this.plot2 = AddPlot(new StringPlotAttributes( ... ));
define AddPlot and AddStringPlot methods which directly receive their corresponding plot Attributes parameters as Optional Arguments.

Code: Select all

this.plot1 = AddPlot("Plot 1", width: 10);
this.plot2 = AddPlot("Plot 2", color: Color:Red);
This won't be a breaking change.

User avatar
orad
Posts: 121
Joined: 14 Nov 2012
Has thanked: 50 times
Been thanked: 20 times

Re: Listing MultiCharts.NET API Issues

Postby orad » 10 Feb 2015

The CStudyControl class has helper methods for creating VariableObject and VariableSeries.

Code: Select all

_simpleVar = (VariableObject<string>)CreateSimpleVar<string>();
_seriesVar = (VariableSeries<double>)CreateSeriesVar<double>();
which is the same as below, except that the helper methods will check if Variable objects are created in the correct stage (Construction/Create) in the study's life-cycle.

Code: Select all

_simpleVar = new VariableObject<string>(this);
_seriesVar = new VariableSeries<double>(this);
However, the syntax for using helper methods is much more verbose due to need to cast. Also if the return type is casted to wrong object (VariableObject <-> VariableSeries) that would make problem at runtime. This could simply be avoided if helper methods just returned the correct type instead of IVar<T>:

Code: Select all

new protected VariableSeries<T> CreateSeriesVar<T>(T defaultVal = default(T), int dataStream = 0)
{
return (VariableSeries<T>)base.CreateSeriesVar(defaultVal, dataStream);
}

new protected VariableObject<T> CreateSimpleVar<T>(T defaultVal = default(T), int dataStream = 0)
{
return (VariableObject<T>)base.CreateSimpleVar(defaultVal, dataStream);
}
in the above code I'm using the new keyword to overwrite (hide) the methods with the new signature, but this should be fixed in the CStudyControl class itself so they return correct types by default. It really doesn't seem to be necessary for these methods to return IVar<T>.


Return to “MultiCharts .NET”