commit a242f682257c7bfbf88c62dfbe4a64cfc54c6dde
parent 4312cc94b4d0d31f6e68e1ae354910ed1e90fada
Author: Florian Dold <dold@taler.net>
Date: Sun, 23 Aug 2026 12:12:49 +0200
TOPS: correct AML forms and reporting
Diffstat:
| M | deployments/tops.rst | | | 248 | +++++++++++++++++++++++++++++++++++++++++++++++++------------------------------ |
1 file changed, 154 insertions(+), 94 deletions(-)
diff --git a/deployments/tops.rst b/deployments/tops.rst
@@ -4,8 +4,8 @@ Taler Operations Deployment
Definitions / Glossary
----------------------
-* GwG: German "Geldwäschegesetz", Swiss law regarding anti-money laundering
-* VQF: Verein für Qualitätssicherung im Finanzwesen, self-regulatory
+* GwG: Swiss "Geldwäschereigesetz", the Swiss Anti-Money Laundering Act
+* VQF: Verein zur Qualitätssicherung von Finanzdienstleistungen, self-regulatory
organization that Taler Operations AG is a member of and thus
needs to stick to their rules
* TmeR: German "Transaktion mit erhöhtem Risiko", i.e.
@@ -252,10 +252,10 @@ Properties are registered at the GNU Taler Account Properties `GNU Taler Account
* ``INVESTIGATION_STATE``
- * The MROS reporting state for the account.
+ * The special-clarification and MROS reporting state for the account.
* Values:
- * ``NONE`` / undefined: No MROS reporting for that account
+ * ``NONE`` / undefined: No pending special clarification and no MROS report
* ``INVESTIGATION_PENDING``: Pending investigation. The AML officer should
submit ``vqf_902_14`` to conclude investigation. Usually the property
would be set by the sanction list tool or some AML program that detects
@@ -263,9 +263,12 @@ Properties are registered at the GNU Taler Account Properties `GNU Taler Account
monitoring (see ``tops-0001.sql`` for an example).
The ``vqf_902_14`` form could also be used to start an
investigation (by setting ``INCRISK_RESULT`` to ``OTHER``).
- * ``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)
+ * ``INVESTIGATION_COMPLETED_WITHOUT_SUSPICION``: Special clarification
+ completed without a suspicion that leads to an MROS report
+ * ``REPORTED_SUSPICION_SIMPLE``: A report was filed under Art. 305ter Abs. 2
+ StGB (German "einfacher Verdacht", simple suspicion)
+ * ``REPORTED_SUSPICION_SUBSTANTIATED``: A report was filed under Art. 9 GwG
+ (German "begründeter Verdacht", substantiated suspicion)
* ``INVESTIGATION_TRIGGER :: Text``
@@ -303,7 +306,7 @@ Account opening/closing:
PEP/Risk classification:
* ``INCR_HIGH_RISK_CUSTOMER`` / ``DECR_HIGH_RISK_CUSTOMER``
-* ``INCR_HIGH_RISK_COUNTRY`` / ``INCR_HIGH_RISK_COUNTRY``
+* ``INCR_HIGH_RISK_COUNTRY`` / ``DECR_HIGH_RISK_COUNTRY``
* ``INCR_PEP`` / ``DECR_PEP``
* ``INCR_PEP_FOREIGN`` / ``DECR_PEP_FOREIGN``
* ``INCR_PEP_DOMESTIC`` / ``DECR_PEP_DOMESTIC``
@@ -719,7 +722,10 @@ Initial collection of basic attributes about customer during onboarding.
ESTABLISHER_LIST[].NATIONALITY :: Text
ESTABLISHER_LIST[].PERSONAL_IDENTIFICATION_DOCUMENT_COPY :: File
ESTABLISHER_LIST[].SIGNING_AUTHORITY_TYPE :: 'SINGLE' | 'COLLECTIVE_TWO' | 'OTHER'
- ESTABLISHER_LIST[].SIGNING_AUTHORITY_EVIDENCE_TYPE :: 'CR' | 'MANDATE' | 'OTHER'
+ when (ESTABLISHER_LIST[].SIGNING_AUTHORITY_TYPE = 'OTHER') {
+ ESTABLISHER_LIST[].SIGNING_AUTHORITY_TYPE_OTHER :: Text
+ }
+ ESTABLISHER_LIST[].SIGNING_AUTHORITY_EVIDENCE :: 'CR' | 'MANDATE' | 'OTHER'
ESTABLISHER_LIST[].SIGNING_AUTHORITY_EVIDENCE_DOCUMENT_COPY :: File
when (ESTABLISHER_LIST[].SIGNING_AUTHORITY_EVIDENCE = 'OTHER') {
ESTABLISHER_LIST[].SIGNING_AUTHORITY_EVIDENCE_OTHER :: Text
@@ -727,7 +733,7 @@ Initial collection of basic attributes about customer during onboarding.
}
CORRESPONDENCE_LANGUAGE :: 'en' | 'de' | 'fr' | 'it'
CUSTOMER_TYPE_VQF :: (
- 'NATURAL' | 'OPERATIONAL' | 'FOUNDATION' |
+ 'NATURAL_PERSON' | 'OPERATIONAL' | 'FOUNDATION' |
'TRUST' | 'LIFE_INSURANCE' | 'OTHER')
* ``SIGNATURE``
@@ -754,7 +760,7 @@ Initial collection of basic attributes about customer during onboarding.
* **Type:** Single Choice
* **Choices:**:
- * ``NATURAL``
+ * ``NATURAL_PERSON``
* **Label DE**: Die Vertragspartei ist eine natürliche Person und es bestehen keine Zweifel, dass
diese selber an den Vermögenswerten wirtschaftlich
@@ -939,10 +945,10 @@ Initial collection of basic attributes about customer during onboarding.
* ``Identifizierungsformular (Kundenbasisdaten)``
**Measure after submission by customer:**
-Depending on ``CUSTOMER_TYPE``, the customer is asked to fill out another
+Depending on ``CUSTOMER_TYPE_VQF``, the customer is asked to fill out another
form:
-* ``NATURAL``: No other form to fill out. A TAN letter will be directly
+* ``NATURAL_PERSON``: No other form to fill out. A TAN letter will be directly
sent to the customer.
* ``OPERATIONAL``: Form ``vqf_902_11_customer``
* ``FOUNDATION``: Form ``vqf_902_12``
@@ -984,7 +990,7 @@ vqf_902_1_officer
ACCEPTANCE_FURTHER_INFO :: Optional[Text]
EMBARGO_TERRORISM_CHECK_RESULT :: 'LISTED' | 'NOT_LISTED'
EMBARGO_TERRORISM_CHECK_DATE :: Date
- when EMBARGO_TERRORISM_INFO = 'LISTED' {
+ when EMBARGO_TERRORISM_CHECK_RESULT = 'LISTED' {
EMBARGO_TERRORISM_INFO :: Text
}
SUPPLEMENTAL_FILES_LIST[].FILE :: File
@@ -1305,14 +1311,23 @@ to document the risk profile of a customer.
* **Type:** Multi-line text
* **Label DE:** Begründung für abweichende Risikobewertung
-* ``HIGH_RISK``
+* ``RISK_CLASSIFICATION_LEVEL``
- * **Type:** Checkbox (yes/no)
+ * **Type:** Single choice
* **Label DE:** [Risikoklassifizierung] Geschäftsbeziehung mit erhöhtem Risiko
+ * **Choices:**
+
+ * ``HIGH_RISK``
+
+ * **Label DE:** Ja
+
+ * ``NO_HIGH_RISK``
+
+ * **Label DE:** Nein
* ``HIGH_RISK_ACCEPTANCE_DATE``
- * **Type:** Checkbox (yes/no)
+ * **Type:** Date
* **Label DE:**
Die Zustimmung einer vorgesetzten Person / Stelle oder der Geschäftsführung
zur Aufnahme einer Geschäftsbeziehung mit erhöhtem Risiko wurde eingeholt
@@ -1760,7 +1775,7 @@ entity or partnership.
* ``TITLE_VQF_902_11_CUSTOMER``
* **DE:**
- Feststellung des Kontrollinhabers an nicht
+ Feststellung des Kontrollinhabers an nicht börsenkotierten,
operativ tätigen juristischen Personen und
Personengesellschaften (K)
@@ -1882,7 +1897,7 @@ entity or partnership.
* ``TITLE_VQF_902_11_OFFICER``
* **DE:**
- Feststellung des Kontrollinhabers an nicht
+ Feststellung des Kontrollinhabers an nicht börsenkotierten,
operativ tätigen juristischen Personen und
Personengesellschaften (K)
@@ -1930,15 +1945,15 @@ out by at the initiative of the AML officer or in response to an alert.
CUSTOMER_NAME :: String
INCRISK_REASON :: Text
INCRISK_MEANS :: 'GATHERING' | 'CONSULTATION' | 'ENQUIRIES' | 'OTHER'
- when INCRISK_MEANS_OTHER = 'OTHER' {
+ when INCRISK_MEANS = 'OTHER' {
INCRISK_MEANS_OTHER :: Text
}
INCRISK_SUMMARY :: Text
INCRISK_DOCUMENTS :: Text
INCRISK_RESULT :: (
- 'NO_SUSPICION' | 'SUBSTANTIATED_SUSPICION' |
+ 'NO_SUSPICION' | 'REASONABLE_SUSPICION' |
'SIMPLE_SUSPICION' | 'OTHER')
- if INCRISK_REASON = 'OTHER' {
+ when INCRISK_RESULT = 'OTHER' {
INCRISK_RESULT_OTHER :: Text
}
@@ -2022,7 +2037,7 @@ out by at the initiative of the AML officer or in response to an alert.
* **Type:** Free-form, multi-line text
* **When:** ``INCRISK_RESULT = 'OTHER'``
- * **Label DE:** Erklärung zu anderem Verdacht
+ * **Label DE:** Erklärung zu anderem Ergebnis
vqf_902_15
@@ -2186,7 +2201,7 @@ Properties:
if (INCRISK_RESULT == "SIMPLE_SUSPICION") {
newProps.INVESTIGATION_STATE = "REPORTED_SUSPICION_SIMPLE";
- } else if (INCRISK_RESULT == "SUBSTANTIATED_SUSPICION") {
+ } else if (INCRISK_RESULT == "REASONABLE_SUSPICION") {
newProps.INVESTIGATION_STATE = "REPORTED_SUSPICION_SUBSTANTIATED";
} else if (INCRISK_RESULT == "NO_SUSPICION") {
newProps.INVESTIGATION_STATE = "INVESTIGATION_COMPLETED_WITHOUT_SUSPICION";
@@ -2322,103 +2337,146 @@ to answer with statistics derived via events:
TBD.
-Based on this, we have the following statistics:
-
-* Number of open accounts on January 1st (self-declaration 3.1.1)
-
- * Implemementation: ``evtcount(INCR_ACCOUNT_OPEN, start=0, end=jan_first_20xx) - evtcount(DECR_ACCOUNT_OPEN, start=0, end=jan_first_20xx)``
-
-* Number of newly opened accounts between 01.01.20XX and 31.12.20XX (self-declaration 3.1.2.)
-
- * Implemementation: ``evtcount(INCR_ACCOUNT_OPEN, start=jan_first_20xx, end=dec_last_20xx)``
-
-* Number of AML files managed during the year 20XX (self-declaration 3.1.3.)
-
- * All accounts ever opened except the ones that were closed *before* 20xx
- * Implemementation: ``evtcount(INCR_ACCOUNT_OPEN, start=0, end=dec_last_20xx) - evtcount(DECR_ACCOUNT_OPEN, start=0, end=jan_first_20xx)``
-
-* Number of AML files closed between 01.01.20XX and 31.12.20XX (self-declaration 3.1.4)
+All annual statistics use the half-open reporting period
+``year_20xx = [year_start, next_year_start)``. Events at ``year_start`` belong
+to the new reporting year; events at ``next_year_start`` do not. The following
+notation is used:
- * Implemementation: ``evtcount(DECR_ACCOUNT_OPEN, start=jan_first_20xx, end=dec_last_20xx)``
+* ``accounts_at(condition, t)`` is the set of AML accounts for which
+ ``condition`` is true immediately before ``t``.
+* ``accounts_during(condition, range)`` is the set of AML accounts for which
+ ``condition`` is true for any non-empty interval within ``range``.
+* ``accounts_with_event(event, range)`` is the set of AML accounts that emitted
+ ``event`` in ``range``. Each account occurs at most once in the set.
+* ``evtcount(event, range)`` counts occurrences of ``event``. This is used for
+ reports, where separate filings by the same customer must be counted
+ separately.
-* Were there business relationships in the year 20XX with high risk? (self-declaration 4.1)
+The set operations must be evaluated from each account's ordered property and
+event history. In particular, two properties must be true at the same time to
+satisfy a conjunction. Define these sets for the selected reporting year:
- * Implementation: ``evtcount(INCR_HIGH_RISK_CUSTOMER, start=0, end=dec_last_20xx) - evtcount(DECR_HIGH_RISK_CUSTOMER, start=0, end=dec_last_20xx) > 0``
-
-* Of those, how many were with PEPs? (self-declaration 4.2.)
-
- * Implementation: ``evtcount(INCR_PEP, start=0, end=dec_last_20xx) - evtcount(DECR_PEP, start=0, end=dec_last_20xx)``
-
-* Of those PEPs, how many were with *foreign* PEPs? (self-declaration 4.3.)
-
- * Implementation: ``evtcount(INCR_PEP_FOREIGN, start=0, end=dec_last_20xx) - evtcount(DECR_PEP_FOREIGN, start=0, end=dec_last_20xx)``
-
-* Number of other additional (other than PEPs and foreign PEPs) high-risk business relationships in 20XX (self-declaration 4.4.)
-
- * Implementation: Difference between 4.5. and 4.2
-
-* Number of high-risk business relationship n total in 20xx (self-declaration 4.5.)
-
- * Implementation: ``evtcount(INCR_HIGH_RISK_CUSTOMER, start=0, end=dec_last_20xx) - evtcount(DECR_HIGH_RISK_CUSTOMER, start=0, end=dec_last_20xx)``
-
-* Number of reports (substantiated suspicion) to MROS during 20xx (self-declaration 5.1)
-
- * Implementation: ``evtcount(REPORTED_SUSPICION_SUBSTANTIATED, range=year_20xx)``
-
-* Number of reports (simple suspicion) to MROS during 20xx (self-declaration 5.2)
-
- * Implementation: ``evtcount(REPORTED_SUSPICION_SIMPLE, range=year_20xx)``
-
-* Total number of reports to MROS during 20xx (self-declaration 5.3)
+.. code:: none
- * Implementation: ``evtcount(REPORTED_SUSPICION_SIMPLE, range=year_20xx) + evtcount(REPORTED_SUSPICION_SUBSTANTIATED, range=year_20xx)``
+ open_start = accounts_at(ACCOUNT_OPEN, year_start)
+ open_end = accounts_at(ACCOUNT_OPEN, next_year_start)
+ open_during = accounts_during(ACCOUNT_OPEN, year_20xx)
+ opened = accounts_with_event(INCR_ACCOUNT_OPEN, year_20xx)
+ closed = accounts_with_event(DECR_ACCOUNT_OPEN, year_20xx)
+
+ is_pep = PEP_DOMESTIC or PEP_FOREIGN or PEP_INTERNATIONAL_ORGANIZATION
+ high_risk = accounts_during(
+ ACCOUNT_OPEN and HIGH_RISK_CUSTOMER, year_20xx)
+ high_risk_pep = accounts_during(
+ ACCOUNT_OPEN and HIGH_RISK_CUSTOMER and is_pep, year_20xx)
+ high_risk_foreign_pep = accounts_during(
+ ACCOUNT_OPEN and HIGH_RISK_CUSTOMER and PEP_FOREIGN, year_20xx)
+ high_risk_country = accounts_during(
+ ACCOUNT_OPEN and HIGH_RISK_COUNTRY, year_20xx)
+
+Based on these sets, the VQF self-declaration statistics are:
+
+* Number of open AML files on January 1st (self-declaration 3.1.1):
+ ``size(open_start)``.
+* Number of newly opened AML files during the year (self-declaration 3.1.2):
+ ``size(opened)``.
+* Number of AML files managed at any time during the year (self-declaration
+ 3.1.3): ``size(open_during)``.
+* Number of AML files closed during the year (self-declaration 3.1.4):
+ ``size(closed)``.
+* Number of open AML files at year end (self-declaration 3.1.5):
+ ``size(open_end)``.
+* Whether any high-risk business relationship was managed during the year
+ (self-declaration 4.1): ``size(high_risk) > 0``.
+* Number of high-risk business relationships involving PEPs
+ (self-declaration 4.2): ``size(high_risk_pep)``.
+* Number of those high-risk PEP relationships involving foreign PEPs
+ (self-declaration 4.3): ``size(high_risk_foreign_pep)``.
+* Number of other high-risk business relationships, excluding those involving
+ PEPs (self-declaration 4.4): ``size(high_risk - high_risk_pep)``.
+* Total number of high-risk business relationships (self-declaration 4.5):
+ ``size(high_risk)``.
+* Whether any relationship involved a contractual party or beneficial owner
+ associated with a high-risk country (self-declaration 4.6):
+ ``size(high_risk_country) > 0``.
+* Number of mandatory reports filed with MROS (self-declaration 5.1):
+ ``evtcount(MROS_REPORTED_SUSPICION_SUBSTANTIATED, year_20xx)``.
+* Number of reports filed under the reporting right (self-declaration 5.2):
+ ``evtcount(MROS_REPORTED_SUSPICION_SIMPLE, year_20xx)``.
+* Total MROS reports filed and notified to VQF (self-declaration 5.3): the sum
+ of the two event counts for 5.1 and 5.2. Only actual filing events may be
+ included.
+
+For example, an account that is open at the start of the year and closes in
+June is included in 3.1.1, 3.1.3, and 3.1.4, but not 3.1.5. A relationship
+that is high-risk in March and downgraded in April remains included in 4.1 and
+4.5 for that reporting year. A PEP relationship is included in 4.2 only if it
+was simultaneously open and classified as high-risk. A temporary high-risk-
+country association is sufficient for 4.6. Two distinct MROS filing events
+for the same account are counted as two reports under 5.1 through 5.3.
Event Reporting (TOPS)
^^^^^^^^^^^^^^^^^^^^^^
-The following event-based statistics are custom-defined by us and shown in the AML officer dashboard.
+The following statistics are custom-defined by us and shown in the AML officer
+dashboard. ``reporting_period`` is an explicitly selected half-open calendar
+period; it must not depend on the current date or an ambiguous ``last_year``
+shortcut.
-* Number of accounts that are opened:
+* Number of accounts that are currently open:
- * Implementation: ``evtcount(INCR_ACCOUNT_OPEN) - evtcount(DECR_ACCOUNT_OPEN)``
+ * Implementation: ``size(accounts_at(ACCOUNT_OPEN, now))``
-* Number of new GwG files in the last year.
+* Number of new GwG files in the selected reporting period:
- * Implementation: ``evtcount(INCR_ACCOUNT_OPEN, range=last_year)``
+ * Implementation:
+ ``size(accounts_with_event(INCR_ACCOUNT_OPEN, reporting_period))``
-* Number of GwG files closed in the last year
+* Number of GwG files closed in the selected reporting period:
- * Implementation: ``evtcount(DECR_ACCOUNT_OPEN), range=last_year)``
+ * Implementation:
+ ``size(accounts_with_event(DECR_ACCOUNT_OPEN, reporting_period))``
* Note: we only close GwG files after 1 year of inactivity, so implementation not exactly pressing ...
-* Number of GwG files of high-risk customers
+* Number of currently open GwG files of high-risk customers:
+
+ * Implementation:
+ ``size(accounts_at(ACCOUNT_OPEN and HIGH_RISK_CUSTOMER, now))``
- * Implementation: ``evtcount(INCR_HIGH_RISK) - evtcount(INCR_HIGH_RISK)``
+* Number of currently open high-risk GwG files involving PEPs:
-* Number of GwG files managed with "increased risk" due to PEP status
+ * Implementation: ``size(accounts_at(ACCOUNT_OPEN and HIGH_RISK_CUSTOMER and
+ (PEP_DOMESTIC or PEP_FOREIGN or PEP_INTERNATIONAL_ORGANIZATION), now))``
- * Implementation: ``evtcount(INCR_PEP) - evtcount(DECR_PEP)``
+* Number of MROS reports based on Art. 9 Abs. 1 GwG in the selected period:
-* Number of MROS reports based on Art 9 Abs. 1 GwG (per year)
+ * Implementation:
+ ``evtcount(MROS_REPORTED_SUSPICION_SUBSTANTIATED, reporting_period)``
- * Implementation: ``evtcount(MROS_REPORTED_SUSPICION_SUBSTANTIATED, range=last_year)``
+* Number of MROS reports based on Art. 305ter Abs. 2 StGB in the selected
+ period:
-* Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)
+ * Implementation:
+ ``evtcount(MROS_REPORTED_SUSPICION_SIMPLE, reporting_period)``
- * Implementation: ``evtcount(MROS_REPORTED_SUSPICION_SIMPLE, range=last_year)``
+* Number of special clarifications concluded in the selected reporting period:
-* Number of customers involved in proceedings for which Art 6 GwG did apply
+ * Implementation:
+ ``size(accounts_with_event(INCR_INVESTIGATION_CONCLUDED, reporting_period))``
- * Implementation: ``evtcount(INCR_INVESTIGATION, range=last_year)``
+Transactions with Increased Risk (TmeR)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Suspicious Transaction Reporting
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+A TmeR ("Transaktion mit erhöhtem Risiko") is a transaction-monitoring
+classification. It triggers special clarification but is not by itself a
+suspicion, a decision to report, or evidence that a report was filed with MROS.
+The special clarification records its result; a separate reporting decision
+and an actual filing are required before an MROS reporting event may be emitted.
-Also called TmeR ("Transaktionen mit erhoehtem Risiko").
-We define fixed criteria that apply to all customers.
+We define fixed TmeR criteria that apply to all customers.
Examples:
@@ -2502,9 +2560,11 @@ FAQ
* Q: What's the difference between simple/substantiated suspicion?
- A: Simple suspicion is a suspicion according to Art 305ter Abs. 2 StGB. It is
- a suspicion that *may* be reported ("Melderecht"). A substantiated suspicion
- is according to Art. 9 GwG and *must* be reported ("Meldepflicht")
+ * A: A simple suspicion is a suspicion according to Art. 305ter Abs. 2 StGB
+ that *may* be reported ("Melderecht"). A substantiated suspicion under
+ Art. 9 GwG *must* be reported ("Meldepflicht"). Neither an alert nor a
+ TmeR alone establishes either result, and a reporting result must not be
+ recorded as an actual filing until the report has been submitted to MROS.
References
----------