-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from flemmerz/feature/risk-governance
Feature/risk governance
- Loading branch information
Showing
8 changed files
with
300 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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%) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |