investfly-sdk 1.5__py3-none-any.whl → 1.6__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.
- investfly/api/IndicatorApiClient.py +12 -1
- investfly/api/RestApiClient.py +2 -1
- investfly/cli/InvestflyCli.py +40 -11
- investfly/samples/indicators/RsiOfSma.py +3 -7
- investfly/samples/indicators/SmaEmaAverage.py +3 -6
- {investfly_sdk-1.5.dist-info → investfly_sdk-1.6.dist-info}/METADATA +2 -1
- {investfly_sdk-1.5.dist-info → investfly_sdk-1.6.dist-info}/RECORD +11 -11
- {investfly_sdk-1.5.dist-info → investfly_sdk-1.6.dist-info}/WHEEL +1 -1
- {investfly_sdk-1.5.dist-info → investfly_sdk-1.6.dist-info}/LICENSE.txt +0 -0
- {investfly_sdk-1.5.dist-info → investfly_sdk-1.6.dist-info}/entry_points.txt +0 -0
- {investfly_sdk-1.5.dist-info → investfly_sdk-1.6.dist-info}/top_level.txt +0 -0
@@ -9,13 +9,24 @@ class IndicatorApiClient:
|
|
9
9
|
def __init__(self, restApiClient: RestApiClient) -> None:
|
10
10
|
self.restApiClient = restApiClient
|
11
11
|
|
12
|
-
def
|
12
|
+
def listCustomIndicators(self) -> List[IndicatorSpec]:
|
13
13
|
indicatorsListDict = self.restApiClient.doGet('/indicator/list/custom')
|
14
14
|
result: List[IndicatorSpec] = []
|
15
15
|
for indicatorDict in indicatorsListDict:
|
16
16
|
result.append(IndicatorSpec.fromDict(indicatorDict))
|
17
17
|
return result
|
18
18
|
|
19
|
+
def listStandardIndicators(self) -> List[IndicatorSpec]:
|
20
|
+
indicatorsListDict = self.restApiClient.doGet('/indicator/list/standard')
|
21
|
+
result: List[IndicatorSpec] = []
|
22
|
+
for indicatorDict in indicatorsListDict:
|
23
|
+
result.append(IndicatorSpec.fromDict(indicatorDict))
|
24
|
+
return result
|
25
|
+
|
26
|
+
def getIndicatorSpec(self, indicatorId: str) -> IndicatorSpec:
|
27
|
+
specDict = self.restApiClient.doGet(f'/indicator/{indicatorId}')
|
28
|
+
return IndicatorSpec.fromDict(specDict)
|
29
|
+
|
19
30
|
def getIndicatorCode(self, indicatorId: str) -> str:
|
20
31
|
return self.restApiClient.doGet(f'/indicator/custom/{indicatorId}/code')
|
21
32
|
|
investfly/api/RestApiClient.py
CHANGED
@@ -19,11 +19,12 @@ class RestApiClient:
|
|
19
19
|
|
20
20
|
def __init__(self, baseUrl: str) -> None:
|
21
21
|
self.headers: Dict[str, str] = {}
|
22
|
+
self.headers['client-mode'] = 'api'
|
22
23
|
self.baseUrl = baseUrl
|
23
24
|
self.log = logging.getLogger(self.__class__.__name__)
|
24
25
|
|
25
26
|
def login(self, username: str, password: str) -> Session:
|
26
|
-
res = requests.post(self.baseUrl + "/user/login", auth=(username, password), verify=False)
|
27
|
+
res = requests.post(self.baseUrl + "/user/login", auth=(username, password), headers=self.headers, verify=False)
|
27
28
|
if res.status_code == 200:
|
28
29
|
self.headers['investfly-client-id'] = res.headers['investfly-client-id']
|
29
30
|
self.headers['investfly-client-token'] = res.headers['investfly-client-token']
|
investfly/cli/InvestflyCli.py
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
import argparse
|
2
|
-
import pickle
|
3
|
-
import os.path
|
4
2
|
import time
|
5
3
|
from typing import List, cast
|
6
4
|
|
@@ -12,6 +10,8 @@ from investfly import samples
|
|
12
10
|
import inspect
|
13
11
|
from pathlib import Path
|
14
12
|
import shutil
|
13
|
+
import json
|
14
|
+
import re
|
15
15
|
|
16
16
|
|
17
17
|
class InvestflyCli:
|
@@ -20,6 +20,15 @@ class InvestflyCli:
|
|
20
20
|
self.running: bool = True
|
21
21
|
self.investflyApi = InvestflyApiClient()
|
22
22
|
|
23
|
+
@staticmethod
|
24
|
+
def extract_class_name(source_code: str, base_class: str) -> str|None:
|
25
|
+
class_pattern = re.compile(r'class\s+(\w+)\s*\(\s*' + base_class + r'\s*\)\s*:', re.IGNORECASE)
|
26
|
+
for line in source_code.splitlines():
|
27
|
+
match = class_pattern.search(line)
|
28
|
+
if match:
|
29
|
+
return match.group(1)
|
30
|
+
return None
|
31
|
+
|
23
32
|
|
24
33
|
def __loginAction(self, args: argparse.Namespace) -> Session:
|
25
34
|
username = args.username
|
@@ -51,10 +60,12 @@ class InvestflyCli:
|
|
51
60
|
return "\n".join(strategiesDictList)
|
52
61
|
|
53
62
|
def __createStrategy(self, args: argparse.Namespace) -> str:
|
54
|
-
name = args.name
|
55
63
|
path = args.file
|
56
64
|
with open(path, 'r') as source_file:
|
57
65
|
code = source_file.read()
|
66
|
+
name = InvestflyCli.extract_class_name(code, "TradingStrategy")
|
67
|
+
if name is None:
|
68
|
+
return "Provided file does not contain class that extends from TradingStrategy"
|
58
69
|
tradingStrategyModel = TradingStrategyModel(strategyName=name, strategyDesc=name, pythonCode=code)
|
59
70
|
tradingStrategyModel = self.investflyApi.strategyApi.createStrategy(tradingStrategyModel)
|
60
71
|
return f'Created strategy {tradingStrategyModel.strategyId}'
|
@@ -106,16 +117,28 @@ class InvestflyCli:
|
|
106
117
|
|
107
118
|
# ==== INDICATOR COMMAND HANDLERS
|
108
119
|
|
109
|
-
def
|
110
|
-
indicators: List[IndicatorSpec] = self.investflyApi.indicatorApi.
|
120
|
+
def __listCustomIndicators(self, args: argparse.Namespace) -> str:
|
121
|
+
indicators: List[IndicatorSpec] = self.investflyApi.indicatorApi.listCustomIndicators()
|
122
|
+
idList = list(map(lambda spec: spec.indicatorId, indicators))
|
123
|
+
return str(idList)
|
124
|
+
|
125
|
+
def __listStandardIndicators(self, args: argparse.Namespace) -> str:
|
126
|
+
indicators: List[IndicatorSpec] = self.investflyApi.indicatorApi.listStandardIndicators()
|
111
127
|
idList = list(map(lambda spec: spec.indicatorId, indicators))
|
112
128
|
return str(idList)
|
113
129
|
|
130
|
+
def __getIndicatorSpec(self, args: argparse.Namespace) -> str:
|
131
|
+
spec = self.investflyApi.indicatorApi.getIndicatorSpec(args.id)
|
132
|
+
jsonDict = spec.toJsonDict()
|
133
|
+
return json.dumps(jsonDict, indent=2)
|
134
|
+
|
114
135
|
def __createUpdateIndicator(self, args: argparse.Namespace):
|
115
136
|
path = args.file
|
116
137
|
with open(path, 'r') as source_file:
|
117
138
|
code = source_file.read()
|
118
|
-
self.investflyApi.indicatorApi.createUpdateIndicator(code)
|
139
|
+
spec = self.investflyApi.indicatorApi.createUpdateIndicator(code)
|
140
|
+
jsonDict = spec.toJsonDict()
|
141
|
+
return json.dumps(jsonDict, indent=2)
|
119
142
|
|
120
143
|
def __downloadIndicatorCode(self, args: argparse.Namespace):
|
121
144
|
indicatorId = args.id
|
@@ -149,7 +172,6 @@ class InvestflyCli:
|
|
149
172
|
parser_listStrategies.set_defaults(func=self.__listStrategies)
|
150
173
|
|
151
174
|
parser_createStrategy = subparser.add_parser('strategy.create', help='Create a new trading strategy')
|
152
|
-
parser_createStrategy.add_argument('-n', '--name', required=True, help='Strategy Name')
|
153
175
|
parser_createStrategy.add_argument('-f', '--file', required=True, help='Python File Path relative to the project root that contains strategy code')
|
154
176
|
parser_createStrategy.set_defaults(func=self.__createStrategy)
|
155
177
|
|
@@ -177,15 +199,22 @@ class InvestflyCli:
|
|
177
199
|
|
178
200
|
# ====== INDICATOR COMMANDS ====
|
179
201
|
|
180
|
-
|
181
|
-
|
202
|
+
parser_listCustomIndicators = subparser.add_parser('indicator.listCustom', help='List Custom Indicators')
|
203
|
+
parser_listCustomIndicators.set_defaults(func=self.__listCustomIndicators)
|
204
|
+
|
205
|
+
parser_listStandardIndicators = subparser.add_parser('indicator.listStandard', help='List Custom Indicators')
|
206
|
+
parser_listStandardIndicators.set_defaults(func=self.__listStandardIndicators)
|
207
|
+
|
208
|
+
parser_getIndicatorSpec = subparser.add_parser('indicator.getIndicator', help="Get Indicator Specification")
|
209
|
+
parser_getIndicatorSpec.add_argument('-i', '--id', required=True, help='Indicator ID')
|
210
|
+
parser_getIndicatorSpec.set_defaults(func=self.__getIndicatorSpec)
|
182
211
|
|
183
212
|
parser_downloadIndicator = subparser.add_parser('indicator.download', help='Download indicator python code and save it to a file')
|
184
|
-
parser_downloadIndicator.add_argument('-i', '--id', required=True, help='
|
213
|
+
parser_downloadIndicator.add_argument('-i', '--id', required=True, help='Indicator ID')
|
185
214
|
parser_downloadIndicator.add_argument('-f', '--file', required=True, help='File path (with file name) to save indicator python code')
|
186
215
|
parser_downloadIndicator.set_defaults(func=self.__downloadIndicatorCode)
|
187
216
|
|
188
|
-
parser_createUpdateIndicator = subparser.add_parser('indicator.
|
217
|
+
parser_createUpdateIndicator = subparser.add_parser('indicator.createupdate', help='Create or update indicator. Indicator ID is retried from ClassName')
|
189
218
|
parser_createUpdateIndicator.add_argument('-f', '--file', required=True, help='File path (with file name) that contains indicator code')
|
190
219
|
parser_createUpdateIndicator.set_defaults(func=self.__createUpdateIndicator)
|
191
220
|
|
@@ -14,14 +14,10 @@ from investfly.utils import *
|
|
14
14
|
|
15
15
|
class RsiOfSma(Indicator):
|
16
16
|
|
17
|
-
|
18
|
-
# To implement a price-based indicator (i.e. indicator that uses price bars [open,high,low,close,volume]),
|
19
|
-
# you extend from PriceBasedIndicator and implement methods shown below
|
20
|
-
|
21
17
|
def getIndicatorSpec(self) -> IndicatorSpec:
|
22
|
-
# In this method, you must construct and return
|
23
|
-
# indicator name, description and any parameters it needs.
|
24
|
-
# added
|
18
|
+
# In this method, you must construct and return IndicatorSpec object that specifies
|
19
|
+
# indicator name, description and any parameters it needs. Stanard parameters like (barinterval, count, lookback)
|
20
|
+
# are automatically added
|
25
21
|
indicator = IndicatorSpec("RSI of SMA")
|
26
22
|
indicator.addParam("sma_period", IndicatorParamSpec(ParamType.INTEGER, True, 5, IndicatorParamSpec.PERIOD_VALUES))
|
27
23
|
indicator.addParam("rsi_period", IndicatorParamSpec(ParamType.INTEGER, True, 10, IndicatorParamSpec.PERIOD_VALUES))
|
@@ -12,13 +12,10 @@ from investfly.utils import *
|
|
12
12
|
|
13
13
|
class SmaEmaAverage(Indicator):
|
14
14
|
|
15
|
-
# To implement a price-based indicator (i.e indicator that uses price bars [open,high,low,close,volume]) in
|
16
|
-
# computation you extend from PriceBasedIndicator and implement methods shown below
|
17
|
-
|
18
15
|
def getIndicatorSpec(self) -> IndicatorSpec:
|
19
|
-
# In this method, you must construct and return
|
20
|
-
# indicator name, description and any parameters it needs.
|
21
|
-
# added
|
16
|
+
# In this method, you must construct and return IndicatorSpec object that specifies
|
17
|
+
# indicator name, description and any parameters it needs. Stanard parameters like (barinterval, count, lookback)
|
18
|
+
# are automatically added
|
22
19
|
indicator = IndicatorSpec("SMA EMA Average")
|
23
20
|
indicator.addParam('period', IndicatorParamSpec(ParamType.INTEGER, True, 5, IndicatorParamSpec.PERIOD_VALUES))
|
24
21
|
return indicator
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: investfly-sdk
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.6
|
4
4
|
Summary: Investfly SDK
|
5
5
|
Author-email: "Investfly.com" <admin@investfly.com>
|
6
6
|
License: The MIT License (MIT)
|
@@ -46,6 +46,7 @@ Requires-Dist: tzdata ==2023.3
|
|
46
46
|
Requires-Dist: urllib3 ==1.26.15
|
47
47
|
Requires-Dist: numpy ==1.26.4
|
48
48
|
Requires-Dist: TA-Lib ==0.4.28
|
49
|
+
Requires-Dist: mypy ==1.12.1
|
49
50
|
|
50
51
|
# About
|
51
52
|
|
@@ -1,13 +1,13 @@
|
|
1
1
|
investfly/__init__.py,sha256=Ku0IZu4VYvNGui70Xu-bG1fB8XtVNQxBey6f5nLIKVU,71
|
2
|
-
investfly/api/IndicatorApiClient.py,sha256=
|
2
|
+
investfly/api/IndicatorApiClient.py,sha256=y9Dr2LpbgxcetY2s45bBGGjzUk6ZT3TzwR-vQ_TU3hw,1447
|
3
3
|
investfly/api/InvestflyApiClient.py,sha256=I_hi1Uw8EGa3jr06cNkrGbhjIT90BPr_YN5EFilykwQ,2111
|
4
4
|
investfly/api/MarketDataApiClient.py,sha256=bOlMzzZzN5A35oo0Iml2xCekV0jOig8Q_L66xi6n0n0,611
|
5
5
|
investfly/api/PortfolioApiClient.py,sha256=llNISIHWSx3wvf83usGhwPhVr-3RYGAndBNpZV9w3W0,1858
|
6
|
-
investfly/api/RestApiClient.py,sha256=
|
6
|
+
investfly/api/RestApiClient.py,sha256=ZHt_9gGZTW3krQyz2_o4w0I6SfQ6K32RTl2RcG95u3g,3302
|
7
7
|
investfly/api/StrategyApiClient.py,sha256=w5_hQrxtQ7-1C1uu0UKL37ZbcjXmtdBAYXPtEiM-MC4,2087
|
8
8
|
investfly/api/__init__.py,sha256=JeeOmrsPbVk4B26DT3hbvBoxAvkMEhJ-PeKeloNGF08,600
|
9
9
|
investfly/api/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
-
investfly/cli/InvestflyCli.py,sha256=
|
10
|
+
investfly/cli/InvestflyCli.py,sha256=2dnJuGOL_qe3HeWqc0cyLss4H3HxDTXrvsHtJ6sIYSw,12114
|
11
11
|
investfly/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
12
|
investfly/models/CommonModels.py,sha256=kbyWsez1voii2K2wyflYCW7i9lYQh49nbrts4bTvvG4,2348
|
13
13
|
investfly/models/Indicator.py,sha256=9v46Ozs2O8UPUjDzVC1MpoGx2iwnA__ZyrySVXxX8Qo,10660
|
@@ -24,8 +24,8 @@ investfly/models/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
24
|
investfly/samples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
25
25
|
investfly/samples/indicators/IndicatorTemplate.py,sha256=Pn3jGVjMVwhqN1-F5FTAUPm4caFa3ORORNtvL353iEc,4470
|
26
26
|
investfly/samples/indicators/NewsSentiment.py,sha256=fcpAqOcNWmqYsP-xwJquCX_6G7Ntr3A1-m31eJHAUOE,65095
|
27
|
-
investfly/samples/indicators/RsiOfSma.py,sha256=
|
28
|
-
investfly/samples/indicators/SmaEmaAverage.py,sha256=
|
27
|
+
investfly/samples/indicators/RsiOfSma.py,sha256=KewPi89ecZ0H0Ymj0FI72XgfWSvVLebuUHsfkr6WgwU,1557
|
28
|
+
investfly/samples/indicators/SmaEmaAverage.py,sha256=daoaKl9F1MWuOIOQInq9_M3P2A9E3bzFHaQ5TgsZ4ds,1576
|
29
29
|
investfly/samples/indicators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
30
30
|
investfly/samples/strategies/SmaCrossOverStrategy.py,sha256=e_gR8gwHJ5m6lU_Ib8jeQrER3cD6q569IIhwglKePew,1680
|
31
31
|
investfly/samples/strategies/SmaCrossOverTemplate.py,sha256=5wDg1ecAC75ijnKs8hP6hG5EG9P58jLK_RRKTIrQnCI,8197
|
@@ -34,9 +34,9 @@ investfly/utils/CommonUtils.py,sha256=lCXAdI8-6PgbutcXJqUmSfuuLXp82FcnlxNVjCJpqL
|
|
34
34
|
investfly/utils/PercentBasedPortfolioAllocator.py,sha256=EHrOyHbaYHLwE-4vUSQCVXwbEgLs-nDjLVRH3cdgslI,1563
|
35
35
|
investfly/utils/__init__.py,sha256=2BqXoOQElv-GIU6wvmf2aaAABAcNny2TETcj7kf9rzM,129
|
36
36
|
investfly/utils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
37
|
-
investfly_sdk-1.
|
38
|
-
investfly_sdk-1.
|
39
|
-
investfly_sdk-1.
|
40
|
-
investfly_sdk-1.
|
41
|
-
investfly_sdk-1.
|
42
|
-
investfly_sdk-1.
|
37
|
+
investfly_sdk-1.6.dist-info/LICENSE.txt,sha256=Jmd2U7G7Z1oNdnRERRzFXN6C--bEo_K56j4v9EpJSTg,1090
|
38
|
+
investfly_sdk-1.6.dist-info/METADATA,sha256=A1ebvr32y2SEMEd5jnuqHIxZMyn6kcpt9y--QDiu62c,7536
|
39
|
+
investfly_sdk-1.6.dist-info/WHEEL,sha256=a7TGlA-5DaHMRrarXjVbQagU3Man_dCnGIWMJr5kRWo,91
|
40
|
+
investfly_sdk-1.6.dist-info/entry_points.txt,sha256=GDRF4baJQXTh90DvdJJx1DeRezWfPt26E567lTs3g6U,66
|
41
|
+
investfly_sdk-1.6.dist-info/top_level.txt,sha256=dlEJ2OGWA3prqMvXELeydS5RTdpSzh7hz1LwR3NMc7A,10
|
42
|
+
investfly_sdk-1.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|