commit 25976e3b1afeed838063ab4059bc7f9d74ead18d
parent 1409a7664f5095120c78e72c34ec37fa3c8b511d
Author: Florian Dold <florian@dold.me>
Date: Thu, 27 Mar 2025 01:28:31 +0100
TOPS events/statistics, derived properties/events
Diffstat:
| M | deployments/tops.rst | | | 302 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------- |
1 file changed, 241 insertions(+), 61 deletions(-)
diff --git a/deployments/tops.rst b/deployments/tops.rst
@@ -222,7 +222,8 @@ Properties
* ``AML_ACCOUNT_OPEN :: Boolean``
* Was this customer activated for deposit operations?
- * We store this to know when to emit the ``ACCOUNT_OPENED`` event
+ * Only set after merchant passes KYC
+ * We store this to know when to emit the ``(INCR|DECR)_ACCOUNT_OPEN`` and related events
* ``AML_DOMESTIC_PEP :: Boolean``
@@ -236,13 +237,9 @@ Properties
* Is the customer a international org PEP?
-* ``AML_HIGH_RISK_BUSINESS :: Boolean``
+* ``AML_HIGH_RISK :: Boolean``
- * Is the customer a high-risk business?
-
-* ``AML_HIGH_RISK_COUNTRY :: Boolean``
-
- * Is the customer associated with a high-risk country?
+ * Is the customer classified as high-risk?
* ``AML_ACCOUNT_IDLE :: Boolean``
@@ -250,7 +247,7 @@ Properties
for idle accounts).
-* ``AML_MROS_STATE``
+* ``AML_INVESTIGATION_STATE``
* The MROS reporting state for the account.
* Values:
@@ -259,44 +256,31 @@ Properties
* ``INVESTIGATION_PENDING``: Pending investigation. The AML officer should
submit ``vqf_902_14`` to conclude investigation.
FIXME: Also have a form to *start* investigation?
- * ``INVESTIGATION_COMPLETED``: Completed according to Art. 6 GwG
+ * ``INVESTIGATION_COMPLETED_WITHOUT_SUSPICION``: Completed according to Art. 6 GwG
* ``REPORTED_SUSPICION_SIMPLE``: Reported under Art. 305 StGB (German "einfacher Verdacht", simple suspicion)
* ``REPORTED_SUSPICION_SUBSTANTIATED``: Reported under Art. 9 GwG (German "begründeter Verdacht", substantiated suspicion)
Events
------
-Account opening:
-
-* ``ACCOUNT_OPENED``
-
- * Only after merchant passes KYC
- * Wallet accounts never count as opened (no business relationship!)
+Account opening/closing:
-* ``ACCOUNT_OPENED_HIGH_RISK``
-* ``ACCOUNT_OPENED_DOMESTIC_PEP``
-* ``ACCOUNT_OPENED_FOREIGN_PEP``
-* ``ACCOUNT_OPENED_HR_COUNTRY``
+* ``INCR_ACCOUNT_OPEN`` / ``DECR_ACCOUNT_OPEN``
- * Account with property ``AML_HIGH_RISK_COUNTRY`` was opened
+PEP/Risk classification:
-Account closing:
+* ``INCR_HIGH_RISK`` / ``DECR_HIGH_RISK``
+* ``INCR_PEP`` / ``DECR_PEP``
+* ``INCR_FOREIGN_PEP`` / ``DECR_FOREIGN_PEP``
+* ``INCR_DOMESTIC_PEP`` / ``DECR_DOMESTIC_PEP``
+* ``INCR_INTERNATIONAL_ORG_PEP`` / ``DECR_INTERNATIONAL_ORG_PEP``
-* ``ACCOUNT_CLOSED``
-* ``ACCOUNT_CLOSED_HIGH_RISK``
-* ``ACCOUNT_CLOSED_DOMESTIC_PEP``
-* ``ACCOUNT_CLOSED_FOREIGN_PEP``
-* ``ACCOUNT_CLOSED_HR_COUNTRY``
- * Account with property ``AML_HIGH_RISK_COUNTRY`` was closed
+MROS Reporting (see ``AML_INVESTIGATION_STATE`` property):
-
-MROS Reporting (see ``AML_MROS_STATE`` property):
-
-* ``ACCOUNT_MROS_REPORTED_SUSPICION_SIMPLE``
-* ``ACCOUNT_MROS_REPORTED_SUSPICION_SUBSTANTIATED``
-* ``ACCOUNT_INVESTIGATION_STARTED``
-* ``ACCOUNT_INVESTIGATION_COMPLETED``
+* ``MROS_REPORTED_SUSPICION_SIMPLE``
+* ``MROS_REPORTED_SUSPICION_SUBSTANTIATED``
+* ``INCR_INVESTIGATION_CONCLUDED`` / ``DECR_INVESTIGATION_CONCLUDED``
PIN Letter
@@ -546,8 +530,8 @@ Initial collection of basic attributes about customer during onboarding.
* ``CORRESPONDENCE_LANGUAGE``
* **Type:** Single selection
- * **Choices:** ISO 639-1 Alpha-2 language codes. Currently only `en`, `de`, `fr` and
- `it` are supported.
+ * **Choices:** ISO 639-1 Alpha-2 language codes. Currently only ``en``, ``de``, ``fr`` and
+ ``it`` are supported.
* ``ESTABLISHER_LIST[].FULL_NAME``
@@ -1414,7 +1398,7 @@ out by at the initiative of the AML officer or in response to an alert.
INCRISK_SUMMARY :: Text
INCRISK_DOCUMENTS :: Text
INCRISK_RESULT :: (
- 'NO_SUSPICION' | 'REASONABLE_SUSPICION' |
+ 'NO_SUSPICION' | 'SUBSTANTIATED_SUSPICION' |
'SIMPLE_SUSPICION' | 'OTHER')
if INCRISK_REASON = 'OTHER' {
INCRISK_RESULT_OTHER :: Text
@@ -1507,6 +1491,158 @@ vqf_902_15
will either not be accepted as customers or the AML officer will need to submit
a PDF form**
+
+Derived Properties and Events (AML Officer)
+-------------------------------------------
+
+When the AML officer submits a form, the AML SPA will derive some pre-defined
+attributes and events from the filled-in form. The AML Officer can change
+(override) these derived properties and events.
+
+vqf_902_1_officer
+^^^^^^^^^^^^^^^^^
+
+Properties:
+
+.. code:: javascript
+
+ if (oldProps.AML_ACCOUNT_OPEN == false) {
+ newProps.AML_ACCOUNT_OPEN = true;
+ }
+
+Events:
+
+.. code:: javascript
+
+ if (propBecameTrue(AML_ACCOUNT_OPEN)) {
+ emit(INCR_ACCOUNT_OPEN);
+
+ const isPep = (
+ newProps.AML_FOREIGN_PEP ||
+ newProps.AML_DOMESTIC_PEP ||
+ newProps.AML_INTERNATIONAL_ORG_PEP
+ );
+
+ if (isPep) {
+ emit(INCR_PEP);
+ }
+
+ if (newProps.AML_FOREIGN_PEP) {
+ emit(INCR_FOREIGN_PEP);
+ }
+
+ if (newProps.AML_DOMESTIC_PEP) {
+ emit(INCR_DOMESTIC_PEP);
+ }
+
+ if (newProps.AML_INTERNATIONAL_ORG_PEP) {
+ emit(INCR_INTERNATIONAL_ORG_PEP);
+ }
+
+ if (newProps.AML_HIGH_RISK) {
+ emit(INCR_HIGH_RISK);
+ }
+ }
+
+
+vqf_902_4
+^^^^^^^^^
+
+properties:
+
+.. code:: javascript
+
+ newProps.AML_FOREIGN_PEP = form.PEP_FOREIGN;
+ newProps.AML_DOMESTIC_PEP = form.PEP_DOMESTIC;
+ newProps.AML_INTERNATIONAL_ORG_PEP = form.PEP_INTERNATIONAL_ORGANIZATION;
+ newProps.AML_HIGH_RISK = form.RISK_CLASSIFICATION_LEVEL == "HIGH_RISK";
+
+Events:
+
+.. code:: javascript
+
+ if (oldProps.AML_ACCOUNT_OPEN) {
+ if (propBecameTrue(AML_FOREIGN_PEP) {
+ emit(INCR_FOREIGN_PEP);
+ }
+ if (propBecameTrue(AML_DOMESTIC_PEP) {
+ emit(INCR_INTERNATIONAL_ORG_PEP);
+ }
+ if (propBecameTrue(AML_DOMESTIC_PEP) {
+ emit(INCR_DOMESTIC_PEP);
+ }
+ if (propBecameFalse(AML_FOREIGN_PEP) {
+ emit(DECR_FOREIGN_PEP);
+ }
+ if (propBecameFalse(AML_DOMESTIC_PEP) {
+ emit(DECR_INTERNATIONAL_ORG_PEP);
+ }
+ if (propBecameFalse(AML_DOMESTIC_PEP) {
+ emit(DECR_DOMESTIC_PEP);
+ }
+ const wasPep = (
+ oldProps.AML_DOMESTIC_PEP ||
+ oldProps.AML_FOREIGN_PEP ||
+ oldProps.AML_INTERNATIONAL_ORG_PEP);
+ const isPep = (
+ newProps.AML_DOMESTIC_PEP ||
+ newProps.AML_FOREIGN_PEP ||
+ newProps.AML_INTERNATIONAL_ORG_PEP);
+ if (wasPep && !isPep) {
+ emit(DECR_PEP);
+ }
+ if (!wasPep & isPep) {
+ emit(INCR_PEP);
+ }
+ if (propBecameTrue(AML_HIGH_RISK)) {
+ emit(INCR_HIGH_RISK);
+ }
+ if (propBecameFalse(AML_HIGH_RISK)) {
+ emit(DECR_HIGH_RISK);
+ }
+ }
+
+
+vqf_902_14
+^^^^^^^^^^
+
+Properties:
+
+.. code:: javascript
+
+
+ if (INCRISK_RESULT == "SIMPLE_SUSPICION") {
+ newProps.AML_INVESTIGATION_STATE = "REPORTED_SUSPICION_SIMPLE";
+ } else if (INCRISK_RESULT == "SUBSTANTIATED_SUSPICION") {
+ newProps.AML_INVESTIGATION_STATE = "REPORTED_SUSPICION_SUBSTANTIATED";
+ } else if (INCRISK_RESULT == "NO_SUSPICION") {
+ newProps.AML_INVESTIGATION_STATE = "INVESTIGATION_COMPLETED_WITHOUT_SUSPICION";
+ } else if (INCRISK_RESULT == "OTHER") {
+ newProps.AML_INVESTIGATION_STATE = "INVESTIGATION_COMPLETED_WITHOUT_SUSPICION";
+ } else {
+ not_reached();
+ }
+
+Events:
+
+.. code:: javascript
+
+ if (oldProps.AML_INVESTIGATION_STATE == "NONE" ||
+ oldProps.AML_INVESTIGATION_STATE == "INVESTIGATION_PENDING" ||
+ oldProps.AML_INVESTIGATION_STATE == null) {
+ if (newProps.AML_INVESTIGATION_STATE == "REPORTED_SUSPICION_SIMPLE" ||
+ newProps.AML_INVESTIGATION_STATE == "REPORTED_SUSPICION_SUBSTANTIATED" ||
+ newProps.AML_INVESTIGATION_STATE == "INVESTIGATION_COMPLETED_WITHOUT_SUSPICION") {
+ emit(INCR_INVESTIGATION_CONCLUDED);
+ }
+ if (newProps.AML_INVESTIGATION_STATE == "REPORTED_SUSPICION_SUBSTANTIATED")
+ emit(MROS_REPORTED_SUSPICION_SUBSTANTIATED);
+ }
+ if (newProps.AML_INVESTIGATION_STATE == "REPORTED_SUSPICION_SIMPLE")
+ emit(MROS_REPORTED_SUSPICION_SIMPLE);
+ }
+ }
+
Reporting
---------
@@ -1524,43 +1660,86 @@ with the following colums (see VQF 902.8):
* Creation date
* Closing date
-Event Reporting
-^^^^^^^^^^^^^^^
+Event Reporting (VQF)
+^^^^^^^^^^^^^^^^^^^^^
+
+The VQF self-declaration contains the following questions that we need
+to answer with statistics derived via events:
+
+ **Original German Text**
+
+ Meldungen an die Meldestelle (MROS)
+
+ * Meldepflicht (Art. 9 Abs. 1 GwG) (nummerische Anzahl)
+ * Melderecht (Art. 305ter Abs. 2 StGB) (nummerische Anzahl)
+ * Total der an die Meldestelle (MROS) und den VQF erfolgten MROS-Meldungen
-The following items should be reported on the status page, based on the collected events:
+ GwG-Files für dauernde Geschäftsbeziehungen (gemäss Art. 7 lit. b SRO-Reglement)
-- Number of accounts that are opened (triggered the deposit limits and were then subject to KYC and AML processes).
+ * Anzahl der am 01.01.20XX betreuten GwG-Files
+ * Zwischen 01.01.20XX und 31.12.20XX hinzugekommene GwG-Files
+ * Anzahl der während des Jahres 20XX betreuten GwG-Files
+ (Relevante Zahl für die jährliche GwG-File Gebühr / Jahresrechnung)
+ * Zwischen 01.01.20XX und 31.12.20XX beendigte GwG-Files
+ * Anzahl der am 31.12.20XX betreuten GwG-Files (gerechnet ab dem 01.01.20XX)
- * German: Anzahl betreuter GwG Files
+ **English Translation**
-- Number of new GwG files in the last year (=> easy via stats).
+ Reports to the Money Laundering Reporting Office Switzerland (MROS)
-- Number of GwG files closed in the last year (=> easy via stats).
- [ Note: we only close GwG files after 1 year of inactivity, so not exactly pressing ...]
+ * Obligation to report (Art. 9 para. 1 AMLA) (numerical count)
+ * Right to report (Art. 305ter para. 2 Swiss Criminal Code) (numerical count)
+ * Total reports made to the Money Laundering Reporting Office Switzerland (MROS) and the VQF
-- Number of GwG files managed with "increased risk" (that remain in this status: so increment if property set, decrement if unset!)
- [ based on all other high-risk events below, *or* high-risk assessment due to "risky business domain" checked ]
+ AMLA Files for ongoing business relationships (according to Art. 7 lit. b SRO regulations)
-- Number of GwG files managed with "increased risk" due to PEP status (that remain in this status: so increment if property set, decrement if unset!)
- [ AML decision needs an easy *property-setting/unsetting* checkbox to say: "controlled by domestic PEP" that increases this counter ]
+ * Number of AMLA files managed as of 01.01.20XX
+ * AMLA files added between 01.01.20XX and 31.12.20XX
+ * Number of AMLA files managed during the year 20XX
+ (Relevant number for the annual AMLA file fee / annual invoice)
+ * AMLA files terminated between 01.01.20XX and 31.12.20XX
+ * Number of AMLA files managed as of 31.12.20XX (calculated from 01.01.20XX)
-- Number of GwG files managed with "increased risk" due to foreign PEP status (that remain in this status: so increment if property set, decrement if unset!)
- [ AML decision needs an easy *property-setting/unsetting* checkbox to say: "controlled by foreign PEP" that increases this counter ]
+FIXME: Define how we implement each of these!
-- Number of GwG files managed with person of nationality or origin of a country classified as "high risk" (that remain in this status: so increment if property set, decrement if unset!)
- [ AML decision needs an easy *property-setting/unsetting* checkbox to say: "controlled by person from high-risk country" that increases this counter ]
+Event Reporting (TOPS)
+^^^^^^^^^^^^^^^^^^^^^^
-- Number of MROS reports based on Art 9 Abs. 1 GwG (per year)
- [ AML decision needs an easy *event* checkbox to say: "reported to MROS under Meldepflicht" that increases this counter ]
+The following event-based statistics are custom-defined by us and shown in the AML officer dashboard.
-- Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)
- [ AML decision needs an easy *event* checkbox to say: "reported to MROS under Melderecht" that increases this counter ]
+* Number of accounts that are opened:
-- Number of customers involved in proceedings for which Art 6 GwG did apply [ AML decision needs *event* counter
- "Customer involved in proceedings requiring investigations after Art 6 GwG" ]
+ * Implementation: ``evtcount(INCR_ACCOUNT_OPEN) - evtcount(DECR_ACCOUNT_OPENED)``
+
+* Number of new GwG files in the last year.
+
+ * Implementation: ``evtcount(INCR_ACCOUNT_OPEN, range=last_year)``
+
+* Number of GwG files closed in the last year
+
+ * Implementation: ``evtcount(DECR_ACCOUNT_OPEN), range=last_year)``
+ * Note: we only close GwG files after 1 year of inactivity, so implementation not exactly pressing ...
+
+* Number of GwG files of high-risk customers
+
+ * Implementation: ``evtcount(INCR_HIGH_RISK) - evtcount(INCR_HIGH_RISK)``
+
+* Number of GwG files managed with "increased risk" due to PEP status
+
+ * Implementation: ``evtcount(INCR_PEP) - evtcount(DECR_PEP)``
+
+* Number of MROS reports based on Art 9 Abs. 1 GwG (per year)
+
+ * Implementation: ``evtcount(MROS_REPORTED_SUSPICION_SUBSTANTIATED, range=last_year)``
+
+* Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)
+
+ * Implementation: ``evtcount(MROS_REPORTED_SUSPICION_SIMPLE, range=last_year)``
+
+* Number of customers involved in proceedings for which Art 6 GwG did apply
+
+ * Implementation: ``evtcount(INCR_INVESTIGATION, range=last_year)``
-- Number of customers involved in proceedings for which Art 6 GwG did apply but was not performed
- [ AML decision needs *event* counter "Failure to investigate after Art 6 GwG" ]
Suspicious Transaction Reporting
@@ -1607,6 +1786,7 @@ Moving logic into the AML programs:
Open Questions
--------------
+
* Do we use ``Boolean`` attributes or always ``'YES' | 'NO'`` to be extensible
in the future?