tradx 0.8.3__py3-none-any.whl → 0.9__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 (28) hide show
  1. tradx/algoContainer.py +82 -2
  2. tradx/baseClass/baseAlgo.py +24 -9
  3. tradx/baseClass/{order.py → interactive/order.py} +6 -0
  4. tradx/baseClass/{orderEvent.py → interactive/orderEvent.py} +3 -1
  5. tradx/baseClass/{position.py → interactive/position.py} +8 -1
  6. tradx/interactiveEngine.py +197 -58
  7. tradx/marketDataEngine.py +254 -76
  8. {tradx-0.8.3.dist-info → tradx-0.9.dist-info}/METADATA +1 -1
  9. tradx-0.9.dist-info/RECORD +33 -0
  10. tradx-0.8.3.dist-info/RECORD +0 -33
  11. /tradx/baseClass/{positionEvent.py → interactive/positionEvent.py} +0 -0
  12. /tradx/baseClass/{tradeConversionEvent.py → interactive/tradeConversionEvent.py} +0 -0
  13. /tradx/baseClass/{tradeEvent.py → interactive/tradeEvent.py} +0 -0
  14. /tradx/baseClass/{candleData.py → market/candleData.py} +0 -0
  15. /tradx/baseClass/{cmInstrument.py → market/cmInstrument.py} +0 -0
  16. /tradx/baseClass/{futureInstrument.py → market/futureInstrument.py} +0 -0
  17. /tradx/baseClass/{index.py → market/index.py} +0 -0
  18. /tradx/baseClass/{instrumentPropertyChangeData.py → market/instrumentPropertyChangeData.py} +0 -0
  19. /tradx/baseClass/{ltpData.py → market/ltpData.py} +0 -0
  20. /tradx/baseClass/{ltpPartialData.py → market/ltpPartialData.py} +0 -0
  21. /tradx/baseClass/{marketDepthData.py → market/marketDepthData.py} +0 -0
  22. /tradx/baseClass/{marketStatusData.py → market/marketStatusData.py} +0 -0
  23. /tradx/baseClass/{openInterestData.py → market/openInterestData.py} +0 -0
  24. /tradx/baseClass/{openInterestPartialData.py → market/openInterestPartialData.py} +0 -0
  25. /tradx/baseClass/{optionsInstrument.py → market/optionsInstrument.py} +0 -0
  26. /tradx/baseClass/{touchLineData.py → market/touchLineData.py} +0 -0
  27. /tradx/baseClass/{touchLinePartialData.py → market/touchLinePartialData.py} +0 -0
  28. {tradx-0.8.3.dist-info → tradx-0.9.dist-info}/WHEEL +0 -0
tradx/algoContainer.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from typing import Dict, Set, Any
2
2
  from tradx.baseClass.baseAlgo import BaseAlgo
3
- from tradx.baseClass.candleData import CandleData
4
- from tradx.baseClass.touchLineData import TouchLineData
3
+ from tradx.baseClass.market.candleData import CandleData
4
+ from tradx.baseClass.market.touchLineData import TouchLineData
5
5
  import asyncio
6
6
 
7
7
 
@@ -88,3 +88,83 @@ class AlgoContainer:
88
88
  if isinstance(message, TouchLineData):
89
89
  for algo in self.subscriptions[message.ExchangeInstrumentID]:
90
90
  asyncio.ensure_future(algo.on_touchLineData(message))
