It is common practice to use indicators in strategies. You can utilize both system indicators and custom indicators in the Strategy Editor.

 

Let us explain the indicator usage in the example of the MACD indicator.

 

The MACD/OsMA indicator has three component lines:

1)MACD
2)Signal Line
3)OsMA

 

clip0662

 

 

ActFX allows you to get the values of any of these lines at any given time period (candle). In order to use the indicator, you must:

1)Declare an object from the TIndicatorMACD class

 

1)Create this object in the procedure OnCreate. You have to set two parameters when creating the object:

       a) History : TСandleHistory — the chart history that the indicator will use.

       b) 'MACD' : String — the name that will appear in the indicators list.

 

2)Set the properties of the newly created object (such as periods etc.) If you do not set the indicator properties, the default values will be used.

 

var

MACD: TIndicatorMACD;

 

procedure OnCreate;

begin

 MACD := TIndicatorMACD.Create(History, 'MACD');

 MACD.PeriodShorterEMA := 12;

 MACD.PeriodLongerEMA := 26;

 MACD.PeriodForSignal := 9;

end;

 

All indicators are based on candle (or in some rare occasions tick) historic data.

 

The used indicators will appear in the candle history settings (at the time when you set up the initial strategy parameters before the strategy is launched).

 

clip0663

 

As mentioned above, the MACD indicator has three component lines. Correspondingly the  TIndicatorMACD class object has three components:

1)The object MACD.Graph holds the values of the MACD line.
2)The object MACD.SignalGraph holds the values of the Signal line.
3)The object MACD.HistoGraph holds the values of the OsMA line.

 

Example:

 

If you need to assign the last (current) value of the Signal line to the variable 'a', the script must include the following line:

 

a:=MACD.SignalGraph.Last;

 

You can also use the Last(), Count and Get() methods to work with these objects.

 

When using the Last() method, the index goes from the most recent value.

When you are using the Get() method, the index starts from the oldest value. Note that indexing  starts with 0 not 1.

 

So you can get the last value of the indicator in the following ways:

 

a:=MACD.SignalGraph.Last(0);

 

a:=MACD.SignalGraph.Get(MACD.SignalGraph.Count-1);

 

 

If the indicator has only one component/line, it is referred to as Graph (with exception of the Fractals indicator).

 

Example:

 

We need to assign the last value of the ADX indicator to the variable 'a'. The script should include the following line:

 

a:=ADX.Graph.Last;

 

 

Example: Let us write a strategy that will open a Buy position when the moving average of the Stochastic indicator (%D) crosses the bottom level bottom-up, and a Sell position if it crosses the top level top-down.

const

 StrategyName = 'MyStrategy';

 

var

 History: TCandleHistory;

 Account: TAccount;

 Amount: Double;

 TopLevel, BottomLevel, TraderRange: Integer;

Stochastic: TIndicatorStochastic;

procedure OnCreate;

begin

 AddCandleHistorySetting(@History, 'Candle History', '', CI_1_Minute, 100);

 History.OnNewCandleEvent := @OnNewCandle;

 AddAccountSetting(@Account, 'Account(Lots)', '');

 AddFloatSetting(@Amount, 'Amount', 1);

 AddIntegerSetting(@TopLevel, 'Top Level (%)', 80);

 AddIntegerSetting(@BottomLevel, 'Bottom Level (%)', 20);

 AddIntegerSetting(@TraderRange, 'Trader Range', 2);

Stochastic := TIndicatorStochastic.Create(History, 'Stochastic');

end;

 

procedure OnNewCandle;

begin

if (Stochastic.GraphD.Last(1) > BottomLevel) and (Stochastic.GraphD.Last(2) < BottomLevel) then

          CreateOrder(History.Instrument, Account, Amount, bsBuy,

                      NullRate, NullRate, TraderRange, 'StochasticTrade');

