HedgeTech 0.1.0__py3-none-any.whl → 0.2.2b0__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.
@@ -0,0 +1,790 @@
1
+ # ========================================|======================================== #
2
+ # Imports #
3
+ # ========================================|======================================== #
4
+
5
+ from typing import (
6
+ Literal,
7
+ )
8
+ from .__io_types import (
9
+ HexUUID,
10
+ OrderStatus,
11
+ )
12
+ from HedgeTech.Auth import AuthSyncClient
13
+ from PIL.Image import open as image_open
14
+ from PIL.ImageFile import ImageFile
15
+ from io import BytesIO
16
+
17
+ # ========================================|======================================== #
18
+ # Class Definitions #
19
+ # ========================================|======================================== #
20
+
21
+ class Order:
22
+
23
+ """
24
+ Represents a single trading order in EMS Engine.
25
+
26
+ This class provides methods to send, edit, check status,
27
+ and delete an order after creation.
28
+
29
+ An Order instance is usually created via
30
+ `EmsEngine_TseIfb_SyncClient` methods.
31
+ """
32
+
33
+ def __init__(
34
+ self,
35
+ *,
36
+ SendOrder_RequestInfo : dict,
37
+ AuthSyncClient : AuthSyncClient,
38
+ SymbolNameOrIsin : str,
39
+ Price : int,
40
+ Volume :int,
41
+ ValidityDate : int = 0,
42
+ Order_ValidityType : Literal[
43
+ 'DAY',
44
+ 'GTC', # Good Till Cancelled
45
+ 'GTD', # Good Till Date
46
+ 'FAK', # Fill And Kill
47
+ 'FOK', # Fill Or Kill
48
+ ] = 'DAY',
49
+ ):
50
+
51
+ """
52
+ Initialize a new Order object.
53
+
54
+ Parameters
55
+ ----------
56
+ SendOrder_RequestInfo : dict
57
+ HTTP request configuration for sending the order.
58
+
59
+ AuthSyncClient : AuthSyncClient
60
+ Authenticated HTTP client.
61
+
62
+ Order_ValidityType : Literal
63
+ Order validity type.
64
+
65
+ ValidityDate : int
66
+ Expiration date (for GTD orders).
67
+
68
+ SymbolNameOrIsin : str
69
+ Symbol name or ISIN code.
70
+
71
+ Price : int
72
+ Order price.
73
+
74
+ Volume : int
75
+ Order volume.
76
+
77
+ Examples
78
+ --------
79
+ >>> order = client.Buy_by_Name(
80
+ ... symbolName="اهرم",
81
+ ... Price=12000,
82
+ ... Volume=1000
83
+ ... )
84
+ """
85
+
86
+ self.__AuthSyncClient = AuthSyncClient
87
+ self.__SendOrder_RequestInfo = SendOrder_RequestInfo
88
+
89
+ self.ValidityType : str = Order_ValidityType
90
+ self.ValidityDate : int = ValidityDate
91
+ self.SymbolNameOrIsin : str = SymbolNameOrIsin
92
+ self.Price : int = Price
93
+ self.Volume : int = Volume
94
+ self.is_deleted : bool = False
95
+
96
+ self.OrderId : HexUUID | None = None
97
+
98
+
99
+ # +--------------------------------------------------------------------------------------+ #
100
+
101
+ def send(self)-> None:
102
+
103
+ """
104
+ Send the order to the trading engine.
105
+
106
+ This method submits the order to EMS Engine
107
+ and assigns OrderId on success.
108
+
109
+ Returns
110
+ -------
111
+ None
112
+
113
+ Notes
114
+ -----
115
+ - Can be called only once.
116
+ - Subsequent calls have no effect.
117
+
118
+ Examples
119
+ --------
120
+ >>> order.send()
121
+ >>> print(order.OrderId)
122
+ '0xA23F...'
123
+ """
124
+
125
+ if self.OrderId is None :
126
+
127
+ SendOrder_Response = self.__AuthSyncClient.httpx_Client.post(**self.__SendOrder_RequestInfo)
128
+
129
+ match SendOrder_Response.status_code :
130
+
131
+ case 200 :
132
+
133
+ self.OrderId = SendOrder_Response.json()['Data']['order_uuid']
134
+ return None
135
+
136
+ case _ : return None
137
+
138
+ else : return None
139
+
140
+ # +--------------------------------------------------------------------------------------+ #
141
+
142
+ def Edit(
143
+ self,
144
+ *,
145
+ Price : int,
146
+ Volume :int,
147
+ Order_ValidityType : Literal[
148
+ 'DAY',
149
+ 'GTC', # Good Till Cancelled
150
+ 'GTD', # Good Till Date
151
+ 'FAK', # Fill And Kill
152
+ 'FOK', # Fill Or Kill
153
+ ] = 'DAY',
154
+ ValidityDate : int = 0,
155
+ )-> None:
156
+
157
+ """
158
+ Edit an existing order.
159
+
160
+ Parameters
161
+ ----------
162
+ Order_ValidityType : Literal
163
+ New validity type.
164
+
165
+ ValidityDate : int
166
+ New expiration date.
167
+
168
+ Price : int
169
+ New order price.
170
+
171
+ Volume : int
172
+ New order volume.
173
+
174
+ Returns
175
+ -------
176
+ None
177
+
178
+ Raises
179
+ ------
180
+ None
181
+
182
+ Examples
183
+ --------
184
+ >>> order.Edit(Price=12500, Volume=800)
185
+ """
186
+
187
+ if self.OrderId is not None:
188
+
189
+ Edit_response = self.__AuthSyncClient.httpx_Client.patch(
190
+ url='https://core.hedgetech.ir/ems-engine/tse-ifb/order/edit',
191
+ data={
192
+ 'order_uuid' : self.OrderId,
193
+ 'Order_ValidityType' : Order_ValidityType,
194
+ 'ValidityDate' : ValidityDate,
195
+ 'Price' : Price,
196
+ 'Volume' : Volume
197
+ }
198
+ )
199
+
200
+
201
+ match Edit_response.status_code:
202
+
203
+ case 200:
204
+
205
+ Edit_response = Edit_response.json()
206
+
207
+ self.OrderId = Edit_response['Data']['order_uuid']
208
+ self.ValidityType = Edit_response['Data']['order_validity_type']
209
+ self.ValidityDate = ValidityDate
210
+ self.Price = Edit_response['Data']['order_price']
211
+ self.Volume = Edit_response['Data']['order_volume']
212
+
213
+ return None
214
+
215
+ case _ : return None
216
+
217
+ else : return None
218
+
219
+ # +--------------------------------------------------------------------------------------+ #
220
+
221
+ def Status(self)-> OrderStatus | None:
222
+
223
+ """
224
+ Retrieve the current status of the order.
225
+
226
+ This method queries the EMS Engine and returns detailed
227
+ execution and lifecycle information of the order.
228
+
229
+ Returns
230
+ -------
231
+ OrderStatus | None
232
+ A dictionary containing order status information.
233
+
234
+ On success, the returned object contains the following fields:
235
+
236
+ - order_uuid : HexUUID
237
+ Unique identifier of the order.
238
+
239
+ - order_status : Literal['InQueue', 'Cancelled', 'Broken', 'Settled']
240
+ Current lifecycle state of the order.
241
+
242
+ * InQueue : Order is waiting for execution.
243
+ * Cancelled : Order was cancelled.
244
+ * Broken : Order was rejected or failed.
245
+ * Settled : Order fully executed.
246
+
247
+ - Price : int
248
+ Order price.
249
+
250
+ - Volume : int
251
+ Total requested volume.
252
+
253
+ - RemainedVolume : int
254
+ Remaining unexecuted volume.
255
+
256
+ - ExecutedVolume : int
257
+ Total executed volume.
258
+
259
+ - OrderSide : Literal['Buy', 'Sell']
260
+ Side of the order.
261
+
262
+ - ValidityType : Literal['DAY', 'GTC', 'GTD']
263
+ Order validity type.
264
+
265
+ - ValidityDate : int
266
+ Expiration date (for GTD orders).
267
+
268
+ Returns None if the request fails or if the order
269
+ has not been sent yet.
270
+
271
+ Raises
272
+ ------
273
+ None
274
+
275
+ Notes
276
+ -----
277
+ - This method requires a valid OrderId.
278
+ - If OrderId is None, None is returned.
279
+ - Network or server errors are silently ignored.
280
+
281
+ Examples
282
+ --------
283
+ >>> status = order.Status()
284
+ >>> print(status["order_status"])
285
+ 'Settled'
286
+
287
+ >>> print(status["ExecutedVolume"])
288
+ 1000
289
+
290
+ >>> if status["RemainedVolume"] == 0:
291
+ ... print("Order fully executed")
292
+
293
+ Example Output
294
+ --------------
295
+ {
296
+ "order_uuid": "0xA91F23BC...",
297
+ "order_status": "Settled",
298
+ "Price": 12000,
299
+ "Volume": 1000,
300
+ "RemainedVolume": 0,
301
+ "ExecutedVolume": 1000,
302
+ "OrderSide": "Buy",
303
+ "ValidityType": "DAY",
304
+ "ValidityDate": 0
305
+ }
306
+ """
307
+
308
+ if self.OrderId is not None:
309
+
310
+ status_respnse = self.__AuthSyncClient.httpx_Client.get(
311
+ url='https://core.hedgetech.ir/ems-engine/tse-ifb/order/status',
312
+ params={'order_uuid' : self.OrderId}
313
+ )
314
+
315
+ match status_respnse.status_code :
316
+
317
+ case 200:
318
+
319
+ return status_respnse.json()['Data']
320
+
321
+ case _ : return None
322
+
323
+ else : return None
324
+
325
+ # +--------------------------------------------------------------------------------------+ #
326
+
327
+ def Delete(self)-> None :
328
+
329
+ """
330
+ Cancel/Delete the order.
331
+
332
+ Sends delete request to EMS Engine.
333
+
334
+ Returns
335
+ -------
336
+ None
337
+
338
+ Notes
339
+ -----
340
+ After deletion, `is_deleted` becomes True.
341
+
342
+ Examples
343
+ --------
344
+ >>> order.Delete()
345
+ >>> print(order.is_deleted)
346
+ True
347
+ """
348
+
349
+ if self.OrderId is not None:
350
+
351
+ Delete_respnse = self.__AuthSyncClient.httpx_Client.delete(
352
+ url= 'https://core.hedgetech.ir/ems-engine/tse-ifb/order/delete',
353
+ params={'order_uuid' : self.OrderId}
354
+ )
355
+
356
+
357
+ match Delete_respnse.status_code :
358
+
359
+ case 200:
360
+
361
+ self.is_deleted = True
362
+ return None
363
+
364
+ case _ : return None
365
+
366
+ else : return None
367
+
368
+ # ================================================================================= #
369
+
370
+ class EmsEngine_TseIfb_SyncClient:
371
+
372
+ """
373
+ Synchronous EMS Engine client for TSE/IFB markets.
374
+
375
+ This client manages authentication, OMS login,
376
+ and order creation.
377
+ """
378
+
379
+ def __init__(
380
+ self,
381
+ AuthSyncClient : AuthSyncClient,
382
+ ):
383
+
384
+
385
+ self.__AuthSyncClient = AuthSyncClient
386
+
387
+ self.Customer_FullName : str | None = None
388
+ self.Customer_TSEBourseCode : str | None = None
389
+ self.oms_session : HexUUID | None = None
390
+
391
+
392
+ # +--------------------------------------------------------------------------------------+ #
393
+
394
+ def Get_Captcha(
395
+ self,
396
+ OMS : Literal[
397
+ 'Omex | Parsian',
398
+ 'Sahra | Karamad',
399
+ ]
400
+ )-> ImageFile:
401
+
402
+ """
403
+ Fetch captcha image for OMS login.
404
+
405
+ Parameters
406
+ ----------
407
+ OMS : Literal
408
+ OMS provider name.
409
+
410
+ Returns
411
+ -------
412
+ ImageFile
413
+ Captcha image.
414
+
415
+ Raises
416
+ ------
417
+ ValueError
418
+ If server returns error.
419
+
420
+ Examples
421
+ --------
422
+ >>> img = client.Get_Captcha("Omex | Parsian")
423
+ >>> img.show()
424
+ """
425
+
426
+ Captcha = self.__AuthSyncClient.httpx_Client.get(
427
+ url='https://core.hedgetech.ir/ems-engine/tse-ifb/oms/login',
428
+ params={'oms' : OMS }
429
+ )
430
+
431
+ if Captcha.status_code == 200: return image_open(BytesIO(Captcha.content))
432
+
433
+ else : raise ValueError(Captcha.json()['detail']['Status']['Description']['en'])
434
+
435
+ # +--------------------------------------------------------------------------------------+ #
436
+
437
+ def oms_login(
438
+ self,
439
+ username: str,
440
+ password: str,
441
+ captcha_value: str,
442
+ ) -> None :
443
+ """
444
+ Authenticate user in OMS system.
445
+
446
+ Parameters
447
+ ----------
448
+ username : str
449
+ Trading account username.
450
+
451
+ password : str
452
+ Trading account password.
453
+
454
+ captcha_value : str
455
+ Captcha solution.
456
+
457
+ Returns
458
+ -------
459
+ None
460
+
461
+ Raises
462
+ ------
463
+ ValueError
464
+ If authentication fails.
465
+
466
+ Examples
467
+ --------
468
+ >>> client.oms_login("user1", "pass123", "A7B9")
469
+ """
470
+
471
+ response = self.__AuthSyncClient.httpx_Client.post(
472
+ url='https://core.hedgetech.ir/ems-engine/tse-ifb/oms/login',
473
+ data={
474
+ 'username' : username,
475
+ 'Password' : password,
476
+ 'Captcha_Value' : captcha_value
477
+ },
478
+ )
479
+
480
+ match response.status_code :
481
+
482
+ case 200 :
483
+
484
+ data = response.json()
485
+
486
+ self.Customer_FullName = data['Data']['Customer_FullName']
487
+ self.Customer_TSEBourseCode = data['Data']['Customer_TSEBourseCode']
488
+ self.oms_session = data['Data']['oms_session']
489
+
490
+ return None
491
+
492
+ case 400 :
493
+
494
+ raise ValueError(response.json()['detail']['Status']['Description']['en'])
495
+
496
+ case _ :
497
+
498
+ raise ValueError(response.text)
499
+
500
+
501
+
502
+ # +--------------------------------------------------------------------------------------+ #
503
+
504
+
505
+ def Buy_by_Name(
506
+ self,
507
+ *,
508
+ symbolName : str,
509
+ Price : int,
510
+ Volume :int,
511
+ Order_ValidityType : Literal[
512
+ 'DAY',
513
+ 'GTC', # Good Till Cancelled
514
+ 'GTD', # Good Till Date
515
+ 'FAK', # Fill And Kill
516
+ 'FOK', # Fill Or Kill
517
+ ] = 'DAY',
518
+ ValidityDate : int = 0,
519
+ )-> Order | None:
520
+
521
+ """
522
+ Create a buy order using symbol name.
523
+
524
+ Parameters
525
+ ----------
526
+ symbolName : str
527
+ Trading symbol name.
528
+
529
+ Price : int
530
+ Order price.
531
+
532
+ Volume : int
533
+ Order volume.
534
+
535
+ Returns
536
+ -------
537
+ Order | None
538
+ Order instance if logged in, otherwise None.
539
+
540
+ Examples
541
+ --------
542
+ >>> order = client.Buy_by_Name(
543
+ ... symbolName="اهرم",
544
+ ... Price=12000,
545
+ ... Volume=1000
546
+ ... )
547
+ >>> order.send()
548
+ """
549
+
550
+ if self.oms_session is not None:
551
+
552
+ return Order(
553
+ AuthSyncClient=self.__AuthSyncClient,
554
+ Order_ValidityType=Order_ValidityType,
555
+ ValidityDate=ValidityDate,
556
+ SymbolNameOrIsin = symbolName,
557
+ Price=Price,
558
+ Volume=Volume,
559
+ SendOrder_RequestInfo = {
560
+ 'url' : 'https://core.hedgetech.ir/ems-engine/tse-ifb/order/new/buy/name',
561
+ 'data' : {
562
+ 'oms_session' : self.oms_session,
563
+ 'Order_ValidityType' : Order_ValidityType,
564
+ 'ValidityDate' : ValidityDate,
565
+ 'symbolName' : symbolName,
566
+ 'Price' : Price,
567
+ 'Volume' : Volume
568
+ }
569
+ }
570
+ )
571
+
572
+ else : return None
573
+
574
+
575
+ # +--------------------------------------------------------------------------------------+ #
576
+
577
+
578
+ def Sell_by_Name(
579
+ self,
580
+ *,
581
+ symbolName : str,
582
+ Price : int,
583
+ Volume :int,
584
+ Order_ValidityType : Literal[
585
+ 'DAY',
586
+ 'GTC', # Good Till Cancelled
587
+ 'GTD', # Good Till Date
588
+ 'FAK', # Fill And Kill
589
+ 'FOK', # Fill Or Kill
590
+ ] = 'DAY',
591
+ ValidityDate : int = 0,
592
+ )-> Order | None:
593
+
594
+ """
595
+ Create a sell order using symbol name.
596
+
597
+ Parameters
598
+ ----------
599
+ symbolName : str
600
+ Trading symbol name.
601
+
602
+ Price : int
603
+ Order price.
604
+
605
+ Volume : int
606
+ Order volume.
607
+
608
+ Returns
609
+ -------
610
+ Order | None
611
+ Order instance if logged in, otherwise None.
612
+
613
+ Examples
614
+ --------
615
+ >>> order = client.Sell_by_Name(
616
+ ... symbolName="اهرم",
617
+ ... Price=12000,
618
+ ... Volume=1000
619
+ ... )
620
+ >>> order.send()
621
+ """
622
+
623
+ if self.oms_session is not None:
624
+
625
+ return Order(
626
+ AuthSyncClient=self.__AuthSyncClient,
627
+ Order_ValidityType=Order_ValidityType,
628
+ ValidityDate=ValidityDate,
629
+ SymbolNameOrIsin = symbolName,
630
+ Price=Price,
631
+ Volume=Volume,
632
+ SendOrder_RequestInfo = {
633
+ 'url' : 'https://core.hedgetech.ir/ems-engine/tse-ifb/order/new/sell/name',
634
+ 'data' : {
635
+ 'oms_session' : self.oms_session,
636
+ 'Order_ValidityType' : Order_ValidityType,
637
+ 'ValidityDate' : ValidityDate,
638
+ 'symbolName' : symbolName,
639
+ 'Price' : Price,
640
+ 'Volume' : Volume
641
+ }
642
+ }
643
+ )
644
+
645
+ else : return None
646
+
647
+ # +--------------------------------------------------------------------------------------+ #
648
+
649
+ def Buy_by_isin(
650
+ self,
651
+ *,
652
+ symbolIsin : str,
653
+ Price : int,
654
+ Volume :int,
655
+ Order_ValidityType : Literal[
656
+ 'DAY',
657
+ 'GTC', # Good Till Cancelled
658
+ 'GTD', # Good Till Date
659
+ 'FAK', # Fill And Kill
660
+ 'FOK', # Fill Or Kill
661
+ ] = 'DAY',
662
+ ValidityDate : int = 0,
663
+ )-> Order | None:
664
+
665
+ """
666
+ Create a buy order using symbol isin.
667
+
668
+ Parameters
669
+ ----------
670
+ symbolIsin : str
671
+ Trading symbol isin.
672
+
673
+ Price : int
674
+ Order price.
675
+
676
+ Volume : int
677
+ Order volume.
678
+
679
+ Returns
680
+ -------
681
+ Order | None
682
+ Order instance if logged in, otherwise None.
683
+
684
+ Examples
685
+ --------
686
+ >>> order = client.Buy_by_isin(
687
+ ... symbolName="اهرم",
688
+ ... Price=12000,
689
+ ... Volume=1000
690
+ ... )
691
+ >>> order.send()
692
+ """
693
+
694
+ if self.oms_session is not None:
695
+
696
+ return Order(
697
+ AuthSyncClient=self.__AuthSyncClient,
698
+ Order_ValidityType=Order_ValidityType,
699
+ ValidityDate=ValidityDate,
700
+ SymbolNameOrIsin = symbolIsin,
701
+ Price=Price,
702
+ Volume=Volume,
703
+ SendOrder_RequestInfo = {
704
+ 'url' : 'https://core.hedgetech.ir/ems-engine/tse-ifb/order/new/buy/isin',
705
+ 'data' : {
706
+ 'oms_session' : self.oms_session,
707
+ 'Order_ValidityType' : Order_ValidityType,
708
+ 'ValidityDate' : ValidityDate,
709
+ 'symbolIsin' : symbolIsin,
710
+ 'Price' : Price,
711
+ 'Volume' : Volume
712
+ }
713
+ }
714
+ )
715
+
716
+ else : return None
717
+
718
+ # +--------------------------------------------------------------------------------------+ #
719
+
720
+ def Sell_by_isin(
721
+ self,
722
+ *,
723
+ symbolIsin : str,
724
+ Price : int,
725
+ Volume :int,
726
+ Order_ValidityType : Literal[
727
+ 'DAY',
728
+ 'GTC', # Good Till Cancelled
729
+ 'GTD', # Good Till Date
730
+ 'FAK', # Fill And Kill
731
+ 'FOK', # Fill Or Kill
732
+ ] = 'DAY',
733
+ ValidityDate : int = 0,
734
+ )-> Order | None:
735
+
736
+ """
737
+ Create a sell order using symbol isin.
738
+
739
+ Parameters
740
+ ----------
741
+ symbolIsin : str
742
+ Trading symbol isin.
743
+
744
+ Price : int
745
+ Order price.
746
+
747
+ Volume : int
748
+ Order volume.
749
+
750
+ Returns
751
+ -------
752
+ Order | None
753
+ Order instance if logged in, otherwise None.
754
+
755
+ Examples
756
+ --------
757
+ >>> order = client.Sell_by_isin(
758
+ ... symbolName="اهرم",
759
+ ... Price=12000,
760
+ ... Volume=1000
761
+ ... )
762
+ >>> order.send()
763
+ """
764
+
765
+ if self.oms_session is not None:
766
+
767
+ return Order(
768
+ AuthSyncClient=self.__AuthSyncClient,
769
+ Order_ValidityType=Order_ValidityType,
770
+ ValidityDate=ValidityDate,
771
+ SymbolNameOrIsin = symbolIsin,
772
+ Price=Price,
773
+ Volume=Volume,
774
+ SendOrder_RequestInfo = {
775
+ 'url' : 'https://core.hedgetech.ir/ems-engine/tse-ifb/order/new/sell/isin',
776
+ 'data' : {
777
+ 'oms_session' : self.oms_session,
778
+ 'Order_ValidityType' : Order_ValidityType,
779
+ 'ValidityDate' : ValidityDate,
780
+ 'symbolIsin' : symbolIsin,
781
+ 'Price' : Price,
782
+ 'Volume' : Volume
783
+ }
784
+ }
785
+ )
786
+
787
+ else : return None
788
+
789
+ # +--------------------------------------------------------------------------------------+ #
790
+