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.
- {tradx-0.1.1.2 → tradx-0.1.2}/.gitignore +2 -1
- {tradx-0.1.1.2 → tradx-0.1.2}/PKG-INFO +2 -2
- {tradx-0.1.1.2 → tradx-0.1.2}/pyproject.toml +2 -2
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/baseAlgo.py +137 -7
- tradx-0.1.2/src/tradx/baseClass/order.py +53 -0
- tradx-0.1.1.2/src/tradx/baseClass/order.py +0 -27
- {tradx-0.1.1.2 → tradx-0.1.2}/.vscode/settings.json +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/README.md +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/examples/example1.log +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/examples/example1.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/examples/example2.log +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/examples/example2.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/__init__.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/algoContainer.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/candleData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/cmInstrument.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/futureInstrument.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/index.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/instrumentPropertyChangeData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/ltpData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/ltpPartialData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/marketDepthData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/marketStatusData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/openInterestData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/openInterestPartialData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/optionsInstrument.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/orderEvent.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/position.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/positionEvent.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/touchLineData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/touchLinePartialData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/tradeConversionEvent.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/baseClass/tradeEvent.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/constants/holidays.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/dualHashMap.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/interactiveEngine.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/logger/logger.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/logger/logger2.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/marketDataEngine.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/src/tradx/py.typed +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_candleData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_interactiveEngine.log +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_interactiveEngine.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_logger.log +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_logger.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_ltpData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_ltpPartailData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_marketDataEngine.log +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_marketDataEngine.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_marketDepthData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_marketStatusData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_openInterestData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_openInterestPartialData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_option.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_orderEvent.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_positionEvent.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_touchLineData.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_tradeConversionEvent.py +0 -0
- {tradx-0.1.1.2 → tradx-0.1.2}/test/test_tradeEvent.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: tradx
|
3
|
-
Version: 0.1.
|
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
|
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.
|
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
|
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
|
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,
|
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 +=
|
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.
|
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
|
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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|