tradx 0.6__tar.gz → 0.7.1__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 (58) hide show
  1. {tradx-0.6 → tradx-0.7.1}/PKG-INFO +1 -1
  2. {tradx-0.6 → tradx-0.7.1}/pyproject.toml +1 -1
  3. tradx-0.7.1/src/tradx/baseClass/baseAlgo.py +495 -0
  4. {tradx-0.6 → tradx-0.7.1}/src/tradx/marketDataEngine.py +2 -1
  5. {tradx-0.6 → tradx-0.7.1}/.gitignore +0 -0
  6. {tradx-0.6 → tradx-0.7.1}/.vscode/settings.json +0 -0
  7. {tradx-0.6 → tradx-0.7.1}/README.md +0 -0
  8. {tradx-0.6 → tradx-0.7.1}/examples/example1.log +0 -0
  9. {tradx-0.6 → tradx-0.7.1}/examples/example1.py +0 -0
  10. {tradx-0.6 → tradx-0.7.1}/examples/example2.log +0 -0
  11. {tradx-0.6 → tradx-0.7.1}/examples/example2.py +0 -0
  12. {tradx-0.6 → tradx-0.7.1}/src/tradx/__init__.py +0 -0
  13. {tradx-0.6 → tradx-0.7.1}/src/tradx/algoContainer.py +0 -0
  14. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/candleData.py +0 -0
  15. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/cmInstrument.py +0 -0
  16. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/futureInstrument.py +0 -0
  17. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/index.py +0 -0
  18. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/instrumentPropertyChangeData.py +0 -0
  19. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/ltpData.py +0 -0
  20. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/ltpPartialData.py +0 -0
  21. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/marketDepthData.py +0 -0
  22. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/marketStatusData.py +0 -0
  23. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/openInterestData.py +0 -0
  24. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/openInterestPartialData.py +0 -0
  25. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/optionsInstrument.py +0 -0
  26. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/order.py +0 -0
  27. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/orderEvent.py +0 -0
  28. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/position.py +0 -0
  29. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/positionEvent.py +0 -0
  30. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/touchLineData.py +0 -0
  31. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/touchLinePartialData.py +0 -0
  32. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/tradeConversionEvent.py +0 -0
  33. {tradx-0.6 → tradx-0.7.1}/src/tradx/baseClass/tradeEvent.py +0 -0
  34. {tradx-0.6 → tradx-0.7.1}/src/tradx/constants/holidays.py +0 -0
  35. {tradx-0.6 → tradx-0.7.1}/src/tradx/dualHashMap.py +0 -0
  36. {tradx-0.6 → tradx-0.7.1}/src/tradx/interactiveEngine.py +0 -0
  37. {tradx-0.6 → tradx-0.7.1}/src/tradx/logger/logger.py +0 -0
  38. {tradx-0.6 → tradx-0.7.1}/src/tradx/logger/logger2.py +0 -0
  39. {tradx-0.6 → tradx-0.7.1}/src/tradx/py.typed +0 -0
  40. {tradx-0.6 → tradx-0.7.1}/test/test_candleData.py +0 -0
  41. {tradx-0.6 → tradx-0.7.1}/test/test_interactiveEngine.log +0 -0
  42. {tradx-0.6 → tradx-0.7.1}/test/test_interactiveEngine.py +0 -0
  43. {tradx-0.6 → tradx-0.7.1}/test/test_logger.log +0 -0
  44. {tradx-0.6 → tradx-0.7.1}/test/test_logger.py +0 -0
  45. {tradx-0.6 → tradx-0.7.1}/test/test_ltpData.py +0 -0
  46. {tradx-0.6 → tradx-0.7.1}/test/test_ltpPartailData.py +0 -0
  47. {tradx-0.6 → tradx-0.7.1}/test/test_marketDataEngine.log +0 -0
  48. {tradx-0.6 → tradx-0.7.1}/test/test_marketDataEngine.py +0 -0
  49. {tradx-0.6 → tradx-0.7.1}/test/test_marketDepthData.py +0 -0
  50. {tradx-0.6 → tradx-0.7.1}/test/test_marketStatusData.py +0 -0
  51. {tradx-0.6 → tradx-0.7.1}/test/test_openInterestData.py +0 -0
  52. {tradx-0.6 → tradx-0.7.1}/test/test_openInterestPartialData.py +0 -0
  53. {tradx-0.6 → tradx-0.7.1}/test/test_option.py +0 -0
  54. {tradx-0.6 → tradx-0.7.1}/test/test_orderEvent.py +0 -0
  55. {tradx-0.6 → tradx-0.7.1}/test/test_positionEvent.py +0 -0
  56. {tradx-0.6 → tradx-0.7.1}/test/test_touchLineData.py +0 -0
  57. {tradx-0.6 → tradx-0.7.1}/test/test_tradeConversionEvent.py +0 -0
  58. {tradx-0.6 → tradx-0.7.1}/test/test_tradeEvent.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tradx