if (Stochastic.GraphD.Last(1) < TopLevel) and (Stochastic.GraphD.Last(2) > TopLevel) then

          CreateOrder(History.Instrument, Account, Amount, bsSell,

                      NullRate, NullRate, TraderRange, 'StochasticTrade');

end;

 

 

Below is the list of indicator objects with descriptions/examples of their usage.

Accelerator/Decelerator Oscillator

Object Class:

ADOscillator: TindicatorADOscillator;

Creating the object

ADOscillator := TIndicatorADOscillator.Create(History, 'ADOscillator');

Getting values

ADOscillator.Graph.Last;

Setting the parameters

ADOscillator.PeriodSmall := 5;

ADOscillator.PeriodBig := 34;

 

ADX

Object Class:

ADX: TIndicatorADX;

Creating the object

ADX := TIndicatorADX.Create(History, 'ADX');

Getting values

ADX.Graph.Last

Setting the parameters

ADX.Period := 14;

 

Alligator

Object Class:

Alligator: TIndicatorAlligator;

Creating the object

Alligator := TIndicatorAlligator.Create(History, 'Alligator');

Getting values

Alligator.JawGraph.Last

Alligator.TeethGraph.Last

Alligator.LipsGraph.Last

Setting the parameters

Alligator.PeriodJaws := 13;

Alligator.ShiftJaws := 8;

Alligator.PeriodTeeth := 5;

Alligator.ShiftTeeth := 3;

Alligator.PeriodLips := 8;

Alligator.ShiftLips := 5;

 

Average True Range

Object Class:

ATR: TIndicatorAverageTrueRange;

Creating the object

ATR := TIndicatorAverageTrueRange.Create(History, 'AverageTrueRange');

Getting values

ATR.Graph.Last

Setting the parameters

ATR.Period := 14;

 

Awesome Oscillator

Object Class:

AwesomeOscillator: TIndicatorAwesomeOscillator;

Creating the object

AwesomeOscillator := TIndicatorAwesomeOscillator.Create(History, 'AwesomeOscillator');

Getting values

AwesomeOscillator.Graph.Last

Setting the parameters

AwesomeOscillator.PeriodSmall := 5;

AwesomeOscillator.PeriodBig := 34;

 

Bollinger Bands

Object Class:

BollingerBands: TIndicatorBollingerBands;

Creating the object

BollingerBands := TIndicatorBollingerBands.Create(History, 'BollingerBands');

Getting values

BollingerBands.TopGraph.Last

BollingerBands.Graph.Last

BollingerBands.BottomGraph.Last

Setting the parameters

BollingerBands.Period := 20;

BollingerBands.Deviation := 2;

 

Commodity Channel Index

Object Class:

CCI: TIndicatorCommodityChannelIndex;

Creating the object

CCI := TIndicatorCommodityChannelIndex.Create(History, 'CommodityChannelIndex');

Getting values

CCI.Graph.Last

Setting the parameters

CCI.Period := 14;

 

DeMarker

Object Class:

DeMarker: TIndicatorDeMarker;

Creating the object

DeMarker := TIndicatorDeMarker.Create(History, 'DeMarker');

Getting values

DeMarker.Graph.Last

Setting the parameters

DeMarker.Period := 14;

 

Envelopes

Object Class:

Envelopes: TIndicatorEnvelopes;

Creating the object

Envelopes := TIndicatorEnvelopes.Create(History, 'Envelopes');

Getting values

Envelopes.TopGraph.Last

Envelopes.BottomGraph.Last

Setting the parameters

Envelopes.Period := 14;

Envelopes.Deviation := 10;

 

Fractals

Object Class:

Fractals: TIndicatorFractals;

Creating the object

Fractals := TIndicatorFractals.Create(History, 'Fractals');

Getting values

Fractals.Value(i)

Setting the parameters

Fractals.Period:=5;

 

The Fractals indicator differs from the other ones in a way that that it has values only for certain candles.

 

clip0734

 

 

From the technical point of view, this indicator cannot be regarded as a continuous graph, only as discrete values:

