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:

  1. Strategy Description (10-15 pages)

    • Trading logic and signal generation
    • Risk management framework
    • Position sizing methodology
    • Entry/exit rules
  2. 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)
  3. System Architecture (5-10 pages)

    • Infrastructure diagram
    • Data flow
    • Order routing
    • Failover mechanisms
  4. Risk Control Framework (10-15 pages)

    • Pre-trade risk checks
    • Position limits
    • Loss limits
    • Circuit breaker logic
    • Kill switch implementation
  5. 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

ViolationSeverityPenalty
Missing audit trailMajor₹5 lakh fine
No kill switchCritical₹10 lakh + suspension
Exceeded order rateMinorWarning → ₹1 lakh
Failed risk checksMajor₹5 lakh + strategy ban
Unreported algoCritical₹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:

  1. Registration is mandatory - no exceptions
  2. Audit trail is non-negotiable - log everything
  3. Kill switch must work - test regularly
  4. Mock trading is required - 30 days minimum
  5. 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.