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.
Files changed (50) hide show
  1. broker-api/get_list_care_by.py +22 -0
  2. dnse/__init__.py +4 -0
  3. dnse/client.py +408 -0
  4. dnse/common.py +103 -0
  5. dnse_sdk_openapi-0.0.1.dist-info/METADATA +120 -0
  6. dnse_sdk_openapi-0.0.1.dist-info/RECORD +50 -0
  7. dnse_sdk_openapi-0.0.1.dist-info/WHEEL +5 -0
  8. dnse_sdk_openapi-0.0.1.dist-info/top_level.txt +5 -0
  9. marketdata-api/get_instruments.py +22 -0
  10. marketdata-api/get_latest_trade.py +22 -0
  11. marketdata-api/get_ohlc.py +31 -0
  12. marketdata-api/get_security_definition.py +22 -0
  13. marketdata-api/get_trades.py +22 -0
  14. marketdata-api/get_working_dates.py +22 -0
  15. trading-api/cancel_order.py +29 -0
  16. trading-api/close_position.py +27 -0
  17. trading-api/create_trading_token.py +26 -0
  18. trading-api/get_accounts.py +22 -0
  19. trading-api/get_balances.py +22 -0
  20. trading-api/get_close_price.py +22 -0
  21. trading-api/get_execution_detail.py +28 -0
  22. trading-api/get_loan_packages.py +27 -0
  23. trading-api/get_order_detail.py +28 -0
  24. trading-api/get_order_history.py +30 -0
  25. trading-api/get_orders.py +27 -0
  26. trading-api/get_position_by_id.py +26 -0
  27. trading-api/get_positions.py +26 -0
  28. trading-api/get_ppse.py +29 -0
  29. trading-api/post_order.py +38 -0
  30. trading-api/put_order.py +35 -0
  31. trading-api/send_email_otp.py +22 -0
  32. websocket-marketdata/expected_price.py +53 -0
  33. websocket-marketdata/foreign_investor.py +51 -0
  34. websocket-marketdata/market_index.py +52 -0
  35. websocket-marketdata/ohlc.py +55 -0
  36. websocket-marketdata/ohlc_closed.py +55 -0
  37. websocket-marketdata/order.py +51 -0
  38. websocket-marketdata/quote.py +50 -0
  39. websocket-marketdata/sec_def.py +52 -0
  40. websocket-marketdata/trade.py +52 -0
  41. websocket-marketdata/trade_extra.py +51 -0
  42. websocket-marketdata/trading_websocket/__init__.py +33 -0
  43. websocket-marketdata/trading_websocket/_version.py +3 -0
  44. websocket-marketdata/trading_websocket/auth.py +59 -0
  45. websocket-marketdata/trading_websocket/client.py +790 -0
  46. websocket-marketdata/trading_websocket/connection.py +151 -0
  47. websocket-marketdata/trading_websocket/encoding.py +78 -0
  48. websocket-marketdata/trading_websocket/exceptions.py +38 -0
  49. websocket-marketdata/trading_websocket/models.py +525 -0
  50. 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.get_list_care_by(dry_run=False)