+1 if the fractal by the candle points up

-1 if there is the fractal by the candle points down

0 if there is no fractal by this candle

To refer to a value of the Fractals, use the method Fractals.Value(). The index specified for the  value points to an individual candle, and starts from the beginning of the charts. This function returns one of the values: -1, 0, or 1. You cannot use the Last() or Get() methods to refer to the Fractals.

 

Example:

 

We need to output the value of the Fractal in the Last (current) candle into the log. The script should include the following line:

 

log(FloatToStr(Fractals.Value(History.Count-1)));

 

 

Gator

Object Class:

Gator: TIndicatorGator;

Creating the object

Gator := TIndicatorGator.Create(History, 'Gator');

Getting values

Gator.GraphUp.Last

Gator.GraphDown.Last

Setting the parameters

Gator.PeriodJaws := 13;

Gator.ShiftJaws := 8;

Gator.PeriodTeeth := 5;

Gator.ShiftTeeth := 3;

Gator.PeriodLips := 8;

Gator.ShiftLips := 5;

 

Linear Regression

Object Class:

LinearRegression: TIndicatorLinearRegression;

Creating the object

LinearRegression := TIndicatorLinearRegression.Create(History, 'LinearRegression');

Getting values

LinearRegression.Graph.Last

Setting the parameters

LinearRegression.Period := 14;

 

MACD/OsMA

Object Class:

MACD: TIndicatorMACD;

Creating the object

MACD := TIndicatorMACD.Create(History, 'MACD');

Getting values

MACD.Graph.Last

MACD.SignalGraph.Last

MACD.HistoGraph.Last

Setting the parameters

MACD.PeriodShorterEMA := 12;

MACD.PeriodLongerEMA := 26;

MACD.PeriodForSignal := 9;

 

Momentum

Object Class:

Momentum: TIndicatorMomentum;

Creating the object

Momentum := TIndicatorMomentum.Create(History, 'Momentum');

Getting values

Momentum.Graph.Last

Setting the parameters

Momentum.Period := 16;

 

Moving Average

Object Class:

MA: TIndicatorMovingAverage;

Creating the object

MA := TIndicatorMovingAverage.Create(History, 'MovingAverage');

Getting values

MA.Graph.Last

Setting the parameters

MA.Period :=5;

MA.Kind := makSimple;

 

There are 3 types of Moving Average: Simple, Exponential, and Weighted. You can indicate the type you want as a parameter in the procedure OnCreate (makSimple, makExponential or makWeighted). If you do not include this setting, makSimple will be used by default.

 

Example:

 

var

MA: TIndicatorMovingAverage;

 

procedure OnCreate;

begin

 MA := TIndicatorMovingAverage.Create(History, 'MovingAverage');

 MA.Period :=5;

MA.Kind := makExponential;

end;

 

 

Parabolic SAR

Object Class:

ParabolicSAR: TIndicatorParabolicSAR;

Creating the object

ParabolicSAR := TIndicatorParabolicSAR.Create(History, 'ParabolicSAR');

Getting values

ParabolicSAR.Graph.Last

Setting the parameters

ParabolicSAR.InitStep := 0.02;

ParabolicSAR.MaxStep := 2;

 

 

Relative Strength Index

Object Class:

RSI: TIndicatorRSI;

Creating the object

RSI := TIndicatorRSI.Create(History, 'RSI');

Getting values

RSI.Graph.Last

Setting the parameters

RSI.Period := 14;

 

Standard Deviation

Object Class:

StandardDeviation: TIndicatorStandardDeviation;

Creating the object

StandardDeviation := TIndicatorStandardDeviation.Create(History, 'StandardDeviation');

Getting values

StandardDeviation.Graph.Last

Setting the parameters

StandardDeviation.Period := 10;

 

Stochastic

Object Class:

Stochastic: TIndicatorStochastic;

Creating the object

Stochastic := TIndicatorStochastic.Create(History, 'Stochastic');

Getting values

Stochastic.GraphK.Last

