Update README.md

This commit is contained in:
Mohammad Taha Ranjbar Shirazi 2026-05-29 14:50:33 +03:30
parent c7aeb221ad
commit 907df6b7d8

764
README.md
View File

@ -1,465 +1,593 @@
# HedgeTech IME Live Data WebSocket API
Professional real-time WebSocket streaming service for Iran Mercantile Exchange (IME) market data.
# HT Data Engine | IME | WebSocket
## Real-Time Mercantile Exchange Streams (IME)
### WebSocket • Real-Time • Low-Latency
---
# Overview
# 1. Overview
The HedgeTech IME Live Data WebSocket service provides ultra low-latency real-time streaming market data for IME contracts.
This documentation describes the **HT Data Engine IME WebSocket API** for subscribing to real-time market data streams from the **Iran Mercantile Exchange (IME)**.
The service is designed for:
The service provides low-latency real-time updates for IME contracts including:
- Trading Platforms
- HFT Systems
- Algorithmic Trading
- Quantitative Infrastructure
- Market Monitoring Systems
- Real-Time Dashboards
- Risk Engines
- Best bid/ask limits
- Aggregate trading statistics
- Allowed price ranges
- Contract open interest information
All streams are powered by Redis Pub/Sub infrastructure and asynchronously distributed through FastAPI WebSocket endpoints.
The API supports two independent subscription endpoints:
- Subscription using **Contract Names**
- Subscription using **Contract IDs**
All WebSocket connections require valid authentication and support subscribing to multiple contracts in a single connection.
---
# Base URL
# 2. Authentication
All IME WebSocket endpoints require authentication.
Clients must provide a valid JWT token during the WebSocket handshake.
## Token Endpoint
```text
https://core.hedgetech.ir/data-engine/ime
https://core.hedgetech.ir/auth/user/token/issue
```
## Request
### Headers
```text
Content-Type: application/x-www-form-urlencoded
```
### Body
```text
username=your_username&password=your_password
```
---
# Available WebSocket Endpoints
## Response Example
| Endpoint | Description |
|---|---|
| `/live/data/websocket/contract/name` | Subscribe using contract names |
| `/live/data/websocket/contract/id` | Subscribe using contract IDs |
---
# Authentication
All WebSocket endpoints require authentication.
Authentication is performed during the WebSocket handshake phase using Authorization headers.
---
## Authorization Header
```text
Authorization: Bearer YOUR_ACCESS_TOKEN
```
---
## Example Authentication Flow
```python
extra_headers = {
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
```json
{
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```
---
# WebSocket: Subscribe By Contract Name
## WebSocket Authorization Header
## Endpoint
```text
Authorization: <your_token>
```
---
## Important Notes
- Unauthorized connections are rejected with WebSocket close code `1008`
- Tokens may be invalidated if account policies or security rules change
- Ensure your account has access to IME live market data services
---
# 3. WebSocket Endpoints
| Endpoint | Description |
|---|---|
| `wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/name` | Subscribe using contract names |
| `wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/id` | Subscribe using contract IDs |
---
# 4. Important Clarification: Contract Name vs Contract ID Endpoints
The IME data engine exposes two separate WebSocket endpoints.
## Contract Name Endpoint
```text
wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/name
```
---
Messages contain:
## Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| contract_name | list[string] | Yes | List of contract names |
---
## Example Connection
```text
wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/name?contract_name=ContractA&contract_name=ContractB
```json
"contractName": "<CONTRACT_NAME>"
```
---
## Python Example
```python
import asyncio
import json
import websockets
async def main():
uri = (
"wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/name"
"?contract_name=ContractA"
"&contract_name=ContractB"
)
headers = {
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
async with websockets.connect(
uri,
additional_headers=headers,
ping_interval=20,
ping_timeout=20,
) as websocket:
while True:
message = await websocket.recv()
data = json.loads(message)
print(json.dumps(data, indent=4))
asyncio.run(main())
```
---
# WebSocket: Subscribe By Contract ID
## Endpoint
## Contract ID Endpoint
```text
wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/id
```
---
Messages contain:
## Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| contract_id | list[string] | Yes | List of contract IDs |
---
## Example Connection
```text
wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/id?contract_id=12345&contract_id=67890
```json
"contractId": "<CONTRACT_ID>"
```
---
## Python Example
## Important
Both endpoints return:
- The exact same market data
- The same payload structure
- The same channel schema
The only difference is the identifier field.
| Endpoint | Identifier Field |
|---|---|
| `/contract/name` | `contractName` |
| `/contract/id` | `contractId` |
---
## Why This Matters
Client applications must correctly detect which identifier field exists in incoming messages.
Recommended approach:
```python
import asyncio
import json
import websockets
identifier = message.get("contractId") or message.get("contractName")
```
async def main():
This prevents parsing issues when switching between endpoints.
uri = (
"wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/id"
"?contract_id=12345"
"&contract_id=67890"
)
---
headers = {
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
# 5. Connection Flow
async with websockets.connect(
uri,
additional_headers=headers,
ping_interval=20,
ping_timeout=20,
) as websocket:
1. Establish WebSocket connection
while True:
2. Provide the Authorization header
message = await websocket.recv()
3. Pass query parameters in the URL
data = json.loads(message)
4. Server validates:
- JWT token
- Contract identifiers
- Subscription permissions
print(json.dumps(data, indent=4))
5. If validation succeeds:
- WebSocket connection is accepted
- Real-time streams begin immediately
asyncio.run(main())
6. If validation fails:
- Connection closes with code `1008`
---
# 6. Query Parameters
## Contract Name Endpoint
| Parameter | Type | Description |
|---|---|---|
| `contract_name` | repeated string | IME contract names |
### Example
```text
wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/name?contract_name=GOLD-APR&contract_name=CEMENT-MAY
```
---
# WebSocket Response Structure
## Contract ID Endpoint
Both endpoints stream identical payload structures.
| Parameter | Type | Description |
|---|---|---|
| `contract_id` | repeated string | IME contract IDs |
The only difference is:
### Example
- `contractName` exists in Name endpoint
- `contractId` exists in ID endpoint
```text
wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/id?contract_id=1001&contract_id=1002
```
---
## Response Example (Contract Name)
# 7. Message Structure
All WebSocket messages follow the same envelope structure.
---
## Contract Name Endpoint Example
```json
{
"channel": "IME Stream",
"contractName": "ContractA",
"timestamp": "2026-05-23T15:10:00.000000",
"data": {}
"contractName": "GOLD-APR",
"timestamp": "2026-05-29T12:00:00.000000Z",
"data": {
"...": "..."
}
}
```
---
## Response Example (Contract ID)
## Contract ID Endpoint Example
```json
{
"channel": "IME Stream",
"contractId": "12345",
"timestamp": "2026-05-23T15:10:00.000000",
"data": {}
"contractId": "1001",
"timestamp": "2026-05-29T12:00:00.000000Z",
"data": {
"...": "..."
}
}
```
---
# Data Payload Structure
# 8. Data Payload Schema
The `data` field contains the complete real-time contract market state.
The `data` field contains multiple market data sections grouped into a single payload.
---
# Full Payload Example
# 8.1 BestLimit
Top bid/ask levels for the contract.
## Example
```json
{
"BestLimit": {
"1": {
"buy_quantity": 0,
"buy_price": 0,
"sell_quantity": 0,
"sell_price": 0
"buy_quantity": 150,
"buy_price": 245000,
"sell_quantity": 100,
"sell_price": 246000
},
"2": {
"buy_quantity": 0,
"buy_price": 0,
"sell_quantity": 0,
"sell_price": 0
"buy_quantity": 120,
"buy_price": 244500,
"sell_quantity": 90,
"sell_price": 246500
},
"3": {
"buy_quantity": 0,
"buy_price": 0,
"sell_quantity": 0,
"sell_price": 0
"buy_quantity": 80,
"buy_price": 244000,
"sell_quantity": 70,
"sell_price": 247000
}
},
}
}
```
---
## Fields
| Field | Description |
|---|---|
| `buy_quantity` | Total bid quantity |
| `buy_price` | Bid price |
| `sell_quantity` | Total ask quantity |
| `sell_price` | Ask price |
---
# 8.2 Aggregate
Aggregate trading statistics for the contract.
## Example
```json
{
"Aggregate": {
"date": "",
"time": "",
"trade_count": 0,
"total_volume": 0,
"total_value": 0,
"closing_price": 0,
"last_price": 0,
"low_price": 0,
"high_price": 0,
"open_price": 0,
"previous_close": 0
},
"date": "2026-05-29",
"time": "12:00:00",
"trade_count": 120,
"total_volume": 4500,
"total_value": 1102500000,
"closing_price": 245500,
"last_price": 245700,
"low_price": 244000,
"high_price": 247000,
"open_price": 244500,
"previous_close": 243000
}
}
```
---
## Fields
| Field | Description |
|---|---|
| `trade_count` | Number of executed trades |
| `total_volume` | Total traded volume |
| `total_value` | Total traded value |
| `closing_price` | Current settlement/closing price |
| `last_price` | Last traded price |
| `low_price` | Session low |
| `high_price` | Session high |
| `open_price` | Session open |
| `previous_close` | Previous settlement/close price |
---
# 8.3 AllowedPriceRange
Allowed trading price boundaries for the contract.
## Example
```json
{
"AllowedPriceRange": {
"minAllowedPrice": 1,
"maxAllowedPrice": 9999999999
},
"minAllowedPrice": 220000,
"maxAllowedPrice": 270000
}
}
```
---
## Fields
| Field | Description |
|---|---|
| `minAllowedPrice` | Minimum allowed trading price |
| `maxAllowedPrice` | Maximum allowed trading price |
---
# 8.4 ContractInfo
Contract open interest statistics.
## Example
```json
{
"ContractInfo": {
"open_interest": 0,
"open_interest_changes": 0
"open_interest": 5400,
"open_interest_changes": 120
}
}
```
---
# Payload Field Documentation
# BestLimit
Represents top order book levels.
---
## Order Book Levels
| Level | Description |
|---|---|
| 1 | Best market level |
| 2 | Second order book level |
| 3 | Third order book level |
---
## BestLimit Fields
## Fields
| Field | Description |
|---|---|
| buy_quantity | Buy order quantity |
| buy_price | Buy order price |
| sell_quantity | Sell order quantity |
| sell_price | Sell order price |
| `open_interest` | Current open interest |
| `open_interest_changes` | Change in open interest |
---
# Aggregate
# 9. Complete Example Payload
Aggregated trading statistics.
| Field | Description |
|---|---|
| date | Trading date |
| time | Last update time |
| trade_count | Total number of trades |
| total_volume | Total traded volume |
| total_value | Total traded value |
| closing_price | Closing price |
| last_price | Last traded price |
| low_price | Lowest traded price |
| high_price | Highest traded price |
| open_price | Opening price |
| previous_close | Previous closing price |
---
# AllowedPriceRange
Allowed trading range.
| Field | Description |
|---|---|
| minAllowedPrice | Minimum allowed price |
| maxAllowedPrice | Maximum allowed price |
---
# ContractInfo
Contract-level metadata.
| Field | Description |
|---|---|
| open_interest | Open interest |
| open_interest_changes | Open interest changes |
---
# Error Handling
---
## Authentication Failure
If the access token is invalid or missing:
```text
WebSocket closed with code 1008 POLICY VIOLATION
```json
{
"channel": "IME Stream",
"contractId": "1001",
"timestamp": "2026-05-29T12:00:00.000000Z",
"data": {
"BestLimit": {
"1": {
"buy_quantity": 150,
"buy_price": 245000,
"sell_quantity": 100,
"sell_price": 246000
},
"2": {
"buy_quantity": 120,
"buy_price": 244500,
"sell_quantity": 90,
"sell_price": 246500
},
"3": {
"buy_quantity": 80,
"buy_price": 244000,
"sell_quantity": 70,
"sell_price": 247000
}
},
"Aggregate": {
"date": "2026-05-29",
"time": "12:00:00",
"trade_count": 120,
"total_volume": 4500,
"total_value": 1102500000,
"closing_price": 245500,
"last_price": 245700,
"low_price": 244000,
"high_price": 247000,
"open_price": 244500,
"previous_close": 243000
},
"AllowedPriceRange": {
"minAllowedPrice": 220000,
"maxAllowedPrice": 270000
},
"ContractInfo": {
"open_interest": 5400,
"open_interest_changes": 120
}
}
}
```
---
## Invalid Contract
# 10. Error Handling
If invalid contract names or IDs are provided:
```text
WebSocket closed with code 1008 POLICY VIOLATION
```
| Code | Description |
|---|---|
| `1008` | Invalid token, invalid contract, or unauthorized access |
| Connection Closed | Internal server error or Redis stream interruption |
---
# Architecture Notes
- All streams are asynchronous
- Data is pushed only on updates
- Multiple contracts can be subscribed simultaneously
- Connections remain active until disconnected
- ISO 8601 timestamps are used
- Built for high-throughput market infrastructure
---
# Production Recommendations
For production-grade integrations:
- Implement automatic reconnect logic
- Enable WebSocket heartbeat
- Configure proper timeout handling
- Monitor connection lifecycle
- Handle transient disconnects gracefully
---
# Production Reconnect Example
# 11. Python Example
```python
import asyncio
import json
import websockets
URI = (
"wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/id"
"?contract_id=12345"
)
async def subscribe(url: str, token: str):
HEADERS = {
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
headers = {
"Authorization": token
}
async def connect():
while True:
try:
async with websockets.connect(
URI,
additional_headers=HEADERS,
ping_interval=20,
ping_timeout=20,
) as websocket:
url,
additional_headers=headers
) as ws:
print("Connected")
async for message in ws:
while True:
payload = json.loads(message)
message = await websocket.recv()
identifier = (
payload.get("contractId")
or payload.get("contractName")
)
data = json.loads(message)
print(
payload["timestamp"],
identifier,
payload["channel"]
)
print(data)
print(payload["data"])
except Exception as e:
url = (
"wss://core.hedgetech.ir/"
"data-engine/ime/live/data/websocket/contract/id"
"?contract_id=1001"
"&contract_id=1002"
)
print("Disconnected:", e)
token = "<your_token>"
await asyncio.sleep(5)
asyncio.run(connect())
asyncio.run(subscribe(url, token))
```
---
# 12. JavaScript Example
# HedgeTech
```javascript
const WebSocket = require('ws');
const url =
'wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/id?contract_id=1001&contract_id=1002';
const token = '<your_token>';
const ws = new WebSocket(
url,
{
headers: {
Authorization: token
}
}
);
ws.on('open', () => {
console.log('Connected');
});
ws.on('message', (message) => {
const data = JSON.parse(message);
const identifier =
data.contractId ||
data.contractName;
console.log(
data.timestamp,
identifier,
data.channel
);
console.log(data.data);
});
ws.on('close', () => {
console.log('Disconnected');
});
```
---
# 13. Subscription Notes
- Multiple contracts can be subscribed in a single connection
- Query parameters must be repeated
- Streams are pushed continuously in real time
- Connections should be handled asynchronously
- Invalid contracts cause immediate connection rejection
---
# 14. Best Practices
- Reconnect using exponential backoff
- Subscribe only to required contracts
- Handle disconnects gracefully
- Normalize `contractId` and `contractName`
- Monitor WebSocket close code `1008`
- Use asynchronous processing pipelines for high-frequency streams
---
# 15. Developer Checklist
- Use the correct endpoint
- Provide valid Authorization header
- Pass repeated query parameters
- Handle both identifier field types
- Parse the nested `data` payload correctly
- Monitor connection lifecycle events
- Handle reconnect scenarios
---
# 16. Future Compatibility Notes
The IME streaming architecture is designed to remain schema-compatible across both endpoint types.
Future extensions may include:
- Additional market channels
- Incremental order-book streams
- Snapshot recovery
- Binary transport protocols
- Sequence numbers
- Compression support
- Dynamic subscribe/unsubscribe actions
Clients are encouraged to write flexible parsers to remain forward-compatible.
Developed and maintained by HedgeTech Infrastructure Team.