tradx 0.1.1.2__py3-none-any.whl → 0.1.2__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.
@@ -1,17 +1,20 @@
1
1
  from abc import ABC, abstractmethod
2
2
  import shortuuid
3
- from typing import Any, TYPE_CHECKING, List
3
+ from typing import Any, TYPE_CHECKING, List, Dict
4
+ from datetime import datetime, timedelta
4
5
  from tradx.baseClass.order import Order
5
6
  from tradx.baseClass.position import Position
7
+
6
8
  import asyncio
7
9
 
8
10
 
9
11
  if TYPE_CHECKING:
10
- from tradx import interactiveEngine, marketDataEngine
12
+ from tradx.marketDataEngine import marketDataEngine
13
+ from tradx.interactiveEngine import interactiveEngine
14
+ from tradx.baseClass.touchLineData import TouchLineData
11
15
  from tradx.baseClass.orderEvent import OrderEvent
12
16
  from tradx.baseClass.tradeEvent import TradeEvent
13
17
  from tradx.baseClass.candleData import CandleData
14
- from tradx.baseClass.touchLineData import TouchLineData
15
18
 
16
19
 
17
20
  class BaseAlgo(ABC):
@@ -71,7 +74,6 @@ class BaseAlgo(ABC):
71
74
  self.order_nos = shortuuid
72
75
  self.position_diary: List[Position] = []
73
76
  self.order_diary: List[Order] = []
74
-
75
77
  # Registering inside interactive engine
76
78
  self.name = interactiveEngine.shortuuid.ShortUUID().random(length=4)
77
79
  self.interactiveEngine.strategy_to_id[self.name] = self
@@ -157,7 +159,16 @@ class BaseAlgo(ABC):
157
159
  else:
158
160
  # Insert the new order by creating an object
159
161
  new_order = Order(
160
- order.OrderUniqueIdentifier, order.AppOrderID, order.OrderStatus
162
+ order.OrderUniqueIdentifier,
163
+ order.AppOrderID,
164
+ order.ProductType,
165
+ order.OrderType,
166
+ order.OrderQuantity,
167
+ order.OrderDisclosedQuantity,
168
+ order.OrderPrice,
169
+ order.OrderStopPrice,
170
+ order.OrderStatus,
171
+ order.OrderSide,
161
172
  )
162
173
  self.order_diary.append(new_order)
163
174
  if self.interactiveEngine.user_logger:
@@ -305,7 +316,7 @@ class BaseAlgo(ABC):
305
316
 
306
317
  qty = 0
307
318
  for position in self.position_diary:
308
- qty += abs(position.Quantity)
319
+ qty += position.Quantity
309
320
  return qty != 0
310
321
 
311
322
  async def liquidateIntradayDummy(self) -> None:
@@ -327,7 +338,7 @@ class BaseAlgo(ABC):
327
338
  if position.Quantity != 0:
328
339
  _order_no = self.order_no()