91
+
92
+
93
+ class SubcribeContainer:
94
+ """
95
+ AlgoContainer is a container class that maps algorithms to their subscriptions and allows broadcasting messages.
96
+ Attributes:
97
+ subscriptions (Dict[int, Set[BaseAlgo]]): A dictionary mapping subscription keys to sets of algorithm instances.
98
+ Methods:
99
+ __init__():
100
+ Initializes the AlgoContainer with an empty subscription map.
101
+ subscribe(key: int, algo: BaseAlgo):
102
+ Subscribes an algorithm to a specific key.
103
+ key (int): The subscription key.
104
+ algo (BaseAlgo): The algorithm instance subscribing.
105
+ unsubscribe(key: int, algo: BaseAlgo):
106
+ Unsubscribes an algorithm from a specific key.
107
+ key (int): The subscription key.
108
+ algo (BaseAlgo): The algorithm instance unsubscribing.
109
+ broadcast(key: int, message: str, dataType: str):
110
+ Broadcasts a message to all algorithms subscribed to a given key.
111
+ key (int): The key to broadcast the message for.
112
+ dataType (str): The type of data being broadcasted (e.g., "bar").
113
+ """
114
+
115
+ def __init__(self) -> None:
116
+ """
117
+ Initializes the algoContainer instance.
118
+
119
+ Attributes:
120
+ subscriptions (Dict[int, Set[BaseAlgo]]):
121
+ A dictionary mapping an integer key (e.g., a topic or identifier)
122
+ to a set of algorithm instances (BaseAlgo).
123
+ """
124
+ self.subscriptions: Dict[int, Set[str]] = {}
125
+
126
+ def subscribe(self, exchangeInstrumentID, xtsMessageCode, uuid: str) -> None:
127
+ """
128
+ Subscribes an algorithm to a given key.
129
+ Args:
130
+ key: The key to subscribe the algorithm to.
131
+ algo (BaseAlgo): The algorithm to be subscribed.
132
+ Raises:
133
+ None
134
+ Returns:
135
+ None
136
+ """
137
+ key = (exchangeInstrumentID, xtsMessageCode)
138
+ if key not in self.subscriptions:
139
+ self.subscriptions[key] = set()
140
+ self.subscriptions[key].add(uuid)
141
+
142
+ def unsubscribe(self, exchangeInstrumentID, xtsMessageCode, uuid: str) -> None:
143
+ """
144
+ Unsubscribe an algorithm from a given key.
145
+ This method removes the specified algorithm from the list of
146
+ subscriptions associated with the given key. If no more algorithms
147
+ are subscribed to the key after removal, the key is deleted from
148
+ the subscriptions.
149
+ Args:
150
+ key: The key from which the algorithm should be unsubscribed.
151
+ algo (BaseAlgo): The algorithm instance to be unsubscribed.
152
+ """
153
+ key = (exchangeInstrumentID, xtsMessageCode)
154
+ if key in self.subscriptions and uuid in self.subscriptions[key]:
155
+ self.subscriptions[key].remove(uuid)
156
+
157
+ # Remove the key if no more algorithms are subscribed
158
+ if not self.subscriptions[key]:
159
+ del self.subscriptions[key]
160
+
161
+ def ifExists(self, exchangeInstrumentID, xtsMessageCode) -> bool:
162
+ """
163
+ Check if a subscription exists for the given exchangeInstrumentID and xtsMessageCode.
164
+ Args:
165
+ exchangeInstrumentID: The exchange instrument ID to check.
166
+ xtsMessageCode: The XTS message code to check.
167
+ Returns:
168
+ bool: True if the subscription exists, False otherwise.
169
+ """
170
+ return (exchangeInstrumentID, xtsMessageCode) in self.subscriptions
@@ -1,9 +1,9 @@
1
1
  from abc import ABC, abstractmethod
2
2
  import shortuuid
3
- from typing import Any, TYPE_CHECKING, List, Dict
3
+ from typing import Any, TYPE_CHECKING, List, Dict, Set
4
4
  from decimal import Decimal
5
- from tradx.baseClass.order import Order
6
- from tradx.baseClass.position import Position
5
+ from tradx.baseClass.interactive.order import Order
6
+ from tradx.baseClass.interactive.position import Position
7
7
 
8
8
  import asyncio
9
9
 
@@ -11,10 +11,10 @@ import asyncio
11
11
  if TYPE_CHECKING:
12
12
  from tradx.marketDataEngine import marketDataEngine
13
13
  from tradx.interactiveEngine import interactiveEngine
14
- from tradx.baseClass.touchLineData import TouchLineData
15
- from tradx.baseClass.orderEvent import OrderEvent
16
- from tradx.baseClass.tradeEvent import TradeEvent
17
- from tradx.baseClass.candleData import CandleData
14
+ from tradx.baseClass.market.touchLineData import TouchLineData
15
+ from tradx.baseClass.interactive.orderEvent import OrderEvent
16
+ from tradx.baseClass.interactive.tradeEvent import TradeEvent
17
+ from tradx.baseClass.market.candleData import CandleData
18
18
 
19
19
 
20
20
  class BaseAlgo(ABC):
