Turbine and .streck

Turbine and .streck

Capture your project’s finances with Turbine — powered by the intuitive and expressive .streck language.

The turbine software and the .streck language are available for macOS, Linux and Windows. (We are on version 1.1.)

MacOS

To download a signed and notarized installation program for macOS, click here.

A signed and notarized installation guarantees that the software has been verified by Apple for the absence of malicious components and confirmed as untampered. Upon installation, the turbine binary is placed in /usr/local/bin.

Linux

To download the Turbine program for Linux, click here. Download, gunzip the file and place the binary in /usr/local/bin.

Windows

To download the Turbine program for Windows, click here. The Windows binary is signed.

Welcome to turbine and the .streck language — your powerful toolkit for modeling, proving, and explaining the dynamics of complex financial scenarios. Whether you are working on interactions between companies, families, or other entities, Turbine helps you bring clarity, precision, and confidence to your financial reasoning.

Tutorial

The streck language is a language with statements, expressions and functions, concepts familiar for everyone who programmed in a computer language, for example Java or Go. The streck language however has one feature up its sleeve: The traditional programming concepts can coexist with a fourth construct: transactions. A transaction is a timestamped sequence of statements, a record of something not only referenced by a line number, but referenceable by its point in time as well. Transactions can be sorted by your computer and since it contains statements it can be executed by your computer as part of a simulation.

Let us have a look at what a hello world program written in streck looks like:

/*  helloworld.streck | illustrating streck and transactions. */

2025-07-14 11:00:00 print 'is this sorted correctly?\n'
2025-07-14 08:00:00 print 'Hello world 🤝 starting simulation.\n'
2025-07-14 17:00:00 print 'simulation end.\n'
To run the example, write turbine helloworld.streck at your prompt. Your console should look something like

prompt> turbine helloworld.streck
Hello world 🤝 starting simulation.
is this sorted correctly?
simulation end.
prompt>
Note that we do not have a procedure as in 'hello world' programs written in other computer languages, but that three transactions are sorted and that statements can be executed. Let us now look at a second more detailed example. Before doing so, however, let us first discuss what a key-value store is. A key-value store is a type of database that stores data as a collection of key-value pairs. The key is a unique identifier used to retrieve the associated value and the value can in general terms be anything - text, numbers, binary data. In turbine the 'value' is an entity or a time-series. Back to our second example, this time we want to record variations in time for an entity named Company1. We also want to look back on our data and compute a summary and output the result on the terminal. We write the following:

/*  retrospect.streck | illustrating entity, time series and summation. */

2024-12-31 23:59:59 
  print 'Retrospect 🤝 starting simulation.\n'
  entity Company1 named 'My Company'
  account Company1.A1920 named 'Bank account'
  account Company1.A3010 named 'Domestic sales of goods'

2025-07-14 13:56:26 
  bookkeep Company1 {
    debit A1920 with 25000.00
    credit A3010 with 25000.00
  } comment 'A change in A1920 and A3010.'

2025-12-31 23:59:59 
  var result = SumYearCredit(Company1,A3010) - 
   SumYearDebit(Company1,A3010)
  print 'The yearly result is: \(result)\n'
  print 'simulation end.\n'
In the example above we create an entity Company1, we define two time series A1920 and A3010, we record a variation on two accounts and we can look back on the change, assign the yearly sale to a local variable and output the sum to the terminal. When executed, the code outputs:

Retrospect 🤝 starting simulation.
The yearly result is: 25000.00
simulation end.

In .streck, we want to write readable code that is easy to understand so the language supports functions, a concept that is useful for two purposes: (1) To capture a parameterized sequence of statements that that can be reused from one or many transactions, and (2) to compute a value that is part of an expression. The first case is in computer science sometimes called a procedure and the second case is called a function. In .streck, we can add a procedure anywhere in a .streck file — even after its first use in a transaction. The normal way is to have the procedures at the beginning of a .streck file or in a separate file included from the command line. Since we have a very short program, we add the procedure to the beginning of the file as in

/*  coherence.streck | illustrating procedures. */

func Sale(priceInclVat) /* ⬷ a procedure. */
{
   bookkeep Company1 {
     debit A1920 with priceInclVat
     credit A3010 with priceInclVat
   } comment 'Interacting with customer.'
}

2024-12-31 23:59:59 
  print 'Coherence 🤝 starting simulation.\n'
  entity Company1 named 'My Company'
  account Company1.A1920 named 'Bank account'
  account Company1.A3010 named 'Domestic sales of goods'

2025-07-14 13:56:26 Sale(25000.00)
2025-07-14 15:56:26 Sale(25000.00)

2025-12-31 23:59:59 
  var result = SumYearCredit(Company1,A3010) - 
   SumYearDebit(Company1,A3010)
  print 'The yearly result is: \(result)\n'
  print 'simulation end.\n'
The program outputs:

Coherence 🤝 starting simulation.
The yearly result is: 50000.00
simulation end.

As with procedures, a function can be defined anywhere in a .streck file or in a file included from the command line:

/*  compliance.streck | illustrating procedures and functions. */

func Gold(ounces, pricePerOunce) /* ⬷ a function. */
{
   return ounces * pricePerOunce
}

func SaleAndPayment_Gold(ounces, priceInclVat₋per₋ounce) /* ⬷ a procedure. */
{
  var priceExclVat = 0.8 * Gold(ounces,priceInclVat₋per₋ounce)
  var priceInclVat = 1.25 * priceExclVat
   
  bookkeep Company1 {
    debit A1510 with priceInclVat
    credit A2611 with priceInclVat - priceExclVat
    credit A3010 with priceExclVat
  } comment 'Sale Gold'
   
  bookkeep Company1 {
    credit A1510 with priceInclVat
    debit A1920 with priceInclVat
  } comment 'Payment Gold'
}