Stochastic.GraphD.Last

Setting the parameters

Stochastic.Period := 5;

Stochastic.AveragePeriod := 3;

Stochastic.Slow:=True;

Stochastic.Slow:=False;

 

There are 2 types of Stochastic: Fast and Slow. You can indicate the type you want as a parameter in the procedure OnCreate: Stochastic.Slow:=True for Slow Stochastic, or  Stochastic.Slow:=False for Fast Stochastic. If you do not include this setting, Stochastic Fast will be used by default.

 

William's Percent Range

Object Class:

WilliamsPercentRange: TIndicatorWilliamsPercentRange;

Creating the object

WilliamsPercentRange := TIndicatorWilliamsPercentRange.Create(History, 'WilliamsPercentRange');

Getting values

WilliamsPercentRange.Graph.Last

Setting the parameters

WilliamsPercentRange.Period := 14;

 

Custom Indicators in the Strategies

In addition to the system indicators, you can also utilize custom indicators in your strategies. You may refer to the Trader Manual to the section Charts → User Indicator Editor to learn about custom indicators).

If you want to use a custom indicator in your strategy, it must be present in the List of User Indicators.

 

Let us explain the custom indicator usage in the example of the Ichimoku Kinko Hyo indicator.

The Ichimoku Kinko Hyo indicator has 5 component lines:

1)Tenkan-sen
2)Kijun-sen
3)Senkou Span A
4)Senkou Span B
5)Chinkou Span

 

clip0735

 

ActFX allows you to get the values of any of these lines at any given time period (candle). In order to use a custom indicator in the strategy, you must:

 

1)Declare an object from the TTIndicatorScript class

 

2)Create this object in the procedure OnCreate. You have to set three parameters when creating the object:

       a) History : TСandleHistory — the chart history that the indicator will use.

       b) 'ScriptIchimoku' : String — the name that will appear in the indicator list (which is shown when you set up the initial strategy  parameters before the strategy is launched)

       c) 'My Ichimoku':  String — the name of the used indicator. This name must coincide with the name in the indicator script.

 

var

ScriptIchimoku: TIndicatorScript;

 

procedure OnCreate;

begin

ScriptIchimoku := TIndicatorScript.Create(History, 'Script Ichimoku', 'My Ichimoku');

end;

 

All indicators are based on candle (or in some rare occasions tick) historic data.

 

Like the system indicators, the custom indicators that are used in the strategy will appear in the candle history settings (which are shown when you set up the initial strategy parameters before the strategy is launched).

clip0736

 

As mentioned above, the Ichimoku Kinko Hyo has 5 component lines. The method GetGraph() is used to refer to the values of these lines. The lines are numbered in the same order as they were listed in the procedure Init in the Indicator script, from number 0 up to number ([the number of indicator lines]-1).

 

Example:

 

The order of lines in the procedure Init in the User Indicator Script is as follows:

 

IchTenkan := TLineGraph.Create();

IchKijun := TLineGraph.Create();

IchSSA := TLineGraph.Create();

IchSSB := TLineGraph.Create();

IchCS := TLineGraph.Create();

 

If we need to assign the last value of the Senkou Span A line (IchSSA) to the variable a, the Strategy Script must include the following line:

 

a := ScriptIchimoku.GetGraph(2).Last

 

You can also use the Last(), Count and Get() methods to work with graph objects.

 

When using the Last() method, the index goes from the most recent value.

When you are using the Get() method, the index starts from the oldest value. Note that indexing  starts with 0 not 1.

 

Example:

 

You can get the last value of the Senkou Span B (IchSSB) line in either one of the following ways:

 

b:=ScriptIchimoku.GetGraph(3).Last(0);

 

b:=ScriptIchimoku.GetGraph(3).Get(ScriptIchimoku.GetGraph(3).Count-1);

 

Example: Let us write a strategy that will open a Buy position when the Tenkan-sen line crosses the Kijun-sen line bottom-up, and a Sell position when it crosses the Kijun-sen line top-down.

 

