Building a Compliance Framework for Algo Trading
Implement a complete compliance framework covering SEBI regulations, audit trails, and risk controls for algorithmic trading.
SEBI’s 2024 circulars mandate strict compliance for algo traders: registration, testing, kill switches, audit trails. Non-compliance brings penalties up to ₹25 crore.
This guide helps you build a complete compliance framework from scratch, ensuring you trade legally and sleep peacefully.
Compliance Architecture
Core Components
- Pre-Trade Controls: Risk checks before order placement
- Order Audit Trail: Complete order lifecycle logging
- Kill Switch: Emergency stop mechanism
- Position Limits: Automated position size controls
- Reporting: Daily compliance reports for internal audit
import logging
from datetime import datetime
import json
class ComplianceFramework:
"""
Complete compliance framework for algo trading
"""
def __init__(self, config: dict):
self.config = config
self.setup_logging()
self.kill_switch_active = False
def setup_logging(self):
"""Setup audit trail logging"""
logging.basicConfig(
filename=f"audit_{datetime.now().strftime('%Y%m%d')}.log",
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
self.logger = logging.getLogger(__name__)
def pre_trade_checks(self, order: dict) -> dict:
"""Pre-trade risk checks"""
checks = {
'kill_switch': self.check_kill_switch(),
'position_limit': self.check_position_limit(order),
'order_value': self.check_order_value(order),
'price_collar': self.check_price_collar(order),
'daily_loss': self.check_daily_loss_limit()
}
# Log all checks
self.logger.info(f"Pre-trade checks for {order}: {checks}")
# Block order if any check fails
passed = all(checks.values())
return {
'passed': passed,
'checks': checks,
'reason': None if passed else self.get_failure_reason(checks)
}
def check_kill_switch(self) -> bool:
"""Check if kill switch is active"""
return not self.kill_switch_active
def check_position_limit(self, order: dict) -> bool:
"""Check position limits"""
current_position = self.get_current_position(order['symbol'])
new_position = current_position + (order['quantity'] if order['side'] == 'buy' else -order['quantity'])
max_position = self.config['position_limits'].get(order['symbol'], 1000)
return abs(new_position) <= max_position
def check_order_value(self, order: dict) -> bool:
"""Check single order value limit"""
order_value = order['quantity'] * order.get('price', 0)
max_order_value = self.config['max_order_value']
return order_value <= max_order_value
def audit_order(self, order: dict, status: str, reason: str = None):
"""Log order to audit trail"""
audit_entry = {
'timestamp': datetime.now().isoformat(),
'order_id': order.get('order_id'),
'symbol': order['symbol'],
'side': order['side'],
'quantity': order['quantity'],
'price': order.get('price'),
'order_type': order['order_type'],
'status': status,
'reason': reason
}
self.logger.info(f"AUDIT: {json.dumps(audit_entry)}")
def activate_kill_switch(self, reason: str):
"""Activate emergency kill switch"""
self.kill_switch_active = True
self.logger.critical(f"KILL SWITCH ACTIVATED: {reason}")
# Cancel all pending orders
self.cancel_all_orders()
# Close all positions
self.emergency_position_closure()
def generate_daily_report(self) -> dict:
"""Generate compliance report"""
return {
'date': datetime.now().strftime('%Y-%m-%d'),
'total_orders': self.count_orders(),
'rejected_orders': self.count_rejected_orders(),
'kill_switch_activations': self.count_kill_switch_events(),
'compliance_violations': self.check_violations()
}
# Usage
config = {
'position_limits': {'NIFTY': 1000, 'BANKNIFTY': 500},
'max_order_value': 1000000,
'max_daily_loss': 50000
}
framework = ComplianceFramework(config)
Building compliance isn’t optional—it’s survival. Regulators watching closely. Implement these controls today, trade confidently tomorrow.