Developing a Bank Simulation Software

Programming
Teaching Notes
Author
Affiliation

Mingze Gao, PhD

Macquarie University

Published

January 20, 2025

In 2025, I plan to incorporate BRMS (Bank Risk Management Simulation) into my teaching to provide students with a hands-on approach to understanding bank risk and financial intermediation. The project aims to feature

In this post, I’ll demonstrate the current capabilities of BRMS. Along the way, I’ll touch on key aspects of bank accounting, provide some example code, and showcase outputs.

Simple banking book accounting

To begin with, a simple bank has just been established with shareholders’ contribution of $10,000. Its balance sheet is shown as below.

A new bank has just been established.
import datetime
from brms.accounting.account import AccountBalances
from brms.accounting.report import Report
from brms.accounting.statement_viewer import HTMLStatementViewer
from brms.models.bank import Bank


bank = Bank()
balances = AccountBalances(
    {
        bank.chart_of_accounts.cash_account: 10_000,
        bank.chart_of_accounts.equity_account: 10_000,
    },
)
bank.initialize(balances)
viewer = HTMLStatementViewer(jupyter=True, hide_zero_balance_accounts=True)

today = datetime.date(2025, 1, 20)
report = Report(ledger=bank.ledger, viewer=viewer, date=today)
report.print_balance_sheet()
               Balance Sheet               
 Assets                                    
   Cash and Cash Equivalents    $10,000.00 
 Total assets                   $10,000.00 
 Liabilities                               
 Total liabilities                   $0.00 
 Net assets                     $10,000.00 
 Shareholders' equity                      
   Shareholders' Equity         $10,000.00 
 Total shareholders' equity     $10,000.00 
                           Date: 2025-01-20

Customer deposit

Now some customers have made some deposits, for example:

  • Customer A deposits $60,000.
  • Customer B deposits $40,000.
  • Customer C deposits $20,000.

Notably, customer deposits are the bank’s liability. We see an increase in both the bank’s total assets and total liabilities, while total shareholders’ equity remains unchanged.

Some customers have made deposits.
from brms.instruments.deposit import Deposit
from brms.models.transaction import DepositTransaction

customer_A_deposit = Deposit(value=60_000)
customer_B_deposit = Deposit(value=40_000)
customer_C_deposit = Deposit(value=20_000)
# fmt: off
tx_deposit1 = DepositTransaction(bank, customer_A_deposit, today, description="Customer A's deposit")
tx_deposit2 = DepositTransaction(bank, customer_B_deposit, today, description="Customer B's deposit")
tx_deposit3 = DepositTransaction(bank, customer_C_deposit, today, description="Customer C's deposit")
# fmt: on
bank.process_transaction(tx_deposit1)
bank.process_transaction(tx_deposit2)
bank.process_transaction(tx_deposit3)

report = Report(ledger=bank.ledger, viewer=viewer, date=today)
report.print_balance_sheet()
                     Balance Sheet                     
 Assets                                                
   Cash and Cash Equivalents               $130,000.00 
 Total assets                              $130,000.00 
 Liabilities                                           
   Deposits and Other Public Borrowings    $120,000.00 
     Deposits                              $120,000.00 
 Total liabilities                         $120,000.00 
 Net assets                                 $10,000.00 
 Shareholders' equity                                  
   Shareholders' Equity                     $10,000.00 
 Total shareholders' equity                 $10,000.00 
                                       Date: 2025-01-20

Deposit withdraw

Depositors can also withdraw from the bank. If Customer C has withdrawn all of their deposits, we see a decrease of cash and deposits.

Customer C has withdrawn their deposits.
from brms.models.transaction import DepositWithdrawTransaction

# fmt: off
tx_deposit_withdraw = DepositWithdrawTransaction(bank, customer_C_deposit, today, description="Customer C withdraw")
# fmt: on
bank.process_transaction(tx_deposit_withdraw)

report = Report(ledger=bank.ledger, viewer=viewer, date=today)
report.print_balance_sheet()
                     Balance Sheet                     
 Assets                                                
   Cash and Cash Equivalents               $110,000.00 
 Total assets                              $110,000.00 
 Liabilities                                           
   Deposits and Other Public Borrowings    $100,000.00 
     Deposits                              $100,000.00 
 Total liabilities                         $100,000.00 
 Net assets                                 $10,000.00 
 Shareholders' equity                                  
   Shareholders' Equity                     $10,000.00 
 Total shareholders' equity                 $10,000.00 
                                       Date: 2025-01-20

Loan disbursement

Of course, the typical business of a bank is to make loans. Let’s assume the bank has made an (interest-only) loan of $80,000 to some borrowers.

The bank has made some loans.
from brms.instruments.base import Instrument
from brms.instruments.mock import MockInstrument
from brms.models.transaction import LoanDisbursementTransaction

(loan := MockInstrument("A loan")).value = 80_000
# fmt: off
tx_loan = LoanDisbursementTransaction(bank, loan, today, description="Loan made to a borrower")
# fmt: on
bank.process_transaction(tx_loan)

report = Report(ledger=bank.ledger, viewer=viewer, date=today)
report.print_balance_sheet()
                     Balance Sheet                     
 Assets                                                
   Cash and Cash Equivalents                $30,000.00 
   Loans and Advances                       $80,000.00 
 Total assets                              $110,000.00 
 Liabilities                                           
   Deposits and Other Public Borrowings    $100,000.00 
     Deposits                              $100,000.00 
 Total liabilities                         $100,000.00 
 Net assets                                 $10,000.00 
 Shareholders' equity                                  
   Shareholders' Equity                     $10,000.00 
 Total shareholders' equity                 $10,000.00 
                                       Date: 2025-01-20

Interest paid on deposits

After some time (e.g., a month), the bank may need to pay interest on customers’ deposits, e.g., $100.

Tip

Income Statement is included given that we’d like to know the profit and loss (P&L) of the bank over the period.

If the bank has only paid interest on deposits over the month…
from brms.models.transaction import InterestPaidOnDepositTransaction

today = today + datetime.timedelta(days=31)

# fmt: off
tx_interest_paid = InterestPaidOnDepositTransaction(bank, 100, today, description="Interest paid on deposits")
# fmt: on
bank.process_transaction(tx_interest_paid)

report = Report(ledger=bank.ledger, viewer=viewer, date=today)
report.print_income_statement()
print("-" * 80)
report.print_balance_sheet()
        Income Statement         
 Income                    $0.00 
 Expense                 $100.00 
   Interest Expense      $100.00 
 Profit                ($100.00) 
                 Date: 2025-02-20
--------------------------------------------------------------------------------
                     Balance Sheet                     
 Assets                                                
   Cash and Cash Equivalents                $29,900.00 
   Loans and Advances                       $80,000.00 
 Total assets                              $109,900.00 
 Liabilities                                           
   Deposits and Other Public Borrowings    $100,000.00 
     Deposits                              $100,000.00 
 Total liabilities                         $100,000.00 
 Net assets                                  $9,900.00 
 Shareholders' equity                                  
   Shareholders' Equity                     $10,000.00 
   Retained Earnings                         ($100.00) 
 Total shareholders' equity                  $9,900.00 
                                       Date: 2025-02-20

If the bank has only paid interest on deposits over this period, it surely has a net loss or negative profit as shown above. However, it is more reasonable that the bank also has earned some profits during the same time, especially because it has made some loans.

Loan interest income

Suppose that over the 1-month period, the bank has earned some interest income from the loans made earlier, e.g., for a total of $800.

… if the bank has also earned interest from loans over the month.
from brms.models.transaction import LoanInterestPaymentTransaction

# fmt: off
tx_interest_earned = LoanInterestPaymentTransaction(bank, 800, today, description="Interest earned from loans")
# fmt: on
bank.process_transaction(tx_interest_earned)

report = Report(ledger=bank.ledger, viewer=viewer, date=today)
report.print_income_statement()
print("-" * 80)
report.print_balance_sheet()
       Income Statement        
 Income                $800.00 
   Interest Income     $800.00 
 Expense               $100.00 
   Interest Expense    $100.00 
 Profit                $700.00 
               Date: 2025-02-20
