Developing a Bank Simulation Software
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
- Bank Accounting β Automate a bankβs accounting system with ledger maintenance and report generation.
- Regulatory Capital & Liquidity β Compute Basel III capital ratios, LCR, and NSFR.
- Scenario-Based Risk Management β Simulate shocks across credit, market, and liquidity risks.
- Strategic Decision-Making β Allow users to adjust lending, funding, and risk strategies.
- Education & Professional Training β Enable students and banks to enhance learning and training.
- GUI & API - Support both graphical user interface and programming access.
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 = AccountBalances(
balances
{10_000,
bank.chart_of_accounts.cash_account: 10_000,
bank.chart_of_accounts.equity_account:
},
)
bank.initialize(balances)= HTMLStatementViewer(jupyter=True, hide_zero_balance_accounts=True)
viewer
= datetime.date(2025, 1, 20)
today = Report(ledger=bank.ledger, viewer=viewer, date=today)
report 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.factory import InstrumentFactory
from brms.models.transaction import TransactionFactory, TransactionType
= InstrumentFactory.create_deposit(value=60_000)
customer_A_deposit = InstrumentFactory.create_deposit(value=40_000)
customer_B_deposit = InstrumentFactory.create_deposit(value=20_000)
customer_C_deposit = TransactionFactory.create_transaction(
tx_deposit1 =bank,
bank=TransactionType.DEPOSIT_RECEIVED,
transaction_type=customer_A_deposit,
instrument=today,
transaction_date="Customer A's Deposits",
description
)= TransactionFactory.create_transaction(
tx_deposit2 =bank,
bank=TransactionType.DEPOSIT_RECEIVED,
transaction_type=customer_B_deposit,
instrument=today,
transaction_date="Customer B's Deposits",
description
)= TransactionFactory.create_transaction(
tx_deposit3 =bank,
bank=TransactionType.DEPOSIT_RECEIVED,
transaction_type=customer_C_deposit,
instrument=today,
transaction_date="Customer C's Deposits",
description
)
bank.process_transaction(tx_deposit1)
bank.process_transaction(tx_deposit2)
bank.process_transaction(tx_deposit3)
= Report(ledger=bank.ledger, viewer=viewer, date=today)
report 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
= TransactionFactory.create_transaction(
tx_deposit_withdraw =bank,
bank=TransactionType.DEPOSIT_WITHDRAWAL,
transaction_type=customer_C_deposit,
instrument=today,
transaction_date="Customer C withdraw",
description
)
bank.process_transaction(tx_deposit_withdraw)
= Report(ledger=bank.ledger, viewer=viewer, date=today)
report 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
:= MockInstrument("A loan")).value = 80_000
(loan # fmt: off
= TransactionFactory.create_transaction(
tx_loan =bank,
bank=TransactionType.LOAN_DISBURSEMENT,
transaction_type=loan,
instrument=today,
transaction_date="Loan made to a borrower",
description
)# fmt: on
bank.process_transaction(tx_loan)
= Report(ledger=bank.ledger, viewer=viewer, date=today)
report 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.
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.instruments.cash import Cash
from brms.models.transaction import InterestPaidOnDepositTransaction
= today + datetime.timedelta(days=31)
today
= TransactionFactory.create_transaction(
tx_interest_paid =bank,
bank=TransactionType.INTEREST_PAID_ON_DEPOSIT,
transaction_type=Cash(value=100),
instrument=today,
transaction_date="Interest paid on deposits",
description
)
bank.process_transaction(tx_interest_paid)
= Report(ledger=bank.ledger, viewer=viewer, date=today)
report
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.
= TransactionFactory.create_transaction(
tx_interest_earned =bank,
bank=TransactionType.LOAN_INTEREST_PAYMENT,
transaction_type=Cash(value=800),
instrument=today,
transaction_date="Interest earned from loans",
description
)
bank.process_transaction(tx_interest_earned)
= Report(ledger=bank.ledger, viewer=viewer, date=today)
report
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
= MockInstrument("A FVTPL Security", BookType.TRADING_BOOK)
fvtpl_security = 1_0000
fvtpl_security.value = TransactionFactory.create_transaction(
tx_fvtpl_purchase =bank,
bank=TransactionType.SECURITY_PURCHASE_TRADING,
transaction_type=fvtpl_security,
instrument=today,
transaction_date="Purchase a FVTPL security",
description
)
bank.process_transaction(tx_fvtpl_purchase)
= Report(ledger=bank.ledger, viewer=viewer, date=today)
report 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
= today + datetime.timedelta(days=1)
today # Assume that the market value of the FVTPL security went down by 5%
= fvtpl_security.value * 0.95
new_fvtpl_instrument_value = MockValuationVisitor(new_value=new_fvtpl_instrument_value)
valuation_visitor = TransactionFactory.create_transaction(
tx_fvtpl_marked_down =bank,
bank=TransactionType.SECURITY_FVTPL_MARK_TO_MARKET,
transaction_type=fvtpl_security,
instrument=today,
transaction_date=valuation_visitor,
valuation_visitor="Mark to market a FVTPL security (down)",
description
)
bank.process_transaction(tx_fvtpl_marked_down)
= Report(ledger=bank.ledger, viewer=viewer, date=today)
report
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
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 + datetime.timedelta(days=1)
today # Assume that the market value of the FVTPL security went up by 10%
= fvtpl_security.value * 1.1
new_fvtpl_instrument_value = MockValuationVisitor(new_value=new_fvtpl_instrument_value)
valuation_visitor = TransactionFactory.create_transaction(
tx_fvtpl_marked_up =bank,
bank=TransactionType.SECURITY_FVTPL_MARK_TO_MARKET,
transaction_type=fvtpl_security,
instrument=today,
transaction_date=valuation_visitor,
valuation_visitor="Mark to market a FVTPL security (up)",
description
)
bank.process_transaction(tx_fvtpl_marked_up)
= Report(ledger=bank.ledger, viewer=viewer, date=today)
report
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,
- On day 1, we had a loss of $500 ($10,000 * 0.95 = $9,500).
- On day 2, we had a gain of $950 ($9,500 * 1.1 = $10,450).
- 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.
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.
= today + datetime.timedelta(days=1)
today # Assume that the market value of the FVTPL security went up by 2%
= fvtpl_security.value * 1.02
new_fvtpl_instrument_value = MockValuationVisitor(new_value=new_fvtpl_instrument_value)
valuation_visitor = TransactionFactory.create_transaction(
tx_fvtpl_marked_up =bank,
bank=TransactionType.SECURITY_FVTPL_MARK_TO_MARKET,
transaction_type=fvtpl_security,
instrument=today,
transaction_date=valuation_visitor,
valuation_visitor="Mark to market a FVTPL security (up)",
description
)
bank.process_transaction(tx_fvtpl_marked_up)# Sale transaction should be created after the previous transaction has been processed
= TransactionFactory.create_transaction(
tx_fvtpl_sale =bank,
bank=TransactionType.SECURITY_SALE_TRADING,
transaction_type=fvtpl_security,
instrument=today,
transaction_date=valuation_visitor,
valuation_visitor="Sale of FVTPL security (net gain)",
description
)
bank.process_transaction(tx_fvtpl_sale)# fmt: on
= Report(ledger=bank.ledger, viewer=viewer, date=today)
report
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:
- Fair Value Through Other Comprehensive Income (FVOCI), or
- 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.
= MockInstrument("A Treausy bond (FVOCI)", BookType.BANKING_BOOK)
fvoci_security = 30_000
fvoci_security.value = TransactionFactory.create_transaction(
tx_fvoci_purchase =bank,
bank=TransactionType.SECURITY_PURCHASE_FVOCI,
transaction_type=fvoci_security,
instrument=today,
transaction_date="Purchase a FVOCI security",
description
)
bank.process_transaction(tx_fvoci_purchase)
= Report(ledger=bank.ledger, viewer=viewer, date=today)
report 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.
= today + datetime.timedelta(days=1)
today # Assume that the market value of the FVTPL security went up by 2%
= fvoci_security.value * 1.02
new_fvoci_instrument_value = MockValuationVisitor(new_value=new_fvoci_instrument_value)
valuation_visitor = TransactionFactory.create_transaction(
tx_fvoci_marked_up =bank,
bank=TransactionType.SECURITY_FVOCI_MARK_TO_MARKET,
transaction_type=fvoci_security,
instrument=today,
transaction_date=valuation_visitor,
valuation_visitor="Mark to market a FVTPL security (up)",
description
)
bank.process_transaction(tx_fvoci_marked_up)
= Report(ledger=bank.ledger, viewer=viewer, date=today)
report
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
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 + datetime.timedelta(days=1)
today # Assume that the market value of the FVOCI security went down by 2%
= fvoci_security.value * 0.98
new_fvoci_instrument_value = MockValuationVisitor(new_value=new_fvoci_instrument_value)
valuation_visitor = TransactionFactory.create_transaction(
tx_fvoci_marked_down =bank,
bank=TransactionType.SECURITY_FVOCI_MARK_TO_MARKET,
transaction_type=fvoci_security,
instrument=today,
transaction_date=valuation_visitor,
valuation_visitor="Mark to market a FVTPL security (down)",
description
)
bank.process_transaction(tx_fvoci_marked_down)
= Report(ledger=bank.ledger, viewer=viewer, date=today)
report
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,
- On day 1, we had a gain of $600.
- On day 2, we had a loss of $612.
- 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 + datetime.timedelta(days=1)
today # Assume that the market value of the FVOCI security went down by 2%
= fvoci_security.value * 0.98
new_fvoci_instrument_value = MockValuationVisitor(new_value=new_fvoci_instrument_value)
valuation_visitor = TransactionFactory.create_transaction(
tx_fvoci_marked_down =bank,
bank=TransactionType.SECURITY_FVOCI_MARK_TO_MARKET,
transaction_type=fvoci_security,
instrument=today,
transaction_date=valuation_visitor,
valuation_visitor="Mark to market a FVTPL security (down)",
description
)
bank.process_transaction(tx_fvoci_marked_down)# Sale transaction should be created after the previous transaction has been processed
= TransactionFactory.create_transaction(
tx_fvoci_sale =bank,
bank=TransactionType.SECURITY_SALE_FVOCI,
transaction_type=fvoci_security,
instrument=today,
transaction_date="Sale of FVOCI security (net loss)",
description
)
bank.process_transaction(tx_fvoci_sale)
= Report(ledger=bank.ledger, viewer=viewer, date=today)
report
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.