dnse-sdk-openapi 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- broker-api/get_list_care_by.py +22 -0
- dnse/__init__.py +4 -0
- dnse/client.py +408 -0
- dnse/common.py +103 -0
- dnse_sdk_openapi-0.0.1.dist-info/METADATA +120 -0
- dnse_sdk_openapi-0.0.1.dist-info/RECORD +50 -0
- dnse_sdk_openapi-0.0.1.dist-info/WHEEL +5 -0
- dnse_sdk_openapi-0.0.1.dist-info/top_level.txt +5 -0
- marketdata-api/get_instruments.py +22 -0
- marketdata-api/get_latest_trade.py +22 -0
- marketdata-api/get_ohlc.py +31 -0
- marketdata-api/get_security_definition.py +22 -0
- marketdata-api/get_trades.py +22 -0
- marketdata-api/get_working_dates.py +22 -0
- trading-api/cancel_order.py +29 -0
- trading-api/close_position.py +27 -0
- trading-api/create_trading_token.py +26 -0
- trading-api/get_accounts.py +22 -0
- trading-api/get_balances.py +22 -0
- trading-api/get_close_price.py +22 -0
- trading-api/get_execution_detail.py +28 -0
- trading-api/get_loan_packages.py +27 -0
- trading-api/get_order_detail.py +28 -0
- trading-api/get_order_history.py +30 -0
- trading-api/get_orders.py +27 -0
- trading-api/get_position_by_id.py +26 -0
- trading-api/get_positions.py +26 -0
- trading-api/get_ppse.py +29 -0
- trading-api/post_order.py +38 -0
- trading-api/put_order.py +35 -0
- trading-api/send_email_otp.py +22 -0
- websocket-marketdata/expected_price.py +53 -0
- websocket-marketdata/foreign_investor.py +51 -0
- websocket-marketdata/market_index.py +52 -0
- websocket-marketdata/ohlc.py +55 -0
- websocket-marketdata/ohlc_closed.py +55 -0
- websocket-marketdata/order.py +51 -0
- websocket-marketdata/quote.py +50 -0
- websocket-marketdata/sec_def.py +52 -0
- websocket-marketdata/trade.py +52 -0
- websocket-marketdata/trade_extra.py +51 -0
- websocket-marketdata/trading_websocket/__init__.py +33 -0
- websocket-marketdata/trading_websocket/_version.py +3 -0
- websocket-marketdata/trading_websocket/auth.py +59 -0
- websocket-marketdata/trading_websocket/client.py +790 -0
- websocket-marketdata/trading_websocket/connection.py +151 -0
- websocket-marketdata/trading_websocket/encoding.py +78 -0
- websocket-marketdata/trading_websocket/exceptions.py +38 -0
- websocket-marketdata/trading_websocket/models.py +525 -0
- websocket-marketdata/trading_websocket/py.typed +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
|
6
|
+
|
|
7
|
+
from dnse import DNSEClient
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main():
|
|
11
|
+
client = DNSEClient(
|
|
12
|
+
api_key="replace-with-api-key",
|
|
13
|
+
api_secret="replace-with-api-secret",
|
|
14
|
+
base_url="https://openapi.dnse.com.vn",
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
status, body = client.send_email_otp(dry_run=False)
|
|
18
|
+
print(status, body)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
if __name__ == "__main__":
|
|
22
|
+
main()
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Market data subscription example.
|
|
3
|
+
|
|
4
|
+
Demonstrates:
|
|
5
|
+
- Subscribing to expected price updates
|
|
6
|
+
|
|
7
|
+
This example shows how to receive real-time market data for multiple symbols.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
|
|
13
|
+
from trading_websocket import TradingClient
|
|
14
|
+
from trading_websocket.models import ExpectedPrice
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def main():
|
|
18
|
+
# Initialize client
|
|
19
|
+
encoding = "msgpack" # json or msgpack
|
|
20
|
+
client = TradingClient(
|
|
21
|
+
api_key="api-key",
|
|
22
|
+
api_secret="api-secret",
|
|
23
|
+
base_url="wss://ws-openapi.dnse.com.vn",
|
|
24
|
+
encoding=encoding,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
def handle_expected_price(expected_price: ExpectedPrice):
|
|
28
|
+
received_at = datetime.fromtimestamp(expected_price.receivedAt).strftime("%H:%M:%S.%f")[:-3] if expected_price.receivedAt else "N/A"
|
|
29
|
+
print(f"[{received_at}] EXPECTED PRICE: {expected_price}")
|
|
30
|
+
|
|
31
|
+
# Connect to gateway
|
|
32
|
+
print("Connecting to WebSocket gateway...")
|
|
33
|
+
await client.connect()
|
|
34
|
+
print(f"Connected! Session ID: {client._session_id}\n")
|
|
35
|
+
|
|
36
|
+
print("Subscribing to expected price for SSI and 41I1G4000...")
|
|
37
|
+
await client.subscribe_expected_price(["SSI", "41I1G4000"],
|
|
38
|
+
on_expected_price=handle_expected_price, encoding=encoding, board_id="G1")
|
|
39
|
+
|
|
40
|
+
print("\nReceiving market data (will run for 1 hour)...\n")
|
|
41
|
+
|
|
42
|
+
# Run for 1H to collect data
|
|
43
|
+
# In a real application, you might run indefinitely or until a specific condition
|
|
44
|
+
await asyncio.sleep(60 * 60 * 8)
|
|
45
|
+
|
|
46
|
+
# Disconnect gracefully
|
|
47
|
+
print("\n\nDisconnecting...")
|
|
48
|
+
await client.disconnect()
|
|
49
|
+
print("Disconnected!")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if __name__ == "__main__":
|
|
53
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Demonstrates:
|
|
3
|
+
- Subscribing to foreigner trading
|
|
4
|
+
|
|
5
|
+
This example shows how to receive real-time foreigner trading data
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
|
|
11
|
+
from trading_websocket import TradingClient
|
|
12
|
+
from trading_websocket.models import ForeignInvestor
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
async def main():
|
|
16
|
+
# Initialize client
|
|
17
|
+
encoding = "json" # json or msgpack
|
|
18
|
+
client = TradingClient(
|
|
19
|
+
api_key="api-key",
|
|
20
|
+
api_secret="api-secret",
|
|
21
|
+
base_url="wss://ws-openapi.dnse.com.vn",
|
|
22
|
+
encoding=encoding,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
def handle_foreign_trading(data: ForeignInvestor):
|
|
26
|
+
received_at = datetime.fromtimestamp(data.receivedAt).strftime("%H:%M:%S.%f")[:-3] if data.receivedAt else "N/A"
|
|
27
|
+
print(f"[{received_at}] Foreign trading: {data}")
|
|
28
|
+
|
|
29
|
+
# Connect to gateway
|
|
30
|
+
print("Connecting to WebSocket gateway...")
|
|
31
|
+
await client.connect()
|
|
32
|
+
print(f"Connected! Session ID: {client._session_id}\n")
|
|
33
|
+
|
|
34
|
+
print("Subscribing to foreigner trading...")
|
|
35
|
+
await client.subscribe_foreign_trading(["HPG", "FPT"], board_id="G1", on_trade=handle_foreign_trading,
|
|
36
|
+
encoding=encoding)
|
|
37
|
+
|
|
38
|
+
print("\nReceiving foreigner trading data (will run for 8 hour)...\n")
|
|
39
|
+
|
|
40
|
+
# Run for 8H to collect data
|
|
41
|
+
# In a real application, you might run indefinitely or until a specific condition
|
|
42
|
+
await asyncio.sleep(60 * 60 * 8)
|
|
43
|
+
|
|
44
|
+
# Disconnect gracefully
|
|
45
|
+
print("\n\nDisconnecting...")
|
|
46
|
+
await client.disconnect()
|
|
47
|
+
print("Disconnected!")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Market index subscription example.
|
|
3
|
+
|
|
4
|
+
Demonstrates:
|
|
5
|
+
- Subscribing to market index
|
|
6
|
+
|
|
7
|
+
This example shows how to receive real-time market index
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
|
|
12
|
+
from trading_websocket import TradingClient
|
|
13
|
+
from trading_websocket.models import MarketIndex
|
|
14
|
+
from datetime import datetime
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def main():
|
|
18
|
+
# Initialize client
|
|
19
|
+
encoding = "msgpack" # json or msgpack
|
|
20
|
+
client = TradingClient(
|
|
21
|
+
api_key="api-key",
|
|
22
|
+
api_secret="api-secret",
|
|
23
|
+
base_url="wss://ws-openapi.dnse.com.vn",
|
|
24
|
+
encoding=encoding,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
def handle_market_index(data: MarketIndex):
|
|
28
|
+
received_at = datetime.fromtimestamp(data.receivedAt).strftime("%H:%M:%S.%f")[:-3] if data.receivedAt else "N/A"
|
|
29
|
+
print(f"[{received_at}] Market index: {data}")
|
|
30
|
+
|
|
31
|
+
# Connect to gateway
|
|
32
|
+
print("Connecting to WebSocket gateway...")
|
|
33
|
+
await client.connect()
|
|
34
|
+
print(f"Connected! Session ID: {client._session_id}\n")
|
|
35
|
+
|
|
36
|
+
print("Subscribing to market index...")
|
|
37
|
+
await client.subscribe_market_index(market_index='HNX', on_market_index=handle_market_index, encoding=encoding)
|
|
38
|
+
|
|
39
|
+
print("\nReceiving market index (will run for 1 hour)...\n")
|
|
40
|
+
|
|
41
|
+
# Run for 1H to collect data
|
|
42
|
+
# In a real application, you might run indefinitely or until a specific condition
|
|
43
|
+
await asyncio.sleep(8 * 60 * 60)
|
|
44
|
+
|
|
45
|
+
# Disconnect gracefully
|
|
46
|
+
print("\n\nDisconnecting...")
|
|
47
|
+
await client.disconnect()
|
|
48
|
+
print("Disconnected!")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
if __name__ == "__main__":
|
|
52
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Market data subscription example.
|
|
3
|
+
|
|
4
|
+
Demonstrates:
|
|
5
|
+
- Subscribing to OHLCV updates
|
|
6
|
+
|
|
7
|
+
This example shows how to receive real-time market data for multiple symbols.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
|
|
13
|
+
from trading_websocket import TradingClient
|
|
14
|
+
from trading_websocket.models import Ohlc
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def main():
|
|
18
|
+
# Initialize client
|
|
19
|
+
encoding = "msgpack" # json or msgpack
|
|
20
|
+
client = TradingClient(
|
|
21
|
+
api_key="api-key",
|
|
22
|
+
api_secret="api-secret",
|
|
23
|
+
base_url="wss://ws-openapi.dnse.com.vn",
|
|
24
|
+
encoding=encoding,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
def handle_ohlc(ohlc: Ohlc):
|
|
28
|
+
received_at = datetime.fromtimestamp(ohlc.receivedAt).strftime("%H:%M:%S.%f")[:-3] if ohlc.receivedAt else "N/A"
|
|
29
|
+
print(f"[{received_at}] OHLC: {ohlc}")
|
|
30
|
+
|
|
31
|
+
# Connect to gateway
|
|
32
|
+
print("Connecting to WebSocket gateway...")
|
|
33
|
+
await client.connect()
|
|
34
|
+
print(f"Connected! Session ID: {client._session_id}\n")
|
|
35
|
+
|
|
36
|
+
print("Subscribing to ohlc for SSI, VN30F1M and VN30...")
|
|
37
|
+
# internal 1 3 5 15 30 1H 1D 1W
|
|
38
|
+
await client.subscribe_ohlc(["SSI", "VN30F1M", "VN30"], resolution="1", on_ohlc=handle_ohlc, encoding=encoding)
|
|
39
|
+
|
|
40
|
+
# Subscribe to 1-minute OHLC
|
|
41
|
+
|
|
42
|
+
print("\nReceiving market data (will run for 1 hour)...\n")
|
|
43
|
+
|
|
44
|
+
# Run for 8H to collect data
|
|
45
|
+
# In a real application, you might run indefinitely or until a specific condition
|
|
46
|
+
await asyncio.sleep(8 * 60 * 60)
|
|
47
|
+
|
|
48
|
+
# Disconnect gracefully
|
|
49
|
+
print("\n\nDisconnecting...")
|
|
50
|
+
await client.disconnect()
|
|
51
|
+
print("Disconnected!")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
if __name__ == "__main__":
|
|
55
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Market data subscription example.
|
|
3
|
+
|
|
4
|
+
Demonstrates:
|
|
5
|
+
- Subscribing to OHLCV updates
|
|
6
|
+
|
|
7
|
+
This example shows how to receive real-time market data for multiple symbols.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
|
|
13
|
+
from trading_websocket import TradingClient
|
|
14
|
+
from trading_websocket.models import Ohlc
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def main():
|
|
18
|
+
# Initialize client
|
|
19
|
+
encoding = "msgpack" # json or msgpack
|
|
20
|
+
client = TradingClient(
|
|
21
|
+
api_key="api-key",
|
|
22
|
+
api_secret="api-secret",
|
|
23
|
+
base_url="wss://ws-openapi.dnse.com.vn",
|
|
24
|
+
encoding=encoding,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
def handle_ohlc(ohlc: Ohlc):
|
|
28
|
+
received_at = datetime.fromtimestamp(ohlc.receivedAt).strftime("%H:%M:%S.%f")[:-3] if ohlc.receivedAt else "N/A"
|
|
29
|
+
print(f"[{received_at}] OHLC: {ohlc}")
|
|
30
|
+
|
|
31
|
+
# Connect to gateway
|
|
32
|
+
print("Connecting to WebSocket gateway...")
|
|
33
|
+
await client.connect()
|
|
34
|
+
print(f"Connected! Session ID: {client._session_id}\n")
|
|
35
|
+
|
|
36
|
+
print("Subscribing to ohlc closed for SSI, VN30F1M and VN30...")
|
|
37
|
+
# internal 1 3 5 15 30 1H 1D 1W
|
|
38
|
+
await client.subscribe_ohlc_closed(["SSI", "VN30F1M", "VN30"], resolution="1", on_ohlc=handle_ohlc, encoding=encoding)
|
|
39
|
+
|
|
40
|
+
# Subscribe to 1-minute OHLC
|
|
41
|
+
|
|
42
|
+
print("\nReceiving market data (will run for 1 hour)...\n")
|
|
43
|
+
|
|
44
|
+
# Run for 8H to collect data
|
|
45
|
+
# In a real application, you might run indefinitely or until a specific condition
|
|
46
|
+
await asyncio.sleep(8 * 60 * 60)
|
|
47
|
+
|
|
48
|
+
# Disconnect gracefully
|
|
49
|
+
print("\n\nDisconnecting...")
|
|
50
|
+
await client.disconnect()
|
|
51
|
+
print("Disconnected!")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
if __name__ == "__main__":
|
|
55
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Order event subscription example.
|
|
3
|
+
|
|
4
|
+
This example shows how to receive real-time order event for stock and derivative orders
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
|
|
10
|
+
from trading_websocket import TradingClient
|
|
11
|
+
from trading_websocket.models import Order
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
async def main():
|
|
15
|
+
# Initialize client
|
|
16
|
+
encoding = "json" # json or msgpack
|
|
17
|
+
client = TradingClient(
|
|
18
|
+
api_key="api-key",
|
|
19
|
+
api_secret="api-secret",
|
|
20
|
+
base_url="wss://ws-openapi.dnse.com.vn",
|
|
21
|
+
encoding=encoding,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
def handle_order(data: Order):
|
|
25
|
+
received_at = datetime.fromtimestamp(data.receivedAt).strftime("%H:%M:%S.%f")[:-3] if data.receivedAt else "N/A"
|
|
26
|
+
print(f"[{received_at}] Order: {data}")
|
|
27
|
+
|
|
28
|
+
# Connect to gateway
|
|
29
|
+
print("Connecting to WebSocket gateway...")
|
|
30
|
+
await client.connect()
|
|
31
|
+
print(f"Connected! Session ID: {client._session_id}\n")
|
|
32
|
+
|
|
33
|
+
print("Subscribing to order event")
|
|
34
|
+
# market_type: DERIVATIVE | STOCK
|
|
35
|
+
await client.subscribe_order_event(market_type="STOCK",
|
|
36
|
+
on_order_event=handle_order, encoding=encoding)
|
|
37
|
+
|
|
38
|
+
print("\nReceiving order event (will run for 1 hour)...\n")
|
|
39
|
+
|
|
40
|
+
# Run for 8H to collect data
|
|
41
|
+
# In a real application, you might run indefinitely or until a specific condition
|
|
42
|
+
await asyncio.sleep(8 * 60 * 60)
|
|
43
|
+
|
|
44
|
+
# Disconnect gracefully
|
|
45
|
+
print("\n\nDisconnecting...")
|
|
46
|
+
await client.disconnect()
|
|
47
|
+
print("Disconnected!")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Demonstrates:
|
|
3
|
+
- Subscribing to quote (BBO) updates
|
|
4
|
+
|
|
5
|
+
This example shows how to receive real-time quote data for multiple symbols.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
|
|
11
|
+
from trading_websocket import TradingClient
|
|
12
|
+
from trading_websocket.models import Quote
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
async def main():
|
|
16
|
+
# Initialize client
|
|
17
|
+
encoding = "msgpack" # json or msgpack
|
|
18
|
+
client = TradingClient(
|
|
19
|
+
api_key="api-key",
|
|
20
|
+
api_secret="api-secret",
|
|
21
|
+
base_url="wss://ws-openapi.dnse.com.vn",
|
|
22
|
+
encoding=encoding,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
def handle_quote(quote: Quote):
|
|
26
|
+
received_at = datetime.fromtimestamp(quote.receivedAt).strftime("%H:%M:%S.%f")[:-3] if quote.receivedAt else "N/A"
|
|
27
|
+
print(f"[{received_at}] QUOTE: {quote}")
|
|
28
|
+
|
|
29
|
+
# Connect to gateway
|
|
30
|
+
print("Connecting to WebSocket gateway...")
|
|
31
|
+
await client.connect()
|
|
32
|
+
print(f"Connected! Session ID: {client._session_id}\n")
|
|
33
|
+
|
|
34
|
+
print("Subscribing to quotes for SSI and 41I1G4000...")
|
|
35
|
+
await client.subscribe_quotes(["SSI", "41I1G4000"], on_quote=handle_quote, encoding=encoding, board_id="G1")
|
|
36
|
+
|
|
37
|
+
print("\nReceiving market data (will run for 1 hour)...\n")
|
|
38
|
+
|
|
39
|
+
# Run for 8H to collect data
|
|
40
|
+
# In a real application, you might run indefinitely or until a specific condition
|
|
41
|
+
await asyncio.sleep(8 * 60 * 60)
|
|
42
|
+
|
|
43
|
+
# Disconnect gracefully
|
|
44
|
+
print("\n\nDisconnecting...")
|
|
45
|
+
await client.disconnect()
|
|
46
|
+
print("Disconnected!")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if __name__ == "__main__":
|
|
50
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Market data subscription example.
|
|
3
|
+
|
|
4
|
+
Demonstrates:
|
|
5
|
+
- Subscribing to security definition updates
|
|
6
|
+
|
|
7
|
+
This example shows how to receive real-time market data for multiple symbols.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
|
|
13
|
+
from trading_websocket import TradingClient
|
|
14
|
+
from trading_websocket.models import SecurityDefinition
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def main():
|
|
18
|
+
# Initialize client
|
|
19
|
+
encoding = "msgpack" # json or msgpack
|
|
20
|
+
client = TradingClient(
|
|
21
|
+
api_key="api-key",
|
|
22
|
+
api_secret="api-secret",
|
|
23
|
+
base_url="wss://ws-openapi.dnse.com.vn",
|
|
24
|
+
encoding=encoding,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
def handle_security_definition(sec_def: SecurityDefinition):
|
|
28
|
+
received_at = datetime.fromtimestamp(sec_def.receivedAt).strftime("%H:%M:%S.%f")[:-3] if sec_def.receivedAt else "N/A"
|
|
29
|
+
print(f"[{received_at}] SECURITY DEFINITION: {sec_def}")
|
|
30
|
+
|
|
31
|
+
# Connect to gateway
|
|
32
|
+
print("Connecting to WebSocket gateway...")
|
|
33
|
+
await client.connect()
|
|
34
|
+
print(f"Connected! Session ID: {client._session_id}\n")
|
|
35
|
+
|
|
36
|
+
print("Subscribing to security definition for SSI and 41I1G2000...")
|
|
37
|
+
await client.subscribe_sec_def(["SSI", "41I1G2000"], on_sec_def=handle_security_definition, encoding=encoding, board_id="G1")
|
|
38
|
+
|
|
39
|
+
print("\nReceiving market data (will run for 1 hour)...\n")
|
|
40
|
+
|
|
41
|
+
# Run for 1H to collect data
|
|
42
|
+
# In a real application, you might run indefinitely or until a specific condition
|
|
43
|
+
await asyncio.sleep(8 * 60 * 60)
|
|
44
|
+
|
|
45
|
+
# Disconnect gracefully
|
|
46
|
+
print("\n\nDisconnecting...")
|
|
47
|
+
await client.disconnect()
|
|
48
|
+
print("Disconnected!")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
if __name__ == "__main__":
|
|
52
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Market data subscription example.
|
|
3
|
+
|
|
4
|
+
Demonstrates:
|
|
5
|
+
- Subscribing to trade updates
|
|
6
|
+
|
|
7
|
+
This example shows how to receive real-time market data for multiple symbols.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
|
|
13
|
+
from trading_websocket import TradingClient
|
|
14
|
+
from trading_websocket.models import Trade
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def main():
|
|
18
|
+
# Initialize client
|
|
19
|
+
encoding = "msgpack" # json or msgpack
|
|
20
|
+
client = TradingClient(
|
|
21
|
+
api_key="api-key",
|
|
22
|
+
api_secret="api-secret",
|
|
23
|
+
base_url="wss://ws-openapi.dnse.com.vn",
|
|
24
|
+
encoding=encoding,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
def handle_trade(trade: Trade):
|
|
28
|
+
received_at = datetime.fromtimestamp(trade.receivedAt).strftime("%H:%M:%S.%f")[:-3] if trade.receivedAt else "N/A"
|
|
29
|
+
print(f"[{received_at}] TRADE: {trade}")
|
|
30
|
+
|
|
31
|
+
# Connect to gateway
|
|
32
|
+
print("Connecting to WebSocket gateway...")
|
|
33
|
+
await client.connect()
|
|
34
|
+
print(f"Connected! Session ID: {client._session_id}\n")
|
|
35
|
+
|
|
36
|
+
print("Subscribing to trades for SSI and 41I1G4000...")
|
|
37
|
+
await client.subscribe_trades(["SSI", "41I1G4000"], on_trade=handle_trade, encoding=encoding, board_id="G1")
|
|
38
|
+
|
|
39
|
+
print("\nReceiving market data (will run for 1 hour)...\n")
|
|
40
|
+
|
|
41
|
+
# Run for 8H to collect data
|
|
42
|
+
# In a real application, you might run indefinitely or until a specific condition
|
|
43
|
+
await asyncio.sleep(8 * 60 * 60)
|
|
44
|
+
|
|
45
|
+
# Disconnect gracefully
|
|
46
|
+
print("\n\nDisconnecting...")
|
|
47
|
+
await client.disconnect()
|
|
48
|
+
print("Disconnected!")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
if __name__ == "__main__":
|
|
52
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Market data subscription example.
|
|
3
|
+
|
|
4
|
+
Demonstrates:
|
|
5
|
+
- Subscribing to trade extra updates
|
|
6
|
+
|
|
7
|
+
This example shows how to receive real-time market data for multiple symbols.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from trading_websocket import TradingClient
|
|
13
|
+
import trading_websocket.models
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def main():
|
|
17
|
+
# Initialize client
|
|
18
|
+
encoding = "msgpack" # json or msgpack
|
|
19
|
+
client = TradingClient(
|
|
20
|
+
api_key="api-key",
|
|
21
|
+
api_secret="api-secret",
|
|
22
|
+
base_url="wss://ws-openapi.dnse.com.vn",
|
|
23
|
+
encoding=encoding,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
def handle_trade_extra(trade: trading_websocket.models.TradeExtra):
|
|
27
|
+
received_at = datetime.fromtimestamp(trade.receivedAt).strftime("%H:%M:%S.%f")[:-3] if trade.receivedAt else "N/A"
|
|
28
|
+
print(f"[{received_at}] TRADE EXTRA: {trade}")
|
|
29
|
+
|
|
30
|
+
# Connect to gateway
|
|
31
|
+
print("Connecting to WebSocket gateway...")
|
|
32
|
+
await client.connect()
|
|
33
|
+
print(f"Connected! Session ID: {client._session_id}\n")
|
|
34
|
+
|
|
35
|
+
print("Subscribing to trade extra for SSI and 41I1G4000...")
|
|
36
|
+
await client.subscribe_trade_extra(["SSI", "41I1G4000"], on_trade_extra=handle_trade_extra, encoding=encoding, board_id="G1")
|
|
37
|
+
|
|
38
|
+
print("\nReceiving market data (will run for 1 hour)...\n")
|
|
39
|
+
|
|
40
|
+
# Run for 8H to collect data
|
|
41
|
+
# In a real application, you might run indefinitely or until a specific condition
|
|
42
|
+
await asyncio.sleep(8 * 60 * 60)
|
|
43
|
+
|
|
44
|
+
# Disconnect gracefully
|
|
45
|
+
print("\n\nDisconnecting...")
|
|
46
|
+
await client.disconnect()
|
|
47
|
+
print("Disconnected!")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Trading WebSocket SDK for Python.
|
|
2
|
+
|
|
3
|
+
Async Python client for real-time trading data via WebSocket.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .client import TradingClient
|
|
7
|
+
from .models import Trade, Quote, Ohlc, Order, Position, AccountUpdate
|
|
8
|
+
from .exceptions import (
|
|
9
|
+
TradingWebSocketError,
|
|
10
|
+
ConnectionError,
|
|
11
|
+
ConnectionClosed,
|
|
12
|
+
AuthenticationError,
|
|
13
|
+
SubscriptionError,
|
|
14
|
+
EncodingError,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
__version__ = "1.0.0"
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"TradingClient",
|
|
21
|
+
"Trade",
|
|
22
|
+
"Quote",
|
|
23
|
+
"Ohlc",
|
|
24
|
+
"Order",
|
|
25
|
+
"Position",
|
|
26
|
+
"AccountUpdate",
|
|
27
|
+
"TradingWebSocketError",
|
|
28
|
+
"ConnectionError",
|
|
29
|
+
"ConnectionClosed",
|
|
30
|
+
"AuthenticationError",
|
|
31
|
+
"SubscriptionError",
|
|
32
|
+
"EncodingError",
|
|
33
|
+
]
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import hmac
|
|
2
|
+
import hashlib
|
|
3
|
+
import time
|
|
4
|
+
from typing import Dict, Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AuthManager:
|
|
8
|
+
"""
|
|
9
|
+
HMAC-SHA256 authentication manager.
|
|
10
|
+
|
|
11
|
+
Handles signature generation and nonce creation for WebSocket authentication.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, api_key: str, api_secret: str):
|
|
15
|
+
"""
|
|
16
|
+
Initialize auth manager.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
api_key: API key
|
|
20
|
+
api_secret: API secret for HMAC signature
|
|
21
|
+
"""
|
|
22
|
+
self.api_key = api_key
|
|
23
|
+
self.api_secret = api_secret
|
|
24
|
+
|
|
25
|
+
def create_auth_message(self) -> Dict[str, Any]:
|
|
26
|
+
timestamp = int(time.time()) # second
|
|
27
|
+
nonce = str(int(time.time() * 1000000)) # microseconds for uniqueness
|
|
28
|
+
|
|
29
|
+
signature = self.compute_signature(timestamp, nonce)
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
"action": "auth",
|
|
33
|
+
"api_key": self.api_key,
|
|
34
|
+
"signature": signature,
|
|
35
|
+
"timestamp": timestamp,
|
|
36
|
+
"nonce": nonce
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
def compute_signature(self, timestamp: int, nonce: str) -> str:
|
|
40
|
+
"""
|
|
41
|
+
Compute HMAC-SHA256 signature.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
timestamp: Unix timestamp in second
|
|
45
|
+
nonce: Unique nonce string
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
Hex-encoded HMAC signature
|
|
49
|
+
"""
|
|
50
|
+
# Message format: {api_key}:{timestamp}:{nonce}
|
|
51
|
+
message = f"{self.api_key}:{timestamp}:{nonce}"
|
|
52
|
+
|
|
53
|
+
signature = hmac.new(
|
|
54
|
+
self.api_secret.encode('utf-8'),
|
|
55
|
+
message.encode('utf-8'),
|
|
56
|
+
hashlib.sha256
|
|
57
|
+
).hexdigest()
|
|
58
|
+
|
|
59
|
+
return signature
|