INET-Complexity / Core-ESL

Open-source, distributed, economic simulation libraries for Java and Scala
8 stars 6 forks source link

Double Entry Accounting #4

Open rafabap opened 7 years ago

rafabap commented 7 years ago

Hybrid accounting system that uses inventories and double-entry accounting.

The Double-entry is simplified so that it uses only stock accounts (ASSETS, LIABILITIES, EQUITY) and ignores flow accounts (INCOME, EXPENSES). Each account has an inventory of contracts.

Each account can hold only one type of contract in its inventory.

The Agents interact with their accounts via a Book, that provides a series of operations given in BookAPI.

davidrpugh commented 7 years ago

@rafabap Let's start with the Book interface. First, I do not understand the terminology. A Book seems to be a collection of Account (or Contract) objects in which case why not call this a BalanceSheet? Second if a Book is just a collection of contracts then I think we should only allow adding/removing of contracts from the Book as well as valuing assets liabilities and equity. Logic for updating the value of a particular contract should be pushed elsewhere.

Excuse the Scala, but something like the following...

abstract class Contract {

  /** agent for whom the contract is a liability */
  def issuer: Agent

  /** agent for whom the contract is an asset */
  def counterparty: Agent

 /** Objective value of a contract */
  def faceValue: Double

} 

/** Immutable storage container for a particular agent's contracts. */
class BalanceSheet[+C <: Contract] private(agent: UUID, contracts: GenSet[C] ) {

  /** Returns a new BalanceSheet with an additional contract .*/
  def add[C1 >: C](contract: C1): BalanceSheet[C1] = {
    new BalanceSheet(agent, contracts + contract)  
  }

  /** Returns a new BalanceSheet after removing a particular contact. */
  def remove(contract: C): BalanceSheet[C] = {
    new BalanceSheet(agent, contracts - contract)
  } 

  /** Collection of contracts that are assets. */
  def assets: GenSet[C] = {
    contracts.filter(contract => contract.counterparty == agent)
  }

  /** Collection of contracts that are liabilities. */
  def liabilities: GenSet[C] = {
    contracts.filter(contract => contract.issuer == agent)
  }

  /** The value of equity is just the difference between the value of assets and the value of liabilities. 
     * @note the value of equity is subjective and depends on the value function `v` used to value the 
     * underlying contracts.
     */
  def equity(v: (Contract) => Double): Double = {
    assets.map(v).sum - liabilities.map(v).sum
  }

  /** Leverage ratio */
  def leverage(v: (Contract) => Double): Double = {
    assets.map(v).sum / equity(v)
  }

}
davidrpugh commented 7 years ago

@rafabap I am also confused about the difference between Contract and an Account.

davidrpugh commented 7 years ago

My most general comment is that I find the terminology very confusing. I generally do not think of Asset, Liability and Equity as being types of Accounts. But might just be me.

I guess you could have something like...

class DepositAccount private(issuer: UUID, counterparty: UUID, initialDeposit: Double) extends Contract {
  val faceValue = initialDeposit

  def debit(value: Double): DepositAccount = {
    new DepositAccount(issuer, counterparty, initialDeposit - value)
  } 

  def credit(value: Double): DepositAccount = {
    new DepositAccount(issuer, counterparty, initialDeposit + value)
  }

}

val agent: UUID = ???
val bank: UUID = ???

val deposit = DepositContract(bank, agent, 1e6)

in the above

davidrpugh commented 7 years ago

@rafabap I just realized that Book used to be called Ledger! I much prefer Ledger as it makes good use of standard accounting terminology (which has been picked up by the blockchain community which I think is useful).

davidrpugh commented 7 years ago

@rafabap Some specific comments about the Account class.

davidrpugh commented 7 years ago

@rafabap Perhaps my lack of comfort with your terminology stems from my being used to Perry Mehrling's terminology. I am reading through the Double-Entry Book-Keeping Wikipedia entry to try and familiarize myself with your terms. Is this the best source?

rafabap commented 7 years ago

@davidrpugh sorry for the confusion! Just a few pints to clarify:

1) double-entry The Wikipedia article is one of the best resources I've found. The problem is that although the rules are consistent across sources, the terminology isn't! I'm happy to go back to using Ledger rather than Book.

The types of Account only matter when defining the sign of debits and credits.

2) double entry vs Inventories

I see our accounting system as a hybrid composed of two parts. The first is the double entry rules, which requires separate accounts implementing their debits and credits. The second is the inventory: a way to keep lists of contracts.

My solution is to combine the two by starting with a standard double-entry ledger havjng a few accounts, and then rather than having a single inventory for the agent, I split it in smaller inventories, each associated to one account. In addition, for clarity, I force that each account includes only one type of contract in its inventory.

davidrpugh commented 7 years ago

@rafabap and @bherd Based on our discussion today we decided to move forward with a message passing solution for handling interaction between Ledger / Book and Transactions, etc. I think we should take a hard look at Akka. Existence of widely used Java and Scala APIs is nice and using the Actor model as our concurrency solution will help constrain our design space in general...

rafabap commented 7 years ago

Hi all, I have implemented most of the comments received so far and during the code review. The concurrent implementation of the Ledger is left for a future date.

I have followed David's advice and decided to split the inventories from the Accounts. Therefore, a Ledger has, on the one hand, a set of accounts; and on the other hand, an inventory of contracts (the inventory is split into assets and liabilities for convenience).

Searching etc. of the inventory is done using functional calls as suggested by Ben.

The invariants provided by the framework are: