Sergey Kosinsky Personal web site

 External functions for Metastock 7.0-9.0



It is well known that Metastock has limited capabilities to write a huge formula. But there is an opportunity to develop any algorithm with so-called external formulas using dynamically linked library. Metastock can transfer to the external formula up to 9 variables of four types: array of prices, numeric, string and set of names. Metastock always transfer an OHLCVOI array for a current base security even the security isn't shown at the chart.
     An external formula returns an array of prices or error with an optional diagnostic message, as shown on the picture below.

      Metastock allows to use the Paste Functions wizard  to select some function from the list. Also it shows help on how to use selected formula in the Format field.

I use the following rules to represent different types of parameters:

- array of prices will have square brackets [] at the end of the parameter's name;

- numeric value will have a name without anything;

- string will be enclosed into double quotes;

- set will be enclosed into square brackets [] and elements of the set will be separated with the pipe character "|" each other.

For convenience any element of such set can have more than one symbolical name, for example Long and L for long positions, Short and S for short, Both and B for for both short and long positions. Metastock isn't case sensitive. Names of parameters will reflect physical sense of a variable whenever possible . 

Function list.

Current version 1.5. of MSX_KSR.DLL includes the following indicators:

ExtFml( "msx_ksr.NRTR", Close[], Koefficient[]);

ExtFml( "msx_ksr.NRTR_WATR", Close[], Length, Multiplier);

ExtFml( "msx_ksr.CER", Close[], Length );