const

 StrategyName = 'Ichimoku_Strategy';

 

var

 History: TCandleHistory;

 Account: TAccount;

 Amount: Double;

 Stop, Limit, TraderRange: Integer;

 ScriptIchimoku: TIndicatorScript;

 

procedure OnCreate;

begin

 AddCandleHistorySetting(@History, 'Candle History', 'EURUSD', CI_1_Hour, 100);

 History.OnNewCandleEvent := @OnNewCandle;

 AddAccountSetting(@Account, 'Account', '');

 AddFloatSetting(@Amount, 'Amount(Lots)', 1);

 AddIntegerSetting(@Stop, 'Stop', 20);

 AddIntegerSetting(@Limit, 'Limit', 30);

 AddIntegerSetting(@TraderRange, 'Trader Range', 0);

 ScriptIchimoku := TIndicatorScript.Create(History, 'ScriptIchimoku', 'My Ichimoku');

end;

 

procedure OnNewCandle;

var

Point: Double;

begin

Point := History.Instrument.PointSize;

                                                                                           

if (ScriptIchimoku.GetGraph(0).Last(2)<ScriptIchimoku.GetGraph(1).Last(2))

  and (ScriptIchimoku.GetGraph(0).Last(1)>ScriptIchimoku.GetGraph(1).Last(1)) then

     CreateOrder(History.Instrument, Account, Amount, bsBuy,

                 History.Instrument.Sell - Point*Stop,

                 History.Instrument.Sell + Point*Limit, TraderRange, 'IchTrade');

 

if (ScriptIchimoku.GetGraph(0).Last(2)>ScriptIchimoku.GetGraph(1).Last(2))

  and (ScriptIchimoku.GetGraph(0).Last(1)<ScriptIchimoku.GetGraph(1).Last(1)) then

     CreateOrder(History.Instrument, Account, Amount, bsSell,

                 History.Instrument.Buy + Point*Stop,

                 History.Instrument.Buy - Point*Limit, TraderRange, 'IchTrade');

end;

 

Below you can find the full script of the custom indicator Ichimoku Kinko Hyo. Keep in mind that it was created in the User Indicator Editor, as it uses other procedures/different script. You may refer to the Trader Manual to the section Charts → User Indicator Editor to learn about custom indicators).

 

Const

IndicatorName = 'My Ichimoku';

Layout = Embedded;    

 

var

 IchKijun: TLineGraph;

 IchTenkan: TLineGraph;

 IchSSA: TLineGraph;

 IchSSB: TLineGraph;

 IchCS: TLineGraph;

 Strokes: TLineGraph;

 Strokes2: TLineGraph;

 Strokes3: TLineGraph;

 Strokes4: TLineGraph;

 TenkanSenPeriod, KijunSenPeriod, SenkouSpanBPeriod: Integer;

 

procedure CreateSettings;

begin

 AddSetting('tenkansenperiod', 'Tenkan-sen Period', '9');

 AddSetting('kijunsenperiod', 'Kijun-sen Period', '26');

 AddSetting('senkouspanbperiod', 'Senkou Span B Period', '52');

 AddSetting('Tenkan_color', 'Tenkan-Sen Color', 'clRed');

 AddSetting('Kijun_color', 'Kijun-Sen Color', 'clBlue');

 AddSetting('SSA_color', 'Senkou Span A Color', 'clGray');

 AddSetting('SSB_color', 'Senkou Span B Color', 'clBlack');

 AddSetting('CS_color', 'Chinkou Span Color', 'clLime');

end;

 

 

procedure ApplySettings;

begin

TenkanSenPeriod:= StrToInt(GetSetting('tenkansenperiod'));

KijunSenPeriod:= StrToInt(GetSetting('kijunsenperiod'));

SenkouSpanBPeriod:= StrToInt(GetSetting('senkouspanbperiod'));

 

IchTenkan.Color := StrToColor(GetSetting('Tenkan_color'));

