Skip to content

Commit 45028e8

Browse files
feat(SDK): Added code snippet for QE API to implement 'is_array_return_type' (#102)
1 parent 92a893e commit 45028e8

File tree

1 file changed

+132
-0
lines changed

1 file changed

+132
-0
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import time
2+
import os
3+
from pathlib import Path
4+
import pandas as pd
5+
6+
from fds.analyticsapi.engines import ApiException
7+
from fds.analyticsapi.engines.api.quant_calculations_api import QuantCalculationsApi
8+
from fds.analyticsapi.engines.api_client import ApiClient
9+
from fds.analyticsapi.engines.configuration import Configuration
10+
from fds.analyticsapi.engines.model.quant_calculation_parameters_root import QuantCalculationParametersRoot
11+
from fds.analyticsapi.engines.model.quant_calculation_parameters import QuantCalculationParameters
12+
from fds.analyticsapi.engines.model.quant_calculation_meta import QuantCalculationMeta
13+
from fds.analyticsapi.engines.model.quant_screening_expression_universe import QuantScreeningExpressionUniverse
14+
from fds.analyticsapi.engines.model.quant_fds_date import QuantFdsDate
15+
from fds.analyticsapi.engines.model.quant_screening_expression import QuantScreeningExpression
16+
from fds.analyticsapi.engines.model.quant_fql_expression import QuantFqlExpression
17+
18+
from urllib3 import Retry
19+
20+
host = os.environ['FACTSET_HOST']
21+
fds_username = os.environ['FACTSET_USERNAME']
22+
fds_api_key = os.environ['FACTSET_API_KEY']
23+
24+
def main():
25+
config = Configuration()
26+
config.host = host
27+
config.username = fds_username
28+
config.password = fds_api_key
29+
# add proxy and/or disable ssl verification according to your development environment
30+
# config.proxy = "<proxyUrl>"
31+
config.verify_ssl = False
32+
33+
# Setting configuration to retry api calls on http status codes of 429 and 503.
34+
config.retries = Retry(total=3, status=3, status_forcelist=frozenset([429, 503]), backoff_factor=2,
35+
raise_on_status=False)
36+
37+
api_client = ApiClient(config)
38+
39+
try:
40+
screeningExpressionUniverse = QuantScreeningExpressionUniverse(source="ScreeningExpressionUniverse",
41+
universe_expr="(ISON_DOW AND P_PRICE > 150)=1", universe_type="Equity",
42+
security_expr="TICKER")
43+
44+
fdsDate = QuantFdsDate(source="FdsDate",
45+
start_date="0", end_date="-2M", frequency="M", calendar="FIVEDAY", override_universal_screen_calendar=False)
46+
47+
screeningExpression1 = QuantScreeningExpression(source="ScreeningExpression",
48+
expr="FG_GICS_SECTOR", name="Sector (scr)")
49+
screeningExpression2 = QuantScreeningExpression(source="ScreeningExpression",
50+
expr="P_PRICE", name="Price (scr)")
51+
52+
# Implmenting "is_array_return_type"
53+
54+
fqlExpression1 = QuantFqlExpression(source="FqlExpression",
55+
expr="P_PRICE(#DATE,#DATE,#FREQ)", name="Price (fql)", is_array_return_type=True)
56+
fqlExpression2 = QuantFqlExpression(source="FqlExpression",
57+
expr="OS_TOP_HLDR_POS(3,#DATE,#DATE,M,,S,SEC)", name="Top 3 Pos (fql)", is_array_return_type=True)
58+
59+
# uncomment the below code line to setup cache control; max-stale=0 will be a fresh adhoc run and the max-stale value is in seconds.
60+
# Results are by default cached for 12 hours; Setting max-stale=300 will fetch a cached result which is 5 minutes older.
61+
# cache_control = "max-stale=0"
62+
quant_calculation_parameters = {"1": QuantCalculationParameters(
63+
universe=screeningExpressionUniverse,
64+
dates=fdsDate,
65+
formulas=[screeningExpression1, screeningExpression2, fqlExpression1, fqlExpression2])
66+
}
67+
68+
quant_calculations_meta = QuantCalculationMeta(format='Feather')
69+
70+
quant_calculation_parameter_root = QuantCalculationParametersRoot(
71+
data=quant_calculation_parameters, meta=quant_calculations_meta)
72+
73+
quant_calculations_api = QuantCalculationsApi(api_client)
74+
75+
post_and_calculate_response = quant_calculations_api.post_and_calculate(
76+
quant_calculation_parameters_root=quant_calculation_parameter_root)
77+
# comment the above line and uncomment the below line to run the request with the cache_control header defined earlier
78+
# post_and_calculate_response = quant_calculations_api.post_and_calculate(
79+
# quant_calculation_parameters_root=quant_calculation_parameter_root, cache_control=cache_control)
80+
81+
if post_and_calculate_response[1] == 201:
82+
output_calculation_result('data', post_and_calculate_response[0])
83+
else:
84+
calculation_id = post_and_calculate_response[0].data.calculationid
85+
print("Calculation Id: " + calculation_id)
86+
87+
status_response = quant_calculations_api.get_calculation_status_by_id(id=calculation_id)
88+
89+
while status_response[1] == 202 and (status_response[0].data.status in ("Queued", "Executing")):
90+
max_age = '5'
91+
age_value = status_response[2].get("cache-control")
92+
if age_value is not None:
93+
max_age = age_value.replace("max-age=", "")
94+
print('Sleeping: ' + max_age)
95+
time.sleep(int(max_age))
96+
status_response = quant_calculations_api.get_calculation_status_by_id(id=calculation_id)
97+
98+
for (calculation_unit_id, calculation_unit) in status_response[0].data.units.items():
99+
if calculation_unit.status == "Success":
100+
print("Calculation Unit Id: " +
101+
calculation_unit_id + " Succeeded!!!")
102+
result_response = quant_calculations_api.get_calculation_unit_result_by_id(id=calculation_id,
103+
unit_id=calculation_unit_id)
104+
print("Calculation Data")
105+
output_calculation_result(
106+
'data', result_response[0].read())
107+
result_response = quant_calculations_api.get_calculation_unit_info_by_id(id=calculation_id,
108+
unit_id=calculation_unit_id)
109+
print("Calculation Info")
110+
output_calculation_result(
111+
'info', result_response[0].read())
112+
else:
113+
print("Calculation Unit Id:" +
114+
calculation_unit_id + " Failed!!!")
115+
print("Error message : " + str(calculation_unit.errors))
116+
117+
except ApiException as e:
118+
print("Api exception Encountered")
119+
print(e)
120+
exit()
121+
122+
123+
def output_calculation_result(output_prefix, result):
124+
filename = Path(f'{output_prefix}-Output.ftr')
125+
print(f'Writing output to {filename}')
126+
filename.write_bytes(result)
127+
df = pd.read_feather(filename)
128+
print(df)
129+
130+
131+
if __name__ == '__main__':
132+
main()

0 commit comments

Comments
 (0)