18
+ print(status, body)
19
+
20
+
21
+ if __name__ == "__main__":
22
+ main()
dnse/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env python3
2
+ from .client import DNSEClient
3
+
4
+ __all__ = ["DNSEClient"]
dnse/client.py ADDED
@@ -0,0 +1,408 @@
1
+ #!/usr/bin/env python3
2
+ import json
3
+ import os
4
+ from urllib import parse
5
+ import urllib3
6
+
7
+
8
+ from .common import build_signature, get_date_header_name
9
+
10
+
11
+ class DNSEClient:
12
+ def __init__(
13
+ self,
14
+ api_key,
15
+ api_secret,
16
+ base_url="https://openapi.dnse.com.vn",
17
+ algorithm="hmac-sha256",
18
+ hmac_nonce_enabled=True,
19
+ ):
20
+ self._api_key = api_key
21
+ self._api_secret = api_secret
22
+ self._base_url = base_url.rstrip("/")
23
+ self._algorithm = algorithm
24
+ self._hmac_nonce_enabled = hmac_nonce_enabled
25
+
26
+ # Tạo PoolManager 1 lần duy nhất, tái sử dụng suốt vòng đời object
27
+ self._http = urllib3.PoolManager(
28
+ num_pools=10, # Số lượng connection pools
29
+ maxsize=10, # Số connections tối đa mỗi pool
30
+ block=False, # Không block khi pool đầy
31
+ timeout=urllib3.Timeout(connect=30.0, read=60.0),
32
+ # cert_reqs = 'CERT_NONE', # Không yêu cầu certificate
33
+ # assert_hostname = False # Không kiểm tra hostname
34
+ )
35
+
36
+ def get_accounts(self, dry_run=False):
37
+ return self._request("GET", "/accounts", dry_run=dry_run)
38
+
39
+ def get_balances(self, account_no, dry_run=False):
40
+ return self._request("GET", f"/accounts/{account_no}/balances", dry_run=dry_run)
41
+
42
+ def get_loan_packages(self, account_no, market_type, symbol=None, dry_run=False):
43
+ query = {"marketType": market_type}
44
+ if symbol:
45
+ query["symbol"] = symbol
46
+ return self._request(
47
+ "GET",
48
+ f"/accounts/{account_no}/loan-packages",
49
+ query=query,
50
+ dry_run=dry_run,
51
+ )
52
+
53
+ def get_positions(self, account_no, market_type, dry_run=False):
54
+ return self._request(
55
+ "GET",
56
+ f"/accounts/{account_no}/positions",
57
+ query={"marketType": market_type},
58
+ dry_run=dry_run,
59
+ )
60
+
61
+ def get_position_by_id(self, market_type, position_id, dry_run=False):
62
+ return self._request(
63
+ "GET",
64
+ f"/accounts/positions/{position_id}",
65
+ query={"marketType": market_type},
66
+ dry_run=dry_run,
67
+ )
68
+
69
+ def get_orders(self, account_no, market_type, order_category=None, dry_run=False):
70
+ query = {"marketType": market_type}
71
+ if order_category:
72
+ query["orderCategory"] = order_category
73
+ return self._request(
74
+ "GET",
75
+ f"/accounts/{account_no}/orders",
76
+ query=query,
77
+ dry_run=dry_run,
78
+ )
79
+
80
+ def get_order_detail(self, account_no, order_id, market_type, order_category=None, dry_run=False):
81
+ query = {"marketType": market_type}
82
+ if order_category:
83
+ query["orderCategory"] = order_category
84
+ return self._request(
85
+ "GET",
86
+ f"/accounts/{account_no}/orders/{order_id}",
87
+ query=query,
88
+ dry_run=dry_run,
89
+ )
90
+
91
+ def get_execution_detail(self, account_no, order_id, market_type, order_category="NORMAL", dry_run=False):
92
+ query = {"marketType": market_type}
93
+ if order_category:
94
+ query["orderCategory"] = order_category
95
+ return self._request(
96
+ "GET",
97
+ f"/accounts/{account_no}/executions/{order_id}",
98
+ query=query,
99
+ dry_run=dry_run,
100
+ )
101
+
102
+ def get_order_history(
103
+ self,
104
+ account_no,
105
+ market_type,
106
+ from_date=None,
107
+ to_date=None,
108
+ page_size=None,
109
+ page_index=None,
110
+ dry_run=False,
111
+ ):
112
+ query = {"marketType": market_type}
113
+ if from_date:
114
+ query["from"] = from_date
115
+ if to_date:
116
+ query["to"] = to_date
117
+ if page_size is not None:
118
+ query["pageSize"] = page_size
119
+ if page_index is not None:
120
+ query["pageIndex"] = page_index
121
+ return self._request(
122
+ "GET",
123
+ f"/accounts/{account_no}/orders/history",
124
+ query=query,
125
+ dry_run=dry_run,
126
+ )
127
+
128
+ def get_ppse(self, account_no, market_type, symbol, price, loan_package_id, dry_run=False):
129
+ return self._request(
130
+ "GET",
131
+ f"/accounts/{account_no}/ppse",
132
+ query={
133
+ "marketType": market_type,
134
+ "symbol": symbol,
135
+ "price": str(price),
136
+ "loanPackageId": str(loan_package_id),
137
+ },
138
+ dry_run=dry_run,
139
+ )
140
+
141
+ def get_security_definition(self, symbol, board_id=None, dry_run=False):
142
+ query = {}
143
+ if board_id:
144
+ query["boardId"] = board_id
145
+ return self._request(
146
+ "GET",
147
+ f"/price/{symbol}/secdef",
148
+ query=query if query else None,
149
+ dry_run=dry_run,
150
+ )
151
+
152
+ def get_ohlc(self, bar_type, query=None, dry_run=False):
153
+ request_query = dict(query or {})
154
+ request_query["type"] = bar_type
155
+ return self._request(
156
+ "GET",
157
+ "/price/ohlc",
158
+ query=request_query,
159
+ dry_run=dry_run,
160
+ )
161
+
162
+ def get_trades(self, symbol, board_id=None, from_date=None, to_date=None, limit=None, order = None, next_page_token=None, dry_run=False):
163
+ query = {}
164
+ if board_id is not None:
165
+ query["boardId"] = board_id
166
+ if from_date is not None:
167
+ query["from"] = from_date
168
+ if to_date is not None:
169
+ query["to"] = to_date
170
+ if limit is not None:
171
+ query["limit"] = limit
172
+ if order is not None:
173
+ query["order"] = order
174
+ if next_page_token is not None:
175
+ query["nextPageToken"] = next_page_token
176
+ return self._request(
177
+ "GET",
178
+ f"/price/{symbol}/trades",
179
+ query=query if query else None,
180
+ dry_run=dry_run,
181
+ )
182
+
183
+ def get_instruments(self, symbol=None, market_id=None, security_group_id=None, index_name=None, limit=None, page=None, dry_run=False):
184
+ query = {}
185
+ if symbol is not None:
186
+ query["symbol"] = symbol
187
+ if market_id is not None:
188
+ query["marketId"] = market_id
189
+ if security_group_id is not None:
190
+ query["securityGroupId"] = security_group_id
191
+ if index_name is not None:
192
+ query["indexName"] = index_name
193
+ if limit is not None:
194
+ query["limit"] = limit
195
+ if page is not None:
196
+ query["page"] = page
197
+ return self._request(
198
+ "GET",
199
+ f"/instruments",
200
+ query=query if query else None,
201
+ dry_run=dry_run,
202
+ )
203
+
204
+ def get_latest_trade(self, symbol, board_id=None, dry_run=False):
205
+ query = {}
206
+ if board_id is not None:
207
+ query["boardId"] = board_id
208
+ return self._request(
209
+ "GET",
210
+ f"/price/{symbol}/trades/latest",
211
+ query=query if query else None,
212
+ dry_run=dry_run,
213
+ )
214
+
215
+ def get_close_price(self, symbol, board_id=None, dry_run=False):
216
+ query = {}
217
+ if board_id is not None:
218
+ query["boardId"] = board_id
219
+ return self._request(
220
+ "GET",
221
+ f"/price/{symbol}/close",
222
+ query=query if query else None,
223
+ dry_run=dry_run,
224
+ )
225
+
226
+ def get_working_dates(self, dry_run=False):
227
+ return self._request(
228
+ "GET",
229
+ f"/market/working-dates",
230
+ dry_run=dry_run,
231
+ )
232
+
233
+ def get_list_care_by(self, dry_run=False):
234
+ return self._request(
235
+ "GET",
236
+ f"/brokers/accounts/care-by",
237
+ dry_run=dry_run,
238
+ )
239
+
240
+ def post_order(self, market_type, payload, trading_token, order_category="NORMAL", dry_run=False):
241
+ headers = {"trading-token": trading_token}
242
+ query = {"marketType": market_type}
243
+ if order_category:
244
+ query["orderCategory"] = order_category
245
+ return self._request(
246
+ "POST",
247
+ "/accounts/orders",
248
+ query=query,
249
+ body=payload,
250
+ headers=headers,
251
+ dry_run=dry_run,
252
+ )
253
+
254
+ def put_order(
255
+ self,
256
+ account_no,
257
+ order_id,
258
+ market_type,
259
+ payload,
260
+ trading_token,
261
+ order_category=None,
262
+ dry_run=False,
263
+ ):
264
+ headers = {"trading-token": trading_token}
265
+ query = {"marketType": market_type}
266
+ if order_category:
267
+ query["orderCategory"] = order_category
268
+ return self._request(
269
+ "PUT",
270
+ f"/accounts/{account_no}/orders/{order_id}",
271
+ query=query,
272
+ body=payload,
273
+ headers=headers,
274
+ dry_run=dry_run,
275
+ )
276
+
277
+ def cancel_order(
278
+ self,
279
+ account_no,
280
+ order_id,
281
+ market_type,
282
+ trading_token,
283
+ order_category=None,
284
+ dry_run=False,
285
+ ):
286
+ headers = {"trading-token": trading_token}
287
+ query = {"marketType": market_type}
288
+ if order_category:
289
+ query["orderCategory"] = order_category
290
+ return self._request(
291
+ "DELETE",
292
+ f"/accounts/{account_no}/orders/{order_id}",
293
+ query=query,
294
+ headers=headers,
295
+ dry_run=dry_run,
296
+ )
297
+
298
+ def create_trading_token(self, otp_type, passcode, dry_run=False):
299
+ return self._request(
300
+ "POST",
301
+ "/registration/trading-token",
302
+ body={"otpType": otp_type, "passcode": passcode},
303
+ dry_run=dry_run,
304
+ )
305
+
306
+ def send_email_otp(self, dry_run=False):
307
+ return self._request(
308
+ "POST",
309
+ "/registration/send-email-otp",
310
+ dry_run=dry_run,
311
+ )
312
+
313
+ def close_position(self, position_id, market_type, trading_token, dry_run=False):
314
+ headers = {"trading-token": trading_token}
315
+ query = {"marketType": market_type}
316
+ return self._request(
317
+ "POST",
318
+ f"/accounts/positions/{position_id}/close",
319
+ query=query,
320
+ headers=headers,
321
+ dry_run=dry_run,
322
+ )
323
+
324
+ def _request(self, method, path, query=None, body=None, headers=None, dry_run=False):
325
+ debug = os.getenv("DEBUG", "").lower() == "true"
326
+ url = self._build_url(path, query)
327
+ date_value, signature_header_value = self._signature_headers(method, path)
328
+ date_header_name = get_date_header_name()
329
+
330
+ # Build headers dict
331
+ req_headers = {
332
+ date_header_name: date_value,
333
+ "X-Signature": signature_header_value,
334
+ "x-api-key": self._api_key,
335
+ }
336
+
337
+ if body is not None:
338
+ req_headers["Content-Type"] = "application/json"
339
+
340
+ if headers:
341
+ req_headers.update(headers)
342
+
343
+ # Prepare body data
344
+ data = None
345
+ if body is not None:
346
+ data = json.dumps(body)
347
+
348
+ if debug or dry_run:
349
+ prefix = "DRY RUN" if dry_run else "DEBUG"
350
+ print(f"{prefix} url:", url)
351
+ print(f"{prefix} method:", method)
352
+ print(f"{prefix} query_params:", query or {})
353
+ print(f"{prefix} headers:", req_headers)
354
+ print(f"{prefix} body:", body)
355
+
356
+ if dry_run:
357
+ return None, None
358
+
359
+ try:
360
+ resp = self._http.request(
361
+ method,
362
+ url,
363
+ body=data,
364
+ headers=req_headers,
365
+ )
366
+ body_text = resp.data.decode("utf-8")
367
+ return resp.status, body_text
368
+ except urllib3.exceptions.HTTPError as err:
369
+ if hasattr(err, 'response') and err.response:
370
+ body_text = err.response.data.decode("utf-8") if err.response.data else ""
371
+ return err.response.status, body_text
372
+ raise
373
+
374
+ def _build_url(self, path, query):
375
+ url = f"{self._base_url}{path}"
376
+ if query:
377
+ url = f"{url}?{parse.urlencode(query)}"
378
+ return url
379
+
380
+ def _signature_headers(self, method, path):
381
+ date_value = self._date_header()
382
+ nonce = None
383
+ if self._hmac_nonce_enabled:
384
+ import uuid
385
+
386
+ nonce = uuid.uuid4().hex
387
+
388
+ headers_list, signature = build_signature(
389
+ self._api_secret,
390
+ method,
391
+ path,
392
+ date_value,
393
+ self._algorithm,
394
+ nonce=nonce,
395
+ header_name=get_date_header_name(),
396
+ )
397
+ signature_header_value = (
398
+ f'Signature keyId="{self._api_key}",algorithm="{self._algorithm}",'
399
+ f'headers="{headers_list}",signature="{signature}"'
400
+ )
401
+ if nonce:
402
+ signature_header_value += f',nonce="{nonce}"'
403
+ return date_value, signature_header_value
404
+
405
+ def _date_header(self):
406
+ from datetime import datetime, timezone
407
+
408
+ return datetime.now(timezone.utc).strftime("%a, %d %b %Y %H:%M:%S %z")
dnse/common.py ADDED
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env python3
2
+ import base64
3
+ import hashlib
4
+ import hmac
5
+ import json
6
+ import os
7
+ from datetime import datetime, timezone
8
+ from urllib import parse, request
9
+ from uuid import uuid4
10
+
11
+
12
+ def get_date_header_name():
13
+ return os.getenv("DATE_HEADER", "Date")
14
+
15
+
16
+ def build_signature(secret, method, path, date_value, algorithm, nonce=None, header_name=None):
17
+ header_name = header_name or get_date_header_name()
18
+ header_key = header_name.lower()
19
+ headers = f"(request-target) {header_key}"
20
+ signature_string = (
21
+ f"(request-target): {method.lower()} {path}\n" f"{header_key}: {date_value}"
22
+ )
23
+ if nonce:
24
+ signature_string += f"\nnonce: {nonce}"
25
+
26
+ if algorithm == "hmac-sha256":
27
+ digestmod = hashlib.sha256
28
+ elif algorithm == "hmac-sha384":
29
+ digestmod = hashlib.sha384
30
+ elif algorithm == "hmac-sha512":
31
+ digestmod = hashlib.sha512
32
+ else:
33
+ digestmod = hashlib.sha1
34
+
35
+ mac = hmac.new(secret.encode("utf-8"), signature_string.encode("utf-8"), digestmod)
36
+ encoded = base64.b64encode(mac.digest()).decode("utf-8")
37
+ escaped = parse.quote(encoded, safe="")
38
+
39
+ return headers, escaped
40
+
41
+
42
+ def send_signed_request(
43
+ url,
44
+ method,
45
+ headers,
46
+ body,
47
+ api_key,
48
+ api_secret,
49
+ algorithm="hmac-sha256",
50
+ hmac_nonce_enabled=True,
51
+ ):
52
+ debug = os.getenv("DEBUG", "").lower() == "true"
53
+ parsed = parse.urlparse(url)
54
+ path = parsed.path
55
+ date_value = datetime.now(timezone.utc).strftime("%a, %d %b %Y %H:%M:%S %z")
56
+ date_header_name = get_date_header_name()
57
+
58
+ nonce = uuid4().hex if hmac_nonce_enabled else None
59
+ headers_list, signature = build_signature(
60
+ api_secret,
61
+ method,
62
+ path,
63
+ date_value,
64
+ algorithm,
65
+ nonce=nonce,
66
+ header_name=date_header_name,
67
+ )
68
+ signature_header_value = (
69
+ f'Signature keyId="{api_key}",algorithm="{algorithm}",'
70
+ f'headers="{headers_list}",signature="{signature}"'
71
+ )
72
+ if nonce:
73
+ signature_header_value += f',nonce="{nonce}"'
74
+
75
+ data = None
76
+ if body is not None:
77
+ data = json.dumps(body).encode("utf-8")
78
+ headers.setdefault("Content-Type", "application/json")
79
+
80
+ req = request.Request(url, data=data, method=method)
81
+ req.add_header(date_header_name, date_value)
82
+ req.add_header("X-Signature", signature_header_value)
83
+
84
+ for key, value in headers.items():
85
+ req.add_header(key, value)
86
+
87
+ if debug:
88
+ query_params = parse.parse_qs(parsed.query)
89
+ print("DEBUG url:", url)
90
+ print("DEBUG method:", method)
91
+ print("DEBUG query_params:", query_params)
92
+ print("DEBUG headers:", dict(req.header_items()))
93
+ print("DEBUG body:", body)
94
+
95
+ try:
96
+ with request.urlopen(req) as resp:
97
+ body_text = resp.read().decode("utf-8")
98
+ print(body_text)
99
+ except request.HTTPError as err:
100
+ body_text = err.read().decode("utf-8") if err.fp else ""
101
+ print(f"HTTP {err.code} {err.reason}")
102
+ if body_text:
103
+ print(body_text)
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.4
2
+ Name: dnse-sdk-openapi
3
+ Version: 0.0.1
4
+ Summary: DNSE OpenAPI SDK
5
+ Description-Content-Type: text/markdown
6
+
7
+ # DNSE OpenAPI Python SDK
8
+
9
+ Official Python SDK for integrating with DNSE OpenAPI.
10
+
11
+ ## Table of Contents
12
+
13
+ - [Overview](#overview)
14
+ - [Installation](#installation)
15
+ - [Usage](#usage)
16
+ - [Dry Run](#dry-run)
17
+ - [Examples](#examples)
18
+
19
+ ### Overview
20
+
21
+ DNSE OpenAPI is an API-first trading platform that enables developers to integrate brokerage, trading, margin, and market data services
22
+ into their own applications.
23
+
24
+ The DNSE Python SDK provides a lightweight client for securely interacting with DNSE OpenAPI REST endpoints. It handles request
25
+ signing, authentication, and communication details, allowing developers to focus on building trading systems, automation strategies,
26
+ and investment applications.
27
+
28
+ ### Installation
29
+
30
+ #### Requirements
31
+
32
+ - Python 3.8+
33
+
34
+ #### Install from PyPI
35
+
36
+ ```console
37
+ pip install openapi-sdk
38
+ ```
39
+
40
+ Upgrade
41
+
42
+ ### Usage
43
+
44
+ Create a `DNSEClient` instance with your API credentials:
45
+
46
+ ```python
47
+ from dnse import DNSEClient
48
+
49
+ client = DNSEClient(
50
+ api_key="your_api_key",
51
+ api_secret="your_api_secret",
52
+ base_url="https://openapi.dnse.com.vn",
53
+ )
54
+
55
+ status, body = client.get_accounts(dry_run=False)
56
+ print(status, body)
57
+ ```
58
+
59
+ ### Dry Run
60
+
61
+ Set `dry_run=True` to preview the request without sending it to DNSE servers. No network call will be executed.
62
+
63
+ ```python
64
+ client.get_accounts(dry_run=True)
65
+ ```
66
+
67
+ ### Examples
68
+
69
+ Run any example from the `sdk/python/examples` directory:
70
+
71
+ ```
72
+ python sdk/python/api/get_accounts.py
73
+ ```
74
+
75
+ #### Trading API
76
+
77
+ | Function | Description |
78
+ |---------------------------|-----------------------------------------------------------------------------------------------------------------------|
79
+ | `get_accounts.py` | Demonstrates how to retrieve all trading sub-accounts managed under the account corresponding to the API Key. |
80
+ | `get_balances.py` | Demonstrates how to retrieve asset balances of a trading sub-account. |
81
+ | `get_loan_packages.py` | Demonstrates how to retrieve available loan package codes. It is necessary for placing an order. |
82
+ | `get_ppse.py` | Demonstrates how to retrieve buying power and selling power before placing an order. |
83
+ | `get_orders.py` | Demonstrates how to retrieve intraday order book. |
84
+ | `get_order_detail.py` | Demonstrates how to retrieve detailed information of a specific order (by ID). |
85
+ | `get_order_history.py` | Demonstrates how to retrieve historical orders. |
86
+ | `get_execution_detail.py` | Demonstrates how to retrieve detailed execution information of an order. |
87
+ | `get_positions.py` | Demonstrates how to retrieve current holding positions. |
88
+ | `get_positions_by_id.py` | Demonstrates how to retrieve detailed information of a specific position (by ID). |
89
+ | `close_position.py` | Demonstrates how to close an existing position (by ID). |
90
+ | `send_email_otp.py` | Demonstrates how to request an OTP sent to your registered email. The OTP is required for generating a trading token. |
91
+ | `create_trading_token.py` | Demonstrates how to generate a Trading Token required for order placement. |
92
+ | `post_order.py` | Demonstrates how to submit a new trading order. |
93
+ | `cancel_order.py` | Demonstrates how to cancel an existing order. |
94
+ | `replace_order.py` | Demonstrates how to modify an existing order. |
95
+
96
+ #### Market Data API
97
+
98
+ | Function | Description |
99
+ |------------------------------|--------------------------------------------------------------------------------------------|
100
+ | `get_security_definition.py` | Demonstrates how to retrieve security definition and instrument details. |
101
+ | `get_instruments.py` | Demonstrates how to retrieve the list of available trading instruments and their metadata. |
102
+ | `get_trades.py` | Demonstrates how to retrieve historical trade data for a specific instrument. |
103
+ | `get_latest_trade.py` | Demonstrates how to retrieve the most recent trade for a specific instrument. |
104
+ | `get_ohlc.py` | Demonstrates how to retrieve OHLC (Open, High, Low, Close) data for a given time range. |
105
+ | `get_close_price.py` | Demonstrates how to retrieve the latest closing price of a specific instrument. |
106
+ | `get_working_dates.py` | Demonstrates how to retrieve trading working dates. |
107
+
108
+ ### WebSocket Market Data
109
+
110
+ | Function | Description |
111
+ |-----------------------|--------------------------------------------------------------------------------------|
112
+ | `sec_def.py` | Demonstrates how to receive real-time security definition updates. |
113
+ | `quote.py` | Demonstrates how to receive real-time best bid and ask prices. |
114
+ | `trade.py` | Demonstrates how to receive real-time trade (tick) data. |
115
+ | `trade_extra.py` | Demonstrates how to receive real-time trade data with additional aggregated metrics. |
116
+ | `ohlc.py` | Demonstrates how to receive real-time OHLC data. |
117
+ | `ohlc_closed.py` | Demonstrates how to receive completed OHLC candle data. |
118
+ | `expected_price.py` | Demonstrates how to receive expected price data during ATO and ATC sessions. |
119
+ | `foreign_investor.py` | Demonstrates how to receive foreign investor trading data. |
120
+ | `market_index.py` | Demonstrates how to receive market index data. |