@@ -74,6 +74,7 @@ class BaseAlgo(ABC):
74
74
  self.order_nos = shortuuid
75
75
  self.position_diary: List[Position] = []
76
76
  self.order_diary: List[Order] = []
77
+ self.uuids = set()
77
78
  # Registering inside interactive engine
78
79
  self.name = interactiveEngine.shortuuid.ShortUUID().random(length=4)
79
80
  self.interactiveEngine.strategy_to_id[self.name] = self
@@ -127,7 +128,13 @@ class BaseAlgo(ABC):
127
128
  Returns:
128
129
  str: An 8-digit unique order identifier.
129
130
  """
130
- return f"{self.name}{self.order_nos.ShortUUID().random(length=4)}"
131
+ # Generate a unique 4-character key not present in self.uuids
132
+ while True:
133
+ ids = self.order_nos.ShortUUID().random(length=4)
134
+ if ids not in self.uuids:
135
+ self.uuids.add(ids)
136
+ break
137
+ return f"{self.name}{ids}"
131
138
 
132
139
  async def order_(self, order: "OrderEvent") -> None:
133
140
  """
@@ -152,6 +159,14 @@ class BaseAlgo(ABC):
152
159
  # Update the status of the existing order
153
160
  existing_order.OrderStatus = order.OrderStatus
154
161
  existing_order.OrderPrice = order.OrderAverageTradedPriceAPI
162
+ if existing_order.AppOrderID != order.AppOrderID:
163
+
164
+ if self.interactiveEngine.user_logger:
165
+ self.interactiveEngine.user_logger.info(
166
+ f"Updated order {order.OrderUniqueIdentifier} App order id from {existing_order.AppOrderID} to {order.AppOrderID}",
167
+ caller=f"{self.__class__.__name__}.order_",
168
+ )
169
+ existing_order.AppOrderID = order.AppOrderID
155
170
  if self.interactiveEngine.user_logger:
156
171
  self.interactiveEngine.user_logger.info(
157
172
  f"Updated order {order.OrderUniqueIdentifier} status to {order.OrderStatus}",
@@ -289,7 +304,7 @@ class BaseAlgo(ABC):
289
304
  )
290
305
 
291
306
  for order in self.order_diary:
292
- if order.OrderStatus in ["PendingNew", "New"]:
307
+ if order.OrderStatus in ["PendingNew", "New", "Replaced", "PendingReplace"]:
293
308
  asyncio.ensure_future(
294
309
  self.interactiveEngine.cancel_order(
295
310
  order.AppOrderID, order.OrderUniqueIdentifier
@@ -1,5 +1,6 @@
1
1
  from pydantic import BaseModel
2
2
  from decimal import Decimal
3
+ import json
3
4
 
4
5
 
5
6
  class Order(BaseModel):
@@ -53,3 +54,8 @@ class Order(BaseModel):
53
54
  OrderSide=OrderSide,
54
55
  TimeInForce=TimeInForce,
55
56
  )
57
+
58
+ @classmethod
59
+ def from_str(cls, message: str):
60
+ data = json.loads(message)
61
+ return cls(**data)
@@ -34,7 +34,9 @@ def parse_datetime(value) -> Any:
34
34
  return datetime(1980, 1, 1) + timedelta(seconds=value)
35
35
  return value
36
36
  class OrderEvent(BaseModel):
37
-
37
+ """
38
+ Order Event class representing an order event in the system.
39
+ """
38
40
 
39
41
  LoginID: str
40
42
  ClientID: str = "*****"
@@ -1,4 +1,5 @@
1
1
  from pydantic import BaseModel
2
+ import json
2
3
 
3
4
 
4
5
  class Position(BaseModel):
@@ -20,8 +21,9 @@ class Position(BaseModel):
20
21
  Constructs all the necessary attributes for the Position object.
21
22
  """
22
23
 
23
- ExchangeSegment: str
24
24
  ExchangeInstrumentID: int
25
+ ExchangeSegment: str
26
+
25
27
  ProductType: str
26
28
  Quantity: int
27
29
 
@@ -44,3 +46,8 @@ class Position(BaseModel):
44
46
  ProductType=ProductType,
45
47
  Quantity=Quantity,
46
48
  )
49
+
50
+ @classmethod
51
+ def from_str(cls, message: str):
52
+ data = json.loads(message)
53
+ return cls(**data)