Lesson 3 · Python for Banking and Finance
Implementing Control Flow for Transaction Logic in Python: Banking and Finance Applications
In this lesson, we will learn how to use Python control flow to handle banking transactions. Control flow helps ensure rules are followed, like flagging…
- CoursePython for Banking and Finance
- Lesson3 of 24
- Video22 min
- FormatJupyter notebook · 20 code cells
What you'll learn
- Understanding our banking transactions data
- Beginner: Basic if statement for transaction rules
- Beginner: Looping over transactions
- Intermediate: Multiple rules and nested control flow
- Intermediate: Functions for transaction checks
- Intermediate: List comprehensions for quick checks
- Advanced: Vectorized conditional logic with numpy
- Advanced: Filtering with control flow expressions
Data
No separate download needed — the notebook creates or downloads everything it uses.
📓 Full notebook
Download .ipynbControl Flow for Transaction Logic#
- In this lesson, we will learn how to use Python control flow to handle banking transactions.
- Control flow helps ensure rules are followed, like flagging large withdrawals and preventing fraudulent activity.
- You will work with real-world-style synthetic transaction data.
- By the end, you will write logic to detect suspicious transactions, approve or reject transfers, and summarize customer activity.
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')
Understanding our banking transactions data#
- The dataset represents real-world-like banking transactions.
- Each row is a transaction involving a customer.
- Important columns are: transaction_id, customer_id, amount, transaction_type, channel, date.
- Beginners often forget to check if amounts are negative or miss if the type is 'Credit' or 'Debit'.
- We will create synthetic data to practice.
np.random.seed(42)
n_transactions = 1000
n_customers = 200
df = pd.DataFrame({
'transaction_id': range(1, n_transactions + 1),
'customer_id': np.random.choice([f'CUST_{i:04d}' for i in range(1, n_customers + 1)], n_transactions),
'amount': np.round(np.random.normal(150, 60, n_transactions), 2),
'transaction_type': np.random.choice(['Debit', 'Credit'], n_transactions),
'channel': np.random.choice(['ATM', 'Online', 'Branch', 'POS'], n_transactions),
'date': pd.date_range(start='2024-01-01', periods=n_transactions, freq='h')
})
print(df.shape)
print(df.head(3))
Beginner: Basic if statement for transaction rules#
- Control flow is used to separate 'Debit' and 'Credit' logic.
- For example, you may want to flag transactions above a certain amount.
- Let us look at a basic if statement applied to transaction amounts.
test_amt = 500
if test_amt > 400:
print('Flag: Large transaction detected!')
amt = 300
if amt > 400:
print('This will not print.')
else:
print('Transaction under threshold.')
txn_type = 'Credit'
if txn_type == 'Debit':
print('This is a withdrawal.')
else:
print('This is a deposit or payment.')
row = df.loc[0]
if row['transaction_type'] == 'Debit' and row['amount'] > 200:
print(f"Large withdrawal by {row['customer_id']}")
else:
print("No flag needed.")
Beginner: Looping over transactions#
- Loops let you apply logic to each transaction.
- For banking, this could mean checking every row for fraud flags.
- Let us sum up all debit amounts using a for loop.
total_debits = 0
for i, row in df.iterrows():
if row['transaction_type'] == 'Debit':
total_debits += row['amount']
print(f'Total debits: {total_debits:.2f}')
large_flags = []
for i, row in df.iterrows():
if row['amount'] > 500:
large_flags.append(row['transaction_id'])
print(f'Number of large transactions: {len(large_flags)}')
Intermediate: Multiple rules and nested control flow#
- Sometimes, you must check more than one condition.
- Use elif and nested ifs to tune your logic for banking needs.
- Example: Flag a transaction only if it is an online debit over 300.
flagged = []
for i, row in df.iterrows():
if row['transaction_type'] == 'Debit':
if row['channel'] == 'Online' and row['amount'] > 300:
flagged.append(row['transaction_id'])
print(f'Number of online debits over 300: {len(flagged)}')
for i, row in df.iterrows():
if row['amount'] < 0:
print(f"Warning: Negative amount in transaction {row['transaction_id']}.")
break
channels = set(df['channel'])
for c in channels:
count = df[(df['channel'] == c) & (df['amount'] > 400)].shape[0]
print(f'Channel: {c}, Transactions >400: {count}')
Intermediate: Functions for transaction checks#
- Functions help package checks for reuse.
- You can write a function to flag suspicious transactions using your logic.
- Let us define a function to apply consistent approval rules.
def approve_transaction(row, amount_limit=800):
if row['amount'] < 0:
return 'Error: Invalid amount'
if row['amount'] > amount_limit:
return 'Flag: Over limit'
if row['transaction_type'] == 'Debit' and row['amount'] > 500:
return 'Flag: Large debit'
return 'Approved'
df['approval_status'] = df.apply(approve_transaction, axis=1)
print(df[['transaction_id', 'amount', 'transaction_type', 'approval_status']].head(5))
Intermediate: List comprehensions for quick checks#
- Python offers compact ways to apply ifs using list comprehensions.
- Let us count quickly how many approved transactions we have.
num_approved = len([a for a in df['approval_status'] if a == 'Approved'])
print(f'Approved transactions: {num_approved}')
Advanced: Vectorized conditional logic with numpy#
- pandas and numpy let you apply rules to every row without explicit loops.
- Use np.where for fast logic over whole columns.
- Example: Mark 'HighRisk' where debits are over 600.
df['high_risk'] = np.where((df['transaction_type'] == 'Debit') & (df['amount'] > 600), True, False)
print(df[['transaction_id', 'amount', 'transaction_type', 'high_risk']].head(6))
print(f"Total high risk transactions: {df['high_risk'].sum()}")
Advanced: Filtering with control flow expressions#
- Sometimes, you need to extract only rows passing complex rules.
- Filtering using & and | lets you chain multiple conditions.
- Example: Find all 'ATM' withdrawals above average amount.
avg_amt = df['amount'].mean()
atm_large = df[(df['channel'] == 'ATM') & (df['amount'] > avg_amt) & (df['transaction_type'] == 'Debit')]
print(f'ATM withdrawals over average: {atm_large.shape[0]}')
print(atm_large[['transaction_id', 'amount']].head(3))
Advanced: Using dictionaries for decision logic#
- Dictionaries let you map control flow results to actions, making logic easier to maintain.
- Example: Assign transaction category using a mapping dict.
channel_map = {'ATM': 'Cash', 'Online': 'Digital', 'Branch': 'Personal', 'POS': 'Retail'}
df['category'] = df['channel'].map(channel_map)
print(df[['channel', 'category']].drop_duplicates())
Error handling: Catching and logging problems#
- Transaction logic should never crash your pipeline.
- Use try/except to catch and report invalid inputs or missing values.
- Example: Handle a missing 'amount' safely without stopping the process.
def robust_approval(row):
try:
if row['amount'] is None or np.isnan(row['amount']):
return 'Error: Missing amount'
elif row['amount'] < 0:
return 'Error: Negative'
else:
return 'Approved'
except Exception as e:
print(f"Exception in transaction {row['transaction_id']}: {e}")
return 'Error: Unknown'
test_row = {'transaction_id': 9999, 'amount': None}
print(robust_approval(test_row))
Best practices and patterns in transaction logic#
- Always validate input types and values.
- Use clear function names and comments for business rules.
- Write concise, layered if-elif-else statements. Avoid deeply nested logic if you can.
- Return errors, flags, or codes, not just print statements.
- Log problems for tracing when things go wrong.
- Use DataFrame vectorization for speed when working with big datasets.
End-to-end challenge: Find and summarize suspicious activity#
- Goal: List all customers with over three flagged transactions and their total at-risk amount.
- Solution steps:
- For each transaction, flag it if it is a debit over 400 or a credit over 1000.
- Summarize counts and sums per customer.
- Output customers with more than three flagged transactions.
df['flag'] = np.where(((df['transaction_type'] == 'Debit') & (df['amount'] > 400)) |
((df['transaction_type'] == 'Credit') & (df['amount'] > 1000)), 1, 0)
flagged = df[df['flag'] == 1]
summary = flagged.groupby('customer_id')['amount'].agg(['count', 'sum']).reset_index()
risky_customers = summary[summary['count'] > 3]
print(risky_customers.sort_values('sum', ascending=False))
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



