dnse-sdk-openapi 1.4.2__tar.gz → 1.4.4__tar.gz

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.
Files changed (65) hide show
  1. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/PKG-INFO +1 -1
  2. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/dnse/api/client.py +36 -2
  3. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/dnse/websocket/client.py +30 -1
  4. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/dnse/websocket/models.py +135 -0
  5. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/dnse_sdk_openapi.egg-info/PKG-INFO +1 -1
  6. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/dnse_sdk_openapi.egg-info/SOURCES.txt +5 -0
  7. dnse_sdk_openapi-1.4.4/marketdata-api/get_foreign_trading.py +22 -0
  8. dnse_sdk_openapi-1.4.4/marketdata-api/get_lastest_session.py +22 -0
  9. dnse_sdk_openapi-1.4.4/marketdata-api/get_trading_session.py +22 -0
  10. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/pyproject.toml +1 -1
  11. dnse_sdk_openapi-1.4.4/websocket-marketdata/session.py +54 -0
  12. dnse_sdk_openapi-1.4.4/websocket-trading/broker_position.py +53 -0
  13. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/README.md +0 -0
  14. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/broker-api/get_list_care_by.py +0 -0
  15. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/dnse/__init__.py +0 -0
  16. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/dnse/api/_version.py +0 -0
  17. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/dnse/api/common.py +0 -0
  18. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/dnse/websocket/_version.py +0 -0
  19. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/dnse/websocket/auth.py +0 -0
  20. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/dnse/websocket/connection.py +0 -0
  21. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/dnse/websocket/encoding.py +0 -0
  22. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/dnse/websocket/exceptions.py +0 -0
  23. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/dnse/websocket/py.typed +0 -0
  24. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/dnse_sdk_openapi.egg-info/dependency_links.txt +0 -0
  25. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/dnse_sdk_openapi.egg-info/top_level.txt +0 -0
  26. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/marketdata-api/get_instruments.py +0 -0
  27. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/marketdata-api/get_latest_quote.py +0 -0
  28. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/marketdata-api/get_latest_trade.py +0 -0
  29. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/marketdata-api/get_ohlc.py +0 -0
  30. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/marketdata-api/get_quotes.py +0 -0
  31. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/marketdata-api/get_security_definition.py +0 -0
  32. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/marketdata-api/get_trades.py +0 -0
  33. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/marketdata-api/get_working_dates.py +0 -0
  34. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/setup.cfg +0 -0
  35. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/cancel_order.py +0 -0
  36. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/close_position.py +0 -0
  37. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/create_trading_token.py +0 -0
  38. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/get_accounts.py +0 -0
  39. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/get_balances.py +0 -0
  40. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/get_close_price.py +0 -0
  41. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/get_corporate_action_history.py +0 -0
  42. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/get_execution_detail.py +0 -0
  43. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/get_loan_packages.py +0 -0
  44. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/get_order_detail.py +0 -0
  45. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/get_order_history.py +0 -0
  46. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/get_orders.py +0 -0
  47. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/get_position_by_id.py +0 -0
  48. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/get_positions.py +0 -0
  49. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/get_ppse.py +0 -0
  50. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/post_order.py +0 -0
  51. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/put_order.py +0 -0
  52. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/trading-api/send_email_otp.py +0 -0
  53. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/websocket-marketdata/estimated_market_index.py +0 -0
  54. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/websocket-marketdata/expected_price.py +0 -0
  55. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/websocket-marketdata/foreign_investor.py +0 -0
  56. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/websocket-marketdata/market_index.py +0 -0
  57. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/websocket-marketdata/ohlc.py +0 -0
  58. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/websocket-marketdata/ohlc_closed.py +0 -0
  59. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/websocket-marketdata/quote.py +0 -0
  60. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/websocket-marketdata/sec_def.py +0 -0
  61. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/websocket-marketdata/trade.py +0 -0
  62. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/websocket-marketdata/trade_extra.py +0 -0
  63. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/websocket-trading/broker_order.py +0 -0
  64. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/websocket-trading/order.py +0 -0
  65. {dnse_sdk_openapi-1.4.2 → dnse_sdk_openapi-1.4.4}/websocket-trading/position.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dnse-sdk-openapi