--------------------------------------------------------------------------------
                     Balance Sheet                     
 Assets                                                
   Cash and Cash Equivalents                $30,700.00 
   Loans and Advances                       $80,000.00 
 Total assets                              $110,700.00 
 Liabilities                                           
   Deposits and Other Public Borrowings    $100,000.00 
     Deposits                              $100,000.00 
 Total liabilities                         $100,000.00 
 Net assets                                 $10,700.00 
 Shareholders' equity                                  
   Shareholders' Equity                     $10,000.00 
   Retained Earnings                           $700.00 
 Total shareholders' equity                 $10,700.00 
                                       Date: 2025-02-20

Overall, the bank has a net profit of $700. We can observe that the bank’s Retained Earnings has increased by $700, too.

Intermediate trading book accounting

Those transactions and non-transactions above all occur to the bank’s banking book.

However, a bank also has a trading book that holds securities for short-term trading P&L purposes. These instruments are named Fair Value Through Profit and Loss (FVTPL).

Accounting for trading book securities is relatively easy.

FVTPL security purchase

Assume that the bank just purchased a FVTPL security for its trading book at its fair value of $10,000.

The bank has purchased some FVTPL securities.
from brms.models.base import BookType
from brms.models.transaction import SecurityPurchaseFVTPLTransaction

fvtpl_security = MockInstrument("A FVTPL Security", BookType.TRADING_BOOK)
fvtpl_security.value = 1_0000
# fmt: off
tx_fvtpl_purchase = SecurityPurchaseFVTPLTransaction(bank, fvtpl_security, today, description="Purchase a FVTPL security")
# fmt: on
bank.process_transaction(tx_fvtpl_purchase)

report = Report(ledger=bank.ledger, viewer=viewer, date=today)
report.print_balance_sheet()
                     Balance Sheet                     
 Assets                                                
   Cash and Cash Equivalents                $20,700.00 
   Loans and Advances                       $80,000.00 
   Assets at FVTPL                          $10,000.00 
 Total assets                              $110,700.00 
 Liabilities                                           
   Deposits and Other Public Borrowings    $100,000.00 
     Deposits                              $100,000.00 
 Total liabilities                         $100,000.00 
 Net assets                                 $10,700.00 
 Shareholders' equity                                  
   Shareholders' Equity                     $10,000.00 
   Retained Earnings                           $700.00 
 Total shareholders' equity                 $10,700.00 
                                       Date: 2025-02-20

The fair value of the security is recorded on the balance sheet under the Assets at FVTPL account.

FVTPL security marking to market

The fair value of FVTPL security is marked to market periodically, e.g., daily. This ensures consistency in that they are held for trading P&N in the first place.

Unrealized trading loss

If the market value of the security went down by 5% ($500) the next day, we need to recognize this unrealized trading loss in the Income Statement.

The FVTPL security is marked to market with an unrealized trading loss.
from brms.instruments.mock import MockValuationVisitor
from brms.models.base import BookType
from brms.models.transaction import SecurityMarkToMarketFVTPLTransaction

today = today + datetime.timedelta(days=1)
# Assume that the market value of the FVTPL security went down by 5%
new_fvtpl_instrument_value = fvtpl_security.value * 0.95
valuation_visitor = MockValuationVisitor(new_value=new_fvtpl_instrument_value)
# fmt: off
tx_fvtpl_marked_down = SecurityMarkToMarketFVTPLTransaction(bank, fvtpl_security, valuation_visitor, today, description="Mark to market a FVTPL security (down)")
# fmt: on
bank.process_transaction(tx_fvtpl_marked_down)

report = Report(ledger=bank.ledger, viewer=viewer, date=today)
report.print_income_statement()
print("-" * 80)
report.print_balance_sheet()
              Income Statement              
 Income                             $300.00 
   Interest Income                  $800.00 
   Trading Income (FVTPL)         ($500.00) 
     Unrealized Trading Loss        $500.00 
 Expense                            $100.00 
   Interest Expense                 $100.00 
 Profit                             $200.00 
                            Date: 2025-02-21
--------------------------------------------------------------------------------
                     Balance Sheet                     
 Assets                                                
   Cash and Cash Equivalents                $20,700.00 
   Loans and Advances                       $80,000.00 
   Assets at FVTPL                           $9,500.00 
 Total assets                              $110,200.00 
 Liabilities                                           
   Deposits and Other Public Borrowings    $100,000.00 
     Deposits                              $100,000.00 
 Total liabilities                         $100,000.00 
 Net assets                                 $10,200.00 
 Shareholders' equity                                  
   Shareholders' Equity                     $10,000.00 
   Retained Earnings                           $200.00 
 Total shareholders' equity                 $10,200.00 
                                       Date: 2025-02-21
Important

Usually, financial reports are generated at a period’s end, such as quarter’s end or year’s end. What’s shown here should be viewed as what if we close the bank’s accounting ledger at this time and generate the reports?

If we were to generate the balance sheet now, such net trading loss would reduce the bank’s retained earnings.

Unrealized trading gain

The day after, if the market value of the security went up by 10% ($950), we need to recognize this unrealized trading gain.

The FVTPL security is marked to market with an unrealized trading gain.
today = today + datetime.timedelta(days=1)
# Assume that the market value of the FVTPL security went up by 10%
new_fvtpl_instrument_value = fvtpl_security.value * 1.1
valuation_visitor = MockValuationVisitor(new_value=new_fvtpl_instrument_value)
# fmt: off
tx_fvtpl_marked_up = SecurityMarkToMarketFVTPLTransaction(bank, fvtpl_security, valuation_visitor, today, description="Mark to market a FVTPL security (up)")
# fmt: on
bank.process_transaction(tx_fvtpl_marked_up)

report = Report(ledger=bank.ledger, viewer=viewer, date=today)
report.print_income_statement()
print("-" * 80)
report.print_balance_sheet()
              Income Statement              
 Income                           $1,250.00 
   Interest Income                  $800.00 
   Trading Income (FVTPL)           $450.00 
     Unrealized Trading Gain        $950.00 
     Unrealized Trading Loss        $500.00 
 Expense                            $100.00 
   Interest Expense                 $100.00 
 Profit                           $1,150.00 
                            Date: 2025-02-22
--------------------------------------------------------------------------------
                     Balance Sheet                     
 Assets                                                
   Cash and Cash Equivalents                $20,700.00 
   Loans and Advances                       $80,000.00 
   Assets at FVTPL                          $10,450.00 
 Total assets                              $111,150.00 
 Liabilities                                           
   Deposits and Other Public Borrowings    $100,000.00 
     Deposits                              $100,000.00 
 Total liabilities                         $100,000.00 
 Net assets                                 $11,150.00 
 Shareholders' equity                                  
   Shareholders' Equity                     $10,000.00 
   Retained Earnings                         $1,150.00 
 Total shareholders' equity                 $11,150.00 
                                       Date: 2025-02-22

Again, if we were to close the bank’s accounting ledger now and check its balance sheet, we will see changes of the bank’s retained earnings.

FVTPL security sale

The next day, if the bank sold the security at the prevailing market price (assumed 2% up), we recognize realized trading gain.

Tracking the P&L of this particular FVTPL security,

  1. On day 1, we had a loss of $500 ($10,000 * 0.95 = $9,500).
  2. On day 2, we had a gain of $950 ($9,500 * 1.1 = $10,450).
  3. On day 3, we had a gain of $209 ($10,450 * 1.02 = $10,659).

The total P&L from this security is therefore a net gain of $659, which shows up in the Income Statement.

Note

Because of the sale, the unrealized trading gain/loss associated with this security must be reclassified to realized gain/loss.

The FVTPL security is sold.
from brms.models.transaction import SecuritySaleFVTPLTransaction

today = today + datetime.timedelta(days=1)
# Assume that the market value of the FVTPL security went up by 2%
new_fvtpl_instrument_value = fvtpl_security.value * 1.02
valuation_visitor = MockValuationVisitor(new_value=new_fvtpl_instrument_value)
# fmt: off
tx_fvtpl_marked_up = SecurityMarkToMarketFVTPLTransaction(bank, fvtpl_security, valuation_visitor, today, description="Mark to market a FVTPL security (up)")
bank.process_transaction(tx_fvtpl_marked_up)
# Sale transaction should be created after the previous transaction has been processed
tx_fvtpl_sale = SecuritySaleFVTPLTransaction(bank, fvtpl_security, today, description="Sale of FVTPL security (net gain)")
bank.process_transaction(tx_fvtpl_sale)
# fmt: on

report = Report(ledger=bank.ledger, viewer=viewer, date=today)
report.print_income_statement()
print("-" * 80)
report.print_balance_sheet()
             Income Statement             
 Income                         $1,459.00 
   Interest Income                $800.00 
   Trading Income (FVTPL)         $659.00 
     Realized Trading Gain      $1,159.00 
     Realized Trading Loss        $500.00 
 Expense                          $100.00 
   Interest Expense               $100.00 
 Profit                         $1,359.00 
                          Date: 2025-02-23
--------------------------------------------------------------------------------
                     Balance Sheet                     
 Assets                                                
   Cash and Cash Equivalents                $31,359.00 
   Loans and Advances                       $80,000.00 
 Total assets                              $111,359.00 
 Liabilities                                           
   Deposits and Other Public Borrowings    $100,000.00 
     Deposits                              $100,000.00 
 Total liabilities                         $100,000.00 
 Net assets                                 $11,359.00 
 Shareholders' equity                                  
   Shareholders' Equity                     $10,000.00 
   Retained Earnings                         $1,359.00 
 Total shareholders' equity                 $11,359.00 
                                       Date: 2025-02-23

Compare this balance sheet to the one before the bank purchased this FVTPL security, the retained earnings increased by exactly $659.

Intermediate banking book accounting

Apart from loans, a bank’s banking book contains other assets that are held mostly for interest income. However, depending on whether the bank intends to hold them until maturity, these non-loan banking book assets can be either:

  1. Fair Value Through Other Comprehensive Income (FVOCI), or
  2. At Amortized Cost or Held to Maturity (HTM).

For example, Treasury bonds, corporate bonds, MBS, etc., are usually FVOCI or HTM banking book assets.

FVOCI security purchase

FVOCI assets in the banking book are typically debt securities that:

  • Earn interest income for the bank.
  • Can be sold before maturity but are not actively traded like FVTPL securities.
  • Experience fair value changes that are recorded in Accumulated Other Comprehensive Income (AOCI) instead of directly impacting net income.
  • Upon sale, unrealized gains/losses from AOCI are transferred to Net Income.

Assume that the bank now purchased a Treasury bond at a fair value of $30,000. The bank may sell the bond before it matures, and hence classify it as a FVOCI asset on the banking book.

The bank has purchased some FVOCI securities.
from brms.models.transaction import SecurityPurchaseFVOCITransaction

fvoci_security = MockInstrument("A Treausy bond (FVOCI)", BookType.BANKING_BOOK)
fvoci_security.value = 30_000
# fmt: off
tx_fvoci_purchase = SecurityPurchaseFVOCITransaction(bank, fvoci_security, today, description="Purchase a FVOCI security")
# fmt: on
bank.process_transaction(tx_fvoci_purchase)

report = Report(ledger=bank.ledger, viewer=viewer, date=today)
report.print_balance_sheet()
                     Balance Sheet                     
 Assets                                                
   Cash and Cash Equivalents                 $1,359.00 
   Loans and Advances                       $80,000.00 
   Investment Securities                    $30,000.00 
     Investment Securities at FVOCI         $30,000.00 
 Total assets                              $111,359.00 
 Liabilities                                           
   Deposits and Other Public Borrowings    $100,000.00 
     Deposits                              $100,000.00 
 Total liabilities                         $100,000.00 
 Net assets                                 $11,359.00 
 Shareholders' equity                                  
   Shareholders' Equity                     $10,000.00 
   Retained Earnings                         $1,359.00 
 Total shareholders' equity                 $11,359.00 
                                       Date: 2025-02-23

The fair value of the security is recorded on the balance sheet under the Investment Securities at FVOCI account.

FVOCI security marking to market

Unrealized gain

Similarly, the next day, we need to mark to market the FVOCI security to ensure its fair value is correctly accounted for. Suppose that its market value went up by 5% ($600 = $30,000*5%).

It is important to note that FVOCI security’s fair value changes affect AOCI, an equity account. It does not affect Income Statement P&L untill it’s eventually sold.

The FVOCI security is marked to market with an unrealized gain.
from brms.models.transaction import SecurityMarkToMarketFVOCITransaction

today = today + datetime.timedelta(days=1)
# Assume that the market value of the FVTPL security went up by 2%
new_fvoci_instrument_value = fvoci_security.value * 1.02
valuation_visitor = MockValuationVisitor(new_value=new_fvoci_instrument_value)
# fmt: off
tx_fvoci_marked_up = SecurityMarkToMarketFVOCITransaction(bank, fvoci_security, valuation_visitor, today, description="Mark to market a FVTPL security (up)")
# fmt: on
bank.process_transaction(tx_fvoci_marked_up)

report = Report(ledger=bank.ledger, viewer=viewer, date=today)
report.print_income_statement()
print("-" * 80)
report.print_balance_sheet()
             Income Statement             
 Income                         $1,459.00 
   Interest Income                $800.00 
   Trading Income (FVTPL)         $659.00 
     Realized Trading Gain      $1,159.00 
     Realized Trading Loss        $500.00 
 Expense                          $100.00 
   Interest Expense               $100.00 
 Profit                         $1,359.00 
                          Date: 2025-02-24
--------------------------------------------------------------------------------
                     Balance Sheet                     
 Assets                                                
   Cash and Cash Equivalents                 $1,359.00 
   Loans and Advances                       $80,000.00 
   Investment Securities                    $30,600.00 
     Investment Securities at FVOCI         $30,600.00 
 Total assets                              $111,959.00 
 Liabilities                                           
   Deposits and Other Public Borrowings    $100,000.00 
     Deposits                              $100,000.00 
 Total liabilities                         $100,000.00 
 Net assets                                 $11,959.00 
 Shareholders' equity                                  
   Shareholders' Equity                     $10,000.00 
   Accumulated OCI                             $600.00 
     Unrealized OCI Gain                       $600.00 
   Retained Earnings                         $1,359.00 
 Total shareholders' equity                 $11,959.00 
                                       Date: 2025-02-24
Important

Because FVOCI’s (even unrealized) gain increases AOCI, and AOCI is part of a bank’s CET1 capital, FVOCI’s fair value movement can cause volatility in the bank’s regulatory capital ratios.

Unrealized loss

If the market value of the security went down by 2% ($612=$30,600*2%) the next day, we recognize this unrealized OCI loss of AOCI.

The FVOCI security is marked to market with an unrealized trading loss.
today = today + datetime.timedelta(days=1)
# Assume that the market value of the FVOCI security went down by 2%
new_fvoci_instrument_value = fvoci_security.value * 0.98
valuation_visitor = MockValuationVisitor(new_value=new_fvoci_instrument_value)
# fmt: off
tx_fvoci_marked_down = SecurityMarkToMarketFVOCITransaction(bank, fvoci_security, valuation_visitor, today, description="Mark to market a FVTPL security (down)")
# fmt: on
bank.process_transaction(tx_fvoci_marked_down)

report = Report(ledger=bank.ledger, viewer=viewer, date=today)
report.print_income_statement()
print("-" * 80)
report.print_balance_sheet()
             Income Statement             
 Income                         $1,459.00 
   Interest Income                $800.00 
   Trading Income (FVTPL)         $659.00 
     Realized Trading Gain      $1,159.00 
     Realized Trading Loss        $500.00 
 Expense                          $100.00 
   Interest Expense               $100.00 
 Profit                         $1,359.00 
                          Date: 2025-02-25
--------------------------------------------------------------------------------
                     Balance Sheet                     
 Assets                                                
   Cash and Cash Equivalents                 $1,359.00 
   Loans and Advances                       $80,000.00 
   Investment Securities                    $29,988.00 
     Investment Securities at FVOCI         $29,988.00 
 Total assets                              $111,347.00 
 Liabilities                                           
   Deposits and Other Public Borrowings    $100,000.00 
     Deposits                              $100,000.00 
 Total liabilities                         $100,000.00 
 Net assets                                 $11,347.00 
 Shareholders' equity                                  
   Shareholders' Equity                     $10,000.00 
   Accumulated OCI                            ($12.00) 
     Unrealized OCI Gain                       $600.00 
     Unrealized OCI Loss                       $612.00 
   Retained Earnings                         $1,359.00 
 Total shareholders' equity                 $11,347.00 
                                       Date: 2025-02-25

FVOCI security sale

The next day, if the bank sold the FVOCI security at the prevailing market price (assumed 2% down), we recognize realized OCI loss.

Tracking the AOCI gain/loss of this particular FVOCI security,

  1. On day 1, we had a gain of $600.
  2. On day 2, we had a loss of $612.
  3. On day 3, we had a loss of $599.76.

The total net loss of this security is therefore $611.76.

Now that the FVOCI security is sold, its gain/loss is moved from AOCI to Income Statement as Investment Income (FVOCI). When P&L accounts of income statement are closed, the net gain/loss of Investment Income (FVOCI) changes the bank’s retained earnings.

The FVOCI security is sold.
from brms.models.transaction import SecuritySaleFVOCITransaction

today = today + datetime.timedelta(days=1)
# Assume that the market value of the FVOCI security went down by 2%
new_fvoci_instrument_value = fvoci_security.value * 0.98
valuation_visitor = MockValuationVisitor(new_value=new_fvoci_instrument_value)
# fmt: off
tx_fvoci_marked_down = SecurityMarkToMarketFVOCITransaction(bank, fvoci_security, valuation_visitor, today, description="Mark to market a FVOCI security (down)")
bank.process_transaction(tx_fvoci_marked_down)
# Sale transaction should be created after the previous transaction has been processed
tx_fvoci_sale = SecuritySaleFVOCITransaction(bank, fvoci_security, today, description="Sale of FVOCI security (net loss)")
bank.process_transaction(tx_fvoci_sale)
# fmt: on

report = Report(ledger=bank.ledger, viewer=viewer, date=today)
report.print_income_statement()
print("-" * 80)
report.print_balance_sheet()
             Income Statement             
 Income                           $847.24 
   Interest Income                $800.00 
   Trading Income (FVTPL)         $659.00 
     Realized Trading Gain      $1,159.00 
     Realized Trading Loss        $500.00 
   Investment Income (FVOCI)    ($611.76) 
     Realized OCI Gain            $600.00 
     Realized OCI Loss          $1,211.76 
 Expense                          $100.00 
   Interest Expense               $100.00 
 Profit                           $747.24 
                          Date: 2025-02-26
--------------------------------------------------------------------------------
                     Balance Sheet                     
 Assets                                                
   Cash and Cash Equivalents                $30,747.24 
   Loans and Advances                       $80,000.00 
 Total assets                              $110,747.24 
 Liabilities                                           
   Deposits and Other Public Borrowings    $100,000.00 
     Deposits                              $100,000.00 
 Total liabilities                         $100,000.00 
 Net assets                                 $10,747.24 
 Shareholders' equity                                  
   Shareholders' Equity                     $10,000.00 
   Retained Earnings                           $747.24 
 Total shareholders' equity                 $10,747.24 
                                       Date: 2025-02-26

Short summary

As shown above, at the moment BRMS can provide a flexible accounting framework to address basic banking transactions and non-transactions. This provides the foundation for scaling up. Next, I will implement various instruments and pricing mechanisms. With the implementation of scenario simulation, it will then be capable of automated accounting and financial performance monitoring.

Back to top