Note: Code changes made in self-scripted indicators are automatically applied to conditions in which this indicators are used if the changes were made in the "body" of e.g. "OnCalculate/OnBarUpdate. Changes of parameters, outputs series, etc. require a manual edit of the conditions.
Bar Numbering Within the Chart
The following example demonstrates the usage of the plot method and the properties of the Chart object.
Note: For demonstration purposes, each time Paint is called up within the "Bar Numbering" section, "New" and "Dispose" will also be called up multiple times. From a performance point of view, this solution can be better implemented by using constant variable declarations and calling up "Dispose" within the OnDispose statement.
The plot method allows you to add a background image to the chart. The following example uses an image with the JPG format located in the main directory on the hard drive (C:).
To enable file selection within the properties dialog of an indicator, you will need a type converter. The following example displays how a selection of WAV files can be programmed for an alert:
usingSystem;usingSystem.IO;usingSystem.Collections;usingSystem.ComponentModel;usingAgenaTrader.Custom;usingAgenaTrader.Plugins;namespaceAgenaTrader.UserCode{[Description("File Picker Example.")]publicclassFilePicker:UserIndicator{privatestring _soundFile ="Alert4.wav";privatestaticstring _dir =Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) +@"\\AgenaTrader\\Sounds\\";internalclassMyConverter:TypeConverter{publicoverrideboolGetStandardValuesSupported(ITypeDescriptorContext context){returntrue;}publicoverrideStandardValuesCollectionGetStandardValues(ITypeDescriptorContext context){if (context ==null) returnnull;ArrayList list =newArrayList();DirectoryInfo dir =newDirectoryInfo(_dir);FileInfo[] files =dir.GetFiles("*.wav");foreach (FileInfo file in files) list.Add(file.Name);returnnewTypeConverter.StandardValuesCollection(list);}}protectedoverridevoidOnStart(){PlaySound(_soundFile);}[Description("Choose file to play.")][Category ("Sound")][TypeConverter(typeof(MyConverter))]publicstring SoundFile{get { return _soundFile; }set { _soundFile = value; }}}}
Returns the currency symbol for the current instrument:
publicstringgetWaehrungssymbol() {string s ="";switch (Instrument.Currency) {caseCurrencies.USD: s ="$"; break;caseCurrencies.EUR: s ="€"; break;caseCurrencies.CHF: s ="CHF"; break;caseCurrencies.GBP: s = ((char)163).ToString(); break;caseCurrencies.JPY: s = ((char)165).ToString(); break;}return s;}
Converts a number into a currency with a thousands separator and 2 decimal places. The block separation per 1000 units can be set in "Culture".
publicstringgetWaehrungOhneSymbol(double d) {// Separate 1000s and two decimal pointsreturnd.ToString("\#,\#\#0.00");}
Converts a number into a currency with a thousands separator and 2 decimal places and a currency symbol:
publicstringgetWaehrungMitSymbol(double d) {// Dollar is prefixed, everything else is added afterwardsstring s=getWaehrungOhneSymbol(d);string w=getWaehrungssymbol();if (w=="$") s=w+" "+s; else s+=" "+w;return s;}
Converts a number into a currency with a thousands separator and 2 decimal places as well as a currency symbol, and fills up to a fixed length with empty spaces. The function is great for outputting values into a table.
publicstringgetWaehrungMitSymbol(double d,int Laenge) {// Leading spaces until a fixed length has been reachedstring s=getWaehrungMitSymbol(d);for (int i=s.Length; i<Laenge; i++) s=" "+s;return s;}
Converts a number into a percentage. Nothing is calculated, only formatted. Leading plus sign, a decimal place and a percent sign.
publicstringgetPercent(double d) {d=Math.Round(d,1);string s=(d>0)?"+":""; // Leading plus signreturn s+d.ToString("0.0")+"%";}
Formats the market price depending on the number of decimal places to which the currency is notated. This includes a thousands separator and fixed length, meaning that zeros are filled on the right hand side. Because Culture Info is being used, you must integrate the NameSpace System.Globalization.
publicstringformat(double d){int tickLength =0;// ticksize.ToString() is for example 6J = "1E-06" and length is then 5// and not 8 as it should be with "0.000001")if (TickSize <1) tickLength =TickSize.ToString("0.\#\#\#\#\#\#\#\#\#\#\#").Length-2;string f ="{0:n"+tickLength.ToString()+"}";returnstring.Format(CultureInfo.CurrentCulture, f, d);}
The bars are numbered from youngest to oldest. This type is used in the OnCalculate() method. The last bar has an index of 0, while the oldest bar has the index Bars.Count-1.
The bars are numbered from oldest to youngest. This type is most commonly used in the OnPaint() method in "for" loops. The oldest Bbar receives an index of 0, while the youngest bar has the index Bars.Count-1. The following function can be used to recalculate the index types:
The name of an indicator (or a strategy) is displayed within the properties dialog and at the top edge of the chart. Use the ToString() method and DisplayName property to overwrite it.
publicoverridestringToString(){return"My Name";}
publicoverridestring DisplayName { get {return"My Name"; } }
Important tip: Always use both override methods in your scripts to assure that your special name is used on all AgenaTrader forms.
Rectangle with Rounded Corners
By using the graphics methods, you can create interesting forms and place them onto the chart. One example of this is the RoundedRectangle class, which is a rectangle with rounded corners.
Example Code:usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Drawing;usingSystem.Linq;usingSystem.Xml;usingSystem.Xml.Serialization;usingSystem.Drawing.Drawing2D;usingAgenaTrader.API;usingAgenaTrader.Custom;usingAgenaTrader.Plugins;namespaceAgenaTrader.UserCode{[Description("Demo of RoundedRectangles")]publicclassDemoRoundedRectangle:UserIndicator{protectedoverridevoidOnInit(){IsOverlay =true;}protectedoverridevoidOnCalculate() {}publicoverridevoidOnPaint(Graphics g,Rectangle r,double min,double max){GraphicsPath path;// draws a rectangle with rounded cornerspath =RoundedRectangle.Create(30,50,100,100,8);g.DrawPath(Pens.Black, path);// draws a filled rectangle with a radius of 20// only round the upper left and lower right cornerpath =RoundedRectangle.Create(160,50,100,100,20,RoundedRectangle.RectangleCorners.TopLeft|RoundedRectangle.RectangleCorners.BottomRight);g.FillPath(Brushes.Orange, path);}}publicabstractclassRoundedRectangle{publicenumRectangleCorners{None =0, TopLeft =1, TopRight =2, BottomLeft =4, BottomRight =8,All = TopLeft | TopRight | BottomLeft | BottomRight}publicstaticGraphicsPathCreate(int x,int y,int width,int height,int radius,RectangleCorners corners){Rectangle r =newRectangle(x,y,width, height);Rectangle tlc =newRectangle(r.Left,r.Top,Math.Min(2* radius,r.Width),Math.Min(2* radius,r.Height));Rectangle trc = tlc;trc.X=r.Right-2* radius;Rectangle blc = tlc;blc.Y=r.Bottom-2* radius;Rectangle brc = blc;brc.X=r.Right-2* radius;Point[] n =newPoint[]{newPoint(tlc.Left,tlc.Bottom),tlc.Location,newPoint(tlc.Right,tlc.Top),trc.Location,newPoint(trc.Right,trc.Top),newPoint(trc.Right,trc.Bottom),newPoint(brc.Right,brc.Top),newPoint(brc.Right,brc.Bottom),newPoint(brc.Left,brc.Bottom),newPoint(blc.Right,blc.Bottom),newPoint(blc.Left,blc.Bottom),blc.Location};GraphicsPath p =newGraphicsPath();p.StartFigure();//Top left cornerif ((RectangleCorners.TopLeft& corners) ==RectangleCorners.TopLeft)p.AddArc(tlc,180,90);elsep.AddLines(newPoint[] { n[0],n[1],n[2] });//Top edgep.AddLine(n[2],n[3]);//Top right cornerif ((RectangleCorners.TopRight& corners) ==RectangleCorners.TopRight)p.AddArc(trc,270,90);elsep.AddLines(newPoint[] { n[3],n[4],n[5] });//Right edgep.AddLine(n[5],n[6]);//Bottom right cornerif ((RectangleCorners.BottomRight& corners) ==RectangleCorners.BottomRight)p.AddArc(brc,0,90);elsep.AddLines(newPoint[] { n[6],n[7],n[8] });//Bottom edgep.AddLine(n[8],n[9]);//Bottom left cornerif ((RectangleCorners.BottomLeft& corners) ==RectangleCorners.BottomLeft)p.AddArc(blc,90,90);elsep.AddLines(newPoint[] { n[9],n[10],n[11] });//Left edgep.AddLine(n[11],n[0]);p.CloseFigure();return p;}publicstaticGraphicsPathCreate(Rectangle rect,int radius,RectangleCorners c){ returnCreate(rect.X,rect.Y,rect.Width,rect.Height,Math.Max(1,radius), c); }publicstaticGraphicsPathCreate(int x,int y,int width,int height,int radius){ returnCreate(x, y, width, height,Math.Max(1,radius),RectangleCorners.All); }publicstaticGraphicsPathCreate(Rectangle rect,int radius){ returnCreate(rect.X,rect.Y,rect.Width,rect.Height,Math.Max(1,radius)); }publicstaticGraphicsPathCreate(int x,int y,int width,int height){ returnCreate(x, y, width, height,8); }publicstaticGraphicsPathCreate(Rectangle rect){ returnCreate(rect.X,rect.Y,rect.Width,rect.Height); }}}