3
- Version: 1.4.2
3
+ Version: 1.4.4
4
4
  Summary: DNSE OpenAPI SDK
5
5
  Description-Content-Type: text/markdown
6
6
 
@@ -31,8 +31,8 @@ class DNSEClient:
31
31
  maxsize=10, # Số connections tối đa mỗi pool
32
32
  block=False, # Không block khi pool đầy
33
33
  timeout=urllib3.Timeout(connect=30.0, read=60.0),
34
- # cert_reqs = 'CERT_NONE', # Không yêu cầu certificate
35
- # assert_hostname = False # Không kiểm tra hostname
34
+ cert_reqs = 'CERT_NONE', # Không yêu cầu certificate
35
+ assert_hostname = False # Không kiểm tra hostname
36
36
  )
37
37
 
38
38
  def get_accounts(self, dry_run=False):
@@ -231,6 +231,27 @@ class DNSEClient:
231
231
  dry_run=dry_run,
232
232
  )
233
233
 
234
+ def get_foreign_trading(self, symbol, board_id=None, from_date=None, to_date=None, limit=None, order = None, next_page_token=None, dry_run=False):
235
+ query = {}
236
+ if board_id is not None:
237
+ query["boardId"] = board_id
238
+ if from_date is not None:
239
+ query["from"] = from_date
240
+ if to_date is not None:
241
+ query["to"] = to_date
242
+ if limit is not None:
243
+ query["limit"] = limit
244
+ if order is not None:
245
+ query["order"] = order
246
+ if next_page_token is not None:
247
+ query["nextPageToken"] = next_page_token
248
+ return self._request(
249
+ "GET",
250
+ f"/price/{symbol}/foreign-trading",
251
+ query=query if query else None,
252
+ dry_run=dry_run,
253
+ )
254
+
234
255
  def get_instruments(self, symbol=None, market_id=None, security_group_id=None, index_name=None, limit=None, page=None, dry_run=False):
235
256
  query = {}
236
257
  if symbol is not None:
@@ -299,6 +320,19 @@ class DNSEClient:
299
320
  dry_run=dry_run,
300
321
  )
301
322
 
323
+ def get_lastest_session(self, tsc_prod_grp_id=None, board_id=None, dry_run=False):
324
+ query = {}
325
+ if tsc_prod_grp_id is not None:
326
+ query["tscProdGrpId"] = tsc_prod_grp_id
327
+ if board_id is not None:
328
+ query["boardId"] = board_id
329
+ return self._request(
330
+ "GET",
331
+ f"/market/trading-session",
332
+ query=query if query else None,
333
+ dry_run=dry_run,
334
+ )
335
+
302
336
  def post_order(self, market_type, payload, trading_token, order_category="NORMAL", dry_run=False):
303
337
  headers = {"trading-token": trading_token}
304
338
  query = {"marketType": market_type}
@@ -25,7 +25,7 @@ from .exceptions import (
25
25
  ConnectionClosed,
26
26
  )
27
27
  from .models import Trade, Quote, Ohlc, Order, AccountUpdate, ExpectedPrice, SecurityDefinition, TradeExtra, \
28
- MarketIndex, ForeignInvestor, Position, EstimatedMarketIndex
28
+ MarketIndex, ForeignInvestor, Position, EstimatedMarketIndex, Session
29
29
 
30
30
  logger = logging.getLogger(__name__)
31
31
  logger.setLevel(logging.INFO)
@@ -54,6 +54,7 @@ _MSG_TYPE_MAP = {
54
54
  "emi": ("estimated_market_index", EstimatedMarketIndex, "marketIndex"),
55
55
  "a": ("account", AccountUpdate, None),
56
56
  "f": ("foreign", ForeignInvestor, None),
57
+ "s": ("session", Session, None),
57
58
  }
58
59
 
59
60
 
@@ -294,6 +295,19 @@ class TradingClient:
294
295
  if on_position_event:
295
296
  self.on("position_event", on_position_event)
296
297
 
