AUSTRA is a small functional language designed to handle financial series and common econometric models. It also implements vectors, matrices and the most frequently used operations from linear algebra, statistics, and probabilities.
AUSTRA formulas are efficiently parsed by a .NET Engine, and they are translated into fast-running native code that calls routines also implemented in .NET that take advantage of multicore systems and SIMD extensions.
This topic introduces the basic syntax of the language.
The lexical syntax of AUSTRA is very similar to most programming languages:
Integer and real numbers are represented as in most programming languages. Here are some examples:
2023;
1.0;
-0.1E-16
Number literals can be suffixed with a lower-case i to represent an imaginary value:
2.0i;
-3i
The identifier i, by its own, represents the imaginary unit:
1-3i = 1 - 3 * i
Complex numbers can also be created using the complex function:
complex(1, -3) = 1 - 3 * i;
complex(3) = 3 + 0i
Since i is not a keyword, you must be careful because it can be redefined as a user variable.
Complex can also be built using the polar notation:
polar(1, pi/2) -- Another way to write the imaginary unit.
String literals are enclosed by double quotes and cannot cross line boundaries.
"A simple string literal";
"A string literal with a quote: ""Wow!"". That was the quote."
Date literals come in two flavours. A simple literal only includes the month and year, assuming the first day of the month:
jan20;
jul2021
Two-digit years are first interpreted as a year inside the XXI century. If the resulting date is more than 20 years ahead, 100 years are subtracted to that date. For instance:
jan20; -- January 1st, 2020
may42 -- May 1st, 1942
A day can be added using this syntax:
6@jan20;
31@jul2021
Though we do not expect anyone to write hundreds of pages of AUSTRA script, we still support line comments for better documentation. Comments always starts with two consecutive hyphens and extends to the next line feed or the end of the expression, whatever comes first:
-- A verbose version of math::min()
if aapl.mean < msft.mean then aapl.mean -- Another comment.
else msft.mean
Every AUSTRA expression must start with a root object. It could be either a global variable, a local variable, a class method, a class variable, or a code definition.
Global variables come in two flavours: persistent variables and session variables. Persistent variables come mostly from an external source, like a JSON file, a database or an external service. In this AUSTRA version, those persisted variables are always time series, because they have a predictable serialization format. This design decision, of course, may change at some point of the evolution of the library.
For instance, when I open the AUSTRA application in my system, it automatically loads a set of series and definitions that are stored in a subfolder Austra of my Documents folder, in a file named data.austra, and its main windows looks something like this:
Persistent series are shown below a Series node. I can type the name of any of these variables in the Code Editor:
aaa
When I press F5, AUSTRA translates the expression and immediately shows the content of the aaa series:
Session variables, as the name indicates, are defined inside a user session, and die with the session. They are defined and removed using the set statement:
set v1 = [1, 2, 3, 4, 5];
set v2 = v1.map(x => 1 / x);
v2.plot;
-- v1 is removed now:
set v1;
-- v2, however, persist for the rest of the session.
v2.plot;
-- More than one variable can be assigned in a single statement.
set pi2 = 2 * pi, pi3 = 3 * pi
Only the value of the variable is stored, but not the formula that was used to calculate that value. This means, for example, that every use of the session variable will return the same value, even if the value was created using a random number generator:
-- v1 is created using random numbers:
set v1 = vec:: random(10);
-- Every use of v1 returns always the same vector:
v1 = v1;
-- This is in contrast with the behavior of local variables.
let v2 = vec:: random(10);
-- This expression will return false:
v2 = v2
Local variables are explained here.
Session variables appears in the Variables panel, each one inside a node according to their types:
Class methods in AUSTRA correspond both to constructors and static methods in traditional OOP languages, like C#.
Let's start with some variables:
i = math:: i;
e = math:: e;
pi = math:: pi and pi = math:: π
The same equivalence is valid for what we normally would consider "global functions":
exp(π*i);
math:: exp(math:: pi * math:: i)
Those global functions and constants are considered as belonging to the math for avoiding problems if any of these symbols is redefined as a persistent or session variable.
Of course, there are more classes than math, and we can use their class methods for creating new objects:
matrix:: random(10);
vec:: new(10);
vec(10)
As the last example shows, when you call a new method on a class, you can omit the ::new part and use just the class name as synonym.
This convention applies to every data type handled by AUSTRA.