3
- Version: 0.6
3
+ Version: 0.7.1
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tradx"
3
- version = "0.6"
3
+ version = "0.7.1"
4
4
  description = "A Package Designed to simplify strategy development on package xts-api-client"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -0,0 +1,495 @@
1
+ from abc import ABC, abstractmethod
2
+ import shortuuid
3
+ from typing import Any, TYPE_CHECKING, List, Dict
4
+ from decimal import Decimal
5
+ from tradx.baseClass.order import Order
6
+ from tradx.baseClass.position import Position
7
+
8
+ import asyncio
9
+
10
+
11
+ if TYPE_CHECKING:
12
+ from tradx.marketDataEngine import marketDataEngine
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
18
+
19
+
20
+ class BaseAlgo(ABC):
21
+ """
22
+ BaseAlgo is an abstract base class for algorithmic trading strategies. It provides a framework for handling market data, orders, and trades, and requires subclasses to implement specific methods for processing data and events.
23
+ Attributes:
24
+ cache (dict): A cache for storing temporary data.
25
+ order_nos (ShortUUID): Instance of ShortUUID for generating unique order identifiers.
26
+ position_diary (List[Position]): A list to store position data.
27
+ order_diary (List[Order]): A list to store order data.
28
+ name (str): A unique identifier for the algorithm.
29
+ Methods:
30
+ __init__(marketDataEngine, interactiveEngine):
31
+ Initializes the BaseAlgo class with marketDataEngine and interactiveEngine instances.
32
+ on_barData(data):
33
+ Abstract method to process candle data. Must be implemented by subclasses.
34
+ subscribe():
35
+ Abstract method to handle subscription logic. Must be implemented by subclasses.
36
+ order_no():
37
+ Generates a unique order identifier.
38
+ order_(order):
39
+ Handles the order event by updating the status of an existing order or inserting a new order.
40
+ on_orderEvent(message):
41
+ Abstract method to handle order events. Must be implemented by subclasses.
42
+ trade_(trade):
43
+ Handles a trade event by updating the position diary and triggering the on_tradeEvent callback.
44
+ on_tradeEvent(message):
45
+ Abstract method to handle trade events. Must be implemented by subclasses.
46
+ unsubscribe():
47
+ Abstract method to handle unsubscription logic. Must be implemented by subclasses.
48
+ initialize():
49
+ Abstract method to initialize the strategy. Must be implemented by subclasses.
50
+ deinitialize():
51
+ Abstract method to deinitialize the strategy. Must be implemented by subclasses.
52
+ liquidateIntraday():
53
+ Class method to liquidate all intraday positions and cancel pending orders.
54
+ isInvested():
55
+ Class method to check if there are any investments by summing the quantities of all positions in the position diary.
56
+ """
57
+
58
+ def __init__(
59
+ self,
60
+ marketDataEngine: "marketDataEngine",
61
+ interactiveEngine: "interactiveEngine",
62
+ ):
63
+ """
64
+ Initialize the BaseAlgo class.
65
+
66
+ Args:
67
+ marketDataEngine (marketDataEngine): Instance of marketDataEngine.
68
+ interactiveEngine (interactiveEngine): Instance of interactiveEngine.
69
+ """
70
+ # Initialize instance variables
71
+ self.cache = {}
72
+ self.marketDataEngine = marketDataEngine
73
+ self.interactiveEngine = interactiveEngine
74
+ self.order_nos = shortuuid
75
+ self.position_diary: List[Position] = []
76
+ self.order_diary: List[Order] = []
77
+ # Registering inside interactive engine
78
+ self.name = interactiveEngine.shortuuid.ShortUUID().random(length=4)
79
+ self.interactiveEngine.strategy_to_id[self.name] = self
80
+
81
+ # Logging the initialization
82
+ if self.marketDataEngine.user_logger:
83
+ self.marketDataEngine.user_logger.info(
84
+ f"Algorithm initialized with ID: {self.name}",
85
+ caller=f"{self.__class__.__name__}.__init__",
86
+ )
87
+
88
+ @abstractmethod
89
+ async def on_barData(self, data: "CandleData") -> None:
90
+ """
91
+ Abstract method (virtual function) to process candle data.
92
+ Must be implemented by subclasses.
93
+
94
+ Args:
95
+ data (any): The input data to process.
96
+ """
97
+ ...
98
+
99
+ @abstractmethod
100
+ async def on_touchLineData(self, data: "TouchLineData") -> None:
101
+ """
102
+ Asynchronous method to handle touch line data.
103
+ Args:
104
+ data (TouchLineData): The touch line data to be processed.
105
+ Returns:
106
+ None
107
+ """
108
+
109
+ ...
110
+
111
+ @abstractmethod
112
+ async def subscribe(self) -> None:
113
+ """
114
+ Abstract method (virtual function) to process subscribe.
115
+ Must be implemented by subclasses.
116
+
117
+ Args:
118
+ data (any): The input data to process.
119
+ """
120
+ ...
121
+
122
+ def order_no(self) -> str:
123
+ """
124
+ Generate a unique order identifier.
125
+ The identifier is an 8-digit string composed of a 4-digit algorithm ID (derived from `self.name`)
126
+ and a 4-digit random sequence generated using the `ShortUUID` library.
127
+ Returns:
128
+ str: An 8-digit unique order identifier.
129
+ """
130
+ return f"{self.name}{self.order_nos.ShortUUID().random(length=4)}"
131
+
132
+ async def order_(self, order: "OrderEvent") -> None:
133
+ """
134
+ Handles the order event by either updating the status of an existing order
135
+ or inserting a new order into the order diary.
136
+ Args:
137
+ order (OrderEvent): The order event containing order details.
138
+ Returns:
139
+ None
140
+ """
141
+
142
+ existing_order = next(
143
+ (
144
+ O
145
+ for O in self.order_diary
146
+ if O.OrderUniqueIdentifier == order.OrderUniqueIdentifier
147
+ ),
148
+ None,
149
+ )
150
+
151
+ if existing_order:
152
+ # Update the status of the existing order
153
+ existing_order.OrderStatus = order.OrderStatus
154
+ if self.interactiveEngine.user_logger:
155
+ self.interactiveEngine.user_logger.info(
156
+ f"Updated order {order.OrderUniqueIdentifier} status to {order.OrderStatus}",
157
+ caller=f"{self.__class__.__name__}.order_",
158
+ )
159
+ else:
160
+ # Insert the new order by creating an object
161
+ new_order = Order(
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.OrderSide,
171
+ order.TimeInForce,
172
+ order.OrderStatus,
173
+ )
174
+ self.order_diary.append(new_order)
175
+ if self.interactiveEngine.user_logger:
176
+ self.interactiveEngine.user_logger.info(
177
+ f"Inserted new order {order.OrderUniqueIdentifier} with status {order.OrderStatus}",
178
+ caller=f"{self.__class__.__name__}.order_",
179
+ )
180
+ asyncio.ensure_future(self.on_orderEvent(order))
181
+
182
+ @abstractmethod
183
+ async def on_orderEvent(self, message: "OrderEvent") -> None:
184
+ """
185
+ On Order Event for strategy.
186
+ """
187
+ ...
188
+
189
+ async def trade_(self, trade: "TradeEvent") -> None:
190
+ """
191
+ Handles a trade event by updating the position diary and triggering the on_tradeEvent callback.
192
+ Args:
193
+ trade (TradeEvent): The trade event to be processed.
194
+ Returns:
195
+ None
196
+ The method performs the following steps:
197
+ 1. Checks if the trade exists in the position diary.
198
+ 2. Updates the position if it exists, otherwise inserts a new position.
199
+ 3. Logs the update or insertion of the position.
200
+ 4. Ensures the on_tradeEvent callback is called asynchronously.
201
+ """
202
+ if trade.OrderStatus != "Filled":
203
+ return
204
+ # Check if the trade exists in the position diary
205
+ existing_position = next(
206
+ (
207
+ _
208
+ for _ in self.position_diary
209
+ if _.ExchangeSegment == trade.ExchangeSegment
210
+ and _.ExchangeInstrumentID == trade.ExchangeInstrumentID
211
+ and _.ProductType == trade.ProductType
212
+ ),
213
+ None,
214
+ )
215
+ # Update the position
216
+ _quantity = (1 if trade.OrderSide == "Buy" else -1) * trade.OrderQuantity
217
+ if existing_position:
218
+ existing_position.Quantity += _quantity
219
+ if self.interactiveEngine.user_logger:
220
+ self.interactiveEngine.user_logger.info(
221
+ f"Updated position for trade {trade.ExchangeInstrumentID}: {existing_position.Quantity}",
222
+ caller=f"{self.__class__.__name__}.trade_",
223
+ )
224
+ else:
225
+ new_position = Position(
226
+ trade.ExchangeSegment,
227
+ trade.ExchangeInstrumentID,
228
+ trade.ProductType,
229
+ _quantity,
230
+ )
231
+ self.position_diary.append(new_position)
232
+ if self.interactiveEngine.user_logger:
233
+ self.interactiveEngine.user_logger.info(
234
+ f"Inserted new position {trade.ExchangeInstrumentID} with quantity {new_position.Quantity}",
235
+ caller=f"{self.__class__.__name__}.trade_",
236
+ )
237
+ asyncio.ensure_future(self.on_tradeEvent(trade))
238
+
239
+ @abstractmethod
240
+ def on_tradeEvent(self, message: "TradeEvent") -> None:
241
+ """
242
+ On trade Event for strategy.
243
+ """
244
+ ...
245
+
246
+ @abstractmethod
247
+ async def unsubscribe(self) -> None:
248
+ """
249
+ Abstract method (virtual function) to handle unsubscription logic.
250
+ Must be implemented by subclasses.
251
+ """
252
+ ...
253
+
254
+ @abstractmethod
255
+ async def initialize(self) -> None:
256
+ """
257
+ Initialize the strategy.
258
+ This function is intended to be a one-time asynchronous setup function for the strategy.
259
+ It can be used to perform any necessary initialization tasks, such as scheduling jobs with APScheduler.
260
+ """
261
+ # Perform initialization tasks here
262
+ ...
263
+
264
+ @abstractmethod
265
+ async def deinitialize(self) -> None:
266
+ """
267
+ Deinitialize the strategy.
268
+ This function is intended to be a one-time asynchronous teardown function for the strategy.
269
+ It can be used to perform any necessary cleanup tasks, such as unscheduling jobs with APScheduler.
270
+ """
271
+ # Perform deinitialization tasks here
272
+ ...
273
+
274
+ async def liquidateIntraday(self) -> None:
275
+ """
276
+ Asynchronously liquidates all intraday positions and cancels pending orders.
277
+ This method iterates through the order diary and cancels any orders that are
278
+ in the "PendingNew" or "New" status. It also iterates through the position
279
+ diary and places market orders to liquidate any positions with a non-zero
280
+ quantity.
281
+ Returns:
282
+ None
283
+ """
284
+ if self.interactiveEngine.user_logger:
285
+ self.interactiveEngine.user_logger.info(
286
+ f"Cancel open order and square off position for strategy {self.name}",
287
+ caller=f"{self.__class__.__name__}.liquidateIntraday",
288
+ )
289
+
290
+ for order in self.order_diary:
291
+ if order.OrderStatus in ["PendingNew", "New"]:
292
+ asyncio.ensure_future(
293
+ self.interactiveEngine.cancel_order(
294
+ order.AppOrderID, order.OrderUniqueIdentifier
295
+ )
296
+ )
297
+ for position in self.position_diary:
298
+ if position.Quantity != 0:
299
+ _order_no = self.order_no()
300
+ asyncio.ensure_future(
301
+ self.interactiveEngine.market_order(
302
+ position.ExchangeSegment,
303
+ position.ExchangeInstrumentID,
304
+ position.ProductType,
305
+ -1 * position.Quantity,
306
+ _order_no,
307
+ )
308
+ )
309
+
310
+ def isInvested(self) -> bool:
311
+ """
312
+ Asynchronously checks if there are any investments by summing the quantities
313
+ of all positions in the position diary.
314
+ Returns:
315
+ bool: True if the total quantity is not zero, indicating that there are
316
+ investments. False otherwise.
317
+ """
318
+
319
+ qty = 0
320
+ for position in self.position_diary:
321
+ qty += abs(position.Quantity)
322
+ return qty != 0
323
+
324
+ async def liquidateIntradayDummy(self) -> None:
325
+
326
+ if self.interactiveEngine.user_logger:
327
+ self.interactiveEngine.user_logger.info(
328
+ f"Cancel open order and square off position for strategy {self.name}",
329
+ caller=f"{self.__class__.__name__}.liquidateIntraday",
330
+ )
331
+
332
+ # for order in self.order_diary:
333
+ # if order.OrderStatus in ["PendingNew", "New"]:
334
+ # asyncio.ensure_future(
335
+ # self.interactiveEngine.cancel_order(
336
+ # order.AppOrderID, order.OrderUniqueIdentifier
337
+ # )
338
+ # )
339
+ for position in self.position_diary:
340
+ if position.Quantity != 0:
341
+ _order_no = self.order_no()
342
+ asyncio.ensure_future(
343
+ self.marketDataEngine.dummy_order(
344
+ position.ExchangeSegment,
345
+ position.ExchangeInstrumentID,
346
+ position.ProductType,
347
+ -1 * position.Quantity,
348
+ _order_no,
349
+ self,
350
+ )
351
+ )
352
+
353
+ async def safe_market_order(
354
+ self, ExchangeSegment, ExchangeInstrumentID, ProductType, Quantity, InitialBid, InitialAsk
355
+ ):
356
+ """
357
+ Places a safe market order by continuously modifying the order until it is filled.
358
+ Args:
359
+ ExchangeSegment (str): The segment of the exchange.
360
+ ExchangeInstrumentID (int): The instrument ID of the exchange.
361
+ ProductType (str): The type of the product.
362
+ Quantity (int): The quantity to be ordered. Positive for buy, negative for sell.
363
+ Returns:
364
+ None
365
+ Raises:
366
+ Exception: If there is an issue with fetching market data or placing/modifying the order.
367
+ This method performs the following steps:
368
+ 1. Generates a unique identifier for the order.
369
+ 2. Fetches the latest market data for the given instrument.
370
+ 3. Places a limit order with a slight price adjustment.
371
+ 4. Continuously checks the order status until it is filled.
372
+ 5. If the order is not filled, modifies the order with updated market data.
373
+ """
374
+ OrderUniqueIdentifier = self.order_no()
375
+ _adjust = Decimal("0.05")
376
+ Data: TouchLineData = (
377
+ await self.marketDataEngine.fetch_ltp(
378
+ [
379
+ {
380
+ "exchangeSegment": ExchangeSegment,
381
+ "exchangeInstrumentID": ExchangeInstrumentID,
382
+ }
383
+ ]
384
+ )
385
+ )[0]
386
+ price = (Data.AskInfo.Price + _adjust).to_eng_string() if Quantity > 0 else (Data.BidInfo.Price - _adjust).to_eng_string()
387
+ await self.interactiveEngine.limit_order(
388
+ ExchangeSegment,
389
+ ExchangeInstrumentID,
390
+ ProductType,
391
+ Quantity,
392
+ price,
393
+ OrderUniqueIdentifier,
394
+ )
395
+ if self.interactiveEngine.user_logger:
396
+ self.interactiveEngine.user_logger.info(
397
+ f"Placing Limit Order for {ExchangeInstrumentID} with Quantity {Quantity} with Price {price} and Initial Bid {InitialBid} and Initial Ask {InitialAsk}",
398
+ caller=f"{self.__class__.__name__}.safe_market_order",
399
+ )
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
+ while order is None or (order is not None and order.OrderStatus != "Filled"):
410
+ await asyncio.sleep(0.1)
411
+ order = next(
412
+ (
413
+ O
414
+ for O in self.order_diary
415
+ if O.OrderUniqueIdentifier == OrderUniqueIdentifier
416
+ ),
417
+ None,
418
+ )
419
+ if order is not None and order.OrderStatus == "Rejected":
420
+ if self.interactiveEngine.user_logger:
421
+ self.interactiveEngine.user_logger.info(
422
+ f"Order Rejected for {ExchangeInstrumentID} with Quantity {Quantity}",
423
+ caller=f"{self.__class__.__name__}.safe_market_order",
424
+ )
425
+ break
426
+ if order is not None and order.OrderStatus != "Filled":
427
+ Data: TouchLineData = (
428
+ await self.marketDataEngine.fetch_ltp(
429
+ [
430
+ {
431
+ "exchangeSegment": ExchangeSegment,
432
+ "exchangeInstrumentID": ExchangeInstrumentID,
433
+ }
434
+ ]
435
+ )
436
+ )[0]
437
+
438
+ await self.interactiveEngine.xt.modify_order(
439
+ order.AppOrderID,
440
+ order.ProductType,
441
+ order.OrderType,
442
+ order.OrderQuantity,
443
+ order.OrderDisclosedQuantity,
444
+ (
445
+ (Data.AskInfo.Price + _adjust).to_eng_string()
446
+ if Quantity > 0
447
+ else (Data.BidInfo.Price - _adjust).to_eng_string()
448
+ ),
449
+ order.OrderStopPrice.to_eng_string(),
450
+ order.TimeInForce,
451
+ order.OrderUniqueIdentifier,
452
+ "*****",
453
+ )
454
+ if self.interactiveEngine.user_logger:
455
+ self.interactiveEngine.user_logger.info(
456
+ f"Modifying Order for {ExchangeInstrumentID} with Quantity {Quantity} and Price "
457
+ f"{(Data.AskInfo.Price + _adjust).to_eng_string() if Quantity > 0 else (Data.BidInfo.Price - _adjust).to_eng_string()}",
458
+ caller=f"{self.__class__.__name__}.safe_market_order",
459
+ )
460
+ await asyncio.sleep(0.7)
461
+
462
+ async def safeLiquidateIntraday(self) -> None:
463
+ """
464
+ Asynchronously liquidates all intraday positions and cancels all open orders.
465
+ This method performs the following actions:
466
+ 1. Logs the action of canceling open orders and squaring off positions if a user logger is available.
467
+ 2. Iterates through the order diary and cancels any orders with a status of "PendingNew" or "New".
468
+ 3. Iterates through the position diary and places market orders to square off any positions with a non-zero quantity.
469
+ Returns:
470
+ None
471
+ """
472
+
473
+ if self.interactiveEngine.user_logger:
474
+ self.interactiveEngine.user_logger.info(
475
+ f"Cancel open order and square off position for strategy {self.name}",
476
+ caller=f"{self.__class__.__name__}.safeLiquidateIntraday",
477
+ )
478
+
479
+ for order in self.order_diary:
480
+ if order.OrderStatus in ["PendingNew", "New"]:
481
+ asyncio.ensure_future(
482
+ self.interactiveEngine.cancel_order(
483
+ order.AppOrderID, order.OrderUniqueIdentifier
484
+ )
485
+ )
486
+ for position in self.position_diary:
487
+ if position.Quantity != 0:
488
+ asyncio.ensure_future(
489
+ self.safe_market_order(
490
+ position.ExchangeSegment,
491
+ position.ExchangeInstrumentID,
492
+ position.ProductType,
493
+ -1 * position.Quantity,
494
+ )
495
+ )
@@ -122,7 +122,8 @@ class marketDataEngine(MarketDataSocketClient):
122
122
 
123
123
  async def on_event_market_status_full(self, data):
124
124
  """On receiving message code 1507:Market Status full"""
125
- __ = MarketStatusData(data)
125
+ # __ = MarketStatusData(data)
126
+ _ = data
126
127
  if self.user_logger:
127
128
  self.user_logger.info(
128
129
  f"1507:Market Status full;{__}",
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
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