We gebruiken Python, en hoewel je enige basiskennis nodig hebt, houden we het begrijpelijk. Voor deze analyse heb je het volgende nodig:
- Een CAMT.053-bestand met transactiedata.
- De Python-pakketten pandas en xml.etree.ElementTree
Pandas kun je - als je dat nog niet gedaan hebt - installeren met:
pip install pandas
Voor een oefenbestand om deze analyse zelf uit te voeren, kun je dit test-CAMT-bestand downloaden
Stap 1: Inlezen van het CAMT.053-bestand
Een CAMT.053-bestand is een XML-formaat dat banktransacties bevat. We gebruiken pandas en xml.etree.ElementTree om het bestand te verwerken.
# inladen van ElemenTree wat we nodig hebben om de XML in te lezen.
import xml.etree.ElementTree as ET
import pandas as pd
# Het ontleden van de CAMT 053 met een leesbaar df als resultaat
def parse_camt053(file_path):
tree = ET.parse(file_path)
root = tree.getroot()
ns = {'ns': 'urn:iso:std:iso:20022:tech:xsd:camt.053.001.02'}
transactions = []
# Loop over alle entries heen
for entry in root.findall('.//ns:Ntry', ns):
try:
# Als er geen bedrag gevonden wordt voor de entry, wordt deze op 0,0 gezet.
amount = float(entry.find('ns:Amt', ns).text) if entry.find('ns:Amt', ns) is not None else 0.0
except ValueError:
amount = 0.0 # Fallback bij conversiefouten
# Hieronder zoekt hij de betreffende velden en koppelt hij ze aan de variabele voor ons overzicht.
currency = entry.find('ns:Amt', ns).attrib.get('Ccy', 'N/A') if entry.find('ns:Amt', ns) is not None else 'N/A'
date = entry.find('.//ns:BookgDt/ns:Dt', ns).text if entry.find('.//ns:BookgDt/ns:Dt', ns) is not None else '-'
debtor = entry.find('.//ns:Dbtr/ns:Nm', ns).text if entry.find('.//ns:Dbtr/ns:Nm', ns) is not None else '-'
debtor_iban = entry.find('.//ns:DbtrAcct/ns:Id/ns:IBAN', ns).text if entry.find('.//ns:DbtrAcct/ns:Id/ns:IBAN', ns) is not None else '-'
creditor = entry.find('.//ns:Cdtr/ns:Nm', ns).text if entry.find('.//ns:Cdtr/ns:Nm', ns) is not None else '-'
creditor_iban_element = entry.find('.//ns:CdtrAcct/ns:Id/ns:IBAN', ns)
creditor_iban = creditor_iban_element.text if creditor_iban_element is not None else '-'
# Koppelt de entry als regel aan ons DataFrame
transactions.append({
"Datum": date,
"Debiteur": debtor,
"Debiteur IBAN": debtor_iban,
"Crediteur": creditor,
"Crediteur IBAN": creditor_iban,
"Bedrag": amount,
"Munteenheid": currency
})
return pd.DataFrame(transactions)
# Laad het CAMT.053-bestand
file_path = "camt053_dummy.xml"
df = parse_camt053(file_path)
# Toon de bovenste rijen
print(df.head())
Stap 2: Groeperen van betalingen per leverancier en datum
We willen weten of er meerdere betalingen op dezelfde dag naar dezelfde leverancier zijn gegaan.
# Je kunt Begunstigde ook vervangen voor IBAN
df_grouped = df.groupby(['Datum', 'Crediteur']).agg(
Aantal_Transacties=('Bedrag', 'count'), # Tel het aantal rijen per groep
Totaal_Bedrag=('Bedrag', 'sum') # Sommeer de bedragen
).reset_index()
print(df_grouped)
Dit laat ons zien hoeveel er per dag per leverancier is overgemaakt.
Stap 3: Detecteren van opgesplitste betalingen
Nu zoeken we naar patronen waarin meerdere betalingen optellen tot een grote factuur of waarin bedragen net onder een goedkeuringsdrempel blijven.
Laten we aannemen dat de goedkeuringsdrempel €1.000 is.
approval_limit = 1000
# Kijk of meerdere betalingen samen de drempel benaderen
df_splitsingen = df_grouped[
(df_grouped['Totaal_Bedrag'] >= (approval_limit * 0.9)) &
(df_grouped['Aantal_Transacties'] > 1)
]
print(df_splitsingen)
Dit filtert de transacties waarbij het totaalbedrag per leverancier en datum minstens 90% van de goedkeuringslimiet bedraagt.
Stap 4: Markeren van verdachte splitsingen
We willen nu specifiek kijken of individuele betalingen binnen deze groepsbedragen net onder de drempel blijven.
verdachte_transacties = df[(df['Bedrag'] >= (approval_limit * 0.9)) & (df['Bedrag'] < approval_limit)]
print(verdachte_transacties)
Dit geeft ons een lijst van verdachte transacties die mogelijk bewust zijn opgesplitst.
Conclusie
Met deze stappen kunnen we eenvoudig verdachte betalingen detecteren. Wil je verder experimenteren? Probeer andere drempelwaarden, kijk per IBAN of visualiseer de resultaten met matplotlib.