Skip to content

Commit

Permalink
Merge pull request #1 from flemmerz/feature/risk-governance
Browse files Browse the repository at this point in the history
Feature/risk governance
  • Loading branch information
flemmerz authored Dec 17, 2024
2 parents 0e54659 + 14d8672 commit 20b28e6
Show file tree
Hide file tree
Showing 8 changed files with 300 additions and 0 deletions.
22 changes: 22 additions & 0 deletions risk_governance/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Risk Governance Framework

Enhanced risk detection and monitoring framework for the NiMu platform.

## Structure

```
/detection
- shell_company_detector.py # Base shell company detection
- uk_shell_detector.py # UK-specific detection rules
- network_analyzer.py # Network analysis tools
/monitoring
- temporal_monitor.py # Long-term pattern monitoring
- behavior_monitor.py # Behavioral pattern analysis
- relationship_monitor.py # Business relationship tracking
/governance
- risk_policies.md # Risk governance policies
- scoring_rules.md # Risk scoring methodology
- review_process.md # Risk review procedures
```
53 changes: 53 additions & 0 deletions risk_governance/detection/shell_company_detector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from typing import Dict, List, Tuple, Set
from dataclasses import dataclass
from fuzzywuzzy import fuzz
from recordlinkage import preprocessing
import phonetics
import re
import networkx as nx

@dataclass
class EntityProfile:
"""Represents a business entity with all its known attributes"""
company_number: str = None
names: List[str] = None # Including trading names, previous names
addresses: List[str] = None
directors: List[Dict] = None
emails: List[str] = None
phone_numbers: List[str] = None
company_type: str = None
incorporation_date: str = None
sic_codes: List[str] = None

class ShellCompanyDetector:
def __init__(self):
self.name_threshold = 85 # Fuzzy matching threshold for names
self.address_threshold = 90 # Fuzzy matching threshold for addresses
self.email_threshold = 95 # Fuzzy matching threshold for emails
self.graph = nx.Graph() # Graph for storing entity relationships

def detect_shell_patterns(self) -> List[Dict]:
"""Main method to detect various shell company patterns"""
patterns = []

# Pattern 1: Nominee Director Patterns
nominee_patterns = self._detect_nominee_directors()
patterns.extend(nominee_patterns)

# Pattern 2: Dormant Company Networks
dormant_patterns = self._detect_dormant_networks()
patterns.extend(dormant_patterns)

# Pattern 3: Rapid Transaction Networks
transaction_patterns = self._detect_rapid_transaction_networks()
patterns.extend(transaction_patterns)

# Pattern 4: Common Address Clusters
address_patterns = self._detect_address_clusters()
patterns.extend(address_patterns)

# Pattern 5: Formation Pattern Analysis
formation_patterns = self._analyze_formation_patterns()
patterns.extend(formation_patterns)

return patterns
38 changes: 38 additions & 0 deletions risk_governance/detection/uk_shell_detector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from typing import Dict, List, Set, Tuple
from dataclasses import dataclass
from datetime import datetime
import networkx as nx
from collections import defaultdict

@dataclass
class UKCompanyIndicators:
"""UK-specific company risk indicators"""
company_number: str
sic_codes: List[str]
psc_data: List[Dict]
confirmation_statement: Dict
accounts_filing: Dict
registered_office: Dict
officers: List[Dict]
charges: List[Dict]

class UKShellDetector:
def __init__(self, base_detector):
self.base_detector = base_detector
self.graph = base_detector.graph
self.companies_house_patterns = self._initialize_ch_patterns()

def analyze_uk_specific_patterns(self) -> Dict:
"""Perform UK-specific analysis"""
results = {
'companies_house_flags': self._check_companies_house_flags(),
'psc_analysis': self._analyze_psc_structures(),
'filing_patterns': self._analyze_filing_patterns(),
'sic_code_patterns': self._analyze_sic_codes(),
'registered_office_patterns': self._analyze_registered_offices(),
'charge_patterns': self._analyze_charges()
}

# Calculate overall UK risk score
results['uk_risk_score'] = self._calculate_uk_risk_score(results)
return results
37 changes: 37 additions & 0 deletions risk_governance/governance/risk_policies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Risk Governance Policies

## 1. Long-term Pattern Monitoring

### Objectives
- Track gradual changes in business behavior
- Monitor slow shifts in transaction patterns
- Analyze historical relationship development

### Implementation
- Quarterly review of business patterns
- Annual risk profile updates
- Continuous monitoring of key risk indicators

## 2. Network Analysis

