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.
@@ -9,13 +9,24 @@ class IndicatorApiClient:
9
9
  def __init__(self, restApiClient: RestApiClient) -> None:
10
10
  self.restApiClient = restApiClient
11
11
 
12
- def listIndicators(self) -> List[IndicatorSpec]:
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
 
@@ -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']
@@ -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 __listIndicators(self, args: argparse.Namespace) -> str:
110
- indicators: List[IndicatorSpec] = self.investflyApi.indicatorApi.listIndicators()
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
- parser_listIndicators = subparser.add_parser('indicator.list', help='List Custom Indicators')
181
- parser_listIndicators.set_defaults(func=self.__listIndicators)
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='IndicatorId ID')
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.update', help='Create or update indicator. Indicator ID is retried from ClassName')
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 IndicatorDefinition object that specifies
23
- # indicator name, description and any parameters it needs. BarSize parameter is automatically
24
- # added from the parent class
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 IndicatorDefinition object that spefies
20
- # indicator name, description and any parameters it needs. BarSize parameter is automatically
21
- # added from the parent class
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.5
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=G2bEWaCvcmotp4jx-IoiqHblZZWAdwaUjDNP5ZoaagM,931
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=XjvJCqAqUMPa7tXkhxGwaOj1xgHkfLcA8Q0027Z6xm8,3236
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=SCRqC4GpaVPB7RDzMAgr7_GpEl0ai4GF1qlBKXsjUws,10565
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=fSPKYPF8vJqhRs2LvMZJp_e7pb5rBPpsXF7Fu3ZdS04,1735
28
- investfly/samples/indicators/SmaEmaAverage.py,sha256=DrKPrcV4QaxKAp8lwQmFue-_LVteKnB-zgIgwx_25Bk,1765
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.5.dist-info/LICENSE.txt,sha256=Jmd2U7G7Z1oNdnRERRzFXN6C--bEo_K56j4v9EpJSTg,1090
38
- investfly_sdk-1.5.dist-info/METADATA,sha256=mf8Zji3FmIY8S0Lk2hJocJftq1oNr604BdKhp_SFx3s,7507
39
- investfly_sdk-1.5.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
40
- investfly_sdk-1.5.dist-info/entry_points.txt,sha256=GDRF4baJQXTh90DvdJJx1DeRezWfPt26E567lTs3g6U,66
41
- investfly_sdk-1.5.dist-info/top_level.txt,sha256=dlEJ2OGWA3prqMvXELeydS5RTdpSzh7hz1LwR3NMc7A,10
42
- investfly_sdk-1.5.dist-info/RECORD,,
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.2.0)
2
+ Generator: setuptools (75.4.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5