quantplay 2.0.8__tar.gz → 2.0.10__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.
- {quantplay-2.0.8 → quantplay-2.0.10}/PKG-INFO +1 -1
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/noren.py +99 -68
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay.egg-info/PKG-INFO +1 -1
- {quantplay-2.0.8 → quantplay-2.0.10}/setup.py +1 -1
- {quantplay-2.0.8 → quantplay-2.0.10}/README.md +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/pyproject.toml +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/aliceblue.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/angelone.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/auto_login/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/auto_login/aliceblue.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/finvasia_utils/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/finvasia_utils/fa_noren.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/five_paisa.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/flattrade.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/ft_utils/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/ft_utils/flattrade_utils.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/ft_utils/ft_noren.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/generics/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/generics/broker.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/iifl_xts.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/kite_utils.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/motilal.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/shoonya.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/uplink/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/uplink/uplink_utils.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/upstox.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/xts.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/xts_utils/Connect.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/xts_utils/Exception.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/xts_utils/InteractiveSocketClient.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/xts_utils/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/broker/zerodha.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/exception/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/exception/exceptions.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/model/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/model/broker/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/model/broker/generics.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/py.typed +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/strategies/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/strategies/equities/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/strategies/equities/intraday/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/strategies/equities/overnight/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/strategies/futures/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/strategies/futures/overnight/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/strategies/options/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/strategies/options/intraday/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/strategies/options/intraday/ladder.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/strategies/options/intraday/musk.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/strategies/options/intraday/short_straddle.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/utils/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/utils/constant.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/utils/exchange.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/utils/number_utils.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/utils/pickle_utils.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/utils/selenium_utils.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/wrapper/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/wrapper/aws/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay/wrapper/aws/s3.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay.egg-info/SOURCES.txt +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay.egg-info/dependency_links.txt +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay.egg-info/requires.txt +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/quantplay.egg-info/top_level.txt +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/setup.cfg +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/tests/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/tests/conftest.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/tests/wrapper/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/tests/wrapper/aws/__init__.py +0 -0
- {quantplay-2.0.8 → quantplay-2.0.10}/tests/wrapper/aws/s3_test.py +0 -0
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from queue import Queue
|
|
3
3
|
import traceback
|
|
4
|
-
from typing import Dict
|
|
4
|
+
from typing import Callable, Dict, Literal
|
|
5
5
|
|
|
6
6
|
import polars as pl
|
|
7
7
|
from retrying import retry
|
|
8
8
|
from json.decoder import JSONDecodeError
|
|
9
9
|
|
|
10
|
+
from quantplay.broker.finvasia_utils.fa_noren import FA_NorenApi
|
|
11
|
+
from quantplay.broker.ft_utils.ft_noren import FT_NorenApi
|
|
10
12
|
from quantplay.broker.generics.broker import Broker
|
|
11
13
|
from quantplay.exception.exceptions import (
|
|
12
14
|
InvalidArgumentException,
|
|
@@ -47,7 +49,9 @@ class Noren(Broker):
|
|
|
47
49
|
self.order_type_sl = "SL-LMT"
|
|
48
50
|
self.trigger_pending_status = "TRIGGER_PENDING"
|
|
49
51
|
|
|
50
|
-
|
|
52
|
+
self.api: FA_NorenApi | FT_NorenApi
|
|
53
|
+
|
|
54
|
+
def set_attributes(self, response: Dict[str, str | None]) -> None:
|
|
51
55
|
self.email = response["email"]
|
|
52
56
|
self.user_id = response["actid"]
|
|
53
57
|
self.full_name = response["uname"]
|
|
@@ -72,9 +76,10 @@ class Noren(Broker):
|
|
|
72
76
|
def get_symbol(self, symbol, exchange=None):
|
|
73
77
|
if symbol not in self.quantplay_symbol_map:
|
|
74
78
|
return symbol
|
|
79
|
+
|
|
75
80
|
return self.quantplay_symbol_map[symbol]
|
|
76
81
|
|
|
77
|
-
def get_transaction_type(self, transaction_type):
|
|
82
|
+
def get_transaction_type(self, transaction_type: Literal["BUY", "SELL"]):
|
|
78
83
|
if transaction_type == "BUY":
|
|
79
84
|
return "B"
|
|
80
85
|
elif transaction_type == "SELL":
|
|
@@ -87,16 +92,19 @@ class Noren(Broker):
|
|
|
87
92
|
def get_order_type(self, order_type):
|
|
88
93
|
if order_type == OrderType.market:
|
|
89
94
|
return "MKT"
|
|
95
|
+
|
|
90
96
|
elif order_type == OrderType.sl:
|
|
91
97
|
return "SL-LMT"
|
|
98
|
+
|
|
92
99
|
elif order_type == OrderType.slm:
|
|
93
100
|
return "SL-MKT"
|
|
101
|
+
|
|
94
102
|
elif order_type == OrderType.limit:
|
|
95
103
|
return "LMT"
|
|
96
104
|
|
|
97
105
|
return order_type
|
|
98
106
|
|
|
99
|
-
def get_product(self, product):
|
|
107
|
+
def get_product(self, product: str):
|
|
100
108
|
if product == "NRML":
|
|
101
109
|
return "M"
|
|
102
110
|
elif product == "CNC":
|
|
@@ -106,9 +114,7 @@ class Noren(Broker):
|
|
|
106
114
|
elif product in ["M", "C", "I"]:
|
|
107
115
|
return product
|
|
108
116
|
|
|
109
|
-
raise InvalidArgumentException(
|
|
110
|
-
"Product {} not supported for trading".format(product)
|
|
111
|
-
)
|
|
117
|
+
raise InvalidArgumentException(f"Product {product} not supported for trading")
|
|
112
118
|
|
|
113
119
|
def event_handler_order_update(self, order):
|
|
114
120
|
try:
|
|
@@ -117,14 +123,11 @@ class Noren(Broker):
|
|
|
117
123
|
order["order_id"] = order["norenordno"]
|
|
118
124
|
order["exchange_order_id"] = order["exchordid"]
|
|
119
125
|
order["exchange"] = order["exch"]
|
|
120
|
-
|
|
121
|
-
# TODO translate symbol
|
|
122
|
-
# -EQ should be removed
|
|
123
|
-
# F&O symbol translation
|
|
124
126
|
order["tradingsymbol"] = order["tsym"]
|
|
125
127
|
|
|
126
128
|
if order["exchange"] == "NSE":
|
|
127
129
|
order["tradingsymbol"] = order["tradingsymbol"].replace("-EQ", "")
|
|
130
|
+
|
|
128
131
|
elif order["exchange"] in ["NFO", "MCX"]:
|
|
129
132
|
order["tradingsymbol"] = self.broker_symbol_map[order["tradingsymbol"]]
|
|
130
133
|
|
|
@@ -210,7 +213,7 @@ class Noren(Broker):
|
|
|
210
213
|
"remarks": tag,
|
|
211
214
|
}
|
|
212
215
|
Constants.logger.info("[PLACING_ORDER] {}".format(json.dumps(data)))
|
|
213
|
-
response = self.api.place_order(
|
|
216
|
+
response = self.api.place_order(
|
|
214
217
|
buy_or_sell=noren_transaction_type,
|
|
215
218
|
product_type=noren_product,
|
|
216
219
|
exchange=exchange,
|
|
@@ -227,10 +230,12 @@ class Noren(Broker):
|
|
|
227
230
|
Constants.logger.info(
|
|
228
231
|
"[PLACE_ORDER_RESPONSE] {} input {}".format(response, json.dumps(data))
|
|
229
232
|
)
|
|
230
|
-
|
|
233
|
+
|
|
234
|
+
if response is not None and "norenordno" in response:
|
|
231
235
|
return response["norenordno"]
|
|
232
236
|
else:
|
|
233
237
|
raise Exception(response)
|
|
238
|
+
|
|
234
239
|
except Exception as e:
|
|
235
240
|
traceback.print_exc()
|
|
236
241
|
exception_message = "Order placement failed with error [{}]".format(str(e))
|
|
@@ -248,12 +253,21 @@ class Noren(Broker):
|
|
|
248
253
|
tradingsymbol = self.get_symbol(tradingsymbol)
|
|
249
254
|
|
|
250
255
|
token = self.symbol_data["{}:{}".format(exchange, tradingsymbol)]["token"]
|
|
251
|
-
|
|
256
|
+
quote = self.api.get_quotes(exchange, str(token))
|
|
257
|
+
|
|
258
|
+
if quote is None:
|
|
259
|
+
raise BrokerException("Response from Broker for LTP is Invalid")
|
|
260
|
+
|
|
261
|
+
return float(quote["lp"])
|
|
252
262
|
|
|
253
263
|
def live_data(self, exchange, tradingsymbol):
|
|
254
264
|
tradingsymbol = self.get_symbol(tradingsymbol)
|
|
255
265
|
token = self.symbol_data["{}:{}".format(exchange, tradingsymbol)]["token"]
|
|
256
|
-
data = self.api.get_quotes(exchange, str(token))
|
|
266
|
+
data = self.api.get_quotes(exchange, str(token))
|
|
267
|
+
|
|
268
|
+
if data is None:
|
|
269
|
+
raise BrokerException("Response from Broker for Market Data is Invalid")
|
|
270
|
+
|
|
257
271
|
return {
|
|
258
272
|
"ltp": float(data["lp"]),
|
|
259
273
|
"upper_circuit": float(data["uc"]),
|
|
@@ -261,15 +275,20 @@ class Noren(Broker):
|
|
|
261
275
|
}
|
|
262
276
|
|
|
263
277
|
def order_history(self, order_id):
|
|
264
|
-
order_history = self.api.single_order_history(order_id)
|
|
278
|
+
order_history = self.api.single_order_history(order_id)
|
|
279
|
+
|
|
280
|
+
if order_history is None:
|
|
281
|
+
raise BrokerException("Response from Broker for Order History is Invalid")
|
|
282
|
+
|
|
265
283
|
order_details = order_history[0]
|
|
266
284
|
|
|
267
|
-
data = {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
285
|
+
data = {
|
|
286
|
+
"order_id": order_id,
|
|
287
|
+
"order_type": order_details["prctyp"],
|
|
288
|
+
"exchange": order_details["exch"],
|
|
289
|
+
"quantity": order_details["qty"],
|
|
290
|
+
"tradingsymbol": order_details["tsym"],
|
|
291
|
+
}
|
|
273
292
|
|
|
274
293
|
return data
|
|
275
294
|
|
|
@@ -289,6 +308,7 @@ class Noren(Broker):
|
|
|
289
308
|
|
|
290
309
|
if "order_type" not in order_to_modify:
|
|
291
310
|
order_to_modify["order_type"] = existing_details["order_type"]
|
|
311
|
+
|
|
292
312
|
if "quantity" not in order_to_modify:
|
|
293
313
|
order_to_modify["quantity"] = existing_details["quantity"]
|
|
294
314
|
|
|
@@ -308,33 +328,39 @@ class Noren(Broker):
|
|
|
308
328
|
order_to_modify["order_id"], response
|
|
309
329
|
)
|
|
310
330
|
)
|
|
331
|
+
|
|
332
|
+
if response is None:
|
|
333
|
+
raise Exception("Response is None")
|
|
334
|
+
|
|
311
335
|
return response
|
|
336
|
+
|
|
312
337
|
except Exception as e:
|
|
313
|
-
exception_message =
|
|
314
|
-
|
|
315
|
-
order_to_modify["order_id"], e
|
|
316
|
-
)
|
|
317
|
-
)
|
|
318
|
-
Constants.logger.error("{}".format(exception_message))
|
|
338
|
+
exception_message = f"OrderModificationFailed for {order_to_modify['order_id']} failed with exception {e}"
|
|
339
|
+
Constants.logger.error(f"{exception_message}")
|
|
319
340
|
raise e
|
|
320
341
|
|
|
321
342
|
@timeit(MetricName="Finvasia:cancel_order")
|
|
322
343
|
def cancel_order(self, order_id, variety=None):
|
|
323
|
-
self.api.cancel_order(order_id)
|
|
344
|
+
self.api.cancel_order(order_id)
|
|
324
345
|
|
|
325
346
|
def stream_order_data(self):
|
|
326
|
-
self.api.start_websocket(
|
|
327
|
-
order_update_callback=self.event_handler_order_update
|
|
328
|
-
)
|
|
347
|
+
self.api.start_websocket(order_update_callback=self.event_handler_order_update)
|
|
329
348
|
|
|
330
349
|
@timeit(MetricName="Finvasia:profile")
|
|
331
350
|
def profile(self) -> UserBrokerProfileResponse:
|
|
351
|
+
if self.user_id is None:
|
|
352
|
+
raise Exception("User ID is unknown")
|
|
353
|
+
|
|
332
354
|
response: UserBrokerProfileResponse = {
|
|
333
|
-
"user_id": self.user_id,
|
|
334
|
-
"full_name": self.full_name,
|
|
335
|
-
"email": self.email,
|
|
355
|
+
"user_id": self.user_id,
|
|
336
356
|
}
|
|
337
357
|
|
|
358
|
+
if self.full_name is not None:
|
|
359
|
+
response["full_name"] = self.full_name
|
|
360
|
+
|
|
361
|
+
if self.email is not None:
|
|
362
|
+
response["email"] = self.email
|
|
363
|
+
|
|
338
364
|
return response
|
|
339
365
|
|
|
340
366
|
@timeit(MetricName="Noren:holdings")
|
|
@@ -344,7 +370,7 @@ class Noren(Broker):
|
|
|
344
370
|
stop_max_attempt_number=3,
|
|
345
371
|
)
|
|
346
372
|
def holdings(self):
|
|
347
|
-
holdings = self.api.get_holdings()
|
|
373
|
+
holdings = self.api.get_holdings()
|
|
348
374
|
if holdings is None or len(holdings) == 0:
|
|
349
375
|
return pl.DataFrame(schema=self.holidings_schema)
|
|
350
376
|
|
|
@@ -387,27 +413,13 @@ class Noren(Broker):
|
|
|
387
413
|
return holdings_df[list(self.holidings_schema.keys())].cast(self.holidings_schema)
|
|
388
414
|
|
|
389
415
|
@timeit(MetricName="Finvasia:positions")
|
|
390
|
-
@retry(
|
|
391
|
-
wait_exponential_multiplier=3000,
|
|
392
|
-
wait_exponential_max=10000,
|
|
393
|
-
stop_max_attempt_number=3,
|
|
394
|
-
retry_on_exception=retry_exception,
|
|
395
|
-
)
|
|
396
416
|
def positions(self, drop_cnc: bool = True) -> pl.DataFrame:
|
|
397
|
-
|
|
398
|
-
try:
|
|
399
|
-
positions = self.api.get_positions() # type:ignore
|
|
400
|
-
if positions is None or len(positions) == 0:
|
|
401
|
-
return pl.DataFrame(schema=self.positions_schema)
|
|
402
|
-
except BrokerException:
|
|
403
|
-
raise
|
|
404
|
-
except JSONDecodeError:
|
|
405
|
-
raise BrokerException("Broker failed to send positions")
|
|
406
|
-
except Exception:
|
|
407
|
-
raise
|
|
417
|
+
positions = self.invoke_noren_api(self.api.get_positions)
|
|
408
418
|
|
|
409
|
-
|
|
419
|
+
if positions is None or len(positions) == 0:
|
|
420
|
+
return pl.DataFrame(schema=self.positions_schema)
|
|
410
421
|
|
|
422
|
+
positions_df = pl.DataFrame(positions)
|
|
411
423
|
positions_df = positions_df.rename(
|
|
412
424
|
{
|
|
413
425
|
"tsym": "tradingsymbol",
|
|
@@ -488,16 +500,9 @@ class Noren(Broker):
|
|
|
488
500
|
|
|
489
501
|
@timeit(MetricName="Finvasia:orders")
|
|
490
502
|
def orders(self, tag: str | None = None, add_ltp: bool = True) -> pl.DataFrame:
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
return pl.DataFrame(schema=self.orders_schema)
|
|
495
|
-
except BrokerException:
|
|
496
|
-
raise
|
|
497
|
-
except JSONDecodeError:
|
|
498
|
-
raise BrokerException("Broker failed to send orders")
|
|
499
|
-
except Exception:
|
|
500
|
-
raise
|
|
503
|
+
orders = self.invoke_noren_api(self.api.get_order_book)
|
|
504
|
+
if orders is None or len(orders) == 0:
|
|
505
|
+
return pl.DataFrame(schema=self.orders_schema)
|
|
501
506
|
|
|
502
507
|
orders_df = pl.DataFrame(orders)
|
|
503
508
|
|
|
@@ -632,6 +637,27 @@ class Noren(Broker):
|
|
|
632
637
|
|
|
633
638
|
return orders_df[list(self.orders_schema.keys())].cast(self.orders_schema)
|
|
634
639
|
|
|
640
|
+
@retry(
|
|
641
|
+
wait_exponential_multiplier=3000,
|
|
642
|
+
wait_exponential_max=10000,
|
|
643
|
+
stop_max_attempt_number=3,
|
|
644
|
+
retry_on_exception=retry_exception,
|
|
645
|
+
)
|
|
646
|
+
def invoke_noren_api(self, fn: Callable, *args, **kwargs) -> Dict:
|
|
647
|
+
try:
|
|
648
|
+
response = fn(*args, **kwargs)
|
|
649
|
+
if "stat" in response and "not_ok" == response["stat"].lower():
|
|
650
|
+
raise TokenException(response["emsg"])
|
|
651
|
+
return response
|
|
652
|
+
|
|
653
|
+
except JSONDecodeError:
|
|
654
|
+
raise BrokerException("Failed to data from broker")
|
|
655
|
+
|
|
656
|
+
except Exception:
|
|
657
|
+
traceback.print_exc()
|
|
658
|
+
# raise RetryableException("Failed to data from broker")
|
|
659
|
+
raise Exception("Failed to data from broker")
|
|
660
|
+
|
|
635
661
|
@timeit(MetricName="Finvasia:positions")
|
|
636
662
|
@retry(
|
|
637
663
|
wait_exponential_multiplier=1000,
|
|
@@ -640,9 +666,7 @@ class Noren(Broker):
|
|
|
640
666
|
retry_on_exception=retry_exception,
|
|
641
667
|
)
|
|
642
668
|
def margins(self) -> Dict:
|
|
643
|
-
api_margins = self.api.get_limits
|
|
644
|
-
if "stat" in api_margins and "not_ok" == api_margins["stat"].lower():
|
|
645
|
-
raise TokenException(api_margins["emsg"])
|
|
669
|
+
api_margins = self.invoke_noren_api(self.api.get_limits)
|
|
646
670
|
|
|
647
671
|
try:
|
|
648
672
|
collateral = 0
|
|
@@ -653,8 +677,10 @@ class Noren(Broker):
|
|
|
653
677
|
api_margins["margin_used"] = 0
|
|
654
678
|
else:
|
|
655
679
|
api_margins["margin_used"] = api_margins["marginused"]
|
|
680
|
+
|
|
656
681
|
if "payin" not in api_margins:
|
|
657
682
|
api_margins["payin"] = 0
|
|
683
|
+
|
|
658
684
|
margin_available = (
|
|
659
685
|
float(api_margins["cash"])
|
|
660
686
|
+ float(collateral)
|
|
@@ -665,23 +691,28 @@ class Noren(Broker):
|
|
|
665
691
|
margins = {}
|
|
666
692
|
margins["margin_used"] = api_margins["margin_used"]
|
|
667
693
|
margins["margin_available"] = margin_available
|
|
694
|
+
|
|
668
695
|
try:
|
|
669
696
|
margins["cash"] = float(api_margins["cash"])
|
|
670
697
|
except Exception:
|
|
671
698
|
margins["cash"] = 0
|
|
699
|
+
|
|
672
700
|
margins["total_balance"] = float(api_margins["cash"]) + float(collateral)
|
|
673
701
|
|
|
674
702
|
return margins
|
|
703
|
+
|
|
675
704
|
except Exception as e:
|
|
676
705
|
logger.error(f"[NOREN_MARGIN_ERROR] {e}")
|
|
677
706
|
RetryableException("[NOREN] Failed to fetch account margin")
|
|
707
|
+
|
|
678
708
|
return {}
|
|
679
709
|
|
|
680
710
|
@timeit(MetricName="Finvasia:account_summary")
|
|
681
711
|
def account_summary(self):
|
|
682
|
-
margins: Dict = self.margins()
|
|
683
712
|
pnl = 0
|
|
713
|
+
margins: Dict = self.margins()
|
|
684
714
|
positions = self.positions()
|
|
715
|
+
|
|
685
716
|
if len(positions) > 0:
|
|
686
717
|
pnl = positions["pnl"].sum()
|
|
687
718
|
|
|
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
|
{quantplay-2.0.8 → quantplay-2.0.10}/quantplay/strategies/options/intraday/short_straddle.py
RENAMED
|
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
|