Разработка системы transaction monitoring для AML

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы transaction monitoring для AML
Сложная
от 1 недели до 3 месяцев
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1258
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1170
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    873
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1092
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    563
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    830

Разработка системы transaction monitoring для AML

Transaction monitoring (TM) — непрерывный процесс анализа транзакций для выявления подозрительной активности. Это не просто блеклист проверка: TM выявляет паттерны (structuring, rapid movement, round-trip) которые по отдельности выглядят нормально, но в совокупности — признак отмывания.

Архитектура TM системы

Два подхода: rule-based (детерминированные правила) и ML-based (anomaly detection). В production используют оба: правила для известных паттернов, ML для обнаружения нового.

Rule Engine

interface MonitoringRule {
  id: string;
  name: string;
  category: "structuring" | "velocity" | "geographic" | "behavioral" | "watchlist";
  evaluate: (context: TransactionContext) => Promise<RuleResult>;
  alertLevel: AlertLevel;
  action: AlertAction;
}

class TransactionMonitoringEngine {
  private rules: MonitoringRule[];
  
  async evaluateTransaction(tx: Transaction): Promise<EvaluationResult> {
    const context = await this.buildContext(tx);
    
    const results = await Promise.all(
      this.rules.map(rule => rule.evaluate(context).catch(err => ({
        triggered: false,
        error: err.message,
      })))
    );
    
    const triggered = results.filter(r => r.triggered);
    
    if (triggered.length === 0) return { action: "ALLOW", ruleHits: [] };
    
    const maxLevel = Math.max(...triggered.map(r => r.alertLevel));
    const action = this.determineAction(maxLevel, triggered);
    
    if (action !== "ALLOW") {
      await this.createAlert(tx, triggered, action);
    }
    
    return { action, ruleHits: triggered };
  }
  
  private async buildContext(tx: Transaction): Promise<TransactionContext> {
    const [history30d, history24h, userProfile, walletRisk] = await Promise.all([
      this.db.getTransactionHistory(tx.userId, 30),
      this.db.getTransactionHistory(tx.userId, 1),
      this.db.getUserProfile(tx.userId),
      this.amlProvider.getWalletRisk(tx.address, tx.asset),
    ]);
    
    return { transaction: tx, history30d, history24h, userProfile, walletRisk };
  }
}

Конкретные правила

const STRUCTURING_RULE: MonitoringRule = {
  id: "TM-001",
  name: "Structuring Detection",
  category: "structuring",
  alertLevel: AlertLevel.HIGH,
  action: AlertAction.FREEZE_AND_REVIEW,
  
  async evaluate(ctx: TransactionContext): Promise<RuleResult> {
    const REPORTING_THRESHOLD = 10000;
    
    // Находим транзакции чуть ниже threshold за 3 дня
    const nearThreshold = ctx.history30d.filter(t => 
      t.usdAmount >= REPORTING_THRESHOLD * 0.7 &&
      t.usdAmount < REPORTING_THRESHOLD &&
      Date.now() - t.timestamp < 3 * 86400000
    );
    
    const currentNearThreshold = ctx.transaction.usdAmount >= REPORTING_THRESHOLD * 0.7 &&
                                 ctx.transaction.usdAmount < REPORTING_THRESHOLD;
    
    if (currentNearThreshold && nearThreshold.length >= 2) {
      return {
        triggered: true,
        alertLevel: AlertLevel.HIGH,
        details: `${nearThreshold.length + 1} transactions just below $${REPORTING_THRESHOLD}`,
        evidence: nearThreshold.map(t => t.id),
      };
    }
    
    return { triggered: false };
  },
};

const VELOCITY_RULE: MonitoringRule = {
  id: "TM-002",
  name: "Unusual Velocity",
  category: "velocity",
  alertLevel: AlertLevel.MEDIUM,
  action: AlertAction.ENHANCED_MONITORING,
  
  async evaluate(ctx: TransactionContext): Promise<RuleResult> {
    const avg30d = ctx.history30d.reduce((sum, t) => sum + t.usdAmount, 0) / 30;
    const total24h = ctx.history24h.reduce((sum, t) => sum + t.usdAmount, 0) + 
                     ctx.transaction.usdAmount;
    
    const velocityRatio = avg30d > 0 ? total24h / avg30d : total24h > 500 ? 999 : 0;
    
    if (velocityRatio >= 10) {
      return {
        triggered: true,
        alertLevel: AlertLevel.MEDIUM,
        details: `24h volume ${total24h.toFixed(0)} USD is ${velocityRatio.toFixed(1)}x daily average`,
      };
    }
    
    return { triggered: false };
  },
};