329
340
  asyncio.ensure_future(
330
- self.marketDataEngine.dummy_market_order(
341
+ self.marketDataEngine.dummy_order(
331
342
  position.ExchangeSegment,
332
343
  position.ExchangeInstrumentID,
333
344
  position.ProductType,
@@ -336,3 +347,122 @@ class BaseAlgo(ABC):
336
347
  self,
337
348
  )
338
349
  )
350
+
351
+ async def safe_market_order(
352
+ self, ExchangeSegment, ExchangeInstrumentID, ProductType, Quantity
353
+ ):
354
+ """
355
+ Places a safe market order by continuously modifying the order until it is filled.
356
+ Args:
357
+ ExchangeSegment (str): The segment of the exchange.
358
+ ExchangeInstrumentID (int): The instrument ID of the exchange.
359
+ ProductType (str): The type of the product.
360
+ Quantity (int): The quantity to be ordered. Positive for buy, negative for sell.
361
+ Returns:
362
+ None
363
+ Raises:
364
+ Exception: If there is an issue with fetching market data or placing/modifying the order.
365
+ This method performs the following steps:
366
+ 1. Generates a unique identifier for the order.
367
+ 2. Fetches the latest market data for the given instrument.
368
+ 3. Places a limit order with a slight price adjustment.
369
+ 4. Continuously checks the order status until it is filled.
370
+ 5. If the order is not filled, modifies the order with updated market data.
371
+ """
372
+ OrderUniqueIdentifier = self.order_no()
373
+ Data: TouchLineData = await self.marketDataEngine.fetch_ltp(
374
+ [
375
+ {
376
+ "exchangeSegment": ExchangeSegment,
377
+ "exchangeInstrumentID": ExchangeInstrumentID,
378
+ }
379
+ ]
380
+ )[0]
381
+ await self.interactiveEngine.limit_order(
382
+ ExchangeSegment,
383
+ ExchangeInstrumentID,
384
+ ProductType,
385
+ Quantity,
386
+ (Data.AskInfo.Price + 0.05 if Quantity > 0 else Data.BidInfo.Price - 0.05),
387
+ OrderUniqueIdentifier,
388
+ )
389
+
390
+ await asyncio.sleep(0.1)
391
+ order = next(
392
+ (
393
+ O
394
+ for O in self.order_diary
395
+ if O.OrderUniqueIdentifier == OrderUniqueIdentifier
396
+ ),
397
+ None,
398
+ )
399
+ while order is None or (order is not None and order.OrderStatus != "Filled"):
400
+ await asyncio.sleep(0.1)
401
+ order = next(
402
+ (
403
+ O
404
+ for O in self.order_diary
405
+ if O.OrderUniqueIdentifier == OrderUniqueIdentifier
406
+ ),
407
+ None,
408
+ )
409
+ if order is not None and order.OrderStatus != "Filled":
410
+ Data: TouchLineData = await self.marketDataEngine.fetch_ltp(
411
+ [
412
+ {
413
+ "exchangeSegment": ExchangeSegment,
414
+ "exchangeInstrumentID": ExchangeInstrumentID,
415
+ }
416
+ ]
417
+ )[0]
418
+ await self.interactiveEngine.xt.modify_order(
419
+ order.AppOrderID,
420
+ order.ProductType,
421
+ order.OrderType,
422
+ order.OrderQuantity,
423
+ order.OrderDisclosedQuantity,
424
+ (
425
+ Data.AskInfo.Price + 0.05
426
+ if Quantity > 0
427
+ else Data.BidInfo.Price - 0.05
428
+ ),
429
+ order.OrderStopPrice,
430
+ order.TimeInForce,
431
+ order.OrderUniqueIdentifier,
432
+ )
433
+ await asyncio.sleep(0.3)
434
+
435
+ async def safeLiquidateIntraday(self) -> None:
436
+ """
437
+ Asynchronously liquidates all intraday positions and cancels all open orders.
438
+ This method performs the following actions:
439
+ 1. Logs the action of canceling open orders and squaring off positions if a user logger is available.
440
+ 2. Iterates through the order diary and cancels any orders with a status of "PendingNew" or "New".
441
+ 3. Iterates through the position diary and places market orders to square off any positions with a non-zero quantity.
442
+ Returns:
443
+ None
444
+ """
445
+
446
+ if self.interactiveEngine.user_logger:
447
+ self.interactiveEngine.user_logger.info(
448
+ f"Cancel open order and square off position for strategy {self.name}",
449
+ caller=f"{self.__class__.__name__}.safeLiquidateIntraday",
450
+ )
451
+
452
+ for order in self.order_diary:
453
+ if order.OrderStatus in ["PendingNew", "New"]:
454
+ asyncio.ensure_future(
455
+ self.interactiveEngine.cancel_order(
456
+ order.AppOrderID, order.OrderUniqueIdentifier
457
+ )
458
+ )
459
+ for position in self.position_diary:
460
+ if position.Quantity != 0:
461
+ asyncio.ensure_future(
462
+ self.safe_market_order(
463
+ position.ExchangeSegment,
464
+ position.ExchangeInstrumentID,
465
+ position.ProductType,
466
+ -1 * position.Quantity,
467
+ )
468
+ )
tradx/baseClass/order.py CHANGED
@@ -1,4 +1,5 @@
1
1
  from pydantic import BaseModel
2
+ from decimal import Decimal
2
3
 
3
4
 
4
5
  class Order(BaseModel):
@@ -16,12 +17,37 @@ class Order(BaseModel):
16
17
  OrderUniqueIdentifier: str
17
18
  AppOrderID: int
18
19
  OrderStatus: str
20
+ ProductType: str
21
+ OrderType: str
22
+ OrderQuantity: int
23
+ OrderDisclosedQuantity: int
24
+ OrderPrice: Decimal
25
+ OrderStopPrice: Decimal
26
+ TimeInForce: str
27
+ OrderSide: str
19
28
 
20
29
  def __init__(
21
- self, OrderUniqueIdentifier: str, AppOrderID: int, OrderStatus: str = ""
30
+ self,
31
+ OrderUniqueIdentifier: str,
32
+ AppOrderID: int,
33
+ ProductType: str,
34
+ OrderType: str,
35
+ OrderQuantity: int,
36
+ OrderDisclosedQuantity: int,
37
+ OrderPrice: Decimal,
38
+ OrderStopPrice: Decimal,
39
+ OrderSide: str,
40
+ OrderStatus: str = "",
22
41
  ):
23
42
  super().__init__(
24
43
  OrderUniqueIdentifier=OrderUniqueIdentifier,
25
44
  AppOrderID=AppOrderID,
45
+ ProductType=ProductType,
46
+ OrderType=OrderType,
47
+ OrderQuantity=OrderQuantity,
48
+ OrderDisclosedQuantity=OrderDisclosedQuantity,
49
+ OrderPrice=OrderPrice,
50
+ OrderStopPrice=OrderStopPrice,
26
51
  OrderStatus=OrderStatus,
52
+ OrderSide=OrderSide,
27
53
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tradx
3
- Version: 0.1.1.2
3
+ Version: 0.1.2
4
4
  Summary: A Package Designed to simplify strategy development on package xts-api-client
5
5
  Author-email: "jatin.kumawat" <jatin.kumawat@rmoneyindia.com>
6
6
  Requires-Python: >=3.12
@@ -8,7 +8,7 @@ Requires-Dist: aiohttp==3.11.11
8
8
  Requires-Dist: pydantic==2.10.4
9
9
  Requires-Dist: pytest==8.3.4
10
10
  Requires-Dist: shortuuid==1.0.13
11
- Requires-Dist: xts-api-client==0.1.6
11
+ Requires-Dist: xts-api-client>=0.1.7
12
12
  Description-Content-Type: text/markdown
13
13
 
14
14
  # Changelog
@@ -4,7 +4,7 @@ tradx/dualHashMap.py,sha256=XsidIc3aMvpVGOvdfV7lOeZaLCWAD5i180BGyAfdYXE,1737
4
4
  tradx/interactiveEngine.py,sha256=DCuEEYJcTn6DEG9pbaZsmGyHeyWGNG2q46Iljel6Drc,34584
5
5
  tradx/marketDataEngine.py,sha256=pIY4dephqzykzPYJk0khYMVmD1QAr-17CtLN1WkcAWM,34597
6
6
  tradx/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- tradx/baseClass/baseAlgo.py,sha256=KClbu25jAP4s3oWjRW1PEaZc0FIqj_ynqT_Xr3fea14,13670
7
+ tradx/baseClass/baseAlgo.py,sha256=TP4gh2O0siSwIZazmoMXtJGgg54pjv2Pu87tPCu8luA,19092
8
8
  tradx/baseClass/candleData.py,sha256=tS-iAoRGwK2xVSvrqmNZPYeB63qD53oPPHaUDfJBWkk,2947
9
9
  tradx/baseClass/cmInstrument.py,sha256=WpibHdJyVGVs0B8o1COiXr4rNXB8bapzFLyRaIG0w9Q,2408
10
10
  tradx/baseClass/futureInstrument.py,sha256=ygsGfzUg337gSwoSaAb8DB31YhLOI-nOv3ApX3z5CWQ,2186
@@ -17,7 +17,7 @@ tradx/baseClass/marketStatusData.py,sha256=lZKJlYB_Bfc1Rpv4rQ15ZQTXgH5EkBDOvH6RS
17
17
  tradx/baseClass/openInterestData.py,sha256=L-WuxyNwdZAFPoSVhfJPKv8jOy5K0rSB2o5EkWVSv9g,3111
18
18
  tradx/baseClass/openInterestPartialData.py,sha256=vpo18P9VCBuCXbxjggg4ahd0uS5WkP14rBvcLwdrTFw,1673
19
19
  tradx/baseClass/optionsInstrument.py,sha256=O3zhNf1R1wmtdPCUaDr7mOM7co0Aeg8AHmPvVpabP60,9886
20
- tradx/baseClass/order.py,sha256=FrRiYJdiIJc2aVqjxvKndXn04z9V3j4wf4eF1W99nNU,886
20
+ tradx/baseClass/order.py,sha256=Xt64sMkp0FCGdckcpDeaieLwcADK7MGng7J5MHdTEwM,1634
21
21
  tradx/baseClass/orderEvent.py,sha256=P4sJW3NKi53JDo8RwMVVKpCA_dIpkcE1-sm9ikpFYWk,2901
22
22
  tradx/baseClass/position.py,sha256=6fzm_Mr1GKSaRArRgsZItgw74_8omy-MBXRTfO12Pwk,1551
23
23
  tradx/baseClass/positionEvent.py,sha256=odOMeBqKUKfJ9Zj7IPcipMyfRTMsQyA-hvTJ_NcqKUk,3484
@@ -28,6 +28,6 @@ tradx/baseClass/tradeEvent.py,sha256=djunJW5AzjeMfJZVMlrFprplB7vrYBi-mmaR1TA0MK4
28
28
  tradx/constants/holidays.py,sha256=GCg0xGvXm1EM0n6YF1KYEnldSiC2sbsc09Iekjwn0ww,1547
29
29
  tradx/logger/logger.py,sha256=DfrjzwYkujTq7arksNTPcQeioXnwT1xgN659blhreog,3232
30
30
  tradx/logger/logger2.py,sha256=ebJ-qqnpnCqvyx1Cz1-kGGULtkH-hfrK6UNfa0bSlH8,2654
31
- tradx-0.1.1.2.dist-info/METADATA,sha256=fRa2M2tn7XNns9vWV-OPZc5X4glQHkX6KglSW1P3ftk,2629
32
- tradx-0.1.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
33
- tradx-0.1.1.2.dist-info/RECORD,,
31
+ tradx-0.1.2.dist-info/METADATA,sha256=3xvSJM8d9adxAb_FV92DHMTqNgEeddWe5F74Xz_REEM,2627
32
+ tradx-0.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
33
+ tradx-0.1.2.dist-info/RECORD,,
File without changes