Update README.md
This commit is contained in:
parent
c7aeb221ad
commit
907df6b7d8
790
README.md
790
README.md
@ -1,465 +1,593 @@
|
|||||||
# HedgeTech IME Live Data WebSocket API
|
# HT Data Engine | IME | WebSocket
|
||||||
|
## Real-Time Mercantile Exchange Streams (IME)
|
||||||
Professional real-time WebSocket streaming service for Iran Mercantile Exchange (IME) market data.
|
### 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
|
- Best bid/ask limits
|
||||||
- HFT Systems
|
- Aggregate trading statistics
|
||||||
- Algorithmic Trading
|
- Allowed price ranges
|
||||||
- Quantitative Infrastructure
|
- Contract open interest information
|
||||||
- Market Monitoring Systems
|
|
||||||
- Real-Time Dashboards
|
|
||||||
- Risk Engines
|
|
||||||
|
|
||||||
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
|
```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 |
|
```json
|
||||||
|---|---|
|
{
|
||||||
| `/live/data/websocket/contract/name` | Subscribe using contract names |
|
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||||
| `/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"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 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
|
```text
|
||||||
wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/name
|
wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/name
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
Messages contain:
|
||||||
|
|
||||||
## Query Parameters
|
```json
|
||||||
|
"contractName": "<CONTRACT_NAME>"
|
||||||
| 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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Python Example
|
## Contract ID Endpoint
|
||||||
|
|
||||||
```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
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/id
|
wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/id
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
Messages contain:
|
||||||
|
|
||||||
## Query Parameters
|
```json
|
||||||
|
"contractId": "<CONTRACT_ID>"
|
||||||
| 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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 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
|
```python
|
||||||
import asyncio
|
identifier = message.get("contractId") or message.get("contractName")
|
||||||
import json
|
```
|
||||||
import websockets
|
|
||||||
|
|
||||||
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 = {
|
# 5. Connection Flow
|
||||||
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
|
|
||||||
|
1. Establish WebSocket connection
|
||||||
|
|
||||||
|
2. Provide the Authorization header
|
||||||
|
|
||||||
|
3. Pass query parameters in the URL
|
||||||
|
|
||||||
|
4. Server validates:
|
||||||
|
- JWT token
|
||||||
|
- Contract identifiers
|
||||||
|
- Subscription permissions
|
||||||
|
|
||||||
|
5. If validation succeeds:
|
||||||
|
- WebSocket connection is accepted
|
||||||
|
- Real-time streams begin immediately
|
||||||
|
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contract ID Endpoint
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `contract_id` | repeated string | IME contract IDs |
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```text
|
||||||
|
wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/id?contract_id=1001&contract_id=1002
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 7. Message Structure
|
||||||
|
|
||||||
|
All WebSocket messages follow the same envelope structure.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contract Name Endpoint Example
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"channel": "IME Stream",
|
||||||
|
"contractName": "GOLD-APR",
|
||||||
|
"timestamp": "2026-05-29T12:00:00.000000Z",
|
||||||
|
"data": {
|
||||||
|
"...": "..."
|
||||||
}
|
}
|
||||||
|
|
||||||
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 Response Structure
|
|
||||||
|
|
||||||
Both endpoints stream identical payload structures.
|
|
||||||
|
|
||||||
The only difference is:
|
|
||||||
|
|
||||||
- `contractName` exists in Name endpoint
|
|
||||||
- `contractId` exists in ID endpoint
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Response Example (Contract Name)
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"channel": "IME Stream",
|
|
||||||
"contractName": "ContractA",
|
|
||||||
"timestamp": "2026-05-23T15:10:00.000000",
|
|
||||||
"data": {}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Response Example (Contract ID)
|
## Contract ID Endpoint Example
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"channel": "IME Stream",
|
"channel": "IME Stream",
|
||||||
"contractId": "12345",
|
"contractId": "1001",
|
||||||
"timestamp": "2026-05-23T15:10:00.000000",
|
"timestamp": "2026-05-29T12:00:00.000000Z",
|
||||||
"data": {}
|
"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
|
```json
|
||||||
{
|
{
|
||||||
"BestLimit": {
|
"BestLimit": {
|
||||||
"1": {
|
"1": {
|
||||||
"buy_quantity": 0,
|
"buy_quantity": 150,
|
||||||
"buy_price": 0,
|
"buy_price": 245000,
|
||||||
"sell_quantity": 0,
|
"sell_quantity": 100,
|
||||||
"sell_price": 0
|
"sell_price": 246000
|
||||||
},
|
},
|
||||||
"2": {
|
"2": {
|
||||||
"buy_quantity": 0,
|
"buy_quantity": 120,
|
||||||
"buy_price": 0,
|
"buy_price": 244500,
|
||||||
"sell_quantity": 0,
|
"sell_quantity": 90,
|
||||||
"sell_price": 0
|
"sell_price": 246500
|
||||||
},
|
},
|
||||||
"3": {
|
"3": {
|
||||||
"buy_quantity": 0,
|
"buy_quantity": 80,
|
||||||
"buy_price": 0,
|
"buy_price": 244000,
|
||||||
"sell_quantity": 0,
|
"sell_quantity": 70,
|
||||||
"sell_price": 0
|
"sell_price": 247000
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
|
|
||||||
"AllowedPriceRange": {
|
|
||||||
"minAllowedPrice": 1,
|
|
||||||
"maxAllowedPrice": 9999999999
|
|
||||||
},
|
|
||||||
|
|
||||||
"ContractInfo": {
|
|
||||||
"open_interest": 0,
|
|
||||||
"open_interest_changes": 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Payload Field Documentation
|
## Fields
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
|---|---|
|
|---|---|
|
||||||
| buy_quantity | Buy order quantity |
|
| `buy_quantity` | Total bid quantity |
|
||||||
| buy_price | Buy order price |
|
| `buy_price` | Bid price |
|
||||||
| sell_quantity | Sell order quantity |
|
| `sell_quantity` | Total ask quantity |
|
||||||
| sell_price | Sell order price |
|
| `sell_price` | Ask price |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Aggregate
|
# 8.2 Aggregate
|
||||||
|
|
||||||
Aggregated trading statistics.
|
Aggregate trading statistics for the contract.
|
||||||
|
|
||||||
| Field | Description |
|
## Example
|
||||||
|---|---|
|
|
||||||
| 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 |
|
|
||||||
|
|
||||||
---
|
```json
|
||||||
|
{
|
||||||
# AllowedPriceRange
|
"Aggregate": {
|
||||||
|
"date": "2026-05-29",
|
||||||
Allowed trading range.
|
"time": "12:00:00",
|
||||||
|
"trade_count": 120,
|
||||||
| Field | Description |
|
"total_volume": 4500,
|
||||||
|---|---|
|
"total_value": 1102500000,
|
||||||
| minAllowedPrice | Minimum allowed price |
|
"closing_price": 245500,
|
||||||
| maxAllowedPrice | Maximum allowed price |
|
"last_price": 245700,
|
||||||
|
"low_price": 244000,
|
||||||
---
|
"high_price": 247000,
|
||||||
|
"open_price": 244500,
|
||||||
# ContractInfo
|
"previous_close": 243000
|
||||||
|
}
|
||||||
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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Invalid Contract
|
## Fields
|
||||||
|
|
||||||
If invalid contract names or IDs are provided:
|
| 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 |
|
||||||
|
|
||||||
```text
|
---
|
||||||
WebSocket closed with code 1008 POLICY VIOLATION
|
|
||||||
|
# 8.3 AllowedPriceRange
|
||||||
|
|
||||||
|
Allowed trading price boundaries for the contract.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"AllowedPriceRange": {
|
||||||
|
"minAllowedPrice": 220000,
|
||||||
|
"maxAllowedPrice": 270000
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Architecture Notes
|
## Fields
|
||||||
|
|
||||||
- All streams are asynchronous
|
| Field | Description |
|
||||||
- Data is pushed only on updates
|
|---|---|
|
||||||
- Multiple contracts can be subscribed simultaneously
|
| `minAllowedPrice` | Minimum allowed trading price |
|
||||||
- Connections remain active until disconnected
|
| `maxAllowedPrice` | Maximum allowed trading price |
|
||||||
- ISO 8601 timestamps are used
|
|
||||||
- Built for high-throughput market infrastructure
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Production Recommendations
|
# 8.4 ContractInfo
|
||||||
|
|
||||||
For production-grade integrations:
|
Contract open interest statistics.
|
||||||
|
|
||||||
- Implement automatic reconnect logic
|
## Example
|
||||||
- Enable WebSocket heartbeat
|
|
||||||
- Configure proper timeout handling
|
```json
|
||||||
- Monitor connection lifecycle
|
{
|
||||||
- Handle transient disconnects gracefully
|
"ContractInfo": {
|
||||||
|
"open_interest": 5400,
|
||||||
|
"open_interest_changes": 120
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Production Reconnect Example
|
## Fields
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `open_interest` | Current open interest |
|
||||||
|
| `open_interest_changes` | Change in open interest |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 9. Complete Example Payload
|
||||||
|
|
||||||
|
```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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 10. Error Handling
|
||||||
|
|
||||||
|
| Code | Description |
|
||||||
|
|---|---|
|
||||||
|
| `1008` | Invalid token, invalid contract, or unauthorized access |
|
||||||
|
| Connection Closed | Internal server error or Redis stream interruption |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 11. Python Example
|
||||||
|
|
||||||
```python
|
```python
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import websockets
|
import websockets
|
||||||
|
|
||||||
URI = (
|
async def subscribe(url: str, token: str):
|
||||||
"wss://core.hedgetech.ir/data-engine/ime/live/data/websocket/contract/id"
|
|
||||||
"?contract_id=12345"
|
|
||||||
)
|
|
||||||
|
|
||||||
HEADERS = {
|
headers = {
|
||||||
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
|
"Authorization": token
|
||||||
}
|
}
|
||||||
|
|
||||||
async def connect():
|
|
||||||
|
|
||||||
while True:
|
|
||||||
|
|
||||||
try:
|
|
||||||
|
|
||||||
async with websockets.connect(
|
async with websockets.connect(
|
||||||
URI,
|
url,
|
||||||
additional_headers=HEADERS,
|
additional_headers=headers
|
||||||
ping_interval=20,
|
) as ws:
|
||||||
ping_timeout=20,
|
|
||||||
) as websocket:
|
|
||||||
|
|
||||||
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(subscribe(url, token))
|
||||||
|
|
||||||
asyncio.run(connect())
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
# 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.
|
|
||||||
Loading…
Reference in New Issue
Block a user