const ROUND_TRIP_RULE: MonitoringRule = {
  id: "TM-003",
  name: "Round Trip Detection",
  category: "behavioral",
  alertLevel: AlertLevel.HIGH,
  action: AlertAction.FREEZE_AND_REVIEW,
  
  async evaluate(ctx: TransactionContext): Promise<RuleResult> {
    // Деньги пришли и ушли через несколько адресов обратно
    if (ctx.transaction.type !== "WITHDRAWAL") return { triggered: false };
    
    const recentDeposits = ctx.history30d.filter(t => 
      t.type === "DEPOSIT" &&
      Math.abs(t.usdAmount - ctx.transaction.usdAmount) < ctx.transaction.usdAmount * 0.05 && // ±5%
      Date.now() - t.timestamp < 7 * 86400000
    );
    
    if (recentDeposits.length > 0) {
      return {
        triggered: true,
        alertLevel: AlertLevel.HIGH,
        details: `Similar deposit ${recentDeposits[0].usdAmount} USD received ${
          Math.round((Date.now() - recentDeposits[0].timestamp) / 3600000)} hours ago`,
      };
    }
    
    return { triggered: false };
  },
};

ML-based Anomaly Detection

Для продвинутых систем — Isolation Forest или Autoencoder для выявления аномалий:

from sklearn.ensemble import IsolationForest
import numpy as np

class TransactionAnomalyDetector:
    def __init__(self):
        self.model = IsolationForest(contamination=0.01, random_state=42)
    
    def extract_features(self, transaction, user_history):
        return [
            transaction['usd_amount'],
            transaction['usd_amount'] / (user_history['avg_30d'] + 1),
            len(user_history['transactions_24h']),
            transaction['hour_of_day'],
            transaction['day_of_week'],
            user_history['unique_counterparties_7d'],
            transaction['aml_risk_score'],
        ]
    
    def predict(self, features) -> float:
        # Returns: -1 anomaly, 1 normal
        # Transform to probability
        score = self.model.score_samples([features])[0]
        return (score + 0.5) * 2  # normalize to [0, 1]

Alert Management и SAR

class AlertManager {
  async createAlert(tx: Transaction, rules: RuleResult[], action: AlertAction): Promise<Alert> {
    const alert = await this.db.createAlert({
      transactionId: tx.id,
      userId: tx.userId,
      triggeredRules: rules.map(r => r.ruleId),
      maxAlertLevel: Math.max(...rules.map(r => r.alertLevel)),
      action,
      status: AlertStatus.OPEN,
      assignedTo: await this.autoAssignCompliance(),
      dueDate: this.calculateDueDate(action),
    });
    
    if (action === AlertAction.FREEZE_AND_REVIEW) {
      await this.freezeUserAccount(tx.userId, alert.id);
    }
    
    await this.notifyComplianceTeam(alert);
    return alert;
  }
  
  async resolveSARAlert(alertId: string, sarDecision: SARDecision): Promise<void> {
    if (sarDecision.submitSAR) {
      await this.sarService.createAndSubmit({
        alertId,
        suspiciousActivity: sarDecision.description,
        supportingTransactions: sarDecision.transactions,
      });
    }
    
    await this.db.updateAlert(alertId, {
      status: sarDecision.submitSAR ? AlertStatus.SAR_SUBMITTED : AlertStatus.CLOSED,
      resolution: sarDecision.resolution,
      resolvedAt: new Date(),
    });
  }
}

Стек

Компонент Технология
Rule engine Node.js + TypeScript
ML detection Python + scikit-learn или TensorFlow
Streaming Apache Kafka для real-time
Storage PostgreSQL + TimescaleDB (time-series)
Alerting Custom + PagerDuty
Dashboard React

Полная TM система с rule engine, ML аномалиями и SAR management: 2-3 месяца.