Just an update with some thoughts for next steps...
In my last update, we talked about this "totem pole" of packages I was putting together.
Countries and Currencies are primordial value types with some helper functions.
Markets are providers of Observables such as yield curves, stock prices, etc.
Jurisdictions define things like laws / regulations, taxes, etc.
Entities are legal entities with a Jurisdiction
FinancialInstruments are Contracts issued by legal Entities that can be bought or sold.
Positions are holdings of FinancialInstruments that support mathematical operations.
GeneralLedgers defines an Account for managing and reporting Positions and Transactions.
Simplified Account
Last time, although there was just a single underlying Account type, I defined five singleton types with the intention of supporting dispatch:
GeneralLedger - A debit Account with no parent. Cannot post entries directly.
DebitGroup - A debit Account with both a parent and children. Cannot post entries directly.
CreditGroup - A credit Account with both a parent and children. Cannot post entries directly.
DebitAccount - A debit Account with a parent but no children. Can post entries directly.
CreditAccount - A crediit Account with a parent but no children. Can post entries directly.
Unfortunately, that idea leads to type instabilities, so I've removed these singleton types. Now, there is just Account. This is cleaner.
Load chart of accounts from CSV
I put together a fairly realistic chart of accounts for an insurance company in CSV format and added a method loadchart to load it to memory. I'll see about making a trimmed down sample I can upload.
This Entry debits Cash and credits Accounts Payable US$10.
Now, a Transaction is more complicated than a simple Entry. For example, a transaction could be "Buy an Insurance Policy". In my case, this transaction involves 4 entries:
Cash is paid - Debit Bank Account and credit Gross Premium.
Set up reserve - Debit Expense for Unearned Premium and credit Unearned Premium Reserve.
Collect levy - Debit Bank account and credit Accounts Payable - Levy.
But how much of what is collected from the customer is used for levy and what is the admin fee? These are functions of the amount paid.
With this example in mind, my initial design for a Transaction is (roughly):
struct Transaction
_entries::Dict{String,Entry}
_module::Function
end
i.e. a dictionary of entries and a module function to tell you how to post the entries via:
function post!(t::Transaction,a::Position)
t._module(t._entries,a)
end
For my example, I define a method:
function buypolicy(e::Dict{String,Entry},a::Position)
levy_rate = .04
fee_rate = .045
premium = a/(1+levy_rate)
levy = premium*levy_rate
fee = premium*fee_rate
GL.post!(e["pay_cash"],premium)
GL.post!(e["set_reserve"],premium)
GL.post!(e["collect_levy"],levy)
GL.post!(e["collect_fee"],fee)
end
and Transaction
Transaction(entries,buypolicy)
In other words, a transaction module is a function that takes a dictionary of entries and a transaction amount, performs some computations and finally posts to the respective accounts.
Note that I've hard coded the levy_rate and fee_rate. Ideally, these should be provided by an Entity which could depend on a Jurisdiction.
Also note that the post! method accepts both a transaction and an amount. My early version of an Entry had the amount as part of the type definition, but that has been removed, which explains why the syntax in the example provided no longer works. The new syntax for the example is:
Added Cash as a FinancialInstrument and using FixedDecimal
Above, I defined usd as a Position using FI.USD. FI is short for FinancialInstruments and USD is an instance of Cash<:FinancialInstrument.
Recall that Currencies.USD is a simple primordial singleton value type, i.e.
julia> typeof(Currencies.USD)
Currency{:USD}
As noted above, currencies can be viewed as either a value type or as a financial instrument. In some cases, but not all, viewing currency as a financial instrument (linked to an entity, e.g. a central bank) would be overkill so we keep Currencies.USD as a simple singleton value type.
In order to work with currency as a financial instrument, I introduced Cash<:FinancialInstrument, i.e.
julia> typeof(FI.USD)
Cash{Currency{:USD}}
Fundamentally, Cash is a contract issued by a central bank or monetary authority similar to the way Stock is issued by a corporation. If I own Cash, that means I have a Position in Cash. Mathematical operations are defined on Positions of FinancialInstruments rather than directly on FinancialInstruments. For example,
By default, if a Position is constructed using Cash as the FinancialInstrument, I use
julia> Currencies.unit(Currencies.USD)
to determine the official number of decimal places for that currency and use the FixedPointDecimals.jl package to specify the amount with the correct number of decimals, e.g.
Despite the substantial effort so far, I am still only scratching the surface and things may need to be redesigned again before stabilizing.
More work on FinancialInstruments
For example, above, I showed how to handle the transaction: "Buy an Insurance Policy". I still haven't actually constructed an InsurancePolicy. An InsurancePolicy is a FinancialInstrument so if I buy a policy, I now have a Position in a FinancialInstrument called InsurancePolicy. The value at t=0 is known, but what about t+1? The value of my policy can depend on many things including interest rates and these should be Observables of a Market.
I expect an iterative process where what we do with FinancialInstruments impacts how we design Markets and how we design Markets will feed back to FinancialInstruments etc so I'll probably keep focusing on FinancialInstruments for now, but hope to look at Markets soon.
Real-Time Balances
One of my goals with this work is to be able to do simulations and real-time balance sheets. A BalanceSheet is a type of FinancialStatement so, in the foreseeable future, we should have a FinancialStatements.jl package, but before that, I'd like to build some capabiity for real-time account balances.
If all account balances change only when there is a transaction, doing real-time balances would be simple, but some account balances, e.g. Unearned Premium Reserve or other deprecations / appreciations, have an inherit time dependence.
A naive way to do this would be to post journal entries every millisecond, but that would pollute the journal. I'm sure there is a simple solution and I have some ideas, but just need to sit down and hash them out. The vision is to be able to simulate say 1 year of transactions in 10 seconds and watch how the balance sheet changes in real / accelerated time.
Financial Statements
Once some designs for financial instruments are hashed out and the path to real-time balances is clear, at some point soon, I'd like to start using the general ledger to build financial reports such a balance sheets and income statements.
Just an update with some thoughts for next steps...
In my last update, we talked about this "totem pole" of packages I was putting together.
Countries
andCurrencies
are primordial value types with some helper functions.Markets
are providers ofObservables
such as yield curves, stock prices, etc.Jurisdictions
define things like laws / regulations, taxes, etc.Entities
are legal entities with aJurisdiction
FinancialInstruments
areContracts
issued by legalEntities
that can be bought or sold.Positions
are holdings ofFinancialInstruments
that support mathematical operations.GeneralLedgers
defines anAccount
for managing and reportingPositions
andTransactions
.Simplified
Account
Last time, although there was just a single underlying
Account
type, I defined five singleton types with the intention of supporting dispatch:GeneralLedger
- A debitAccount
with no parent. Cannot post entries directly.DebitGroup
- A debitAccount
with both a parent and children. Cannot post entries directly.CreditGroup
- A creditAccount
with both a parent and children. Cannot post entries directly.DebitAccount
- A debitAccount
with a parent but no children. Can post entries directly.CreditAccount
- A crediitAccount
with a parent but no children. Can post entries directly.Unfortunately, that idea leads to type instabilities, so I've removed these singleton types. Now, there is just
Account
. This is cleaner.Load chart of accounts from CSV
I put together a fairly realistic chart of accounts for an insurance company in CSV format and added a method
loadchart
to load it to memory. I'll see about making a trimmed down sample I can upload.Added
Transaction
Last time,
GeneralLedgers
included an example:To run the example from the REPL:
The purpose of this example is to demonstrate how to create a simple ledger and post an entry:
(Warning: The following syntax is no longer valid. See below for the updated syntax.)
This
Entry
debitsCash
and creditsAccounts Payable
US$10.Now, a
Transaction
is more complicated than a simpleEntry
. For example, a transaction could be "Buy an Insurance Policy". In my case, this transaction involves 4 entries:Bank Account
and creditGross Premium
.Expense for Unearned Premium
and creditUnearned Premium Reserve
.Bank account
and creditAccounts Payable - Levy
.Administration Fee
and creditAccounts Payable - Admin Fee
.But how much of what is collected from the customer is used for levy and what is the admin fee? These are functions of the amount paid.
With this example in mind, my initial design for a
Transaction
is (roughly):i.e. a dictionary of entries and a
module
function to tell you how to post the entries via:For my example, I define a method:
and
Transaction
In other words, a transaction
module
is a function that takes a dictionary of entries and a transaction amount, performs some computations and finally posts to the respective accounts.Note that I've hard coded the
levy_rate
andfee_rate
. Ideally, these should be provided by anEntity
which could depend on aJurisdiction
.Also note that the
post!
method accepts both a transaction and an amount. My early version of anEntry
had the amount as part of the type definition, but that has been removed, which explains why the syntax in the example provided no longer works. The new syntax for the example is:Alternatively, you could define
and then
Added
Cash
as aFinancialInstrument
and usingFixedDecimal
Above, I defined
usd
as aPosition
usingFI.USD
.FI
is short forFinancialInstruments
andUSD
is an instance ofCash<:FinancialInstrument
.Recall that
Currencies.USD
is a simple primordial singleton value type, i.e.As noted above, currencies can be viewed as either a value type or as a financial instrument. In some cases, but not all, viewing currency as a financial instrument (linked to an entity, e.g. a central bank) would be overkill so we keep
Currencies.USD
as a simple singleton value type.In order to work with currency as a financial instrument, I introduced
Cash<:FinancialInstrument
, i.e.Fundamentally,
Cash
is a contract issued by a central bank or monetary authority similar to the wayStock
is issued by a corporation. If I ownCash
, that means I have aPosition
inCash
. Mathematical operations are defined onPosition
s ofFinancialInstruments
rather than directly onFinancialInstruments
. For example,By default, if a
Position
is constructed usingCash
as theFinancialInstrument
, I useto determine the official number of decimal places for that currency and use the FixedPointDecimals.jl package to specify the amount with the correct number of decimals, e.g.
This gives us more control on rounding to the "penny", makes displaying easier and I expect computations to be faster than
Float64
.This is just the default behavior. If you want, you can still construct a cash position using
Float64
(or any other<:Real
) via:Next steps
Despite the substantial effort so far, I am still only scratching the surface and things may need to be redesigned again before stabilizing.
More work on
FinancialInstruments
For example, above, I showed how to handle the transaction: "Buy an Insurance Policy". I still haven't actually constructed an
InsurancePolicy
. AnInsurancePolicy
is aFinancialInstrument
so if I buy a policy, I now have aPosition
in aFinancialInstrument
calledInsurancePolicy
. The value att=0
is known, but what aboutt+1
? The value of my policy can depend on many things including interest rates and these should beObservables
of aMarket
.I expect an iterative process where what we do with
FinancialInstruments
impacts how we designMarkets
and how we designMarkets
will feed back toFinancialInstruments
etc so I'll probably keep focusing onFinancialInstruments
for now, but hope to look atMarkets
soon.Real-Time Balances
One of my goals with this work is to be able to do simulations and real-time balance sheets. A
BalanceSheet
is a type ofFinancialStatement
so, in the foreseeable future, we should have a FinancialStatements.jl package, but before that, I'd like to build some capabiity for real-time account balances.If all account balances change only when there is a transaction, doing real-time balances would be simple, but some account balances, e.g.
Unearned Premium Reserve
or other deprecations / appreciations, have an inherit time dependence.A naive way to do this would be to post journal entries every millisecond, but that would pollute the journal. I'm sure there is a simple solution and I have some ideas, but just need to sit down and hash them out. The vision is to be able to simulate say 1 year of transactions in 10 seconds and watch how the balance sheet changes in real / accelerated time.
Financial Statements
Once some designs for financial instruments are hashed out and the path to real-time balances is clear, at some point soon, I'd like to start using the general ledger to build financial reports such a balance sheets and income statements.
As always, feedback is welcome 😊🙏