SEBI's 2025 Algo Trading Rules: Complete Compliance Guide
Navigate SEBI's latest algorithmic trading regulations with this comprehensive guide covering registration, risk controls, audit requirements, and penalties.
SEBI’s 2025 algorithmic trading framework marks a watershed moment for Indian markets. Whether you’re a retail algo trader, prop desk, or institutional fund, these regulations fundamentally reshape how you develop, test, and deploy automated strategies.
This comprehensive guide breaks down every requirement, provides practical implementation roadmaps, and helps you achieve full compliance while maintaining operational efficiency.
Overview: What Changed in 2025
Key Regulatory Updates
Mandatory Registration: All algo traders must register with exchanges Pre-deployment Testing: Strategies require exchange-approved testing Real-time Monitoring: Continuous surveillance of algo activities Kill Switch: Mandatory emergency stop mechanisms Audit Trail: Complete logging of all algo decisions Risk Limits: Position and order rate restrictions Periodic Reporting: Monthly compliance submissions
Who is Affected?
✅ Retail algo traders using APIs ✅ Proprietary trading firms ✅ Fund managers with automated strategies ✅ Market makers and liquidity providers ✅ High-frequency traders
❌ Discretionary traders without automation ❌ Manual order placement through terminals
Part 1: Registration Requirements
Step 1: Algo Registration Application
from dataclasses import dataclass
from typing import List, Optional
import json
@dataclass
class AlgoRegistrationForm:
"""
SEBI Algo Registration Form Structure
"""
# Applicant Details
entity_name: str
pan: str
registered_address: str
contact_person: str
contact_email: str
contact_phone: str
# Trading Details
trading_member_code: str
broker_name: str
exchanges: List[str] # NSE, BSE, MCX, etc.
# Strategy Details
strategy_name: str
strategy_type: str # 'directional', 'market_making', 'arbitrage', 'statistical'
instruments_traded: List[str] # 'equity', 'derivatives', 'currency', 'commodity'
average_order_value: float
max_orders_per_second: int
holding_period: str # 'intraday', 'short_term', 'long_term'
# Technical Infrastructure
trading_system_description: str
order_management_system: str
risk_management_system: str
datacenter_location: str
# Risk Controls
max_position_limit: float
max_loss_limit: float
max_order_rate: int
kill_switch_implemented: bool
# Backtesting Documentation
backtest_period_years: int
backtest_sharpe_ratio: float
backtest_max_drawdown: float
# Personnel
key_personnel: List[dict] # Name, qualification, experience
def to_json(self) -> str:
"""Export to JSON for submission"""
return json.dumps(self.__dict__, indent=2)
def validate(self) -> List[str]:
"""
Validate form for completeness
Returns list of missing/invalid fields
"""
errors = []
# Required fields
if not self.pan or len(self.pan) != 10:
errors.append("Invalid PAN")
if not self.exchanges:
errors.append("At least one exchange required")
if not self.kill_switch_implemented:
errors.append("Kill switch is mandatory")
if self.backtest_period_years < 3:
errors.append("Minimum 3 years backtesting required")
if self.max_orders_per_second > 100:
errors.append("Orders/sec exceeds retail limit (100)")
return errors
# Example: Fill registration form
registration = AlgoRegistrationForm(
entity_name="Quantum Trading LLP",
pan="AAACQ1234F",
registered_address="Mumbai, Maharashtra",
contact_person="Rahul Sharma",
contact_email="[email protected]",
contact_phone="+91-9876543210",
trading_member_code="12345",
broker_name="Zerodha",
exchanges=["NSE", "BSE"],
strategy_name="Mean Reversion Alpha",
strategy_type="statistical",
instruments_traded=["equity", "derivatives"],
average_order_value=50000,
max_orders_per_second=10,
holding_period="intraday",
trading_system_description="Python-based quantitative system using moving average crossovers",
order_management_system="Custom OMS with Zerodha Kite Connect API",
risk_management_system="Real-time position monitoring with automatic limits",
datacenter_location="AWS Mumbai (ap-south-1)",
max_position_limit=1000000,
max_loss_limit=50000,
max_order_rate=10,
kill_switch_implemented=True,
backtest_period_years=5,
backtest_sharpe_ratio=1.8,
backtest_max_drawdown=0.15,
key_personnel=[
{
"name": "Rahul Sharma",
"qualification": "CFA, B.Tech IIT",
"experience": "8 years quantitative trading"
}
]
)
# Validate before submission
errors = registration.validate()
if errors:
print("Registration Errors:")
for error in errors:
print(f" ❌ {error}")
else:
print("✅ Registration form valid")
print(registration.to_json())
Step 2: Documentation Requirements
Mandatory Documents:
-
Strategy Description (10-15 pages)
- Trading logic and signal generation
- Risk management framework
- Position sizing methodology
- Entry/exit rules
-
Backtesting Report (20-30 pages)
- 3+ years historical performance
- Walk-forward analysis
- Out-of-sample testing
- Transaction cost modeling
- Risk metrics (Sharpe, Sortino, Max DD)
-
System Architecture (5-10 pages)
- Infrastructure diagram
- Data flow
- Order routing
- Failover mechanisms
-
Risk Control Framework (10-15 pages)
- Pre-trade risk checks
- Position limits
- Loss limits
- Circuit breaker logic
- Kill switch implementation
-
Disaster Recovery Plan (5-10 pages)
- System failure scenarios
- Recovery procedures
- Emergency contacts
- Position unwinding protocols
Part 2: Pre-Deployment Testing
Mock Trading Requirements
import logging
from datetime import datetime, timedelta
from typing import Dict, List
class SEBIComplianceLogger:
"""
Audit trail logging as per SEBI requirements
All algo decisions must be logged for regulatory review
"""
def __init__(self, strategy_id: str, log_path: str = '/var/log/trading/audit'):
self.strategy_id = strategy_id
self.log_path = log_path
self.setup_logging()
def setup_logging(self):
"""
Configure logging with SEBI-compliant format
"""
log_file = f"{self.log_path}/algo_{self.strategy_id}_{datetime.now().strftime('%Y%m%d')}.log"
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s | %(levelname)s | %(message)s',
handlers=[
logging.FileHandler(log_file),
logging.StreamHandler()
]
)
self.logger = logging.getLogger(f'algo_{self.strategy_id}')
def log_signal(self, signal: Dict):
"""
Log trading signal generation
Required fields:
- Timestamp
- Symbol
- Signal (BUY/SELL/HOLD)
- Reason
- Indicator values
- Decision logic
"""
log_entry = {
'timestamp': datetime.now().isoformat(),
'event_type': 'SIGNAL_GENERATED',
'strategy_id': self.strategy_id,
'symbol': signal['symbol'],
'signal': signal['action'],
'reason': signal['reason'],
'indicators': signal.get('indicators', {}),
'confidence': signal.get('confidence', None)
}
self.logger.info(f"SIGNAL: {log_entry}")
def log_risk_check(self, check_type: str, passed: bool, details: Dict):
"""
Log pre-trade risk checks
"""
log_entry = {
'timestamp': datetime.now().isoformat(),
'event_type': 'RISK_CHECK',
'check_type': check_type,
'passed': passed,
'details': details
}
self.logger.info(f"RISK_CHECK: {log_entry}")
def log_order(self, order: Dict):
"""
Log order placement
"""
log_entry = {
'timestamp': datetime.now().isoformat(),
'event_type': 'ORDER_PLACED',
'order_id': order['order_id'],
'symbol': order['symbol'],
'action': order['action'],
'quantity': order['quantity'],
'price': order.get('price'),
'order_type': order['order_type']
}
self.logger.info(f"ORDER: {log_entry}")
def log_execution(self, execution: Dict):
"""
Log order execution
"""
log_entry = {
'timestamp': datetime.now().isoformat(),
'event_type': 'ORDER_EXECUTED',
'order_id': execution['order_id'],
'executed_quantity': execution['quantity'],
'executed_price': execution['price'],
'exchange_timestamp': execution['exchange_timestamp']
}
self.logger.info(f"EXECUTION: {log_entry}")
def log_risk_breach(self, breach_type: str, details: Dict):
"""
Log risk limit breaches (critical)
"""
log_entry = {
'timestamp': datetime.now().isoformat(),
'event_type': 'RISK_BREACH',
'breach_type': breach_type,
'severity': 'CRITICAL',
'details': details
}
self.logger.critical(f"RISK_BREACH: {log_entry}")
# Usage in trading system
compliance_logger = SEBIComplianceLogger(strategy_id='MEAN_REV_001')
# Log signal
signal = {
'symbol': 'RELIANCE',
'action': 'BUY',
'reason': 'RSI oversold + price below lower BB',
'indicators': {
'rsi': 28,
'bb_lower': 2450,
'current_price': 2448
},
'confidence': 0.85
}
compliance_logger.log_signal(signal)
# Log risk check
compliance_logger.log_risk_check(
check_type='POSITION_LIMIT',
passed=True,
details={'current_position_value': 450000, 'limit': 1000000}
)
Mock Trading Phase (Mandatory 30 Days)
class MockTradingValidator:
"""
Validate strategy during mandatory mock trading period
"""
def __init__(self, strategy_id: str, start_date: datetime):
self.strategy_id = strategy_id
self.start_date = start_date
self.trades = []
self.violations = []
def record_trade(self, trade: Dict):
"""Record mock trade"""
self.trades.append({
**trade,
'timestamp': datetime.now()
})
def check_compliance(self) -> Dict:
"""
Check if mock trading meets SEBI requirements
"""
days_elapsed = (datetime.now() - self.start_date).days
results = {
'duration_compliant': days_elapsed >= 30,
'days_elapsed': days_elapsed,
'total_trades': len(self.trades),
'violations': len(self.violations),
'ready_for_live': False
}
# Minimum trade count
if len(self.trades) < 100:
results['issues'] = [f"Insufficient trades ({len(self.trades)}/100 minimum)"]
return results
# No major violations
critical_violations = [v for v in self.violations if v['severity'] == 'CRITICAL']
if critical_violations:
results['issues'] = [f"{len(critical_violations)} critical violations detected"]
return results
# Duration check
if not results['duration_compliant']:
results['issues'] = [f"Mock trading period incomplete ({days_elapsed}/30 days)"]
return results
# All checks passed
results['ready_for_live'] = True
results['message'] = "✅ Strategy ready for live deployment"
return results
# Track mock trading
validator = MockTradingValidator(
strategy_id='MEAN_REV_001',
start_date=datetime(2025, 1, 1)
)
# After 30 days of mock trading
compliance_status = validator.check_compliance()
if compliance_status['ready_for_live']:
print("Strategy approved for live trading")
else:
print(f"Issues: {compliance_status.get('issues', [])}")
Part 3: Kill Switch Implementation
Mandatory Emergency Controls
class KillSwitch:
"""
SEBI-mandated kill switch implementation
Must immediately halt all trading on trigger
"""
def __init__(self, strategy_manager, notification_system):
self.strategy_manager = strategy_manager
self.notification_system = notification_system
self.active = True
self.triggers = []
def add_trigger(self, trigger_type: str, condition: callable):
"""
Add kill switch trigger
Common triggers:
- Daily loss limit exceeded
- Position limit breached
- System error rate high
- Manual activation
"""
self.triggers.append({
'type': trigger_type,
'condition': condition
})
def check_triggers(self) -> bool:
"""
Check all kill switch triggers
"""
for trigger in self.triggers:
if trigger['condition']():
self.activate(reason=trigger['type'])
return True
return False
def activate(self, reason: str):
"""
Activate kill switch
Actions:
1. Stop all strategy execution
2. Cancel pending orders
3. Close open positions (optional)
4. Notify authorities
5. Log incident
"""
if not self.active:
return
print(f"🚨 KILL SWITCH ACTIVATED: {reason}")
# 1. Stop strategies
self.strategy_manager.halt_all_strategies()
# 2. Cancel pending orders
self.strategy_manager.cancel_all_orders()
# 3. Send notifications
self.notification_system.send_critical_alert(
subject="KILL SWITCH ACTIVATED",
message=f"Trading halted. Reason: {reason}",
recipients=['[email protected]', '[email protected]']
)
# 4. Log to audit trail
compliance_logger.log_risk_breach(
breach_type='KILL_SWITCH_ACTIVATED',
details={'reason': reason, 'timestamp': datetime.now().isoformat()}
)
# 5. Report to exchange
self.report_to_exchange(reason)
self.active = False
def report_to_exchange(self, reason: str):
"""
Mandatory reporting to exchange
"""
report = {
'strategy_id': self.strategy_manager.strategy_id,
'event': 'KILL_SWITCH_ACTIVATION',
'reason': reason,
'timestamp': datetime.now().isoformat(),
'open_positions': self.strategy_manager.get_positions(),
'pending_orders': self.strategy_manager.get_pending_orders()
}
# Submit to exchange API
# exchange.submit_incident_report(report)
print(f"📊 Incident report submitted to exchange")
# Setup kill switch
kill_switch = KillSwitch(strategy_manager, notification_system)
# Add triggers
kill_switch.add_trigger(
'DAILY_LOSS_LIMIT',
lambda: strategy_manager.daily_pnl < -50000
)
kill_switch.add_trigger(
'POSITION_LIMIT',
lambda: strategy_manager.total_position_value() > 1000000
)
kill_switch.add_trigger(
'ERROR_RATE',
lambda: strategy_manager.error_rate_per_minute() > 10
)
# Monitor continuously
while trading:
kill_switch.check_triggers()
time.sleep(1)
Part 4: Penalties and Enforcement
Violation Levels
| Violation | Severity | Penalty |
|---|---|---|
| Missing audit trail | Major | ₹5 lakh fine |
| No kill switch | Critical | ₹10 lakh + suspension |
| Exceeded order rate | Minor | Warning → ₹1 lakh |
| Failed risk checks | Major | ₹5 lakh + strategy ban |
| Unreported algo | Critical | ₹20 lakh + prosecution |
Staying Compliant
✅ Daily: Monitor and log all trades ✅ Weekly: Review risk limit adherence ✅ Monthly: Submit compliance report to exchange ✅ Quarterly: Internal compliance audit ✅ Annually: Strategy re-certification
Conclusion
SEBI’s 2025 framework raises the bar for algo trading in India. Key takeaways:
- Registration is mandatory - no exceptions
- Audit trail is non-negotiable - log everything
- Kill switch must work - test regularly
- Mock trading is required - 30 days minimum
- Penalties are severe - compliance is cheaper than fines
Start your compliance journey today. The cost of non-compliance far exceeds the cost of proper implementation.
Need compliance assistance? Contact us for expert guidance on SEBI algo trading regulations.