### Objectives
- Monitor indirect business relationships
- Track industry-specific patterns
- Identify subtle connection changes

### Implementation
- Monthly network analysis reports
- Industry comparison reviews
- Relationship mapping updates

## 3. Behavioral Analysis

### Objectives
- Monitor payment pattern changes
- Track supplier relationship changes
- Analyze customer concentration

### Implementation
- Weekly behavioral pattern reviews
- Monthly relationship assessments
- Quarterly concentration analysis
40 changes: 40 additions & 0 deletions risk_governance/governance/scoring_rules.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Risk Scoring Methodology

## Base Risk Score Components

### 1. Historical Pattern Score (30%)
- Transaction history consistency
- Payment behavior patterns
- Growth pattern alignment

### 2. Network Risk Score (25%)
- Business relationship quality
- Industry connection patterns
- Supplier/customer concentration

### 3. Behavioral Risk Score (25%)
- Payment pattern consistency
- Business relationship stability
- Operational pattern alignment

### 4. Structural Risk Score (20%)
- Corporate structure complexity
- Ownership transparency
- Governance framework

## Risk Score Adjustments

### Industry Factors
- Industry risk level (+/-15%)
- Market position impact (+/-10%)
- Sector stability factor (+/-10%)

### Time-based Factors
- Historical performance (+/-20%)
- Consistency bonus (-15%)
- Rapid change penalty (+25%)

### Relationship Factors
- Customer concentration (+/-15%)
- Supplier diversity (+/-10%)
- Banking relationship strength (+/-10%)
34 changes: 34 additions & 0 deletions risk_governance/monitoring/behavior_monitor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from typing import Dict, List
from dataclasses import dataclass

@dataclass
class BehaviorPattern:
pattern_type: str
indicators: List[str]
severity: float
evidence: Dict

class BehaviorMonitor:
def __init__(self):
self.behavior_thresholds = {
'payment_pattern': 0.2,
'supplier_change': 0.15,
'customer_concentration': 0.3
}

def analyze_behavior_patterns(self, data: Dict) -> List[BehaviorPattern]:
patterns = []

# Analyze payment patterns
payment_patterns = self._analyze_payment_patterns(data)
patterns.extend(payment_patterns)

# Analyze supplier relationships
supplier_patterns = self._analyze_supplier_patterns(data)
patterns.extend(supplier_patterns)

# Analyze customer patterns
customer_patterns = self._analyze_customer_patterns(data)
patterns.extend(customer_patterns)

return patterns
36 changes: 36 additions & 0 deletions risk_governance/monitoring/relationship_monitor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from typing import Dict, List
from dataclasses import dataclass
import networkx as nx

@dataclass
class RelationshipPattern:
pattern_type: str
entities: List[str]
strength: float
indicators: List[str]

class RelationshipMonitor:
def __init__(self):
self.relationship_thresholds = {
'direct': 0.7,
'indirect': 0.4,
'industry': 0.3
}
self.graph = nx.Graph()

def analyze_relationship_patterns(self, data: Dict) -> List[RelationshipPattern]:
patterns = []

# Analyze direct relationships
direct_patterns = self._analyze_direct_relationships(data)
patterns.extend(direct_patterns)

# Analyze indirect relationships
indirect_patterns = self._analyze_indirect_relationships(data)
patterns.extend(indirect_patterns)

# Analyze industry patterns
industry_patterns = self._analyze_industry_patterns(data)
patterns.extend(industry_patterns)

return patterns
40 changes: 40 additions & 0 deletions risk_governance/monitoring/temporal_monitor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from typing import Dict, List
from datetime import datetime, timedelta
from dataclasses import dataclass

@dataclass
class TemporalPattern:
pattern_type: str
time_period: str
indicators: List[str]
confidence: float

class TemporalMonitor:
def __init__(self):
self.monitoring_periods = {
'short': 30, # days
'medium': 180,
'long': 365
}
self.pattern_thresholds = {
'growth': 0.25,
'change': 0.15,
'volatility': 0.20
}

def analyze_long_term_patterns(self, history: Dict) -> List[TemporalPattern]:
patterns = []

# Analyze growth patterns
growth_patterns = self._analyze_growth_patterns(history)
patterns.extend(growth_patterns)

# Analyze behavioral changes
behavior_patterns = self._analyze_behavioral_changes(history)
patterns.extend(behavior_patterns)

# Analyze relationship evolution
relationship_patterns = self._analyze_relationship_patterns(history)
patterns.extend(relationship_patterns)

return patterns

0 comments on commit 20b28e6

Please sign in to comment.