12. Monitoreo de transacciones¶
Este microservicio tiene como objeto monitorear transacciones financieras informadas por una aplicación de terceros. El propósito de este servicio es poder detectar transacciones inusuales para, de forma inmediata, alertar a las partes interesadas de la entidad financiera.
El monitoreo se realiza mediante un sistema basado en reglas.
12.1 Reglas de monitoreo de transacciones¶
Las transacciones que son informadas por la entidad al servicio de monitoreo de Trak.e, son evaluadas mediante ciertas reglas configurables en el servicio, para la detección automática de operaciones inusuales con el fin de generar alertas. Estas alertas son, luego, estudiadas por analistas de la mencionada entidad para un mejor análisis y toma de decisiones.
Particularmente, Trak.e emplea un sistema basado en reglas de desarrollo propio. Un sistema basado en reglas es aquel que utiliza reglas definidas por humanos expertos en cierto dominio para realizar deducciones y efectuar acciones. Son denominados, también, simplemente como sistemas expertos: se los considera una forma de representar el conocimiento de personas expertas dentro de un sistema automático. Las reglas, por lo general, tienen la forma de sentencias
if-then
; es decir, son de la formaif A then B
.
Cada regla activa se ejecuta una vez por cada transacción inyectada. Se permite agregar cualquier cantidad de reglas de monitoreo de legajo, pero a lo sumo 50 pueden estar activas al mismo tiempo.
12.2 Implementación¶
Las reglas siguen el esquema visto para la matriz de riesgo y el cálculo del perfil transaccional: reglas escritas en lenguaje Python.
12.2.1 Parámetros¶
Las variables disponibles son:
-
profile
: Al evaluar la regla se pone en el contexto de ejecución la variableprofile
que contiene el legajo que se esta procesando actualmente. Todos los atributos detallados en la sección Legajos se encuentra disponible en este objeto. -
transaction
: Contiene la información de la transacción que se esta procesando actualmente. Todos los atributos informados por la entidad mediante la API de transacciones esta disponible. -
hist_trxs
: Si la regla incluye información sobre la transaccionalidad del legajo, se puede acceder al histórico de la transaccionalidad del legajo con este nombre. La variable es puesta en contexto de ejecución en formato de pandas.DataFrame, donde cada fila del DataFrame representa una transacción y las columnas del DataFrame son los atributos de las transacciones (utilizando guion bajo como separador en caso de ser atributos anidados). Es posible que el historial este vacío (sin filas ni columnas) si el cliente no registra transacciones.
12.2.2 Resultado de la regla¶
La regla debe definir una variable de nombre SHOULD_RAISE
cuyo valor debe ser
un valor de verdad que indica si debería generar una nueva alerta. Los valores posibles y su interpretación son:
True
: Se evaluó la regla y se determinó un comportamiento inusual, por lo que se levantará una alerta en trak.e para que un analista de la entidad gestione y resuelva sobre la anomalía.False
: Se evaluó la regla y se determinó que no había comportamientos inusuales.None
: No se evaluó la regla. O bien no aplica, o falta algún valor critico para hacerlo.
Nota
Contexto:
Además de los valores True
, False
y None
utilizados
para interpretar la evaluación de la regla, se devuelve el
contexto de la evaluación, particularmente aquellas variables públicas definidas. Esto permite guardar valores
calculados durante la ejecución de la regla y que los mismos estén
disponibles al momento de ver los resultados.
Nota
Por cuestiones de seguridad, no es posible utilizar el lenguaje Python
completo al momento de definir una regla, si no sólo un subconjunto del
lenguaje. En particular, no está permitido realizar import
s. Sin embargo,
para comodidad del programador, se pueden utilizar algunos módulos, clases y
funciones incluidas en Python.
Nota
Módulos, clases y funciones permitidos al momento de definir reglas:
- Clase
Decimal
del módulodecimal
: Esta clase permite manejar números decimales con precisión fija y arbitraria. Puede consultar la documentación de esta clase aquí. - Modulo
pandas
: Este módulo permite realizar análisis de datos de manera rápida, potente, flexible y simple. En particular es necesario para trabajar con el histórico de las transacciones. Notar que, al igual que en la mayoría de los ejemplos que se encuentran en la página, en las reglas uno se refiere a este modulo utilizando la abreviaciónpd
. La documentación del módulo puede consultarse aquí. - Clase
datetime
del módulodatetime
: Esta clase permite representar y trabajar flexiblemente con fechas y horas. Notar que en trak.e todas las fechas y horas se representan en milisegundos desde el Epoch, por lo que luego de trabajar las fechas se deben reconvertir a este formato antes de realizar comparaciones con los atrbiutos del legajo o de las transacciones. La documentación de esta clase puede encontrarse en aquí. - Clase
timedelta
del módulodatetime
: Esta clase permite representar y trabajar con intervalos de tiempo. Cómo ejemplo, la diferencia entre dos objetos de tipodatetime
sera un objeto de tipotimedelta
. La documentación de la clase puede encontrarse aquí. - Función
strptime
: Esta función permite analizar gramaticalmente una fecha y hora en formato texto y devolver el objetodatetime
que corresponde. La función recibe dos argumentos; la fecha y hora, y el string que describe el formato. Algunos ejemplos:>>> strptime("20-06-2021", "%d-%m-%Y") datetime.datetime(2021, 6, 20, 0, 0) >>> strptime("20-06-21", "%d-%m-%y") datetime.datetime(2021, 6, 20, 0, 0) >>> strptime("20-06-21, 20:08", "%d-%m-%y, %H:%M") datetime.datetime(2021, 6, 20, 20, 8)
- Módulo
json
: Este modulo contiene funciones par trabajar cómodamente con objetos JSON. La documentación del módulo puede encontrarse aquí. - Módulo
math
: Contiene varias funciones matemáticas de utilidad. La documentación esta aquí. - Además pueden utilizarse algunas funciones de utilidad:
max
,min
,sum
,all
,any
,round
,len
,isinstance
yrange
. - Además pueden utilizarse los constructores estándar
str
,int
,float
,list
,tuple
,dict
,set
ybool
. - También se encuentran definidas en el contexto las excepciones estándar
IndexError
yKeyError
, por lo que puede controlarlas en su código.
12.3 Ejemplos¶
12.3.1 Excede cantidad de transacciones¶
- Descripción: Algo muy habitual es evaluar la cantidad de transacciones que realizo un cliente en un determinado período. Una regla básica para evaluar esto es la siguiente:
init = datetime.now().replace(hour=0, minute=0, second=0,
microsecond=0) - timedelta(days=30)
init_timestamp = int(init.timestamp()) * 1000
cant_trx = hist_trxs[(hist_trxs["timestamp"] >= init_timestamp) & (
hist_trxs["side"] == transaction.side)].shape[0]
SHOULD_RAISE = cant_trx >= 20
12.3.2 Excede monto fijo¶
- Descripción:Esta regla evalúa si el total acumulado de transacciones excede un monto fijo predeterminado.
init = datetime.now().replace(hour=0, minute=0, second=0,
microsecond=0) - timedelta(days=30)
init_timestamp = int(init.timestamp()) * 1000
total_amount = hist_trxs[
(hist_trxs["timestamp"] >= init_timestamp) & (
hist_trxs["side"] == transaction.side)
].amount.sum().item()
SHOULD_RAISE = total_amount + transaction.amount >= 1e7
12.3.3 Excede perfil transaccional¶
- Descripción: Esta regla evalúa las transacciones y verifica que, acumulando el monto con el resto de las operaciones del período, el legajo no exceda su perfil transaccional oportunamente asignado.
transactional_profile = profile["transactional_profile_amount"]
if not transactional_profile:
SHOULD_RAISE = None
transactional_profile_period = 31536000000 # 365*24*60*60*1000
now = transaction["timestamp"]
from_ = now - transactional_profile_period
sum_amount_deposit = sum(hist_trxs[hist_trxs["side"] == "deposit"][hist_trxs["timestamp"] > from_]["amount"])
sum_amount_extraction = sum(hist_trxs[hist_trxs["side"] == "extraction"][hist_trxs["timestamp"] > from_]["amount"])
if transaction.side == "deposit":
sum_amount_deposit += transaction.amount
elif transaction.side == "extraction":
sum_amount_extraction += transaction.amount
if sum_amount_deposit + sum_amount_extraction > transactional_profile:
SHOULD_RAISE = True
else:
SHOULD_RAISE = False
12.3.4 Cambio repentino de perfil¶
-
Descripción: Esta regla evalúa las transacciones buscando anomalías en los montos operados por el cliente. Para ello compara el mes actual con su promedio histórico de depósitos y extracciones realizados.
-
Parámetros:
Parámetro | Significado | Tipo | Valor por defecto |
---|---|---|---|
side |
La regla se puede configurar para trabajar sobre los depósitos o sobre las extracciones. | Literal "deposit" o "extraction" |
"deposit" |
profile_change_min_seniority |
Esta regla necesita que el legajo tenga cierta antigüedad, una historia de transaccionalidad en la entidad que permita determinar un promedio histórico confiable. La regla será evaluada sólo para aquellos legajos que hayan sido creados hace cierto tiempo. | Entero, representando un tiempo en milisegundos. | int(1.814e10) (210 días) |
profile_change_lookback_period |
Este parámetro representa cuánto tiempo consideraremos para definir cuál es el comportamiento promedio. | Entero, representando un tiempo en milisegundos. | int(1.555e10) (180 días) |
profile_change_min_threshold |
Este parámetro representa un monto mínimo de interés, y sirve para evitar tener un exceso de alertas por montos pequeños de dinero. Si el comportamiento del mes actual es menor a este valor la regla no será evaluada. | Flotante, representando un monto de dinero. | 350000 |
profile_change_tolerable_deviation |
Diccionario que representa, para PF/PJ y segun el nivel de riesgo, cuanto se permite que se desvie la transaccionalidad respecto al comportamiento promedio. | Diccionario de diccionario de flotantes, representando un cambio porcentual. | * 0.6 para PJ de riesgo bajo *0.4 para PJ de risgo medio *0.25 para PJ de riesgo alto *0.8 para PF de riesgo bajo *0.6 para PF de riesgo medio *0.4 para PF de riesgo alto |
# allowed sides: "deposit"/"extraction"
side = "deposit"
# profile_change_min_seniority: Profile newer than this will not trigger the
# rule. Defaults to 210 days i.e. 7 months
profile_change_min_seniority: int = int(1.814e10)
# profile_change_lookback_period. How long will the rule look back in order to
# define a usual behavior. Defaults to 180 days, i.e. 6 months
profile_change_lookback_period: int = int(1.555e10)
# Minimum amount of money that will trigger the rule.If current month behavior
# is less than this threshold, the rule is not applied.
profile_change_min_threshold: float = 350000
# threshold for each person type and risk value. These are floating point
# numbers between 0 and 1 representing a percentage that the profile might
# overcome each month.
tolerable_deviation = dict(
legal_person=dict(
low=0.6,
medium=0.4,
high=0.25,
),
natural_person=dict(
low=0.8,
medium=0.6,
high=0.4,
),
)
timestamp = transaction.timestamp
created_at = profile.created_at
person_type = profile.person_type
risk = profile.risk
if not timestamp or not created_at or not person_type or not risk:
SHOULD_RAISE = None
elif transaction.side != side:
SHOULD_RAISE = None
elif timestamp - created_at < profile_change_min_seniority:
# Not enough seniority to consider this profile
SHOULD_RAISE = None
else:
trx_now = datetime.fromtimestamp(timestamp // 1000)
period_end = int(trx_now.replace(day=1, hour=0, minute=0, second=0, microsecond=0).timestamp() * 1000)
period_init = period_end - profile_change_lookback_period
one_month = int(2.592e9)
this_month_behavior = (
hist_trxs.loc[(hist_trxs["timestamp"] >= period_end) & (hist_trxs["side"] == side)].amount.sum()
+ transaction["amount"]
)
if this_month_behavior < profile_change_min_threshold:
SHOULD_RAISE = None
else:
average_behavior = (
hist_trxs.loc[
(period_init <= hist_trxs["timestamp"])
& (hist_trxs["timestamp"] < period_end)
& (hist_trxs["side"] == side)
].amount.sum()
* one_month
/ profile_change_lookback_period
)
deviation = (this_month_behavior - average_behavior) / this_month_behavior
SHOULD_RAISE = bool(deviation > tolerable_deviation[person_type][risk])
Recurso |
---|
transaction_transaction |
transaction_rule |
transaction_summary |