tradx 0.1.0__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.
@@ -0,0 +1,279 @@
1
+ from decimal import Decimal
2
+ from pydantic import BaseModel, BeforeValidator
3
+ from typing_extensions import Annotated
4
+ from enum import Enum
5
+ from datetime import datetime
6
+ from typing import TYPE_CHECKING, List, Any
7
+
8
+ if TYPE_CHECKING:
9
+ from pandas.core.series import Series
10
+ from pandas import DataFrame
11
+
12
+
13
+ class OptionType(Enum):
14
+ CE = 3
15
+ PE = 4
16
+
17
+
18
+ def parse_int(value: Any) -> int:
19
+ if isinstance(value, str):
20
+ return int(value)
21
+ return value
22
+
23
+
24
+ def captilize_str(value: str) -> str:
25
+ return value.upper()
26
+
27
+
28
+ class OptionsInstrument(BaseModel):
29
+ ExchangeSegment: str
30
+ ExchangeInstrumentID: int
31
+ InstrumentType: int
32
+ Name: str
33
+ Description: str
34
+ Series: str
35
+ NameWithSeries: str
36
+ InstrumentID: int
37
+ PriceBand_High: Decimal
38
+ PriceBand_Low: Decimal
39
+ FreezeQty: int
40
+ TickSize: Decimal
41
+ LotSize: int
42
+ Multiplier: Decimal
43
+ UnderlyingInstrumentId: int
44
+ UnderlyingIndexName: str
45
+ ContractExpiration: datetime
46
+ StrikePrice: Decimal
47
+ OptionType: Annotated[OptionType, BeforeValidator(parse_int)]
48
+ DisplayName: str
49
+ PriceNumerator: int
50
+ PriceDenominator: int
51
+ DetailedDescription: str
52
+
53
+ class Config:
54
+ use_enum_values = True
55
+
56
+ def __init__(
57
+ self,
58
+ ExchangeSegment: str,
59
+ ExchangeInstrumentID: int,
60
+ InstrumentType: int,
61
+ Name: str,
62
+ Description: str,
63
+ Series: str,
64
+ NameWithSeries: str,
65
+ InstrumentID: int,
66
+ PriceBand_High: Decimal,
67
+ PriceBand_Low: Decimal,
68
+ FreezeQty: int,
69
+ TickSize: Decimal,
70
+ LotSize: int,
71
+ Multiplier: Decimal,
72
+ UnderlyingInstrumentId: int,
73
+ UnderlyingIndexName: Annotated[
74
+ str,
75
+ BeforeValidator(str, captilize_str),
76
+ ],
77
+ ContractExpiration: datetime,
78
+ StrikePrice: Decimal,
79
+ OptionType: Any,
80
+ DisplayName: str,
81
+ PriceNumerator: int,
82
+ PriceDenominator: int,
83
+ DetailedDescription: str,
84
+ ):
85
+ super().__init__(
86
+ ExchangeSegment=ExchangeSegment,
87
+ ExchangeInstrumentID=ExchangeInstrumentID,
88
+ InstrumentType=InstrumentType,
89
+ Name=Name,
90
+ Description=Description,
91
+ Series=Series,
92
+ NameWithSeries=NameWithSeries,
93
+ InstrumentID=InstrumentID,
94
+ PriceBand_High=PriceBand_High,
95
+ PriceBand_Low=PriceBand_Low,
96
+ FreezeQty=FreezeQty,
97
+ TickSize=TickSize,
98
+ LotSize=LotSize,
99
+ Multiplier=Multiplier,
100
+ UnderlyingInstrumentId=UnderlyingInstrumentId,
101
+ UnderlyingIndexName=UnderlyingIndexName,
102
+ ContractExpiration=ContractExpiration,
103
+ StrikePrice=StrikePrice,
104
+ OptionType=OptionType,
105
+ DisplayName=DisplayName,
106
+ PriceNumerator=PriceNumerator,
107
+ PriceDenominator=PriceDenominator,
108
+ DetailedDescription=DetailedDescription,
109
+ )
110
+
111
+ def __init__(self, df: "Series"):
112
+ super().__init__(**df)
113
+
114
+
115
+ class OptionManager:
116
+ """
117
+ Manages a list of options instruments and provides methods to search and filter them.
118
+ """
119
+
120
+ def __init__(self, option_master: "DataFrame"):
121
+ """
122
+ Initializes the OptionManager with a DataFrame of options data.
123
+ Args:
124
+ option_master (pandas.DataFrame): DataFrame containing options data.
125
+ """
126
+ self.__list: List[OptionsInstrument] = []
127
+ for index, row in option_master.iterrows():
128
+ self.__list.append(OptionsInstrument(row))
129
+
130
+ self.__all_underline = list(
131
+ set([option.UnderlyingIndexName for option in self.__list])
132
+ )
133
+
134
+ def search_expiry_by_underline(self, underline: str) -> List[datetime]:
135
+ """
136
+ Searches for all contract expirations for a given underlying index name.
137
+ Args:
138
+ underline (str): The underlying index name to search for.
139
+ Returns:
140
+ List[OptionsInstrument.ContractExpiration]: A sorted list of contract expirations.
141
+ """
142
+ return sorted(
143
+ list(
144
+ set(
145
+ option.ContractExpiration
146
+ for option in self.__list
147
+ if option.UnderlyingIndexName == underline
148
+ )
149
+ )
150
+ )
151
+
152
+ def search_all_underline(self) -> List[str]:
153
+ """
154
+ Retrieves all unique underlying index names.
155
+ Returns:
156
+ List[OptionsInstrument.UnderlyingIndexName]: A list of all unique underlying index names.
157
+ """
158
+ return self.__all_underline
159
+
160
+ def search_option_by_underline(self, underline: str) -> List[OptionsInstrument]:
161
+ """
162
+ Searches for all options instruments for a given underlying index name.
163
+ Args:
164
+ underline (str): The underlying index name to search for.
165
+ Returns:
166
+ List[OptionsInstrument]: A list of options instruments.
167
+ """
168
+ return [
169
+ option for option in self.__list if option.UnderlyingIndexName == underline
170
+ ]
171
+
172
+ def search_option_by_expiry_underline(
173
+ self, underline: str, expiry: datetime
174
+ ) -> List[OptionsInstrument]:
175
+ """
176
+ Searches for all options instruments for a given underlying index name and contract expiration.
177
+ Args:
178
+ underline (str): The underlying index name to search for.
179
+ expiry (OptionsInstrument.ContractExpiration): The contract expiration to search for.
180
+ Returns:
181
+ List[OptionsInstrument]: A list of options instruments.
182
+ """
183
+ return [
184
+ option
185
+ for option in self.__list
186
+ if option.UnderlyingIndexName == underline
187
+ and option.ContractExpiration == expiry
188
+ ]
189
+
190
+ def search_option(
191
+ self,
192
+ ExchangeSegment: str = None,
193
+ ExchangeInstrumentID: int = None,
194
+ InstrumentType: int = None,
195
+ Name: str = None,
196
+ Series: str = None,
197
+ UnderlyingIndexName: str = None,
198
+ ContractExpiration: datetime = None,
199
+ StrikePrice: int = None,
200
+ OptionType: int = None,
201
+ minimumExpiry: bool = False,
202
+ ) -> List[OptionsInstrument]:
203
+ """
204
+ Searches for options based on various criteria.
205
+ Args:
206
+ ExchangeSegment (str): Exchange segment to search for.
207
+ ExchangeInstrumentID (int): Exchange instrument ID to search for.
208
+ InstrumentType (int): Instrument type to search for.
209
+ Name (str): Name to search for.
210
+ Series (str): Series to search for.
211
+ UnderlyingIndexName (str): Underlying index name to search for.
212
+ ContractExpiration (datetime): Contract expiration to search for.
213
+ StrikePrice (int): Strike price to search for.
214
+ OptionType (int): Option type to search for.
215
+ minimumExpiry (bool): If True, only return options with the minimum expiration date.
216
+ Returns:
217
+ pandas.DataFrame: DataFrame containing the search results.
218
+ """
219
+ assert ExchangeSegment is None or isinstance(
220
+ ExchangeSegment, str
221
+ ), "ExchangeSegment must be a string"
222
+ assert ExchangeInstrumentID is None or isinstance(
223
+ ExchangeInstrumentID, int
224
+ ), "ExchangeInstrumentID must be an integer"
225
+ assert InstrumentType is None or isinstance(
226
+ InstrumentType, int
227
+ ), "InstrumentType must be an integer"
228
+ assert Name is None or isinstance(Name, str), "Name must be a string"
229
+ assert Series is None or isinstance(Series, str), "Series must be a string"
230
+ assert UnderlyingIndexName is None or isinstance(
231
+ UnderlyingIndexName, str
232
+ ), "UnderlyingIndexName must be a string"
233
+ assert ContractExpiration is None or isinstance(
234
+ ContractExpiration, datetime
235
+ ), "ContractExpiration must be a datetime"
236
+ assert StrikePrice is None or isinstance(
237
+ StrikePrice, int
238
+ ), "StrikePrice must be an integer"
239
+ assert OptionType is None or isinstance(
240
+ OptionType, int
241
+ ), "OptionType must be an integer"
242
+ assert isinstance(minimumExpiry, bool), "minimumExpiry must be a boolean"
243
+
244
+ criteria = {
245
+ "ExchangeSegment": ExchangeSegment,
246
+ "ExchangeInstrumentID": ExchangeInstrumentID,
247
+ "InstrumentType": InstrumentType,
248
+ "Name": Name,
249
+ "Series": Series,
250
+ "UnderlyingIndexName": UnderlyingIndexName,
251
+ "ContractExpiration": ContractExpiration,
252
+ "StrikePrice": StrikePrice,
253
+ "OptionType": OptionType,
254
+ }
255
+ criteria = {k: v for k, v in criteria.items() if v is not None}
256
+
257
+ if not criteria:
258
+ return self.__list
259
+
260
+ results = self.__list
261
+ for key, value in criteria.items():
262
+ if key == "Name":
263
+ results = [option for option in results if value in option.Name]
264
+ elif key == "ContractExpiration":
265
+ results = [
266
+ option for option in results if option.ContractExpiration <= value
267
+ ]
268
+ else:
269
+ results = [
270
+ option for option in results if getattr(option, key) == value
271
+ ]
272
+
273
+ if minimumExpiry:
274
+ _min_expiry = min([option.ContractExpiration for option in results])
275
+ results = [
276
+ option for option in results if option.ContractExpiration == _min_expiry
277
+ ]
278
+
279
+ return results
@@ -0,0 +1,27 @@
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
+ )
@@ -0,0 +1,90 @@
1
+ from pydantic import BaseModel, BeforeValidator
2
+ from typing_extensions import Annotated
3
+ from typing import Optional, Any
4
+ from datetime import datetime, timedelta
5
+ from decimal import Decimal
6
+ import json
7
+
8
+ def parse_decimal(value) -> Any:
9
+ """
10
+ Parses the given value and returns a decimal representation.
11
+ If the value is a string, it returns 0.0. Otherwise, it returns the value as is.
12
+ Args:
13
+ value: The value to be parsed. It can be of any type.
14
+ Returns:
15
+ Any: The parsed decimal value or the original value.
16
+ """
17
+
18
+ if isinstance(value, str):
19
+ return 0.0
20
+ return value
21
+ def parse_datetime(value) -> Any:
22
+ """
23
+ Parses the given value into a datetime object if it is an integer.
24
+ If the value is an integer, it is interpreted as the number of seconds since January 1, 1980.
25
+ The function returns a datetime object representing that date and time.
26
+ If the value is not an integer, it is returned as-is.
27
+ Args:
28
+ value (Any): The value to be parsed. Expected to be an integer representing seconds since January 1, 1980, or any other type.
29
+ Returns:
30
+ Any: A datetime object if the input is an integer, otherwise the input value unchanged.
31
+ """
32
+
33
+ if isinstance(value, int):
34
+ return datetime(1980, 1, 1) + timedelta(seconds=value)
35
+ return value
36
+ class OrderEvent(BaseModel):
37
+
38
+
39
+ LoginID: str
40
+ ClientID: str = "*****"
41
+ AppOrderID: int
42
+ OrderReferenceID: Optional[str]
43
+ GeneratedBy: str
44
+ ExchangeOrderID: Optional[str]
45
+ OrderCategoryType: str
46
+ ExchangeSegment: str
47
+ ExchangeInstrumentID: int
48
+ OrderSide: str
49
+ OrderType: str
50
+ ProductType: str
51
+ TimeInForce: str
52
+ OrderPrice: Decimal
53
+ OrderQuantity: int
54
+ OrderStopPrice: Decimal
55
+ OrderStatus: str
56
+ OrderAverageTradedPrice: Annotated[Decimal, BeforeValidator(parse_decimal)]
57
+ LeavesQuantity: int
58
+ CumulativeQuantity: int
59
+ OrderDisclosedQuantity: int
60
+ OrderGeneratedDateTime: datetime
61
+ ExchangeTransactTime: datetime
62
+ LastUpdateDateTime: datetime
63
+ OrderExpiryDate: datetime
64
+ CancelRejectReason: Optional[str]
65
+ OrderUniqueIdentifier: str
66
+ OrderLegStatus: str
67
+ IsSpread: bool
68
+ BoLegDetails: int
69
+ BoEntryOrderId: Optional[str]
70
+ OrderAverageTradedPriceAPI: Annotated[Decimal, BeforeValidator(parse_decimal)]
71
+ OrderSideAPI: str
72
+ OrderGeneratedDateTimeAPI: str
73
+ ExchangeTransactTimeAPI: str
74
+ LastUpdateDateTimeAPI: str
75
+ OrderExpiryDateAPI: str
76
+ AlgoID: Optional[str]
77
+ AlgoCategory: int
78
+ MessageSynchronizeUniqueKey: str
79
+ MessageCode: int
80
+ MessageVersion: int
81
+ TokenID: int
82
+ ApplicationType: int
83
+ SequenceNumber: int
84
+ TradingSymbol: str
85
+
86
+ def __init__(self, message: str):
87
+ data = json.loads(message)
88
+ super().__init__(**data)
89
+
90
+
@@ -0,0 +1,46 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class Position(BaseModel):
5
+ """
6
+ A class to represent a financial position.
7
+ Attributes:
8
+ -----------
9
+ ExchangeSegment : str
10
+ The segment of the exchange where the instrument is traded.
11
+ ExchangeInstrumentID : int
12
+ The unique identifier of the instrument on the exchange.
13
+ ProductType : str
14
+ The type of the financial product.
15
+ Quantity : int
16
+ The quantity of the financial instrument. Default is 0.
17
+ Methods:
18
+ --------
19
+ __init__(self, ExchangeSegment: str, ExchangeInstrumentID: int, ProductType: str, Quantity: int = 0):
20
+ Constructs all the necessary attributes for the Position object.
21
+ """
22
+
23
+ ExchangeSegment: str
24
+ ExchangeInstrumentID: int
25
+ ProductType: str
26
+ Quantity: int
27
+
28
+ def __init__(
29
+ self,
30
+ ExchangeSegment: str,
31
+ ExchangeInstrumentID: int,
32
+ ProductType: str,
33
+ Quantity: int = 0,
34
+ ):
35
+ assert isinstance(ExchangeSegment, str), "ExchangeSegment must be a string"
36
+ assert isinstance(
37
+ ExchangeInstrumentID, int
38
+ ), "ExchangeInstrumentID must be an integer"
39
+ assert isinstance(ProductType, str), "ProductType must be a string"
40
+ assert isinstance(Quantity, int), "Quantity must be an integer"
41
+ super().__init__(
42
+ ExchangeSegment=ExchangeSegment,
43
+ ExchangeInstrumentID=ExchangeInstrumentID,
44
+ ProductType=ProductType,
45
+ Quantity=Quantity,
46
+ )
@@ -0,0 +1,84 @@
1
+ from pydantic import BaseModel
2
+ from typing import Optional
3
+ from datetime import datetime
4
+ from decimal import Decimal
5
+ import json
6
+
7
+
8
+ class PositionEvent(BaseModel):
9
+ """
10
+ PositionEvent class represents a trading position event with various attributes related to trading positions.
11
+ Attributes:
12
+ LoginID (str): The login ID of the user.
13
+ AccountID (str): The account ID associated with the position.
14
+ TradingSymbol (str): The trading symbol of the instrument.
15
+ ExchangeSegment (str): The exchange segment where the instrument is traded.
16
+ ExchangeInstrumentID (int): The unique identifier for the instrument on the exchange.
17
+ ProductType (str): The type of product being traded.
18
+ Multiplier (Decimal): The multiplier for the instrument.
19
+ Marketlot (int): The market lot size of the instrument.
20
+ BuyAveragePrice (Decimal): The average price at which the instrument was bought.
21
+ SellAveragePrice (Decimal): The average price at which the instrument was sold.
22
+ LongPosition (int): The quantity of long positions.
23
+ ShortPosition (int): The quantity of short positions.
24
+ NetPosition (int): The net position (long - short).
25
+ BuyValue (Decimal): The total value of bought positions.
26
+ SellValue (Decimal): The total value of sold positions.
27
+ NetValue (Decimal): The net value (buy - sell).
28
+ UnrealizedMTM (Decimal): The unrealized mark-to-market value.
29
+ RealizedMTM (Decimal): The realized mark-to-market value.
30
+ MTM (Decimal): The total mark-to-market value.
31
+ BEP (Decimal): The break-even price.
32
+ SumOfTradedQuantityAndPriceBuy (Decimal): The sum of traded quantity and price for buy transactions.
33
+ SumOfTradedQuantityAndPriceSell (Decimal): The sum of traded quantity and price for sell transactions.
34
+ IsDayWiseNetWise (str): Indicator if the position is day-wise or net-wise.
35
+ StatisticsLevel (str): The level of statistics.
36
+ IsInterOpPosition (bool): Indicator if the position is interoperable.
37
+ childPositions (dict): Dictionary of child positions.
38
+ MessageCode (int): The message code.
39
+ MessageVersion (int): The version of the message.
40
+ TokenID (int): The token ID.
41
+ ApplicationType (int): The type of application.
42
+ SequenceNumber (int): The sequence number of the message.
43
+ Methods:
44
+ from_string(cls, message: str): Class method to create an instance of PositionEvent from a JSON string.
45
+ """
46
+
47
+ LoginID: str
48
+ AccountID: str
49
+ TradingSymbol: str
50
+ ExchangeSegment: str
51
+ ExchangeInstrumentID: int
52
+ ProductType: str
53
+ Multiplier: Decimal
54
+ Marketlot: int
55
+ BuyAveragePrice: Decimal
56
+ SellAveragePrice: Decimal
57
+ LongPosition: int
58
+ ShortPosition: int
59
+ NetPosition: int
60
+ BuyValue: Decimal
61
+ SellValue: Decimal
62
+ NetValue: Decimal
63
+ UnrealizedMTM: Decimal
64
+ RealizedMTM: Decimal
65
+ MTM: Decimal
66
+ BEP: Decimal
67
+ SumOfTradedQuantityAndPriceBuy: Decimal
68
+ SumOfTradedQuantityAndPriceSell: Decimal
69
+ IsDayWiseNetWise: str
70
+ StatisticsLevel: str
71
+ IsInterOpPosition: bool
72
+ childPositions: dict
73
+ MessageCode: int
74
+ MessageVersion: int
75
+ TokenID: int
76
+ ApplicationType: int
77
+ SequenceNumber: int
78
+
79
+ def __init__(self, message: str):
80
+ data = json.loads(message)
81
+ super().__init__(**data)
82
+
83
+
84
+