Cheat sheet

Cheat sheet

Comments

a + b;    # This is a single line comment
          // Another single line comment

/*
      I am also a comment, but can span
      multiple lines if I wan to
 */

/#
      Do not forget me, another multipline
      comment.
#/

c + d;

Raise to the power

x ^ y

Enter a series with observations

cpi = observe( date, obs1, obs2 );

e.g.

cpi = observe( dateIndex( 2020, 1, 1 ), 100, 100.1, 100.2 );

This loads 100 in 2020 Jan, 100.1 in Feb and so on.

Missing values

Use a . e.g.

cpi = observe( dateIndex( 2020, 1, 1 ), 100, ., ., 101, 102 );

This loads 100 in Jan, 101 in April and so on.

Merge series

cpi = merge( cpi1, cpi2, cpi3 ... );

Here cpi1 takes preference so if it shares an observation with cpi2 then the observation in cpi1 will be used.

Index a series to 2015=100

avg2015 = avg( limit( dateIndex( 2015, 1, 1 ), dateIndex( 2015, 12, 31 ), cpi ) );
index   = 100 * cpi / avg2015;

Merge two series with a common observation in 2015Q1

di = dateIndex( 2015, 1, 1 );
series = merge(  series1, series2 / series2[ di ] * series2[ di ] );

Calculate logs

fdm does not want you to be confused between natural and base 10 logs, so there is no log function, only ln for natural and log10 for base 10 calculations, thus

lcpi = ln( cpi );

is probably what you are looking for, but, if you want base 10, you can use

lcpi = log10( cpi );

Calculate percentage changes

From one period to the next

Depending on the frequency, this would be quarter on quarter or month on month growth rates.

growth = p( cpi );

The returned values are simply the percentage changes between consecutive observations. A value of 0.1 represents 10% so you may want to multiply by 100 to print it out nicely.

Year on year

growth = py( cpi );

Here the returned growth rates represents the growth from say January last year to January this year.

Annualised

growth = pa( cpi );

These values are month on month (or quarter on quarter) growth rates that have been annualised.

Lags

To lag a series use

ly = y(-1);
ly4 = y(-4);

Differences

Differencing time series is an important topic. fdm distinguishes between regular frequencies such as monthly and quarterly and irregular frequencies such as daily.

When you have a monthly series with observations as follows

2020 Jan 100.0
2020 Feb 100.1
2020 Mar 101.1
2020 Apr 101.2

and you difference it, you will get a new series with three observations

2020 Feb 0.1
2020 Mar 1.0
2020 Apr 0.1

If one observation was missing in the original series, e.g. if it was

2020 Jan 100.0
2020 Feb 100.1
2020 Mar <missing>
2020 Apr 101.2

then differencing it yields only a single observation

2020 Feb 0.1

This is because there is nothing to difference Apr 2020 to. This is how it works for regular series. Observations are made regularly and if there is no observation it means there is a missing value and differencing will yield gaps and actually be problematic.

Not so with irregular or daily data. Here dates do not follow a regular pattern. Weekends and holidays cause large gaps but it should not hamper the differencing of the series. So differencing e.g.

2019-Dec-31 (Tue)	100
2020-Jan-01 (Wed)	<missing>
2020-Jan-02 (Thu)	100.1
2020-Jan-03 (Fri)	100.2
2020-Jan-04 (Sat)	<missing>
2020-Jan-05 (Sun)	<missing>
2020-Jan-06 (Mon)	100.3
2020-Jan-07 (Tue)	100.4
2020-Jan-08 (Wed)	100.5

should not be bothered by the holiday (on 2020-01-01) or by the weekend and should return

2020-Jan-02 (Thu)	0.1
2020-Jan-03 (Fri)	0.1
2020-Jan-06 (Mon)	0.1
2020-Jan-07 (Tue)	0.1
2020-Jan-08 (Wed)	0.1

Even though the input series contains three missing observations or gaps, the differenced series still has five observations as it simply ignored these gaps and used the previous available observation.

This is the distinguishing factor between regular and irregular time series. When differencing a regular time series, it can only difference observations made exactly one bar apart. An irregular time series will use all observations and will difference despite gaps. The only requirement to difference in a given bar is that there be a previous observation available.

fdm handles this with the previous functions. Thus to difference a regular time series use

dy = d( y );   # same as y - y(-1)

but to difference an irregular time series use

dy = dPrev( y );    # same as y - prev( y )

Likewise, for regular series, use

dy = d( y );    # y - y(-1) or y - lag( y )
dy = dLn( y );  # Change in logs
dy = dy( y );   # Change over a year, e.g. y - y(-4) for quarterly

and for irregular series use

dy = dPrev( y );     # y - prev( y )
dy = dLnPrev( y );   # Change in logs for daily observations
dy = dyPrev( y );    # Change over a year, ignores gaps and used most recent
                     # (earlier) value

Formatting output

Numbers are fixed format by default. The number of decimals to show after the decimal separator is four by default.

print( pi () );     # +3.1416
format( 10 );
print( pi () );     # +3.1415926536

Think of fdm as a programming language when dealing with numbers. Just as C or C++ is not locale aware, so with fdm. Numbers are separated with a decimal point in calculations. The output format can however be specified. Things like prefixes, postfixes, field lengths and so on can be set.

Please see the format function and its many friends for more details.

Matrices

fdm offers a lot of matrix functionality. To define a matrix, say a 10x5 matrix, use

A = matrix( 10, 5 );

Now A contains a lot of zeroes. You can also load, row by row, data when using the matrix function.

A = matrix( 3, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9 );

Now A is

[ 1 2 3
  4 5 6
  7 8 9 ]

You can create matrices filled with random numbers

A = matrixRand( 10 );         # 10 x 10 matrix
A = matrixRand( 2, 3 );       #  2 x  3 matrix
A = matrixRand( 3, 3, 3 );    #  3 x  3 matrix with each random number containing 3 random digits
A = matrixRand( 3, 3, 100 );  # Go big or go home, here each number will have 100 random digits

Matrices can be added and multiplied and inverted just as in your textbook. See the matrix section in the function manual for more detail.

User defined functions

Define a new function

define( "square", "a", a * a );
define( "hypot", "a", "b", sqrt( a * a + b * b ) );
define( "diag", "A", "i", {
	print( "Will return diagonal of A" ),
	print( "Found at position i", i ),
	print( "And also report on it" ),
	A[ i; i ]
} );

Parent scope

x = 10;

define( "myFunc", "x", {
	print( "My x is", x ),
	print( "My parent's x is", parent( x ) )
} );

Optimise a function

There are numerous algorithms, using the downhill simplex method of Nelder and Mead, for example.

# Define a function
# Rosenbrock with a = 1 and b = 100

# Parameters
a = 1;
b = 100;

define( "rb", "A",
{
  # Parameters taken from parent context
  a = parent( a );
  b = parent( b );

  # Note A is a column vector
  x = A[ 1; 1 ];
  y = A[ 2; 1 ];

  ( a - x ) ^ 2 + b * ( y - x ^ 2 ) ^ 2;
} );

# Optimise
print( funcOptimNm( "rb", matrix( 2, 1, 0, 0 ) ) );