tradx 0.1.1.2__tar.gz → 0.1.2__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 (59) hide show
  1. {tradx-0.1.1.2 → tradx-0.1.2}/.gitignore +2 -1
  2. {tradx-0.1.1.2 → tradx-0.1.2}/PKG-INFO +2 -2
  3. {tradx-0.1.1.2 → tradx-0.1.2}/pyproject.toml +2 -2
  4. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/baseAlgo.py +137 -7
  5. tradx-0.1.2/src/tradx/baseClass/order.py +53 -0
  6. tradx-0.1.1.2/src/tradx/baseClass/order.py +0 -27
  7. {tradx-0.1.1.2 → tradx-0.1.2}/.vscode/settings.json +0 -0
  8. {tradx-0.1.1.2 → tradx-0.1.2}/README.md +0 -0
  9. {tradx-0.1.1.2 → tradx-0.1.2}/examples/example1.log +0 -0
  10. {tradx-0.1.1.2 → tradx-0.1.2}/examples/example1.py +0 -0
  11. {tradx-0.1.1.2 → tradx-0.1.2}/examples/example2.log +0 -0
  12. {tradx-0.1.1.2 → tradx-0.1.2}/examples/example2.py +0 -0
  13. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/__init__.py +0 -0
  14. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/algoContainer.py +0 -0
  15. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/candleData.py +0 -0
  16. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/cmInstrument.py +0 -0
  17. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/futureInstrument.py +0 -0
  18. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/index.py +0 -0
  19. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/instrumentPropertyChangeData.py +0 -0
  20. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/ltpData.py +0 -0
  21. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/ltpPartialData.py +0 -0
  22. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/marketDepthData.py +0 -0
  23. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/marketStatusData.py +0 -0
  24. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/openInterestData.py +0 -0
  25. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/openInterestPartialData.py +0 -0
  26. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/optionsInstrument.py +0 -0
  27. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/orderEvent.py +0 -0
  28. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/position.py +0 -0
  29. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/positionEvent.py +0 -0
  30. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/touchLineData.py +0 -0
  31. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/touchLinePartialData.py +0 -0
  32. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/tradeConversionEvent.py +0 -0
  33. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/tradeEvent.py +0 -0
  34. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/constants/holidays.py +0 -0
  35. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/dualHashMap.py +0 -0
  36. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/interactiveEngine.py +0 -0
  37. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/logger/logger.py +0 -0
  38. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/logger/logger2.py +0 -0
  39. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/marketDataEngine.py +0 -0
  40. {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/py.typed +0 -0
  41. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_candleData.py +0 -0
  42. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_interactiveEngine.log +0 -0
  43. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_interactiveEngine.py +0 -0
  44. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_logger.log +0 -0
  45. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_logger.py +0 -0
  46. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_ltpData.py +0 -0
  47. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_ltpPartailData.py +0 -0
  48. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_marketDataEngine.log +0 -0
  49. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_marketDataEngine.py +0 -0
  50. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_marketDepthData.py +0 -0
  51. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_marketStatusData.py +0 -0
  52. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_openInterestData.py +0 -0
  53. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_openInterestPartialData.py +0 -0
  54. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_option.py +0 -0
  55. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_orderEvent.py +0 -0
  56. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_positionEvent.py +0 -0
  57. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_touchLineData.py +0 -0
  58. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_tradeConversionEvent.py +0 -0
  59. {tradx-0.1.1.2 → tradx-0.1.2}/test/test_tradeEvent.py +0 -0
@@ -12,4 +12,5 @@ wheels/
12
12
 
13
13
  # User-generated files
14
14
  .env
15
- uv.lock
15
+ uv.lock
16
+ uv.lock
@@ -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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tradx"
3
- version = "0.1.1.2"
3
+ version = "0.1.2"
4
4
  description = "A Package Designed to simplify strategy development on package xts-api-client"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -12,7 +12,7 @@ dependencies = [
12
12
  "pydantic==2.10.4",
13
13
  "pytest==8.3.4",
14
14
  "shortuuid==1.0.13",
15
- "xts-api-client==0.1.6",
15
+ "xts-api-client>=0.1.7",
16
16
  ]
17
17
 
18
18
  [build-system]
@@ -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
+ )
@@ -0,0 +1,53 @@
1
+ from pydantic import BaseModel
2
+ from decimal import Decimal
3
+
4
+
5
+ class Order(BaseModel):
6
+ """
7
+ Order class representing an order in the system.
8
+ Attributes:
9
+ OrderUniqueIdentifier (str): A unique identifier for the order.
10
+ AppOrderID (int): The application-specific order ID.
11
+ OrderStatus (str): The status of the order. Defaults to an empty string.
12
+ Methods:
13
+ __init__(OrderUniqueIdentifier: str, AppOrderID: int, OrderStatus: str = ""):
14
+ Initializes a new instance of the Order class.
15
+ """
16
+
17
+ OrderUniqueIdentifier: str
18
+ AppOrderID: int
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
28
+
29
+ def __init__(
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 = "",
41
+ ):
42
+ super().__init__(
43
+ OrderUniqueIdentifier=OrderUniqueIdentifier,
44
+ AppOrderID=AppOrderID,
45
+ ProductType=ProductType,
46
+ OrderType=OrderType,
47
+ OrderQuantity=OrderQuantity,
48
+ OrderDisclosedQuantity=OrderDisclosedQuantity,
49
+ OrderPrice=OrderPrice,
50
+ OrderStopPrice=OrderStopPrice,
51
+ OrderStatus=OrderStatus,
52
+ OrderSide=OrderSide,
53
+ )
@@ -1,27 +0,0 @@
1
- from pydantic import BaseModel
2
-
3
-
4
- class Order(BaseModel):
5
- """
6
- Order class representing an order in the system.
7
- Attributes:
8
- OrderUniqueIdentifier (str): A unique identifier for the order.
9
- AppOrderID (int): The application-specific order ID.
10
- OrderStatus (str): The status of the order. Defaults to an empty string.
11
- Methods:
12
- __init__(OrderUniqueIdentifier: str, AppOrderID: int, OrderStatus: str = ""):
13
- Initializes a new instance of the Order class.
14
- """
15
-
16
- OrderUniqueIdentifier: str
17
- AppOrderID: int
18
- OrderStatus: str
19
-
20
- def __init__(
21
- self, OrderUniqueIdentifier: str, AppOrderID: int, OrderStatus: str = ""
22
- ):
23
- super().__init__(
24
- OrderUniqueIdentifier=OrderUniqueIdentifier,
25
- AppOrderID=AppOrderID,
26
- OrderStatus=OrderStatus,
27
- )
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes