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.
tradx/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ def hello() -> str:
2
+ return "Hello from tradx!"
tradx/algoContainer.py ADDED
@@ -0,0 +1,90 @@
1
+ from typing import Dict, Set, Any
2
+ from tradx.baseClass.baseAlgo import BaseAlgo
3
+ from tradx.baseClass.candleData import CandleData
4
+ from tradx.baseClass.touchLineData import TouchLineData
5
+ import asyncio
6
+
7
+
8
+ class AlgoContainer:
9
+ """
10
+ AlgoContainer is a container class that maps algorithms to their subscriptions and allows broadcasting messages.
11
+ Attributes:
12
+ subscriptions (Dict[int, Set[BaseAlgo]]): A dictionary mapping subscription keys to sets of algorithm instances.
13
+ Methods:
14
+ __init__():
15
+ Initializes the AlgoContainer with an empty subscription map.
16
+ subscribe(key: int, algo: BaseAlgo):
17
+ Subscribes an algorithm to a specific key.
18
+ key (int): The subscription key.
19
+ algo (BaseAlgo): The algorithm instance subscribing.
20
+ unsubscribe(key: int, algo: BaseAlgo):
21
+ Unsubscribes an algorithm from a specific key.
22
+ key (int): The subscription key.
23
+ algo (BaseAlgo): The algorithm instance unsubscribing.
24
+ broadcast(key: int, message: str, dataType: str):
25
+ Broadcasts a message to all algorithms subscribed to a given key.
26
+ key (int): The key to broadcast the message for.
27
+ dataType (str): The type of data being broadcasted (e.g., "bar").
28
+ """
29
+
30
+ def __init__(self) -> None:
31
+ """
32
+ Initializes the algoContainer instance.
33
+
34
+ Attributes:
35
+ subscriptions (Dict[int, Set[BaseAlgo]]):
36
+ A dictionary mapping an integer key (e.g., a topic or identifier)
37
+ to a set of algorithm instances (BaseAlgo).
38
+ """
39
+ self.subscriptions: Dict[int, Set[BaseAlgo]] = {}
40
+
41
+ def subscribe(self, key, algo: BaseAlgo) -> None:
42
+ """
43
+ Subscribes an algorithm to a given key.
44
+ Args:
45
+ key: The key to subscribe the algorithm to.
46
+ algo (BaseAlgo): The algorithm to be subscribed.
47
+ Raises:
48
+ None
49
+ Returns:
50
+ None
51
+ """
52
+
53
+ if key not in self.subscriptions:
54
+ self.subscriptions[key] = set()
55
+ self.subscriptions[key].add(algo)
56
+
57
+ def unsubscribe(self, key, algo: BaseAlgo) -> None:
58
+ """
59
+ Unsubscribe an algorithm from a given key.
60
+ This method removes the specified algorithm from the list of
61
+ subscriptions associated with the given key. If no more algorithms
62
+ are subscribed to the key after removal, the key is deleted from
63
+ the subscriptions.
64
+ Args:
65
+ key: The key from which the algorithm should be unsubscribed.
66
+ algo (BaseAlgo): The algorithm instance to be unsubscribed.
67
+ """
68
+
69
+ if key in self.subscriptions and algo in self.subscriptions[key]:
70
+ self.subscriptions[key].remove(algo)
71
+
72
+ # Remove the key if no more algorithms are subscribed
73
+ if not self.subscriptions[key]:
74
+ del self.subscriptions[key]
75
+
76
+ async def broadcast(self, message: Any) -> None:
77
+ """
78
+ Broadcast a message to all algorithms subscribed to a given key.
79
+
80
+ Args:
81
+ key (str): The key to broadcast the message for.
82
+ message (str): The message to broadcast.
83
+ """
84
+ if message.ExchangeInstrumentID in self.subscriptions:
85
+ if isinstance(message, CandleData):
86
+ for algo in self.subscriptions[message.ExchangeInstrumentID]:
87
+ asyncio.ensure_future(algo.on_barData(message))
88
+ if isinstance(message, TouchLineData):
89
+ for algo in self.subscriptions[message.ExchangeInstrumentID]:
90
+ asyncio.ensure_future(algo.on_touchLineData(message))
@@ -0,0 +1,338 @@
1
+ from abc import ABC, abstractmethod
2
+ import shortuuid
3
+ from typing import Any, TYPE_CHECKING, List
4
+ from tradx.baseClass.order import Order
5
+ from tradx.baseClass.position import Position
6
+ import asyncio
7
+
8
+
9
+ if TYPE_CHECKING:
10
+ from tradx import interactiveEngine, marketDataEngine
11
+ from tradx.baseClass.orderEvent import OrderEvent
12
+ from tradx.baseClass.tradeEvent import TradeEvent
13
+ from tradx.baseClass.candleData import CandleData
14
+ from tradx.baseClass.touchLineData import TouchLineData
15
+
16
+
17
+ class BaseAlgo(ABC):
18
+ """
19
+ 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.
20
+ Attributes:
21
+ cache (dict): A cache for storing temporary data.
22
+ order_nos (ShortUUID): Instance of ShortUUID for generating unique order identifiers.
23
+ position_diary (List[Position]): A list to store position data.
24
+ order_diary (List[Order]): A list to store order data.
25
+ name (str): A unique identifier for the algorithm.
26
+ Methods:
27
+ __init__(marketDataEngine, interactiveEngine):
28
+ Initializes the BaseAlgo class with marketDataEngine and interactiveEngine instances.
29
+ on_barData(data):
30
+ Abstract method to process candle data. Must be implemented by subclasses.
31
+ subscribe():
32
+ Abstract method to handle subscription logic. Must be implemented by subclasses.
33
+ order_no():
34
+ Generates a unique order identifier.
35
+ order_(order):
36
+ Handles the order event by updating the status of an existing order or inserting a new order.
37
+ on_orderEvent(message):
38
+ Abstract method to handle order events. Must be implemented by subclasses.
39
+ trade_(trade):
40
+ Handles a trade event by updating the position diary and triggering the on_tradeEvent callback.
41
+ on_tradeEvent(message):
42
+ Abstract method to handle trade events. Must be implemented by subclasses.
43
+ unsubscribe():
44
+ Abstract method to handle unsubscription logic. Must be implemented by subclasses.
45
+ initialize():
46
+ Abstract method to initialize the strategy. Must be implemented by subclasses.
47
+ deinitialize():
48
+ Abstract method to deinitialize the strategy. Must be implemented by subclasses.
49
+ liquidateIntraday():
50
+ Class method to liquidate all intraday positions and cancel pending orders.
51
+ isInvested():
52
+ Class method to check if there are any investments by summing the quantities of all positions in the position diary.
53
+ """
54
+
55
+ def __init__(
56
+ self,
57
+ marketDataEngine: "marketDataEngine",
58
+ interactiveEngine: "interactiveEngine",
59
+ ):
60
+ """
61
+ Initialize the BaseAlgo class.
62
+
63
+ Args:
64
+ marketDataEngine (marketDataEngine): Instance of marketDataEngine.
65
+ interactiveEngine (interactiveEngine): Instance of interactiveEngine.
66
+ """
67
+ # Initialize instance variables
68
+ self.cache = {}
69
+ self.marketDataEngine = marketDataEngine
70
+ self.interactiveEngine = interactiveEngine
71
+ self.order_nos = shortuuid
72
+ self.position_diary: List[Position] = []
73
+ self.order_diary: List[Order] = []
74
+
75
+ # Registering inside interactive engine
76
+ self.name = interactiveEngine.shortuuid.ShortUUID().random(length=4)
77
+ self.interactiveEngine.strategy_to_id[self.name] = self
78
+
79
+ # Logging the initialization
80
+ if self.marketDataEngine.user_logger:
81
+ self.marketDataEngine.user_logger.info(
82
+ f"Algorithm initialized with ID: {self.name}",
83
+ caller=f"{self.__class__.__name__}.__init__",
84
+ )
85
+
86
+ @abstractmethod
87
+ async def on_barData(self, data: "CandleData") -> None:
88
+ """
89
+ Abstract method (virtual function) to process candle data.
90
+ Must be implemented by subclasses.
91
+
92
+ Args:
93
+ data (any): The input data to process.
94
+ """
95
+ ...
96
+
97
+ @abstractmethod
98
+ async def on_touchLineData(self, data: "TouchLineData") -> None:
99
+ """
100
+ Asynchronous method to handle touch line data.
101
+ Args:
102
+ data (TouchLineData): The touch line data to be processed.
103
+ Returns:
104
+ None
105
+ """
106
+
107
+ ...
108
+
109
+ @abstractmethod
110
+ async def subscribe(self) -> None:
111
+ """
112
+ Abstract method (virtual function) to process subscribe.
113
+ Must be implemented by subclasses.
114
+
115
+ Args:
116
+ data (any): The input data to process.
117
+ """
118
+ ...
119
+
120
+ def order_no(self) -> str:
121
+ """
122
+ Generate a unique order identifier.
123
+ The identifier is an 8-digit string composed of a 4-digit algorithm ID (derived from `self.name`)
124
+ and a 4-digit random sequence generated using the `ShortUUID` library.
125
+ Returns:
126
+ str: An 8-digit unique order identifier.
127
+ """
128
+ return f"{self.name}{self.order_nos.ShortUUID().random(length=4)}"
129
+
130
+ async def order_(self, order: "OrderEvent") -> None:
131
+ """
132
+ Handles the order event by either updating the status of an existing order
133
+ or inserting a new order into the order diary.
134
+ Args:
135
+ order (OrderEvent): The order event containing order details.
136
+ Returns:
137
+ None
138
+ """
139
+
140
+ existing_order = next(
141
+ (
142
+ O
143
+ for O in self.order_diary
144
+ if O.OrderUniqueIdentifier == order.OrderUniqueIdentifier
145
+ ),
146
+ None,
147
+ )
148
+
149
+ if existing_order:
150
+ # Update the status of the existing order
151
+ existing_order.OrderStatus = order.OrderStatus
152
+ if self.interactiveEngine.user_logger:
153
+ self.interactiveEngine.user_logger.info(
154
+ f"Updated order {order.OrderUniqueIdentifier} status to {order.OrderStatus}",
155
+ caller=f"{self.__class__.__name__}.order_",
156
+ )
157
+ else:
158
+ # Insert the new order by creating an object
159
+ new_order = Order(
160
+ order.OrderUniqueIdentifier, order.AppOrderID, order.OrderStatus
161
+ )
162
+ self.order_diary.append(new_order)
163
+ if self.interactiveEngine.user_logger:
164
+ self.interactiveEngine.user_logger.info(
165
+ f"Inserted new order {order.OrderUniqueIdentifier} with status {order.OrderStatus}",
166
+ caller=f"{self.__class__.__name__}.order_",
167
+ )
168
+ asyncio.ensure_future(self.on_orderEvent(order))
169
+
170
+ @abstractmethod
171
+ async def on_orderEvent(self, message: "OrderEvent") -> None:
172
+ """
173
+ On Order Event for strategy.
174
+ """
175
+ ...
176
+
177
+ async def trade_(self, trade: "TradeEvent") -> None:
178
+ """
179
+ Handles a trade event by updating the position diary and triggering the on_tradeEvent callback.
180
+ Args:
181
+ trade (TradeEvent): The trade event to be processed.
182
+ Returns:
183
+ None
184
+ The method performs the following steps:
185
+ 1. Checks if the trade exists in the position diary.
186
+ 2. Updates the position if it exists, otherwise inserts a new position.
187
+ 3. Logs the update or insertion of the position.
188
+ 4. Ensures the on_tradeEvent callback is called asynchronously.
189
+ """
190
+
191
+ # Check if the trade exists in the position diary
192
+ existing_position = next(
193
+ (
194
+ _
195
+ for _ in self.position_diary
196
+ if _.ExchangeSegment == trade.ExchangeSegment
197
+ and _.ExchangeInstrumentID == trade.ExchangeInstrumentID
198
+ and _.ProductType == trade.ProductType
199
+ ),
200
+ None,
201
+ )
202
+ # Update the position
203
+ _quantity = (1 if trade.OrderSide == "Buy" else -1) * trade.OrderQuantity
204
+ if existing_position:
205
+ existing_position.Quantity += _quantity
206
+ if self.interactiveEngine.user_logger:
207
+ self.interactiveEngine.user_logger.info(
208
+ f"Updated position for trade {trade.ExchangeInstrumentID}: {existing_position.Quantity}",
209
+ caller=f"{self.__class__.__name__}.trade_",
210
+ )
211
+ else:
212
+ new_position = Position(
213
+ trade.ExchangeSegment,
214
+ trade.ExchangeInstrumentID,
215
+ trade.ProductType,
216
+ _quantity,
217
+ )
218
+ self.position_diary.append(new_position)
219
+ if self.interactiveEngine.user_logger:
220
+ self.interactiveEngine.user_logger.info(
221
+ f"Inserted new position {trade.ExchangeInstrumentID} with quantity {new_position.Quantity}",
222
+ caller=f"{self.__class__.__name__}.trade_",
223
+ )
224
+ asyncio.ensure_future(self.on_tradeEvent(trade))
225
+
226
+ @abstractmethod
227
+ def on_tradeEvent(self, message: "TradeEvent") -> None:
228
+ """
229
+ On trade Event for strategy.
230
+ """
231
+ ...
232
+
233
+ @abstractmethod
234
+ async def unsubscribe(self) -> None:
235
+ """
236
+ Abstract method (virtual function) to handle unsubscription logic.
237
+ Must be implemented by subclasses.
238
+ """
239
+ ...
240
+
241
+ @abstractmethod
242
+ async def initialize(self) -> None:
243
+ """
244
+ Initialize the strategy.
245
+ This function is intended to be a one-time asynchronous setup function for the strategy.
246
+ It can be used to perform any necessary initialization tasks, such as scheduling jobs with APScheduler.
247
+ """
248
+ # Perform initialization tasks here
249
+ ...
250
+
251
+ @abstractmethod
252
+ async def deinitialize(self) -> None:
253
+ """
254
+ Deinitialize the strategy.
255
+ This function is intended to be a one-time asynchronous teardown function for the strategy.
256
+ It can be used to perform any necessary cleanup tasks, such as unscheduling jobs with APScheduler.
257
+ """
258
+ # Perform deinitialization tasks here
259
+ ...
260
+
261
+ async def liquidateIntraday(self) -> None:
262
+ """
263
+ Asynchronously liquidates all intraday positions and cancels pending orders.
264
+ This method iterates through the order diary and cancels any orders that are
265
+ in the "PendingNew" or "New" status. It also iterates through the position
266
+ diary and places market orders to liquidate any positions with a non-zero
267
+ quantity.
268
+ Returns:
269
+ None
270
+ """
271
+ if self.interactiveEngine.user_logger:
272
+ self.interactiveEngine.user_logger.info(
273
+ f"Cancel open order and square off position for strategy {self.name}",
274
+ caller=f"{self.__class__.__name__}.liquidateIntraday",
275
+ )
276
+
277
+ for order in self.order_diary:
278
+ if order.OrderStatus in ["PendingNew", "New"]:
279
+ asyncio.ensure_future(
280
+ self.interactiveEngine.cancel_order(
281
+ order.AppOrderID, order.OrderUniqueIdentifier
282
+ )
283
+ )
284
+ for position in self.position_diary:
285
+ if position.Quantity != 0:
286
+ _order_no = self.order_no()
287
+ asyncio.ensure_future(
288
+ self.interactiveEngine.market_order(
289
+ position.ExchangeSegment,
290
+ position.ExchangeInstrumentID,
291
+ position.ProductType,
292
+ -1 * position.Quantity,
293
+ _order_no,
294
+ )
295
+ )
296
+
297
+ def isInvested(self) -> bool:
298
+ """
299
+ Asynchronously checks if there are any investments by summing the quantities
300
+ of all positions in the position diary.
301
+ Returns:
302
+ bool: True if the total quantity is not zero, indicating that there are
303
+ investments. False otherwise.
304
+ """
305
+
306
+ qty = 0
307
+ for position in self.position_diary:
308
+ qty += position.Quantity
309
+ return qty != 0
310
+
311
+ async def liquidateIntradayDummy(self) -> None:
312
+
313
+ if self.interactiveEngine.user_logger:
314
+ self.interactiveEngine.user_logger.info(
315
+ f"Cancel open order and square off position for strategy {self.name}",
316
+ caller=f"{self.__class__.__name__}.liquidateIntraday",
317
+ )
318
+
319
+ # for order in self.order_diary:
320
+ # if order.OrderStatus in ["PendingNew", "New"]:
321
+ # asyncio.ensure_future(
322
+ # self.interactiveEngine.cancel_order(
323
+ # order.AppOrderID, order.OrderUniqueIdentifier
324
+ # )
325
+ # )
326
+ for position in self.position_diary:
327
+ if position.Quantity != 0:
328
+ _order_no = self.order_no()
329
+ asyncio.ensure_future(
330
+ self.marketDataEngine.dummy_order(
331
+ position.ExchangeSegment,
332
+ position.ExchangeInstrumentID,
333
+ position.ProductType,
334
+ -1 * position.Quantity,
335
+ _order_no,
336
+ self,
337
+ )
338
+ )
@@ -0,0 +1,89 @@
1
+ from pydantic import BaseModel
2
+ from decimal import Decimal
3
+ from datetime import datetime, timezone
4
+ import json
5
+ from typing import Dict, Any
6
+
7
+
8
+ class CandleData(BaseModel):
9
+ """
10
+ CandleData model representing candlestick data for trading.
11
+
12
+ Attributes:
13
+ MessageCode (int): The message code.
14
+ MessageVersion (int): The version of the message.
15
+ ApplicationType (int): The type of application.
16
+ TokenID (int): The token ID.
17
+ ExchangeSegment (int): The exchange segment.
18
+ BarTime (datetime): The time of the bar.
19
+ BarVolume (Decimal): The volume of the bar.
20
+ OpenInterest (Decimal): The open interest.
21
+ SumOfQtyInToPrice (Decimal): The sum of quantity into price.
22
+ ExchangeInstrumentID (int): The exchange instrument ID.
23
+ Open (Decimal): The opening price.
24
+ High (Decimal): The highest price.
25
+ Low (Decimal): The lowest price.
26
+ Close (Decimal): The closing price.
27
+ Methods:
28
+ from_string(cls, message: str):
29
+ Creates an instance of CandleData from a JSON string.
30
+ __getitem__(self, item):
31
+ Allows access to specific attributes using dictionary-like indexing.
32
+ __str__(self):
33
+ Returns a JSON string representation of the instance with selected attributes.
34
+ """
35
+
36
+ MessageCode: int
37
+ MessageVersion: int
38
+ ApplicationType: int
39
+ TokenID: int
40
+ ExchangeSegment: int
41
+ BarTime: int
42
+ BarVolume: Decimal
43
+ OpenInterest: Decimal
44
+ SumOfQtyInToPrice: Decimal
45
+ ExchangeInstrumentID: int
46
+ BarTime: datetime
47
+ Open: Decimal
48
+ High: Decimal
49
+ Low: Decimal
50
+ Close: Decimal
51
+
52
+ def __init__(self, input_data: Any):
53
+ if isinstance(input_data, dict):
54
+ input_data["BarTime"] = datetime.fromtimestamp(
55
+ input_data["BarTime"], timezone.utc
56
+ )
57
+ super().__init__(**input_data)
58
+ elif isinstance(input_data, str):
59
+ data = json.loads(input_data)
60
+ data["BarTime"] = datetime.fromtimestamp(data["BarTime"], timezone.utc)
61
+ super().__init__(**data)
62
+ else:
63
+ raise ValueError("Unsupported input type for CandleData")
64
+
65
+ def __getitem__(self, item):
66
+ allowed_keys = {
67
+ "High",
68
+ "Low",
69
+ "Open",
70
+ "Close",
71
+ "ExchangeInstrumentID",
72
+ "BarTime",
73
+ "Volume",
74
+ }
75
+ if item in allowed_keys:
76
+ return getattr(self, item)
77
+
78
+ def __str__(self):
79
+ allowed_keys = {
80
+ "High",
81
+ "Low",
82
+ "Open",
83
+ "Close",
84
+ "ExchangeInstrumentID",
85
+ "BarTime",
86
+ "BarVolume",
87
+ }
88
+ filtered_data = {key: getattr(self, key) for key in allowed_keys}
89
+ return json.dumps(filtered_data, default=str, indent=4)
@@ -0,0 +1,84 @@
1
+ from decimal import Decimal
2
+ from pydantic import BaseModel
3
+ from typing import TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from pandas.core.series import Series
7
+
8
+
9
+ class CMInstrument(BaseModel):
10
+ ExchangeSegment: str
11
+ ExchangeInstrumentID: int
12
+ InstrumentType: int
13
+ Name: str
14
+ Description: str
15
+ Series: str
16
+ NameWithSeries: str
17
+ InstrumentID: int
18
+ PriceBand_High: Decimal
19
+ PriceBand_Low: Decimal
20
+ FreezeQty: int
21
+ TickSize: Decimal
22
+ LotSize: int
23
+ Multiplier: Decimal
24
+ DisplayName: str
25
+ ISIN: str
26
+ PriceNumerator: int
27
+ PriceDenominator: int
28
+ DetailedDescription: str
29
+ ExtendedSurvlndicator: int
30
+ Cautionlndicator: int
31
+ GSMIndicator: int
32
+
33
+ def __init__(
34
+ self,
35
+ ExchangeSegment: str,
36
+ ExchangeInstrumentID: int,
37
+ InstrumentType: int,
38
+ Name: str,
39
+ Description: str,
40
+ Series: str,
41
+ NameWithSeries: str,
42
+ InstrumentID: int,
43
+ PriceBand_High: Decimal,
44
+ PriceBand_Low: Decimal,
45
+ FreezeQty: int,
46
+ TickSize: Decimal,
47
+ LotSize: int,
48
+ Multiplier: Decimal,
49
+ DisplayName: str,
50
+ ISIN: str,
51
+ PriceNumerator: int,
52
+ PriceDenominator: int,
53
+ DetailedDescription: str,
54
+ ExtendedSurvlndicator: int,
55
+ Cautionlndicator: int,
56
+ GSMIndicator: int,
57
+ ):
58
+ super().__init__(
59
+ ExchangeSegment=ExchangeSegment,
60
+ ExchangeInstrumentID=ExchangeInstrumentID,
61
+ InstrumentType=InstrumentType,
62
+ Name=Name,
63
+ Description=Description,
64
+ Series=Series,
65
+ NameWithSeries=NameWithSeries,
66
+ InstrumentID=InstrumentID,
67
+ PriceBand_High=PriceBand_High,
68
+ PriceBand_Low=PriceBand_Low,
69
+ FreezeQty=FreezeQty,
70
+ TickSize=TickSize,
71
+ LotSize=LotSize,
72
+ Multiplier=Multiplier,
73
+ DisplayName=DisplayName,
74
+ ISIN=ISIN,
75
+ PriceNumerator=PriceNumerator,
76
+ PriceDenominator=PriceDenominator,
77
+ DetailedDescription=DetailedDescription,
78
+ ExtendedSurvlndicator=ExtendedSurvlndicator,
79
+ Cautionlndicator=Cautionlndicator,
80
+ GSMIndicator=GSMIndicator,
81
+ )
82
+
83
+ def __init__(self, df: "Series"):
84
+ super().__init__(**df)
@@ -0,0 +1,74 @@
1
+ from decimal import Decimal
2
+ from pydantic import BaseModel
3
+ from datetime import datetime
4
+ from typing import TYPE_CHECKING
5
+
6
+ if TYPE_CHECKING:
7
+ from pandas.core.series import Series
8
+
9
+ class FutureInstrument(BaseModel):
10
+ ExchangeSegment: str
11
+ ExchangeInstrumentID: int
12
+ InstrumentType: int
13
+ Name: str
14
+ Description: str
15
+ Series: str
16
+ NameWithSeries: str
17
+ InstrumentID: int
18
+ PriceBand_High: Decimal
19
+ PriceBand_Low: Decimal
20
+ FreezeQty: int
21
+ TickSize: Decimal
22
+ LotSize: int
23
+ Multiplier: Decimal
24
+ ContractExpiration: datetime
25
+ DisplayName: str
26
+ PriceNumerator: int
27
+ PriceDenominator: int
28
+ DetailedDescription: str
29
+
30
+ def __init__(
31
+ self,
32
+ ExchangeSegment: str,
33
+ ExchangeInstrumentID: int,
34
+ InstrumentType: int,
35
+ Name: str,
36
+ Description: str,
37
+ Series: str,
38
+ NameWithSeries: str,
39
+ InstrumentID: int,
40
+ PriceBand_High: Decimal,
41
+ PriceBand_Low: Decimal,
42
+ FreezeQty: int,
43
+ TickSize: Decimal,
44
+ LotSize: int,
45
+ Multiplier: Decimal,
46
+ ContractExpiration: datetime,
47
+ DisplayName: str,
48
+ PriceNumerator: int,
49
+ PriceDenominator: int,
50
+ DetailedDescription: str,
51
+ ):
52
+ super().__init__(
53
+ ExchangeSegment=ExchangeSegment,
54
+ ExchangeInstrumentID=ExchangeInstrumentID,
55
+ InstrumentType=InstrumentType,
56
+ Name=Name,
57
+ Description=Description,
58
+ Series=Series,
59
+ NameWithSeries=NameWithSeries,
60
+ InstrumentID=InstrumentID,
61
+ PriceBand_High=PriceBand_High,
62
+ PriceBand_Low=PriceBand_Low,
63
+ FreezeQty=FreezeQty,
64
+ TickSize=TickSize,
65
+ LotSize=LotSize,
66
+ Multiplier=Multiplier,
67
+ ContractExpiration=ContractExpiration,
68
+ DisplayName=DisplayName,
69
+ PriceNumerator=PriceNumerator,
70
+ PriceDenominator=PriceDenominator,
71
+ DetailedDescription=DetailedDescription,
72
+ )
73
+ def __init__(self, df: "Series"):
74
+ super().__init__(**df)