IchKijun.Color := StrToColor(GetSetting('Kijun_color'));

IchSSA.Color := StrToColor(GetSetting('SSA_color'));

IchSSB.Color := StrToColor(GetSetting('SSB_color'));

IchCS.Color := StrToColor(GetSetting('CS_color'));

 

Strokes.Color := StrToColor(GetSetting('SSA_color'));

Strokes2.Color := StrToColor(GetSetting('SSA_color'));

Strokes3.Color := StrToColor(GetSetting('SSB_color'));

Strokes4.Color := StrToColor(GetSetting('SSB_color'));

SetTitle('Ichimoku: ' +GetSetting('tenkansenperiod') + ', '

  +GetSetting('kijunsenperiod') + ', ' +GetSetting('senkouspanbperiod'));

end;

 

 

procedure Init;

begin

 IchTenkan := TLineGraph.Create();

 IchKijun := TLineGraph.Create();

 IchSSA := TLineGraph.Create();

 IchSSB := TLineGraph.Create();

 IchCS := TLineGraph.Create();

 Strokes := TLineGraph.Create();

 Strokes2 := TLineGraph.Create();

 Strokes3 := TLineGraph.Create();

 Strokes4 := TLineGraph.Create();

end;

 

 

procedure Recalculate;

begin

FullRecalculation;

end;

 

 

function Middle(per:integer; ValInd:integer):Double;

var min, max: double;

   i: integer;

begin

min:=SourceGraph.LowValue(ValInd);

max:=SourceGraph.HighValue(ValInd);

   for i:=1 to per-1 do

   begin

    if SourceGraph.HighValue(ValInd-i) > max then

     max:= SourceGraph.HighValue(ValInd-i);

    if SourceGraph.LowValue(ValInd-i) < min then

     min:= SourceGraph.LowValue(ValInd-i);

   end;

   result:=(max+min)/2;

end;

 

 

procedure Add(const ValueIndex: Integer);

var Tenkan, Kijun, SSA, SSB, CS: double;

                                           

begin

   Tenkan:=Middle(TenkanSenPeriod,ValueIndex);

   IchTenkan.AddXY(SourceGraph.XValue(ValueIndex), Tenkan);

 

   Kijun:=Middle(KijunSenPeriod,ValueIndex);

   IchKijun.AddXY(SourceGraph.XValue(ValueIndex), Kijun);

 

   SSA:=(Tenkan+Kijun)/2;

   IchSSA.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod), SSA);

 

   SSB:=Middle(SenkouSpanBPeriod,ValueIndex);

   IchSSB.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod), SSB);

 

   CS:=SourceGraph.CloseValue(ValueIndex);

   IchCS.AddXY(SourceGraph.XValue(ValueIndex-KijunSenPeriod), CS);

 

   if (round(ValueIndex/2) = (ValueIndex/2)) and (SSA>SSB) then

   begin

   Strokes.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod),SSA);

   Strokes2.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod),SSB);

   Strokes3.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod),SSB);

   Strokes4.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod),SSB);

   end;

   if (round(ValueIndex/2) <> (ValueIndex/2)) and (SSA>SSB) then

   begin

   Strokes.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod),SSB);

   Strokes2.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod),SSA);

   Strokes3.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod),SSB);

   Strokes4.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod),SSB);

   end;

 

   if (round(ValueIndex/2) = (ValueIndex/2)) and (SSA<SSB) then

   begin

   Strokes.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod),SSA);

   Strokes2.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod),SSA);

   Strokes3.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod),SSA);

   Strokes4.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod),SSB);

   end;

   if (round(ValueIndex/2) <> (ValueIndex/2)) and (SSA<SSB) then

   begin

   Strokes.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod),SSA);

   Strokes2.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod),SSA);

   Strokes3.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod),SSB);

   Strokes4.AddXY(SourceGraph.XValue(ValueIndex+KijunSenPeriod),SSA);

   end;

 

end;