# ODIN Market Feed SDK

A robust and feature-rich Node.js SDK for connecting to the ODIN Market Feed WebSocket API. Stream real-time market data, touchline quotes, and best five quotes with built-in compression, fragmentation handling, and auto-reconnection support.

## Features

✨ **Easy to Use** - Simple, intuitive API for quick integration  
🔄 **Auto-Reconnection** - Automatic reconnection with configurable retry logic  
🗜️ **Compression Support** - Built-in zlib compression for efficient data transfer  
📦 **Fragmentation Handling** - Automatic packet fragmentation and defragmentation  
🔒 **Type Safety** - Full TypeScript support with comprehensive type definitions  
⚡ **High Performance** - Optimized for high-frequency market data streaming  
🛡️ **Robust Error Handling** - Comprehensive validation and error management  

## Installation

```bash
npm install odin-market-feed-sdk
```

Or with yarn:

```bash
yarn add odin-market-feed-sdk
```

## Quick Start

```typescript
import { ODINMarketFeedClient } from 'odin-market-feed-sdk';

const client = new ODINMarketFeedClient();

// Set up event handlers
client.onMessage = (message) => {
  console.log('Received:', message);
};

// Connect to the server
await client.connect({
  host: 'market-feed.example.com',
  port: 8080,
  useSSL: true,
  userId: 'YOUR_USER_ID'
});

// Subscribe to market data
await client.subscribeTouchline(['1_2885', '1_3045']);

// Disconnect when done
await client.disconnect();
```

## Usage

### Creating a Client

```typescript
import { ODINMarketFeedClient } from 'odin-market-feed-sdk';

// Basic initialization
const client = new ODINMarketFeedClient();

// With event handlers
const client = new ODINMarketFeedClient({
  onOpen: () => console.log('Connected'),
  onMessage: (msg) => console.log('Message:', msg),
  onError: (err) => console.error('Error:', err),
  onClose: (code, reason) => console.log('Closed:', code, reason)
});
```

### Connecting to Server

```typescript
await client.connect({
  host: 'market-feed.example.com',
  port: 8080,
  useSSL: true,
  userId: 'YOUR_USER_ID',
  enableCompression: true,        // Optional, default: true
  receiveBufferSize: 8192         // Optional, default: 8192
});
```

### Subscribing to Market Data

#### Touchline Data

Subscribe to real-time touchline data for multiple tokens:

```typescript
// Token format: 'MarketSegmentID_Token'
const tokens = [
  '1_2885',   // NSE - Reliance
  '1_3045',   // NSE - TCS
  '1_11536'   // NSE - HDFC Bank
];

await client.subscribeTouchline(tokens);
```

Unsubscribe from touchline data:

```typescript
await client.unsubscribeTouchline(['1_2885', '1_3045']);
```

#### Best Five Quotes

Subscribe to best five bid/ask quotes:

```typescript
await client.subscribeBestFive('2885', 1);  // token, marketSegmentId
```

Unsubscribe from best five:

```typescript
await client.unsubscribeBestFive('2885', 1);
```

### Event Handlers

```typescript
client.onOpen = () => {
  console.log('Connection established');
};

client.onMessage = (message: string) => {
  console.log('Received market data:', message);
  // Parse and process message
};

client.onError = (error: string) => {
  console.error('Error occurred:', error);
};

client.onClose = (code: number, reason: string) => {
  console.log(`Connection closed: ${code} - ${reason}`);
};
```

### Auto-Reconnection

Configure automatic reconnection behavior:

```typescript
// Set maximum reconnection attempts (default: 5)
client.setMaxReconnectAttempts(10);

// Set delay between reconnection attempts in ms (default: 5000)
client.setReconnectDelay(3000);

// Disable auto-reconnection
client.setMaxReconnectAttempts(0);
```

### Checking Connection State

```typescript
// Check if connected
if (client.isConnected()) {
  console.log('Client is connected');
}

// Get current state
import { ClientState } from 'odin-market-feed-sdk';

const state = client.getState();
// ClientState.DISCONNECTED
// ClientState.CONNECTING
// ClientState.CONNECTED
// ClientState.RECONNECTING
// ClientState.ERROR
```

### Compression

```typescript
// Enable compression (default: enabled)
client.setCompression(true);

// Disable compression
client.setCompression(false);
```

### Disconnecting

```typescript
// Graceful disconnect
await client.disconnect();

// Clean up resources
client.dispose();
```

## Advanced Usage

### Custom Market Data Service

```typescript
import { ODINMarketFeedClient, ClientState } from 'odin-market-feed-sdk';

class MarketDataService {
  private client: ODINMarketFeedClient;
  private subscribedTokens: string[] = [];

  constructor() {
    this.client = new ODINMarketFeedClient({
      onOpen: this.handleOpen.bind(this),
      onMessage: this.handleMessage.bind(this),
      onError: this.handleError.bind(this),
      onClose: this.handleClose.bind(this)
    });

    this.client.setMaxReconnectAttempts(5);
    this.client.setReconnectDelay(5000);
  }

  private handleOpen(): void {
    // Re-subscribe after reconnection
    if (this.subscribedTokens.length > 0) {
      this.client.subscribeTouchline(this.subscribedTokens);
    }
  }

  private handleMessage(message: string): void {
    // Parse and process market data
    this.parseAndProcess(message);
  }

  private handleError(error: string): void {
    // Custom error handling
    console.error('Market data error:', error);
  }

  private handleClose(code: number, reason: string): void {
    console.log(`Connection closed: ${code} - ${reason}`);
  }

  private parseAndProcess(message: string): void {
    // Your custom parsing logic
  }

  async connect(config: any): Promise<void> {
    await this.client.connect(config);
  }

  async subscribe(tokens: string[]): Promise<void> {
    this.subscribedTokens = tokens;
    await this.client.subscribeTouchline(tokens);
  }

  async disconnect(): Promise<void> {
    await this.client.disconnect();
    this.client.dispose();
  }
}
```

## API Reference

### ODINMarketFeedClient

#### Constructor

```typescript
constructor(handlers?: EventHandlers)
```

#### Methods

| Method | Parameters | Returns | Description |
|--------|-----------|---------|-------------|
| `connect` | `config: ConnectionConfig` | `Promise<void>` | Connect to WebSocket server |
| `disconnect` | - | `Promise<void>` | Disconnect from server |
| `subscribeTouchline` | `tokens: string[]` | `Promise<void>` | Subscribe to touchline data |
| `unsubscribeTouchline` | `tokens: string[]` | `Promise<void>` | Unsubscribe from touchline data |
| `subscribeBestFive` | `token: string, marketSegmentId: number` | `Promise<void>` | Subscribe to best five quotes |
| `unsubscribeBestFive` | `token: string, marketSegmentId: number` | `Promise<void>` | Unsubscribe from best five quotes |
| `sendMessage` | `message: string` | `Promise<void>` | Send raw message to server |
| `isConnected` | - | `boolean` | Check if client is connected |
| `getState` | - | `ClientState` | Get current connection state |
| `setCompression` | `enabled: boolean` | `void` | Enable/disable compression |
| `setMaxReconnectAttempts` | `attempts: number` | `void` | Set max reconnection attempts |
| `setReconnectDelay` | `delay: number` | `void` | Set reconnection delay in ms |
| `dispose` | - | `void` | Clean up resources |

#### Event Handlers

```typescript
onOpen?: () => void;
onMessage?: (message: string) => void;
onError?: (error: string) => void;
onClose?: (code: number, reason: string) => void;
```

### Types

#### ConnectionConfig

```typescript
interface ConnectionConfig {
  host: string;
  port: number;
  useSSL: boolean;
  userId: string;
  receiveBufferSize?: number;
  enableCompression?: boolean;
}
```

#### ClientState

```typescript
enum ClientState {
  DISCONNECTED = 'DISCONNECTED',
  CONNECTING = 'CONNECTING',
  CONNECTED = 'CONNECTED',
  RECONNECTING = 'RECONNECTING',
  ERROR = 'ERROR'
}
```

## Examples

See the [examples](./examples) directory for complete working examples:

- [basic-usage.ts](./examples/basic-usage.ts) - Simple connection and subscription
- [advanced-usage.ts](./examples/advanced-usage.ts) - Auto-reconnection and error handling

## Error Handling

The SDK provides comprehensive error handling:

```typescript
try {
  await client.connect(config);
  await client.subscribeTouchline(tokens);
} catch (error) {
  console.error('Operation failed:', error);
  // Handle error appropriately
}

// Or use event handlers
client.onError = (error: string) => {
  // Log error, send alert, etc.
  console.error('Client error:', error);
};
```

## Best Practices

1. **Always handle errors**: Use try-catch blocks or error event handlers
2. **Dispose properly**: Call `dispose()` when done to clean up resources
3. **Re-subscribe after reconnection**: Maintain a list of subscribed tokens
4. **Use compression**: Keep compression enabled for better performance
5. **Configure reconnection**: Set appropriate reconnection parameters for your use case
6. **Validate tokens**: Ensure tokens are in correct format before subscribing

## Token Format

Tokens should follow the format: `MarketSegmentID_TokenID`

Examples:
- `1_2885` - NSE segment, token 2885
- `2_3045` - BSE segment, token 3045

## Requirements

- Node.js >= 14.0.0
- TypeScript >= 5.0.0 (for development)

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

MIT

## Support

For issues, questions, or contributions, please visit the [GitHub repository](https://github.com/yourusername/odin-market-feed-sdk).

## Changelog

### 1.0.0
- Initial release
- WebSocket connection with SSL support
- Touchline and Best Five subscriptions
- Auto-reconnection support
- Compression handling
- TypeScript support