298
+ async def subscribe_broker_position_event(
299
+ self,
300
+ investor_id: str,
301
+ market_type="STOCK",
302
+ on_position_event: Optional[Callable[[Position], None]] = None,
303
+ encoding="json"
304
+ ) -> None:
305
+ channel = f"position.broker.{market_type}.{investor_id}.{encoding}"
306
+ await self._subscribe_channel(channel, [])
307
+
308
+ if on_position_event:
309
+ self.on("position_event", on_position_event)
310
+
297
311
  async def subscribe_sec_def(
298
312
  self, symbols: List[str], on_sec_def: Optional[Callable[[SecurityDefinition], None]] = None,
299
313
  encoding="json", board_id=None
@@ -384,6 +398,21 @@ class TradingClient:
384
398
  if on_ohlc:
385
399
  self.on("ohlc", on_ohlc)
386
400
 
401
+ async def subscribe_session(
402
+ self,
403
+ product_group_id: str,
404
+ board_id: str = "*",
405
+ on_session: Optional[Callable[[Session], None]] = None, encoding="json"
406
+ ) -> None:
407
+ channel = f"session.{product_group_id}.{board_id}.json"
408
+
409
+ if encoding == "msgpack":
410
+ channel = f"session.{product_group_id}.{board_id}.msgpack"
411
+ await self._subscribe_channel(channel, [])
412
+
413
+ if on_session:
414
+ self.on("session", on_session)
415
+
387
416
  async def subscribe_ohlc_closed(
388
417
  self,
389
418
  symbols: List[str],
@@ -568,6 +568,141 @@ class Ohlc:
568
568
  )
569
569
 
570
570
 
571
+ @dataclass
572
+ class Session:
573
+ marketId: str
574
+ boardId: str
575
+ eventId: str
576
+ tradingSessionId: int
577
+ tscProdGrpId: str
578
+ receivedAt: Optional[float] = field(default=None, repr=False)
579
+
580
+ @classmethod
581
+ def from_dict(cls, data: Dict[str, Any]) -> "Session":
582
+ return cls(
583
+ marketId=data.get("marketId", ""),
584
+ boardId=data.get("boardId", ""),
585
+ eventId=data.get("eventId", ""),
586
+ tradingSessionId=data.get("tradingSessionId", 0),
587
+ tscProdGrpId=data.get("tscProdGrpId", ""),
588
+ receivedAt=data.get("_receivedAt")
589
+ )
590
+
591
+
592
+ @dataclass
593
+ class Order:
594
+ id: str
595
+ side: str
596
+ accountNo: str
597
+ symbol: str
598
+
599
+ price: float
600
+ priceSecure: float
601
+ averagePrice: float
602
+
603
+ quantity: int
604
+ fillQuantity: int
605
+ canceledQuantity: int
606
+ leaveQuantity: int
607
+
608
+ orderType: str
609
+ orderStatus: str
610
+
611
+ loanPackageId: int
612
+ marketType: str
613
+
614
+ transDate: str
615
+ createdDate: str
616
+ modifiedDate: str
617
+
618
+ @classmethod
619
+ def from_dict(cls, data: Dict[str, Any]) -> "Order":
620
+ return cls(
621
+ id=data.get("id"),
622
+ side=data.get("side"),
623
+ accountNo=data.get("accountNo") or data.get("account_no"),
624
+ symbol=data.get("symbol") or data.get("s"),
625
+
626
+ price=float(data.get("price", 0.0)),
627
+ priceSecure=float(data.get("priceSecure", 0.0)),
628
+ averagePrice=float(data.get("averagePrice", 0.0)),
629
+
630
+ quantity=int(data.get("quantity", 0)),
631
+ fillQuantity=int(data.get("fillQuantity", 0)),
632
+ canceledQuantity=int(data.get("canceledQuantity", 0)),
633
+ leaveQuantity=int(data.get("leaveQuantity", 0)),
634
+
635
+ orderType=data.get("orderType"),
636
+ orderStatus=data.get("orderStatus"),
637
+
638
+ loanPackageId=int(data.get("loanPackageId", 0)),
639
+ marketType=data.get("marketType"),
640
+
641
+ transDate=data.get("transDate"),
642
+ createdDate=data.get("createdDate"),
643
+ modifiedDate=data.get("modifiedDate"),
644
+ )
645
+
646
+
647
+ @dataclass
648
+ class Session:
649
+ marketId: str
650
+ boardId: str
651
+ eventId: str
652
+ tradingSessionId: int
653
+ tscProdGrpId: str
654
+ time: Optional[str] = None
655
+ receivedAt: Optional[float] = field(default=None, repr=False)
656
+
657
+ @classmethod
658
+ def from_dict(cls, data: Dict[str, Any]) -> "Session":
659
+ return cls(
660
+ marketId=data.get("marketId", ""),
661
+ boardId=data.get("boardId", ""),
662
+ eventId=data.get("eventId", ""),
663
+ tradingSessionId=data.get("tradingSessionId", 0),
664
+ tscProdGrpId=data.get("tscProdGrpId", ""),
665
+ time=parse_timestamp(data.get("sendingTime")),
666
+ receivedAt=data.get("_receivedAt"),
667
+ )
668
+
669
+
670
+ @dataclass
671
+ class Position:
672
+ symbol: str
673
+ quantity: int
674
+ averagePrice: Decimal
675
+ marketValue: Decimal
676
+ costBasis: Decimal
677
+ unrealizedPl: Decimal
678
+ unrealizedPlPercent: Decimal
679
+ timestamp: datetime
680
+
681
+ @classmethod
682
+ def from_dict(cls, data: Dict[str, Any]) -> "Position":
683
+ """Parse position from message data.
684
+
685
+ Args:
686
+ data: Raw message dict with either abbreviated or full field names
687
+
688
+ Returns:
689
+ Position instance
690
+
691
+ Example:
692
+ >>> Position.from_dict({"S": "AAPL", "q": 100, "ap": "150.00", ...})
693
+ """
694
+ return cls(
695
+ symbol=data.get("symbol"),
696
+ quantity=data.get("quantity"),
697
+ averagePrice=Decimal(str(data.get("averagePrice"))),
698
+ marketValue=Decimal(str(data.get("marketValue"))),
699
+ costBasis=Decimal(str(data.get("costBasis"))),
700
+ unrealizedPl=Decimal(str(data.get("unrealizedPl"))),
701
+ unrealizedPlPercent=Decimal(str(data.get("unrealizedPlPercent"))),
702
+ timestamp=datetime.fromtimestamp((data.get("timestamp")) / 1000),
703
+ )
704
+
705
+
571
706
  @dataclass
572
707
  class AccountUpdate:
573
708
  cash: Decimal
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dnse-sdk-openapi
3
- Version: 1.4.2
3
+ Version: 1.4.4
4
4
  Summary: DNSE OpenAPI SDK
5
5
  Description-Content-Type: text/markdown
6
6
 
@@ -17,13 +17,16 @@ dnse_sdk_openapi.egg-info/PKG-INFO
17
17
  dnse_sdk_openapi.egg-info/SOURCES.txt
18
18
  dnse_sdk_openapi.egg-info/dependency_links.txt
19
19
  dnse_sdk_openapi.egg-info/top_level.txt
20
+ marketdata-api/get_foreign_trading.py
20
21
  marketdata-api/get_instruments.py
22
+ marketdata-api/get_lastest_session.py
21
23
  marketdata-api/get_latest_quote.py
22
24
  marketdata-api/get_latest_trade.py
23
25
  marketdata-api/get_ohlc.py
24
26
  marketdata-api/get_quotes.py
25
27
  marketdata-api/get_security_definition.py
26
28
  marketdata-api/get_trades.py
29
+ marketdata-api/get_trading_session.py
27
30
  marketdata-api/get_working_dates.py
28
31
  trading-api/cancel_order.py
29
32
  trading-api/close_position.py
@@ -51,8 +54,10 @@ websocket-marketdata/ohlc.py
51
54
  websocket-marketdata/ohlc_closed.py
52
55
  websocket-marketdata/quote.py
53
56
  websocket-marketdata/sec_def.py
57
+ websocket-marketdata/session.py
54
58
  websocket-marketdata/trade.py
55
59
  websocket-marketdata/trade_extra.py
56
60
  websocket-trading/broker_order.py
61
+ websocket-trading/broker_position.py
57
62
  websocket-trading/order.py
58
63
  websocket-trading/position.py
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env python3
2
+ import os
3
+ import sys
4
+
5
+ sys.path.insert(0, 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.get_foreign_trading(symbol="SSI", board_id="G1", from_date=1781037427, to_date=1781062643, limit = 100, order = "DESC", next_page_token=None, dry_run=False)
18
+ print(status, body)
19
+
20
+
21
+ if __name__ == "__main__":
22
+ main()
@@ -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.get_lastest_session(tsc_prod_grp_id="FIO", board_id="G1", dry_run=False)
18
+ print(status, body)
19
+
20
+
21
+ if __name__ == "__main__":
22
+ main()
@@ -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.get_trading_session(tsc_prod_grp_id="FBX", board_id="", dry_run=False)
18
+ print(status, body)
19
+
20
+
21
+ if __name__ == "__main__":
22
+ main()
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dnse-sdk-openapi"
7
- version = "1.4.2"
7
+ version = "1.4.4"
8
8
  description = "DNSE OpenAPI SDK"
9
9
  readme = "README.md"
10
10
 
@@ -0,0 +1,54 @@
1
+ """
2
+ Demonstrates:
3
+ - Subscribing to session data
4
+
5
+ This example shows how to receive real-time session data
6
+ """
7
+
8
+ import asyncio
9
+ import os
10
+ import sys
11
+ from datetime import datetime
12
+
13
+ sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
14
+
15
+ from dnse import TradingClient
16
+ from dnse.websocket.models import Session
17
+
18
+
19
+ async def main():
20
+ # Initialize client
21
+ encoding = "msgpack" # json or msgpack
22
+ client = TradingClient(
23
+ api_key="api-key",
24
+ api_secret="api-secret",
25
+ base_url="wss://ws-openapi.dnse.com.vn",
26
+ encoding=encoding,
27
+ )
28
+
29
+ def handle_session(session: Session):
30
+ received_at = datetime.fromtimestamp(session.receivedAt).strftime("%H:%M:%S.%f")[:-3] if session.receivedAt else "N/A"
31
+ print(f"[{received_at}] Session: {session}")
32
+
33
+ # Connect to gateway
34
+ print("Connecting to WebSocket gateway...")
35
+ await client.connect()
36
+ print(f"Connected! Session ID: {client._session_id}\n")
37
+
38
+ print("Subscribing to session data...")
39
+ await client.subscribe_session(product_group_id="STX", board_id = "G1", on_session=handle_session, encoding=encoding)
40
+
41
+ print("\nReceiving session data (will run for 1 hour)...\n")
42
+
43
+ # Run for 8H to collect data
44
+ # In a real application, you might run indefinitely or until a specific condition
45
+ await asyncio.sleep(8 * 60 * 60)
46
+
47
+ # Disconnect gracefully
48
+ print("\n\nDisconnecting...")
49
+ await client.disconnect()
50
+ print("Disconnected!")
51
+
52
+
53
+ if __name__ == "__main__":
54
+ asyncio.run(main())
@@ -0,0 +1,53 @@
1
+ """
2
+ Position event subscription example.
3
+
4
+ This example shows how to receive real-time customer's position events of broker for stock and derivative
5
+ """
6
+
7
+ import asyncio
8
+ from datetime import datetime
9
+
10
+ from dnse import TradingClient
11
+ from dnse.websocket.models import Position
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_position(data: Position):
25
+ received_at = datetime.fromtimestamp(data.receivedAt).strftime("%H:%M:%S.%f")[:-3] if data.receivedAt else "N/A"
26
+ print(f"[{received_at}] Position: {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 position event")
34
+ # market_type: DERIVATIVE | STOCK
35
+ await client.subscribe_broker_position_event(
36
+ investor_id="your-customer-investor-id",
37
+ market_type="STOCK",
38
+ on_position_event=handle_position, encoding=encoding)
39
+
40
+ print("\nReceiving position event (will run for 8 hour)...\n")
41
+
42
+ # Run for 8H to collect data
43
+ # In a real application, you might run indefinitely or until a specific condition
44
+ await asyncio.sleep(8 * 60 * 60)
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())