vortex-api 2.0.5__tar.gz → 2.0.7__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.
- {vortex_api-2.0.5/vortex_api.egg-info → vortex_api-2.0.7}/PKG-INFO +5 -17
- vortex_api-2.0.7/pyproject.toml +41 -0
- vortex_api-2.0.7/vortex_api/__version__.py +1 -0
- {vortex_api-2.0.5 → vortex_api-2.0.7}/vortex_api/api.py +255 -23
- {vortex_api-2.0.5 → vortex_api-2.0.7/vortex_api.egg-info}/PKG-INFO +5 -17
- {vortex_api-2.0.5 → vortex_api-2.0.7}/vortex_api.egg-info/SOURCES.txt +0 -1
- vortex_api-2.0.5/pyproject.toml +0 -3
- vortex_api-2.0.5/setup.py +0 -53
- vortex_api-2.0.5/vortex_api/__version__.py +0 -8
- {vortex_api-2.0.5 → vortex_api-2.0.7}/LICENSE +0 -0
- {vortex_api-2.0.5 → vortex_api-2.0.7}/README.md +0 -0
- {vortex_api-2.0.5 → vortex_api-2.0.7}/setup.cfg +0 -0
- {vortex_api-2.0.5 → vortex_api-2.0.7}/vortex_api/__init__.py +0 -0
- {vortex_api-2.0.5 → vortex_api-2.0.7}/vortex_api/vortex_feed.py +0 -0
- {vortex_api-2.0.5 → vortex_api-2.0.7}/vortex_api.egg-info/dependency_links.txt +0 -0
- {vortex_api-2.0.5 → vortex_api-2.0.7}/vortex_api.egg-info/requires.txt +0 -0
- {vortex_api-2.0.5 → vortex_api-2.0.7}/vortex_api.egg-info/top_level.txt +0 -0
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vortex_api
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.7
|
|
4
4
|
Summary: Vortex APIs to place orders in Rupeezy application
|
|
5
|
-
|
|
6
|
-
Download-URL: https://github.com/RupeezyTech/pyvortex
|
|
7
|
-
Author: Astha Credit & Securities Pvt Ltd.
|
|
8
|
-
Author-email: tech@rupeezy.in
|
|
5
|
+
Author-email: "Astha Credit & Securities Pvt Ltd." <tech@rupeezy.in>
|
|
9
6
|
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://vortex.rupeezy.in
|
|
8
|
+
Project-URL: Repository, https://github.com/RupeezyTech/pyvortex
|
|
10
9
|
Classifier: Intended Audience :: Developers
|
|
11
10
|
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
12
11
|
Classifier: Natural Language :: English
|
|
13
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
14
12
|
Classifier: Programming Language :: Python :: 3
|
|
15
13
|
Classifier: Operating System :: OS Independent
|
|
16
14
|
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
17
15
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
-
|
|
16
|
+
Requires-Python: >=3.8
|
|
19
17
|
Description-Content-Type: text/markdown
|
|
20
18
|
License-File: LICENSE
|
|
21
19
|
Requires-Dist: requests>=2.25.1
|
|
@@ -25,17 +23,7 @@ Requires-Dist: pyOpenSSL>=17.5.0
|
|
|
25
23
|
Requires-Dist: python-dateutil>=2.6.1
|
|
26
24
|
Requires-Dist: autobahn[twisted]==19.11.2
|
|
27
25
|
Requires-Dist: service_identity>=18.1.0
|
|
28
|
-
Dynamic: author
|
|
29
|
-
Dynamic: author-email
|
|
30
|
-
Dynamic: classifier
|
|
31
|
-
Dynamic: description
|
|
32
|
-
Dynamic: description-content-type
|
|
33
|
-
Dynamic: download-url
|
|
34
|
-
Dynamic: home-page
|
|
35
|
-
Dynamic: license
|
|
36
26
|
Dynamic: license-file
|
|
37
|
-
Dynamic: requires-dist
|
|
38
|
-
Dynamic: summary
|
|
39
27
|
|
|
40
28
|
# Vortex API Python Client
|
|
41
29
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77.0.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vortex_api"
|
|
7
|
+
version = "2.0.7"
|
|
8
|
+
description = "Vortex APIs to place orders in Rupeezy application"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Astha Credit & Securities Pvt Ltd.", email = "tech@rupeezy.in" }
|
|
13
|
+
]
|
|
14
|
+
requires-python = ">=3.8"
|
|
15
|
+
|
|
16
|
+
dependencies = [
|
|
17
|
+
"requests>=2.25.1",
|
|
18
|
+
"wrapt>=1.15.0",
|
|
19
|
+
"six>=1.11.0",
|
|
20
|
+
"pyOpenSSL>=17.5.0",
|
|
21
|
+
"python-dateutil>=2.6.1",
|
|
22
|
+
"autobahn[twisted]==19.11.2",
|
|
23
|
+
"service_identity>=18.1.0"
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
classifiers = [
|
|
27
|
+
"Intended Audience :: Developers",
|
|
28
|
+
"Intended Audience :: Financial and Insurance Industry",
|
|
29
|
+
"Natural Language :: English",
|
|
30
|
+
"Programming Language :: Python :: 3",
|
|
31
|
+
"Operating System :: OS Independent",
|
|
32
|
+
"Topic :: Office/Business :: Financial :: Investment",
|
|
33
|
+
"Topic :: Software Development :: Libraries :: Python Modules"
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://vortex.rupeezy.in"
|
|
38
|
+
Repository = "https://github.com/RupeezyTech/pyvortex"
|
|
39
|
+
|
|
40
|
+
[tool.setuptools.packages.find]
|
|
41
|
+
include = ["vortex_api"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.0.7"
|
|
@@ -2,6 +2,7 @@ import requests
|
|
|
2
2
|
import csv
|
|
3
3
|
import datetime
|
|
4
4
|
import logging
|
|
5
|
+
import math
|
|
5
6
|
from enum import Enum
|
|
6
7
|
import inspect
|
|
7
8
|
import wrapt
|
|
@@ -238,7 +239,7 @@ class VortexAPI:
|
|
|
238
239
|
Depricating Soon. Use SSO Login instead. Login using password and totp directly
|
|
239
240
|
|
|
240
241
|
Documentation:
|
|
241
|
-
https://vortex.rupeezy.in/docs/authentication/
|
|
242
|
+
https://vortex.rupeezy.in/docs/latest/authentication/
|
|
242
243
|
|
|
243
244
|
Args:
|
|
244
245
|
client_code(str): Client Code of the account
|
|
@@ -264,7 +265,7 @@ class VortexAPI:
|
|
|
264
265
|
Download list of all available instruments and their details across all exchanges
|
|
265
266
|
|
|
266
267
|
Documentation:
|
|
267
|
-
https://vortex.rupeezy.in/docs/historical/#instrument-list
|
|
268
|
+
https://vortex.rupeezy.in/docs/latest/historical/#instrument-list
|
|
268
269
|
|
|
269
270
|
Returns:
|
|
270
271
|
dict: CSV Array of all instruments. The first row contains headers
|
|
@@ -283,7 +284,7 @@ class VortexAPI:
|
|
|
283
284
|
Place an order for a specific security
|
|
284
285
|
|
|
285
286
|
Documentation:
|
|
286
|
-
https://vortex.rupeezy.in/docs/order/#placing-an-order
|
|
287
|
+
https://vortex.rupeezy.in/docs/latest/order/#placing-an-order
|
|
287
288
|
|
|
288
289
|
Args:
|
|
289
290
|
exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
|
|
@@ -343,7 +344,7 @@ class VortexAPI:
|
|
|
343
344
|
Method to modify an order using the Vortex API.
|
|
344
345
|
|
|
345
346
|
Documentation:
|
|
346
|
-
https://vortex.rupeezy.in/docs/order/#modifying-an-order
|
|
347
|
+
https://vortex.rupeezy.in/docs/latest/order/#modifying-an-order
|
|
347
348
|
|
|
348
349
|
Args:
|
|
349
350
|
exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
|
|
@@ -386,7 +387,7 @@ class VortexAPI:
|
|
|
386
387
|
Method to cancel an order using the Vortex API.
|
|
387
388
|
|
|
388
389
|
Documentation:
|
|
389
|
-
https://vortex.rupeezy.in/docs/order/#cancel-an-order
|
|
390
|
+
https://vortex.rupeezy.in/docs/latest/order/#cancel-an-order
|
|
390
391
|
|
|
391
392
|
Args:
|
|
392
393
|
exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
|
|
@@ -404,7 +405,7 @@ class VortexAPI:
|
|
|
404
405
|
Method to get all orders.
|
|
405
406
|
|
|
406
407
|
Documentation:
|
|
407
|
-
https://vortex.rupeezy.in/docs/order/#fetching-order-book
|
|
408
|
+
https://vortex.rupeezy.in/docs/latest/order/#fetching-order-book
|
|
408
409
|
|
|
409
410
|
Args:
|
|
410
411
|
limit (int): Limit is the number of orders to be fetched.
|
|
@@ -421,7 +422,7 @@ class VortexAPI:
|
|
|
421
422
|
Method to get the order history of a particular order
|
|
422
423
|
|
|
423
424
|
Documentation:
|
|
424
|
-
https://vortex.rupeezy.in/docs/order/
|
|
425
|
+
https://vortex.rupeezy.in/docs/latest/order/
|
|
425
426
|
|
|
426
427
|
Args:
|
|
427
428
|
order_id (str): Order id for which history has to be fetched
|
|
@@ -437,7 +438,7 @@ class VortexAPI:
|
|
|
437
438
|
Method to get the position book using the Vortex API.
|
|
438
439
|
|
|
439
440
|
Documentation:
|
|
440
|
-
https://vortex.rupeezy.in/docs/positions/#fetch-all-positions
|
|
441
|
+
https://vortex.rupeezy.in/docs/latest/positions/#fetch-all-positions
|
|
441
442
|
|
|
442
443
|
Returns:
|
|
443
444
|
dict: Dictionary containing the response data from the API.
|
|
@@ -450,7 +451,7 @@ class VortexAPI:
|
|
|
450
451
|
Method to get the holdings of the user using the Vortex API.
|
|
451
452
|
|
|
452
453
|
Documentation:
|
|
453
|
-
https://vortex.rupeezy.in/docs/holdings/
|
|
454
|
+
https://vortex.rupeezy.in/docs/latest/holdings/
|
|
454
455
|
|
|
455
456
|
Returns:
|
|
456
457
|
dict: Dictionary containing the response data from the API.
|
|
@@ -463,7 +464,7 @@ class VortexAPI:
|
|
|
463
464
|
Method to get today's trades of the user using the Vortex API.
|
|
464
465
|
|
|
465
466
|
Documentation:
|
|
466
|
-
https://vortex.rupeezy.in/docs/positions/#get-trades
|
|
467
|
+
https://vortex.rupeezy.in/docs/latest/positions/#get-trades
|
|
467
468
|
|
|
468
469
|
Returns:
|
|
469
470
|
dict: Dictionary containing the response data from the API.
|
|
@@ -476,7 +477,7 @@ class VortexAPI:
|
|
|
476
477
|
Method to get the funds of the user using the Vortex API.
|
|
477
478
|
|
|
478
479
|
Documentation:
|
|
479
|
-
https://vortex.rupeezy.in/docs/user/#available-funds
|
|
480
|
+
https://vortex.rupeezy.in/docs/latest/user/#available-funds
|
|
480
481
|
|
|
481
482
|
Returns:
|
|
482
483
|
dict: Dictionary containing the response data from the API.
|
|
@@ -490,7 +491,7 @@ class VortexAPI:
|
|
|
490
491
|
Get the margin required for placing an order for a specific security.
|
|
491
492
|
|
|
492
493
|
Documentation:
|
|
493
|
-
https://vortex.rupeezy.in/docs/margin/#order-margin
|
|
494
|
+
https://vortex.rupeezy.in/docs/latest/margin/#order-margin
|
|
494
495
|
|
|
495
496
|
Args:
|
|
496
497
|
exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
|
|
@@ -532,12 +533,25 @@ class VortexAPI:
|
|
|
532
533
|
}
|
|
533
534
|
return self._make_api_request("POST", endpoint, data=data)
|
|
534
535
|
|
|
536
|
+
def brokerage_plan(self)-> dict:
|
|
537
|
+
"""
|
|
538
|
+
Get brokerage plan details of the user.
|
|
539
|
+
|
|
540
|
+
Documentation:
|
|
541
|
+
https://vortex.rupeezy.in/docs/latest/user/
|
|
542
|
+
|
|
543
|
+
Returns:
|
|
544
|
+
dict: JSON response containing the details of the brokerage plan of the user
|
|
545
|
+
"""
|
|
546
|
+
endpoint = "/user/profile/brokerage"
|
|
547
|
+
return self._make_api_request("GET", endpoint, data=None,params=None)
|
|
548
|
+
|
|
535
549
|
def quotes(self, instruments: list, mode: Constants.QuoteModes)-> dict:
|
|
536
550
|
"""
|
|
537
551
|
Gets quotes of up to 1000 instruments at a time.
|
|
538
552
|
|
|
539
553
|
Documentation:
|
|
540
|
-
https://vortex.rupeezy.in/docs/historical/#fetch-price-quotes
|
|
554
|
+
https://vortex.rupeezy.in/docs/latest/historical/#fetch-price-quotes
|
|
541
555
|
|
|
542
556
|
Args:
|
|
543
557
|
instrument(list): List of instruments. The items should be like ( "NSE_EQ-22", "NSE_FO-1234")
|
|
@@ -556,7 +570,7 @@ class VortexAPI:
|
|
|
556
570
|
Gets historical candle data of a particular instrument.
|
|
557
571
|
|
|
558
572
|
Documentation:
|
|
559
|
-
https://vortex.rupeezy.in/docs/historical/#fetch-historical-candle-data
|
|
573
|
+
https://vortex.rupeezy.in/docs/latest/historical/#fetch-historical-candle-data
|
|
560
574
|
|
|
561
575
|
Args:
|
|
562
576
|
exchange (Constants.ExchangeTypes): Possible values: [NSE_EQ, NSE_FO, BSE_EQ, BSE_FO, NSE_CD or MCX_FO]
|
|
@@ -586,7 +600,7 @@ class VortexAPI:
|
|
|
586
600
|
Returns the login URL for the Vortex API.
|
|
587
601
|
|
|
588
602
|
Documentation:
|
|
589
|
-
https://vortex.rupeezy.in/docs/authentication/
|
|
603
|
+
https://vortex.rupeezy.in/docs/latest/authentication/
|
|
590
604
|
|
|
591
605
|
Returns:
|
|
592
606
|
str: The login URL for the Vortex API.
|
|
@@ -599,7 +613,7 @@ class VortexAPI:
|
|
|
599
613
|
Exchange the auth code received from the login URL for an access token.
|
|
600
614
|
|
|
601
615
|
Documentation:
|
|
602
|
-
https://vortex.rupeezy.in/docs/authentication/
|
|
616
|
+
https://vortex.rupeezy.in/docs/latest/authentication/
|
|
603
617
|
|
|
604
618
|
Args:
|
|
605
619
|
auth_code (str): The authorization code received from the login URL.
|
|
@@ -623,20 +637,238 @@ class VortexAPI:
|
|
|
623
637
|
sha.update(text.encode('utf-8'))
|
|
624
638
|
return sha.hexdigest()
|
|
625
639
|
|
|
626
|
-
def _setup_client_code(self, login_object: dict) -> bool:
|
|
627
|
-
"""
|
|
640
|
+
def _setup_client_code(self, login_object: dict) -> bool:
|
|
641
|
+
"""
|
|
628
642
|
Sets up access token after login
|
|
629
643
|
|
|
630
|
-
Args:
|
|
644
|
+
Args:
|
|
631
645
|
login_object(dict): Login object received
|
|
632
646
|
|
|
633
|
-
Returns:
|
|
647
|
+
Returns:
|
|
634
648
|
(bool): Whether successful or not
|
|
635
649
|
"""
|
|
636
650
|
|
|
637
|
-
if (('data' in login_object ) and login_object["data"] != None and login_object["data"]["access_token"] != None):
|
|
651
|
+
if (('data' in login_object ) and login_object["data"] != None and login_object["data"]["access_token"] != None):
|
|
638
652
|
self.access_token = login_object["data"]["access_token"]
|
|
639
653
|
return True
|
|
640
|
-
|
|
654
|
+
|
|
641
655
|
return False
|
|
642
|
-
|
|
656
|
+
|
|
657
|
+
def save_backtest_result(self, stats, name: str, symbol: str = "", description: str = "", tags: list = None) -> dict:
|
|
658
|
+
"""
|
|
659
|
+
Save backtest results to Rupeezy for viewing on the developer portal.
|
|
660
|
+
|
|
661
|
+
Args:
|
|
662
|
+
stats: The Stats object returned by Backtest.run() or Backtest.optimize()
|
|
663
|
+
from the backtesting.py library.
|
|
664
|
+
name (str): A label for this backtest run (e.g. "SMA Crossover v2").
|
|
665
|
+
symbol (str, optional): Primary instrument symbol.
|
|
666
|
+
description (str, optional): Notes about this run.
|
|
667
|
+
tags (list[str], optional): Tags for filtering (e.g. ["intraday", "nifty"]).
|
|
668
|
+
|
|
669
|
+
Returns:
|
|
670
|
+
dict: { "status": "success", "backtest_id": "bt_abc123", "url": "https://..." }
|
|
671
|
+
"""
|
|
672
|
+
payload = _serialize_stats(stats, name, symbol, description, tags or [])
|
|
673
|
+
endpoint = "/strategies/backtests"
|
|
674
|
+
|
|
675
|
+
return self._make_api_request("POST", endpoint, data=payload)
|
|
676
|
+
|
|
677
|
+
# ─── Backtest serialization helpers (module-level) ───────────────────────────
|
|
678
|
+
|
|
679
|
+
def _safe_float(val):
|
|
680
|
+
"""Convert a value to float, returning None for NaN/None/invalid."""
|
|
681
|
+
if val is None:
|
|
682
|
+
return None
|
|
683
|
+
try:
|
|
684
|
+
f = float(val)
|
|
685
|
+
if math.isnan(f) or math.isinf(f):
|
|
686
|
+
return None
|
|
687
|
+
return round(f, 4)
|
|
688
|
+
except (ValueError, TypeError):
|
|
689
|
+
return None
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
def _safe_isoformat(val):
|
|
693
|
+
"""Convert a datetime-like value to ISO format string."""
|
|
694
|
+
if val is None:
|
|
695
|
+
return None
|
|
696
|
+
try:
|
|
697
|
+
return val.isoformat()
|
|
698
|
+
except AttributeError:
|
|
699
|
+
return str(val)
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
def _duration_to_days(val):
|
|
703
|
+
"""Convert a timedelta-like value to integer days."""
|
|
704
|
+
if val is None:
|
|
705
|
+
return None
|
|
706
|
+
try:
|
|
707
|
+
return val.days
|
|
708
|
+
except AttributeError:
|
|
709
|
+
return None
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
def _serialize_stats(stats, name, symbol, description, tags):
|
|
713
|
+
def _sf(val):
|
|
714
|
+
if val is None:
|
|
715
|
+
return 0.0
|
|
716
|
+
try:
|
|
717
|
+
f = float(val)
|
|
718
|
+
return 0.0 if (math.isnan(f) or math.isinf(f)) else round(f, 4)
|
|
719
|
+
except (ValueError, TypeError):
|
|
720
|
+
return 0.0
|
|
721
|
+
|
|
722
|
+
def _dd(val):
|
|
723
|
+
if val is None:
|
|
724
|
+
return 0
|
|
725
|
+
try:
|
|
726
|
+
return val.days
|
|
727
|
+
except AttributeError:
|
|
728
|
+
return 0
|
|
729
|
+
|
|
730
|
+
summary = {
|
|
731
|
+
"return_pct": _sf(stats.get("Return [%]")),
|
|
732
|
+
"return_ann_pct": _sf(stats.get("Return (Ann.) [%]")),
|
|
733
|
+
"volatility_ann_pct": _sf(stats.get("Volatility (Ann.) [%]")),
|
|
734
|
+
"cagr_pct": _sf(stats.get("CAGR [%]")),
|
|
735
|
+
"buy_hold_return_pct": _sf(stats.get("Buy & Hold Return [%]")),
|
|
736
|
+
"alpha_pct": _sf(stats.get("Alpha [%]")),
|
|
737
|
+
"beta": _sf(stats.get("Beta")),
|
|
738
|
+
"sharpe_ratio": _sf(stats.get("Sharpe Ratio")),
|
|
739
|
+
"sortino_ratio": _sf(stats.get("Sortino Ratio")),
|
|
740
|
+
"calmar_ratio": _sf(stats.get("Calmar Ratio")),
|
|
741
|
+
"max_drawdown_pct": _sf(stats.get("Max. Drawdown [%]")),
|
|
742
|
+
"avg_drawdown_pct": _sf(stats.get("Avg. Drawdown [%]")),
|
|
743
|
+
"max_drawdown_duration_days": _dd(stats.get("Max. Drawdown Duration")),
|
|
744
|
+
"avg_drawdown_duration_days": _dd(stats.get("Avg. Drawdown Duration")),
|
|
745
|
+
"equity_final": _sf(stats.get("Equity Final [$]")),
|
|
746
|
+
"equity_peak": _sf(stats.get("Equity Peak [$]")),
|
|
747
|
+
"commissions_total": _sf(stats.get("Commissions [$]")),
|
|
748
|
+
"exposure_time_pct": _sf(stats.get("Exposure Time [%]")),
|
|
749
|
+
"total_trades": int(stats.get("# Trades", 0)),
|
|
750
|
+
"win_rate_pct": _sf(stats.get("Win Rate [%]")),
|
|
751
|
+
"best_trade_pct": _sf(stats.get("Best Trade [%]")),
|
|
752
|
+
"worst_trade_pct": _sf(stats.get("Worst Trade [%]")),
|
|
753
|
+
"avg_trade_pct": _sf(stats.get("Avg. Trade [%]")),
|
|
754
|
+
"max_trade_duration_days": _dd(stats.get("Max. Trade Duration")),
|
|
755
|
+
"avg_trade_duration_days": _dd(stats.get("Avg. Trade Duration")),
|
|
756
|
+
"profit_factor": _sf(stats.get("Profit Factor")),
|
|
757
|
+
"expectancy_pct": _sf(stats.get("Expectancy [%]")),
|
|
758
|
+
"sqn": _sf(stats.get("SQN")),
|
|
759
|
+
"kelly_criterion": _sf(stats.get("Kelly Criterion")),
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
# --- Strategy name and parameters ---
|
|
763
|
+
strategy_name = "Unknown"
|
|
764
|
+
parameters = {}
|
|
765
|
+
strategy = stats.get("_strategy")
|
|
766
|
+
if strategy is not None:
|
|
767
|
+
strategy_class = strategy if isinstance(strategy, type) else strategy.__class__
|
|
768
|
+
strategy_name = strategy_class.__name__
|
|
769
|
+
for attr in vars(strategy_class):
|
|
770
|
+
if attr.startswith("_"):
|
|
771
|
+
continue
|
|
772
|
+
val = getattr(strategy_class, attr, None)
|
|
773
|
+
if callable(val):
|
|
774
|
+
continue
|
|
775
|
+
if isinstance(val, (int, float, str, bool)):
|
|
776
|
+
parameters[attr] = val
|
|
777
|
+
|
|
778
|
+
# --- Equity curve ---
|
|
779
|
+
equity_curve = []
|
|
780
|
+
ec = stats.get("_equity_curve")
|
|
781
|
+
if ec is not None and hasattr(ec, "index"):
|
|
782
|
+
equity_series = ec["Equity"]
|
|
783
|
+
step = max(1, len(equity_series) // 500)
|
|
784
|
+
for i in range(0, len(equity_series), step):
|
|
785
|
+
equity_curve.append({
|
|
786
|
+
"date": equity_series.index[i].strftime("%Y-%m-%d"),
|
|
787
|
+
"equity": round(float(equity_series.iloc[i]), 2),
|
|
788
|
+
})
|
|
789
|
+
if equity_curve and equity_curve[-1]["date"] != equity_series.index[-1].strftime("%Y-%m-%d"):
|
|
790
|
+
equity_curve.append({
|
|
791
|
+
"date": equity_series.index[-1].strftime("%Y-%m-%d"),
|
|
792
|
+
"equity": round(float(equity_series.iloc[-1]), 2),
|
|
793
|
+
})
|
|
794
|
+
|
|
795
|
+
# --- Drawdown curve (computed from equity peak) ---
|
|
796
|
+
drawdown_curve = []
|
|
797
|
+
if ec is not None and hasattr(ec, "index"):
|
|
798
|
+
equity_series = ec["Equity"]
|
|
799
|
+
running_max = equity_series.cummax()
|
|
800
|
+
drawdown = ((equity_series - running_max) / running_max) * 100
|
|
801
|
+
step = max(1, len(drawdown) // 500)
|
|
802
|
+
for i in range(0, len(drawdown), step):
|
|
803
|
+
dd_val = round(float(drawdown.iloc[i]), 4)
|
|
804
|
+
if dd_val < -0.01:
|
|
805
|
+
drawdown_curve.append({
|
|
806
|
+
"date": drawdown.index[i].strftime("%Y-%m-%d"),
|
|
807
|
+
"equity": round(float(equity_series.iloc[i]), 2),
|
|
808
|
+
"drawdown_pct": dd_val,
|
|
809
|
+
})
|
|
810
|
+
|
|
811
|
+
# --- Trade log ---
|
|
812
|
+
trades_list = []
|
|
813
|
+
trades = stats.get("_trades")
|
|
814
|
+
if trades is not None and hasattr(trades, "iterrows"):
|
|
815
|
+
for i, trade in trades.iterrows():
|
|
816
|
+
size = trade.get("Size", 0)
|
|
817
|
+
entry_time = trade.get("EntryTime")
|
|
818
|
+
exit_time = trade.get("ExitTime")
|
|
819
|
+
duration = 0
|
|
820
|
+
if hasattr(entry_time, "strftime") and hasattr(exit_time, "strftime"):
|
|
821
|
+
duration = (exit_time - entry_time).days
|
|
822
|
+
trades_list.append({
|
|
823
|
+
"trade_number": i + 1,
|
|
824
|
+
"side": "LONG" if size > 0 else "SHORT",
|
|
825
|
+
"size": abs(int(size)) if size else 0,
|
|
826
|
+
"entry_bar": int(trade.get("EntryBar", 0)),
|
|
827
|
+
"exit_bar": int(trade.get("ExitBar", 0)),
|
|
828
|
+
"entry_date": entry_time.strftime("%Y-%m-%d") if hasattr(entry_time, "strftime") else str(entry_time),
|
|
829
|
+
"exit_date": exit_time.strftime("%Y-%m-%d") if hasattr(exit_time, "strftime") else str(exit_time),
|
|
830
|
+
"entry_price": _sf(trade.get("EntryPrice")),
|
|
831
|
+
"exit_price": _sf(trade.get("ExitPrice")),
|
|
832
|
+
"pnl_abs": _sf(trade.get("PnL")),
|
|
833
|
+
"pnl_pct": _sf(trade.get("ReturnPct")), # already in % form
|
|
834
|
+
"duration_days": duration,
|
|
835
|
+
})
|
|
836
|
+
|
|
837
|
+
# --- Monthly returns ---
|
|
838
|
+
monthly_returns = []
|
|
839
|
+
if ec is not None and hasattr(ec, "index"):
|
|
840
|
+
try:
|
|
841
|
+
equity_series = ec["Equity"]
|
|
842
|
+
monthly = equity_series.resample("ME").last()
|
|
843
|
+
pct = monthly.pct_change().dropna() * 100
|
|
844
|
+
for date, ret in pct.items():
|
|
845
|
+
monthly_returns.append({
|
|
846
|
+
"year": date.year,
|
|
847
|
+
"month": date.month,
|
|
848
|
+
"return_pct": _sf(ret),
|
|
849
|
+
})
|
|
850
|
+
except Exception:
|
|
851
|
+
pass
|
|
852
|
+
|
|
853
|
+
# --- Dates as YYYY-MM-DD ---
|
|
854
|
+
start_val = stats.get("Start")
|
|
855
|
+
end_val = stats.get("End")
|
|
856
|
+
start_date = start_val.strftime("%Y-%m-%d") if hasattr(start_val, "strftime") else str(start_val)
|
|
857
|
+
end_date = end_val.strftime("%Y-%m-%d") if hasattr(end_val, "strftime") else str(end_val)
|
|
858
|
+
|
|
859
|
+
return {
|
|
860
|
+
"name": name[:200],
|
|
861
|
+
"symbol": symbol[:50],
|
|
862
|
+
"description": description[:2000],
|
|
863
|
+
"tags": tags[:20],
|
|
864
|
+
"strategy_name": strategy_name,
|
|
865
|
+
"start_date": start_date,
|
|
866
|
+
"end_date": end_date,
|
|
867
|
+
"starting_capital": round(float(equity_curve[0]["equity"]), 2) if equity_curve else 0,
|
|
868
|
+
"parameters": parameters,
|
|
869
|
+
"summary": summary,
|
|
870
|
+
"equity_curve": equity_curve,
|
|
871
|
+
"drawdown_curve": drawdown_curve,
|
|
872
|
+
"trades": trades_list,
|
|
873
|
+
"monthly_returns": monthly_returns,
|
|
874
|
+
}
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vortex_api
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.7
|
|
4
4
|
Summary: Vortex APIs to place orders in Rupeezy application
|
|
5
|
-
|
|
6
|
-
Download-URL: https://github.com/RupeezyTech/pyvortex
|
|
7
|
-
Author: Astha Credit & Securities Pvt Ltd.
|
|
8
|
-
Author-email: tech@rupeezy.in
|
|
5
|
+
Author-email: "Astha Credit & Securities Pvt Ltd." <tech@rupeezy.in>
|
|
9
6
|
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://vortex.rupeezy.in
|
|
8
|
+
Project-URL: Repository, https://github.com/RupeezyTech/pyvortex
|
|
10
9
|
Classifier: Intended Audience :: Developers
|
|
11
10
|
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
12
11
|
Classifier: Natural Language :: English
|
|
13
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
14
12
|
Classifier: Programming Language :: Python :: 3
|
|
15
13
|
Classifier: Operating System :: OS Independent
|
|
16
14
|
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
17
15
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
-
|
|
16
|
+
Requires-Python: >=3.8
|
|
19
17
|
Description-Content-Type: text/markdown
|
|
20
18
|
License-File: LICENSE
|
|
21
19
|
Requires-Dist: requests>=2.25.1
|
|
@@ -25,17 +23,7 @@ Requires-Dist: pyOpenSSL>=17.5.0
|
|
|
25
23
|
Requires-Dist: python-dateutil>=2.6.1
|
|
26
24
|
Requires-Dist: autobahn[twisted]==19.11.2
|
|
27
25
|
Requires-Dist: service_identity>=18.1.0
|
|
28
|
-
Dynamic: author
|
|
29
|
-
Dynamic: author-email
|
|
30
|
-
Dynamic: classifier
|
|
31
|
-
Dynamic: description
|
|
32
|
-
Dynamic: description-content-type
|
|
33
|
-
Dynamic: download-url
|
|
34
|
-
Dynamic: home-page
|
|
35
|
-
Dynamic: license
|
|
36
26
|
Dynamic: license-file
|
|
37
|
-
Dynamic: requires-dist
|
|
38
|
-
Dynamic: summary
|
|
39
27
|
|
|
40
28
|
# Vortex API Python Client
|
|
41
29
|
|
vortex_api-2.0.5/pyproject.toml
DELETED
vortex_api-2.0.5/setup.py
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import io
|
|
2
|
-
import os
|
|
3
|
-
from codecs import open
|
|
4
|
-
from setuptools import setup,find_packages
|
|
5
|
-
|
|
6
|
-
current_dir = os.path.abspath(os.path.dirname(__file__))
|
|
7
|
-
|
|
8
|
-
about = {}
|
|
9
|
-
|
|
10
|
-
about = {}
|
|
11
|
-
with open(os.path.join(current_dir, "vortex_api", "__version__.py"), "r", "utf-8") as f:
|
|
12
|
-
exec(f.read(), about)
|
|
13
|
-
|
|
14
|
-
print("about hash is",about)
|
|
15
|
-
|
|
16
|
-
with io.open('README.md', 'rt', encoding='utf8') as f:
|
|
17
|
-
readme = f.read()
|
|
18
|
-
|
|
19
|
-
print("keys are",about.keys)
|
|
20
|
-
|
|
21
|
-
setup(
|
|
22
|
-
name=about["__name__"],
|
|
23
|
-
version=about["__version__"],
|
|
24
|
-
description=about["__description__"],
|
|
25
|
-
long_description=readme,
|
|
26
|
-
long_description_content_type='text/markdown',
|
|
27
|
-
author=about["__author__"],
|
|
28
|
-
author_email=about["__author_email__"],
|
|
29
|
-
url=about["__url__"],
|
|
30
|
-
download_url=about["__download_url__"],
|
|
31
|
-
license=about["__license__"],
|
|
32
|
-
packages=["vortex_api"],
|
|
33
|
-
install_requires=[
|
|
34
|
-
"requests>=2.25.1",
|
|
35
|
-
"wrapt>=1.15.0",
|
|
36
|
-
"six>=1.11.0",
|
|
37
|
-
"pyOpenSSL>=17.5.0",
|
|
38
|
-
"python-dateutil>=2.6.1",
|
|
39
|
-
"autobahn[twisted]==19.11.2",
|
|
40
|
-
"service_identity>=18.1.0"
|
|
41
|
-
],
|
|
42
|
-
classifiers=[
|
|
43
|
-
"Intended Audience :: Developers",
|
|
44
|
-
"Intended Audience :: Financial and Insurance Industry",
|
|
45
|
-
"Natural Language :: English",
|
|
46
|
-
"License :: OSI Approved :: MIT License",
|
|
47
|
-
"Programming Language :: Python :: 3",
|
|
48
|
-
"Operating System :: OS Independent",
|
|
49
|
-
"Topic :: Office/Business :: Financial :: Investment",
|
|
50
|
-
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
51
|
-
"Topic :: Software Development :: Libraries"
|
|
52
|
-
],
|
|
53
|
-
)
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
__name__ = "vortex_api"
|
|
2
|
-
__description__ = "Vortex APIs to place orders in Rupeezy application"
|
|
3
|
-
__url__ = "https://vortex.rupeezy.in"
|
|
4
|
-
__download_url__ = "https://github.com/RupeezyTech/pyvortex"
|
|
5
|
-
__version__ = "2.0.5"
|
|
6
|
-
__author__ = "Astha Credit & Securities Pvt Ltd."
|
|
7
|
-
__author_email__ = "tech@rupeezy.in"
|
|
8
|
-
__license__ = "MIT"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|