2024-12-31 23:59:59 
  print 'Compliance 🤝 starting simulation.\n'
  entity Company1 named 'My Company'
  account Company1.A1510 named 'Accounts Receivable'
  account Company1.A1920 named 'Bank account'
  account Company1.A2611 named 'Output VAT'
  account Company1.A3010 named 'Domestic sales of goods'

2025-07-14 13:56:26 SaleAndPayment_Gold(10, 3384.49)
2025-07-15 15:43:12 SaleAndPayment_Gold(10, 3373.38)
/* ⬷ the parameters are 'ounces' followed by 'price per ounce'. */

2025-12-31 23:59:59 
  var yearlyResult = SumYearCredit(Company1,A3010) -
   SumYearDebit(Company1,A3010)
  var assetsCash = SumYearDebit(Company1,A1920) - 
   SumYearCredit(Company1,A1920)
  print 'The result is: \(yearlyResult)\n'
  print 'The accumulation is: \(assetsCash)\n'
  print 'simulation end.\n'
This example gives us the sum:

Compliance 🤝 starting simulation.
The result is: 54062.96
The accumulation is: 67578.70
simulation end.

In the example above, we have four accounts, one function, and one procedure. Using the defined procedure SaleAndPayment_Gold, we can record both the sale of goods and the corresponding payment. We also output two values: yearlyResult and assetsCash, the latter representing accumulated funds expected to be carried forward to the daybook for future years.

We have now seen streck examples for documenting sales and purchases. We can also use turbine to compute the monthly Vat as in the following example:

/*  consistent.streck | VAT is closing the month. */

func SalesGoods25(priceExclVat)
{
  var priceInclVat = 1.25 * priceExclVat
   
  bookkeep Company1 {
    debit A1510 with priceInclVat
    credit A2611 with priceInclVat - priceExclVat
    credit A3010 with priceExclVat
  } comment 'Sale goods 25%.'
}

func ExpenseSnowClearance(priceInclVat) {
   
  var priceExclVat = 0.8 * priceInclVat
   
  bookkeep Company1 {
    debit A5164 with priceExclVat
    debit A2641 with priceInclVat - priceExclVat
    credit A2440 with priceInclVat
  } comment 'Expense snow clearance.'
}

func MonthlyVat() {
   
  var salesVat = SumMonthCredit(Company1,A2611)
  var purchaseVat = SumMonthDebit(Company1,A2641)
   
  bookkeep Company1 {
    debit A2611 with salesVat
    credit A2650 with salesVat
    credit A2641 with purchaseVat
    debit A2650 with purchaseVat
  } comment 'VAT January 2025'
   
  print 'The sales Vat is: \(salesVat)\n'
  print 'The purchase Vat is: \(purchaseVat)\n'
   
}

2024-12-31 23:59:59
   
  print 'Consistent 🤝 starting simulation.\n'
   
  entity Company1 named 'My Company'
   
  account Company1.A1510 named 'Accounts receivable'
  account Company1.A2440 named 'Accounts payable'
  account Company1.A2611 named 'Output VAT'
  account Company1.A2641 named 'Input VAT (Recoverable)'
  account Company1.A2650 named 'VAT payable/receivable'
  account Company1.A3010 named 'Domestic sales of goods'
  account Company1.A5164 named 'Snow-clearance'

2025-01-14 13:56:26 SalesGoods25(25000.00)
2025-01-14 13:56:26 ExpenseSnowClearance(18750.00)
2025-01-31 23:59:59 MonthlyVat()

2025-12-31 23:59:59
  print 'simulation end.\n'
In this example we close the month with a computation on A2611, A2650, and A2641. The program outputs

Consistent 🤝 starting simulation.
The sales Vat is: 6250.00
The purchase Vat is: 3750.00
simulation end.
So we finish the month by writing out the values to report to a tax agency.

Additional Details on .streck

In this section, facets of the .streck language are described. We look at reserved words, the available predefined functions and other details.

Keywords

The streck language has fourteen plus five plus three keywords. A keyword has a special meaning in streck and can not be used as an identifier for a function, procedure, entity, or time series.

account
credit
entity
named
var
bookkeep
debit
func
print
with
comment
else
if
return

Five additional keywords are defined to construct transaction sequences:

ending
interval
occurring
schedule
starting

And three keywords are reserved for handling change in accounting method:

before
end
do

A transaction sequence is by turbine ended before ending in case the ending is defined and before last transaction in case ending is not specified.

How to use the keywords are described in the Tutorial section in this document.

Predeclared Names

Eight functions are predeclared in streck: SumYearDebit, SumYearCredit, SumMonthDebit, SumMonthCredit, SumDayDebit, SumDayCredit, SumAllDebit, SumAllCredit. Each function accepts an entity identifier as its first argument and a time series key as its second argument.

Identifiers

An identifier in streck is a Unicode token that does not begin with a digit.

Command-Line Usage

You can specify multiple .streck files as arguments when running turbine from the command line as in

prompt> turbine definition.streck daybook-2025-and-closing.streck
All transactions from the provided files are aggregated, sorted in chronological order, and then executed. Prior to execution, all definitions are collected and made available for use within the transactions.

Revision Handling and .streck

Your streck files are UTF-8 encoded text files. This means your work can be tracked with for example the Git revision handling system.