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 |

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).

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.

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 |

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).

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; |