ExtFml( "MSX_KSR.RENKO_WATR", Close[], Multiplier, Smooth,

ExtFml( "msx_ksr.WriteData", DataArray[], "FileName");

ExtFml( "msx_ksr.ReadData", "FileName");

ExtFml( "msx_ksr.TradeFile", Close[], BuySell[], [Long|L|Short|S|Both|B], "Strategy");

The functions were described in the "Modern-Trading" magazine issue 4, 2001 in the article "Trend indicator" (PDF in Russian) as well as another indicators published at the  Konstantin's site (aka konkop)Function reference.

The  "NRTR", "NRTR_WATR" , "CER" & "RENKO_WATR" functions are the Metastock version of the following ELA codes for "$NRTR_DT", "$NRTR_WATR" , "CER" & "Renko_Adaptive" respectively.

Functions "WriteData" and "ReadData" were created during adaptation of some indicators working with charts of different time frame.

1. Base function  "$NRTR_DT". Calculates the dynamics of percent sliding filter. The variant was proposed by Dmitry Tolstonogov:
"New Russian" Trailing Reverse Function based on percentage channel
Coded by Dmitri Tolstonogov (aka DT)
Inputs: K(Numeric);
Vars: Trend(0), HPrice(C), LPrice(C), Reverse(0);
if Trend >=0 then begin
if C > HPrice then HPrice = C;
Reverse = HPrice*(1 - K*.01);
if C <= Reverse then begin
Trend = -1;
LPrice = C;
Reverse = LPrice*(1 + K*.01);
if Trend <= 0 then begin
if C < LPrice then LPrice = C;
Reverse = LPrice*(1 + K*.01);
if C > Reverse then begin
Trend = 1;
HPrice = C;
Reverse = HPrice*(1 - K*.01);
$NRTR_DT = Reverse;

2. Function "$NRTR_WATR". Calculates an sliding filter based on average true range.

North Russian Trailing Reverse Function based on WeightedAverage True Range with Multiplier. Coded by Konstantin Kopyrkin (aka konkop) and Dmitri Tolstonogov (aka DT) Ekaterinburg-Irkutsk, Russia
Inputs: Len(Numeric), {WAverage TrueRange Length}
M(Numeric); {Multiplier}
Vars: Trend(0), HPrice(C), LPrice(C), Reverse(0), TrueHi(H), TrueLo(L), TrueRng(0), WATR(0);
{Calculate Weighted Average TrueRange}
If Close[1] > High Then TrueHi = Close[1] Else TrueHi = High; {Calculate TrueHigh}
If Close[1] < Low Then TrueLo = Close[1] Else TrueLo = Low; {Calculate TrueLow}
TrueRng = TrueHi - TrueLo; {Calculate TrueRange}
WATR = WAverage(TrueRng,Len); {Calculate WATR}
{Calculate Trailing Reverse Level}
if Trend >=0 then begin {UpTrend}
if C > HPrice then HPrice = C;
Reverse = HPrice - M*WATR;
if C < Reverse then begin
Trend = -1;
LPrice = C;
Reverse = LPrice + M*WATR;
if Trend <= 0 then begin {DownTrend}
if C < LPrice then LPrice = C;
Reverse = LPrice + M*WATR;
if C >= Reverse then begin
Trend = 1;
HPrice = C;
Reverse = HPrice - M*WATR;
$NRTR_WATR = Reverse;



3. Function "CER". Indicator "Centered Extremum Range" (CER)©
(Centered Extremum Range, modified  26.09.2001)

Written by: Konstantin Kopyrkin (aka konkop) 22.09.2001
Description: Centered Extremum Range (CER) indicator.
Copyright(c) konkop, 2001

Inputs: Len(1);{Smoothing length}
Vars: CentAvg(C), Up(0), Dn(0), CER(0);

CentAvg = 0.5*(Ñ + CentAvg[1]);
If C[2]<C[1] and C<C[1] then Up = 100*(C[1]-CentAvg)/CentAvg;
If C[2]>C[1] and C>C[1] then Dn = 100*(C[1]-CentAvg)/CentAvg;
CER = Up - Dn;


4. Renko-Adaptive indicator "Renko_Adaptive" (based on ATR)
{Renko-Adaptive indicator (based on ATR)
Written by konkop 07.03.2002.
Attention: set MaxBarsBack (f.e. =30) in this study according with
MaxBarsBack value in the Renko_Adaptive strategy
for correct step-by-step calculations of the buy/sell levels

Inputs: K(1),

vars:Brick(0) ,DN(0), UP(0), BricksUp(0), BricksDn(0);

Value1 = AvgTrueRange(Smooth);

If BarNumber = 1 Then Begin
Up = H;
Dn = L;
Brick = K*(H - L);
If BarNumber > 1 then begin
If C > UP + Brick Then begin
BricksUp = IFF(Brick = 0, 0, Floor((C - Up)/Brick)*Brick);
UP = Up + BricksUp;
Brick = K*Value1;
DN = Up - Brick;
BricksDn = 0;
If C < Dn - Brick Then begin
BricksDn = IFF(Brick = 0, 0, Floor((Dn - C)/Brick)*Brick);
Dn = Dn - BricksDn;
Brick = K*Value1;
Up = Dn + Brick;
BricksUp = 0;

Plot1(UP, "Up");
Plot2(DN, "Dn");
{***************end of code****************}


"WriteData" function allows to write any data array into a file. Each line of such file contains three fields separated by comma. There are the following fields: date YYYYMMDD, time HHNNSSS and a floating point number, where YYYY is four digit year, and MM,DD,HH,NN - two digit month, day, hour and minute respectively and SSS is a sequential number of a tick within a minute.
   "ReadData" function allows to read data, which have been created with "WriteData" function or by any external application. The data can be used in an indicator applied to any chart. If data in the file and the chart have different periodicity, then  "ReadData" function will skip rows or repeat a row with the nearest date and time if needed. Both indicators can be used to pass  data array or trade signals from a daily chart to an intraday chart.

Installation guide.

     To install all the indicators you should download DLL , then unzip and put the DLL into the folder:
"C:\Program Files\Equis\MetaStock\External Function DLLs", and create the following custom plot based indicators with the Metastock Formula Builder:

Indicator with NRTR

{ExtFml( "msx_ksr.NRTR", DataArray[], Koefficient[]}

ExtFml("msx_ksr.NRTR", Close, Ko);


Indicator with NRTR_WATR

{ExtFml( "msx_ksr.NRTR_WATR", DataArray[], Length, Multiplier)}

Mu:=Input("Multiplier", 1,10, 4);
ExtFml("msx_ksr.NRTR_WATR", Close, Ln, Mu);


Indicator with CER

{ExtFml( "msx_ksr.CER",Close[], Length)}

ExtFml("msx_ksr.CER",Close, Len);


Indicator with both  NRTR & CER

Len:=Input("Smoothing length",1,100,8);
ExtFml("msx_ksr.NRTR", Close, ExtFml("MSX_KSR.CER", Close, Len));


Indicator with RENKO_WATR

{ExtFml( "msx_ksr.RENKO_WATR", Close[], Multiplier, Smooth,


ExtFml( "msx_ksr.RENKO_WATR", Close, Multiplier, Smooth, Up);
ExtFml( "msx_ksr.RENKO_WATR", Close, Multiplier, Smooth, Dn);


Trading strategy with RENKO_WATR

{ExtFml( "msx_ksr.RENKO_WATR", Close[], Multiplier, Smooth,
Note! Multiplier and Smooth parameters have to be defined explicitly}

ExtFml( "msx_ksr.RENKO_WATR", Close, 10,5, Long);

Using the "WriteData" and "ReadData" functions within custom indicators.

Create the following indicators with the Metastock Formula Builder:


The WriteData custom indicator using the WriteData formula to write data to a file.

{ExtFml( "msx_ksr.WriteData",DataArray[], "Filename")
Replace Mov(C,25,S)  with your own data}   
DataArray:= Mov(C,25,S);  

ExtFml( "msx_ksr.WriteData",  DataArray,  "D:\quote\files\eesr" );


The Read custom indicator using the Read formula to read data from a file.

{ExtFml( "msx_ksr.ReadData", "Filename")}
ExtFml( "msx_ksr.ReadData", "D:\quote\files\eesr" );

Remark:You can place a macro %S and %P in the "Filename" string passed as the second parameter to the WriteData and ReadData function. The macros will be automatically replaced with the actual security symbol and periodicity (Note, that a symbol name should not contain the ":\/?*" and other non alphanumeric characters which are not allowed in the name of a regular file):


ExtFml( "msx_ksr.ReadData", "D:\quote\files\%S-%P" );


The actual filename could look like D:\quote\files\EESR.MICEX-D and  D:\quote\files\EESR.MICEX-10 
for the daily and 10 minutes chart shown below.  Place the WriteData custom indicator on a daily periodicity chart. Unified Energy System daily chart.

Every time when you open or refresh the chart, the file D:\quote\files\eesr will be created or updated.


Place the "ReadData" custom indicator on the second intraday chart of any periodicity. 

Unified Energy System 10 minutes intraday chart.


No periodicity changed.

The same chart with periodicity changed upwards to daily.

Explanation on using the TradeFile function.

     If the parameter 'ClosePositionAtLastBar' is equal either 'yes' or 'true' or '1' then position will be automatically closed at a last bar. Parameter 'Directory' specifies a folder where the function will store files. Parameter 'Author' defines a nick of the author. The Author field will be used as a part of a file name to identify the author among another authors.
     4. An output file will be overwritten each time when a chart is refreshed.
     5. A description on the file locates here Specification of a file of registration of trades

Here is an example on how to use the  TradeFile function to wtite trades into a file.

{this simplest strategy combines two crosses of two moving averages with different periods for demonstration purpose only}

BS1:=If(Mov(C, 3, S) > Mov(C, 10, S), 1, -1);
BS2:=If(Mov(C, 5, S) > Mov(C, 30, S), 1, -1);

{Variable BuySell should be equal to 1 to enter a long position , -1 to enter a short position and 0 to exit}


{ExtFml( "msx_ksr.TradeFile", Close[], Multiplier, Smooth, [Up|U||Dn|D])}
{Long positions only}
F1:=ExtFml( "msx_ksr.TradeFile", Close, BuySell, Long, "MyStrategyLong");

{Short positions only}
F2:=ExtFml( "msx_ksr.TradeFile", Close, BuySell, Short, "MyStrategyShort");

{Both long and short positions}
F3:=ExtFml( "msx_ksr.TradeFile", Close, BuySell, Both, "MyStrategyBoth");

{It is useful to draw a plot with the current position. Always place the formula at a separate inner window}


The chart shows using the indicator described in the example above. 

; This file was created 04/08/2002 17:24:33 with TradeFile() MSX function
; developed by Sergei R. Kosinski, Saint-Petersburg, Russia,

Here is a msx_ksr.ini with default values. Change 'Directory' to the folder which you want to collect files in. Change 'Author' to the nickname you are known around.


Visit my feedback page to ask a question.

Sergey R. Kosinsky,
СанктSaint-Petersburg, Russia.
Created: 18 ноября 2001

Last update : February 20, 2011