SPAR Engine API

Overview

Through the SPAR API (Style, Performance, and Risk) monitor your portfolios’ returns against equity and fixed income benchmarks, and peer universes, with MPT risk statistics such as beta, standard deviation, r-squared, alpha, and tracking error. 

API Definition

swagger_file_format

API Documentation

SDK Library

Code Snippet

Building and running a calculation
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;

using FactSet.AnalyticsAPI.Engines.v2.Api;
using FactSet.AnalyticsAPI.Engines.v2.Client;
using FactSet.AnalyticsAPI.Engines.v2.Model;

using FactSet.Protobuf.Stach;
using Google.Protobuf;

namespace FactSet.AnalyticsAPI.Engines.v2.Example.Examples
{
    public class SPAREngineExample
    {
        private static Configuration _engineApiConfiguration;
        private const string BASE_PATH = "https://api.factset.com";
        private const string USER_NAME = "<username-serial>";
        private const string PASSWORD = "<apiKey>";
        private const string SPAR_DEFAULT_DOCUMENT = "pmw_root:/spar_documents/Factset Default Document";
        private const string SPAR_BENCHMARK_R_1000 = "R.1000";
        private const string SPAR_BENCHMARK_RUSSELL_PR_2000 = "RUSSELL_P:R.2000";
        private const string SPAR_BENCHMARK_RUSSELL_PREFIX = "RUSSELL";
        private const string SPAR_BENCHMARK_RUSSELL_RETURN_TYPE = "GTR";

        private static Configuration GetEngineApiConfiguration()
        {
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            if (_engineApiConfiguration != null)
            {
                return _engineApiConfiguration;
            }

            _engineApiConfiguration = new Configuration
            {
                BasePath = BASE_PATH,
                Username = USER_NAME,
                Password = PASSWORD
            };

            return _engineApiConfiguration;
        }

        public static void Main(string[] args)
        {
            try
            {
                var calculationParameters = new CalculationParameters
                {
                    Spar = new Dictionary<string, SPARCalculationParameters> { { "1", GetSparCalculationParameters() } }
                };

                var calculationApi = new CalculationsApi(GetEngineApiConfiguration());

                var runCalculationResponse = calculationApi.RunCalculationWithHttpInfo(calculationParameters);

                var calculationId = runCalculationResponse.Headers["Location"][0].Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).Last();
                ApiResponse<OutstandingCalculations> getStatus = null;

                while (getStatus == null || getStatus.Data.Status == OutstandingCalculations.StatusEnum.Queued || getStatus.Data.Status == OutstandingCalculations.StatusEnum.Executing)
                {
                    if (getStatus != null)
                    {
                        if (getStatus.Headers.ContainsKey("Cache-Control"))
                        {
                            var maxAge = getStatus.Headers["Cache-Control"][0];
                            if (string.IsNullOrWhiteSpace(maxAge))
                            {
                                Console.WriteLine("Sleeping for 2 seconds");
                                // Sleep for at least 2 seconds.
                                Thread.Sleep(2000);
                            }
                            else
                            {
                                var age = int.Parse(maxAge.Replace("max-age=", ""));
                                Console.WriteLine($"Sleeping for {age} seconds");
                                Thread.Sleep(age * 1000);
                            }
                        }
                    }

                    getStatus = calculationApi.GetCalculationByIdWithHttpInfo(calculationId);
                }
                Console.WriteLine("Calculation Completed");

                // Check for failed calculations
                foreach (var sparCalculationParameters in getStatus.Data.Spar)
                {
                    if (sparCalculationParameters.Value.Status == Calculation.StatusEnum.Failed)
                    {
                        Console.WriteLine($"CalculationId : {sparCalculationParameters.Key} Failed!!!");
                        Console.WriteLine($"Error message : {sparCalculationParameters.Value.Error}");
                    }
                }

                // Get result of successful calculations
                foreach (var sparCalculationParameters in getStatus.Data.Spar)
                {
                    PrintResult(sparCalculationParameters);
                }

                Console.ReadKey();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }

        private static SPARCalculationParameters GetSparCalculationParameters()
        {
            // Build SPAR Engine calculation parameters
            var componentsApi = new ComponentsApi(GetEngineApiConfiguration());

            var componentsResponse = componentsApi.GetSPARComponentsWithHttpInfo(SPAR_DEFAULT_DOCUMENT);

            if (componentsResponse.StatusCode != HttpStatusCode.OK)
            {
                LogError(componentsResponse);
                return null;
            }

            var sparComponentId = componentsResponse.Data.First().Key;
            Console.WriteLine($"SPAR Component Id : {sparComponentId}");


            var sparAccountIdentifier = new SPARIdentifier(SPAR_BENCHMARK_R_1000, SPAR_BENCHMARK_RUSSELL_RETURN_TYPE, SPAR_BENCHMARK_RUSSELL_PREFIX);
            var sparAccounts = new List<SPARIdentifier> { sparAccountIdentifier };
            var sparBenchmarkIdentifier = new SPARIdentifier(SPAR_BENCHMARK_RUSSELL_PR_2000, SPAR_BENCHMARK_RUSSELL_RETURN_TYPE, SPAR_BENCHMARK_RUSSELL_PREFIX);

            var sparCalculation = new SPARCalculationParameters(sparComponentId, sparAccounts, sparBenchmarkIdentifier);

            return sparCalculation;
        }

        private static void PrintResult(KeyValuePair<string, Calculation> calculation)
        {
            if (calculation.Value.Status == Calculation.StatusEnum.Success)
            {
                ApiResponse<string> resultResponse = null;

                var utilityApi = new UtilityApi(GetEngineApiConfiguration());
                resultResponse = utilityApi.GetByUrlWithHttpInfo(calculation.Value.Result);

                if (resultResponse.StatusCode != HttpStatusCode.OK)
                {
                    LogError(resultResponse);
                    return;
                }

                Console.WriteLine($"CalculationId : {calculation.Key} Succeeded!!!");
                Console.WriteLine($"CalculationId : {calculation.Key} Result");
                Console.WriteLine("/****************************************************************/");

                // converting the data to Package object
                var jpSettings = JsonParser.Settings.Default;
                var jp = new JsonParser(jpSettings.WithIgnoreUnknownFields(true));
                var package = jp.Parse<Package>(resultResponse.Data);

                // To convert package to 2D tables.
                var tables = package.ConvertToTableFormat();
                Console.WriteLine(tables[0]);

                // Uncomment the following line to generate an Excel file
                // package.GenerateCSV();
                Console.WriteLine("/****************************************************************/");
            }
        }

        private static void LogError<T>(ApiResponse<T> response)
        {
            Console.WriteLine("Error!!!");
            Console.WriteLine("Status Code: " + response.StatusCode);
            Console.WriteLine("Request Key: " + response.Headers["X-DataDirect-Request-Key"]);
            Console.WriteLine($"Reason: {response.Data}");
        }
    }
}

 

import java.util.List;
import java.util.Map;

import factset.analyticsapi.engines.v2.*;
import factset.analyticsapi.engines.v2.api.*;
import factset.analyticsapi.engines.v2.models.*;
import factset.analyticsapi.engines.v2.models.OutstandingCalculations.StatusEnum;

import com.google.protobuf.util.JsonFormat;
import com.google.protobuf.InvalidProtocolBufferException;
import com.factset.protobuf.stach.PackageProto.Package.Builder;
import com.factset.protobuf.stach.PackageProto.Package;

public class SPAREngineExample {
  private static ApiClient apiClient = null;
  private static final String BASE_PATH = "https://api.factset.com";
  private static final String USERNAME = "<username-serial>";
  private static final String PASSWORD = "<apiKey>";
  public static final String SPAR_DEFAULT_DOCUMENT = "pmw_root:/spar_documents/Factset Default Document";
  private static final String COMPONENT_NAME = "Returns Data";
  private static final String COMPONENT_CATEGORY = "Raw Data / Returns";

  public static void main(String[] args) throws InterruptedException {
    try {
      // Build SPAR Calculation Parameters List

      // Get all component from SPAR_DEFAULT_DOCUMENT with Name COMPONENT_NAME & category COMPONENT_CATEGORY
      ComponentsApi componentsApi = new ComponentsApi(getApiClient());
      Map<String, ComponentListEntity> components = componentsApi.getSPARComponents(SPAR_DEFAULT_DOCUMENT);
      String componentId = components.entrySet().stream().filter(
          c -> c.getValue().getName().equals(COMPONENT_NAME) && c.getValue().getCategory().equals(COMPONENT_CATEGORY))
          .iterator().next().getKey();
      System.out.println("ID of component with Name '" + COMPONENT_NAME + "' and category '" + COMPONENT_CATEGORY
          + "' : " + componentId);

      CalculationParameters parameters = new CalculationParameters();

      SPARCalculationParameters sparItem = new SPARCalculationParameters();

      sparItem.setComponentid(componentId);

      SPARIdentifier accountIdentifier1 = new SPARIdentifier();
      accountIdentifier1.setId("R.1000");
      accountIdentifier1.setPrefix("RUSSELL");
      accountIdentifier1.setReturntype("GTR");
      sparItem.addAccountsItem(accountIdentifier1);

      SPARIdentifier accountIdentifier2 = new SPARIdentifier();
      accountIdentifier2.setId("RUSSELL_P:R.2000");
      accountIdentifier2.setPrefix("RUSSELL");
      accountIdentifier2.setReturntype("GTR");
      sparItem.addAccountsItem(accountIdentifier2);

      SPARIdentifier benchmarkIdentifier = new SPARIdentifier();
      benchmarkIdentifier.setId("R.2000");
      benchmarkIdentifier.setPrefix("RUSSELL");
      benchmarkIdentifier.setReturntype("GTR");
      sparItem.setBenchmark(benchmarkIdentifier);

      SPARDateParameters dateParameters = new SPARDateParameters();
      dateParameters.setStartdate("20180101");
      dateParameters.setEnddate("20181231");
      dateParameters.setFrequency("Monthly");
      sparItem.setDates(dateParameters);

      parameters.putSparItem("1", sparItem);

      // Run Calculation Request
      CalculationsApi apiInstance = new CalculationsApi(getApiClient());
      ApiResponse<Void> createResponse = null;

      createResponse = apiInstance.runCalculationWithHttpInfo(parameters);

      String[] locationList = createResponse.getHeaders().get("Location").get(0).split("/");
      String requestId = locationList[locationList.length - 1];

      // Get Calculation Request Status
      ApiResponse<OutstandingCalculations> getStatus = null;

      while (getStatus == null || getStatus.getData().getStatus() == StatusEnum.QUEUED
          || getStatus.getData().getStatus() == StatusEnum.EXECUTING) {
        if (getStatus != null) {
          List<String> cacheControl = getStatus.getHeaders().get("Cache-Control");
          if (cacheControl != null) {
            int maxAge = Integer.parseInt(cacheControl.get(0).replaceAll("max-age=", ""));
            System.out.println("Sleeping for: " + maxAge + " seconds");
            Thread.sleep(maxAge * 1000);
          } else {
            System.out.println("Sleeping for: 2 seconds");
            Thread.sleep(2 * 1000);
          }
        }
        getStatus = apiInstance.getCalculationByIdWithHttpInfo(requestId);
      }

      System.out.println("Calculation Completed!!!");

      // Check for Failed Calculations
      for (Map.Entry<String, Calculation> calculationParameters : getStatus.getData().getSpar().entrySet()) {
        if (calculationParameters.getValue().getStatus() == Calculation.StatusEnum.FAILED) {
          System.out.println("CalculationId : " + calculationParameters.getKey() + " Failed!!!");
          System.out.println("Error message : " + calculationParameters.getValue().getError());
          return;
        }
      }

      // Get Result of Successful Caculations
      for (Map.Entry<String, Calculation> calculationParameters : getStatus.getData().getSpar().entrySet()) {
        if (calculationParameters.getValue().getStatus() == Calculation.StatusEnum.SUCCESS) {
          UtilityApi utilityApiInstance = new UtilityApi(apiClient);
          ApiResponse<String> resultResponse = utilityApiInstance
              .getByUrlWithHttpInfo(calculationParameters.getValue().getResult());
          System.out.println("CalculationId : " + calculationParameters.getKey() + " Succeeded!!!");
          System.out.println("CalculationId : " + calculationParameters.getKey() + " Result");

          Builder builder = Package.newBuilder();
          try {
            JsonFormat.parser().ignoringUnknownFields().merge(resultResponse.getData(), builder);
          } catch (InvalidProtocolBufferException e) {
            System.out.println("Error while deserializing the response");
            e.printStackTrace();
          }

          Package result = (Package) builder.build();
          // To convert result to 2D tables.
          List<TableData> tables = StachExtensions.convertToTableFormat(result);
          System.out.println(tables.get(0)); // Prints the result in 2D table format.
          // Uncomment the following line to generate an Excel file
          // StachExtensions.generateExcel(result);
        }
      }
    } catch (ApiException e) {
      handleException("SPAREngineExample#Main", e);
      return;
    }
  }

  private static ApiClient getApiClient() throws ApiException {
    if (apiClient != null) {
      return apiClient;
    }

    apiClient = new ApiClient();
    apiClient.setConnectTimeout(30000);
    apiClient.setReadTimeout(30000);
    apiClient.setBasePath(BASE_PATH);
    apiClient.setUsername(USERNAME);
    apiClient.setPassword(PASSWORD);

    return apiClient;
  }

  private static void handleException(String method, ApiException e) {
    System.err.println("Exception when calling " + method);
    if (e.getResponseHeaders() != null && e.getResponseHeaders().containsKey("x-datadirect-request-key")) {
      System.out.println("x-datadirect-request-key: " + e.getResponseHeaders().get("x-datadirect-request-key").get(0));
    }
    System.out.println("Status code: " + e.getCode());
    System.out.println("Reason: " + e.getResponseBody());
    e.printStackTrace();
  }
}

 

import time
import json

from google.protobuf import json_format
from google.protobuf.json_format import MessageToJson
from google.protobuf.json_format import MessageToDict
from fds.protobuf.stach.Package_pb2 import Package

from fds.analyticsapi.engines.v2.configuration import Configuration;
from fds.analyticsapi.engines.v2.api_client import ApiClient;
from fds.analyticsapi.engines.v2.api.components_api import ComponentsApi
from fds.analyticsapi.engines.v2.api.calculations_api import CalculationsApi
from fds.analyticsapi.engines.v2.api.utility_api import UtilityApi
from fds.analyticsapi.engines.v2.models.calculation_parameters import CalculationParameters
from fds.analyticsapi.engines.v2.models.spar_calculation_parameters import SPARCalculationParameters
from fds.analyticsapi.engines.v2.models.spar_identifier import SPARIdentifier
from fds.analyticsapi.engines.v2.models.spar_date_parameters import SPARDateParameters

from stach_extensions import StachExtensions

host = "https://api.factset.com"
username = "<username-serial>"
password = "<apiKey>"

spar_document_name = "pmw_root:/spar_documents/Factset Default Document";
spar_benchmark_r_1000 = "R.1000";
spar_benchmark_russell_pr_2000 = "RUSSELL_P:R.2000";
spar_benchmark_russell_prefix = "RUSSELL"
spar_benchmark_russell_return_type = "GTR"
startdate = "20180101"
enddate = "20181231"
frequency = "Monthly"

config = Configuration()
config.host = host
config.username = username
config.password = password
# add proxy and/or disable ssl verification according to your development environment
# config.proxy = "<proxyUrl>"
# config.verify_ssl = False

api_client = ApiClient(config)

components_api = ComponentsApi(api_client);

components = components_api.get_spar_components_with_http_info(spar_document_name)
component_id = list(components[0].keys())[0]

spar_account_identifier = SPARIdentifier(spar_benchmark_r_1000, spar_benchmark_russell_return_type, spar_benchmark_russell_prefix)
spar_accounts =[spar_account_identifier]
spar_benchmark_identifier = SPARIdentifier(spar_benchmark_russell_pr_2000, spar_benchmark_russell_return_type, spar_benchmark_russell_prefix);
spar_dates = SPARDateParameters(startdate, enddate, frequency)

spar_calculation_parameters = {"1": SPARCalculationParameters(component_id, spar_accounts, spar_benchmark_identifier, spar_dates)}
calculations = CalculationParameters(spar=spar_calculation_parameters)
print(calculations)

calculations_api = CalculationsApi(api_client)
run_calculation_response = calculations_api.run_calculation_with_http_info(calculations=calculations)

if(run_calculation_response[1] != 202):
    print(batch_api_post_result[2].get("x-datadirect-request-key"))
    quit()

calculation_id = run_calculation_response[2].get("location").split("/")[-1]
print("Calculation Id: " + calculation_id)

calculation_status = calculations_api.get_calculation_by_id_with_http_info(calculation_id)
while (calculation_status[1] == 200 and (calculation_status[0].status == "Queued" or calculation_status[0].status == "Executing")):
    age_value = calculation_status[2].get("cache-control")
    if(age_value != None):
        max_age = age_value.replace("max-age=", "")
        print('Sleeping: ' + max_age)
        time.sleep(int(max_age))
    calculation_status = calculations_api.get_calculation_by_id_with_http_info(calculation_id)

if(calculation_status[1] != 200):
    print(calculation_status[2].get("x-datadirect-request-key"))
    quit()

print("Calculation Completed!!!");

for calculation_key, calculation_item in calculation_status[0].spar.items():
    if calculation_item.status == "Failed":
        print("Spar Calculation : " + calculation_key + " Failed!!!")
        print("Error Message : " + calculation_item.error)
    elif calculation_item.status == "Success":
        utility_api = UtilityApi(api_client)
        calculation_result = utility_api.get_by_url_with_http_info(calculation_item.result)

        if(calculation_result[1] != 200):
            print(calculation_result[2].get('x-datadirect-request-key'))
            quit()

        # converting the data to Package object
        result =  json_format.Parse(json.dumps(calculation_result[0]), Package())
        # print(MessageToJson(result)) # To print the result object as a JSON
        # print(MessageToDict(result)) # To print the result object as a Dictionary
        tables = StachExtensions.convert_to_table_format(result) # To convert result to 2D tables.
        print(tables[0]) # Prints the result in 2D table format.
        # StachExtensions.generate_excel(result) # To get the result in table format exported to excel file.

 

Converting API output to Table format
using System;
using System.Collections.Generic;
using System.Linq;
using FactSet.Protobuf.Stach;
using FactSet.Protobuf.Stach.Table;

namespace FactSet.AnalyticsAPI.Engines.v2.Example.Examples
{
    public static class StachExtensions
    {
        public static void GenerateCSV(this Package package)
        {
            foreach (var table in package.ConvertToTableFormat())
            {
                System.IO.File.WriteAllText($"{Guid.NewGuid():N}.csv", table.ToString());
            }
        }

        public static List<Table> ConvertToTableFormat(this Package package)
        {
            var tables = new List<Table>();
            foreach (var primaryTableId in package.PrimaryTableIds)
            {
                tables.Add(GenerateTable(package, primaryTableId));
            }

            return tables;
        }

        private static Table GenerateTable(Package package, string primaryTableId)
        {
            var primaryTable = package.Tables[primaryTableId];
            var headerId = primaryTable.Definition.HeaderTableId;
            var headerTable = package.Tables[headerId];
            var columnIds = primaryTable.Definition.Columns.Select(c => c.Id).ToList();
            var headerColumnIds = headerTable.Definition.Columns.Select(c => c.Id).ToList();
            var dimensionColumnsCount = primaryTable.Definition.Columns.Count(c => c.IsDimension);
            var rowCount = primaryTable.Data.Rows.Count;
            var headerRowCount = headerTable.Data.Rows.Count;

            var table = new Table
            {
                Rows = new List<Row>()
            };
            // Constructs the column headers by considering dimension columns and header rows
            foreach (var columnId in headerColumnIds)
            {
                var headerRow = new Row { Cells = new List<string>() };
                for (int j = 0; j < dimensionColumnsCount; j++)
                {
                    headerRow.Cells.Add("");
                }

                for (int i = 0; i < headerRowCount; i++)
                {
                    headerRow.Cells.Add(Convert.ToString(headerTable.Data.Columns[columnId]
                        .GetValueHelper(headerTable.Definition.Columns.First(c => c.Id == columnId).Type, i)));
                }
                table.Rows.Add(headerRow);
            }
            // Constructs the column data
            for (int i = 0; i < rowCount; i++)
            {
                var dataRow = new Row { Cells = new List<string>() };
                foreach (var columnId in columnIds)
                {
                    dataRow.Cells.Add(Convert.ToString(primaryTable.Data.Columns[columnId]
                        .GetValueHelper(primaryTable.Definition.Columns.First(c => c.Id == columnId).Type, i)));
                }
                table.Rows.Add(dataRow);
            }

            return table;
        }
    }

    public static class SeriesDataHelper
    {
        public static object GetValueHelper(this SeriesData seriesData, DataType dataType, int index)
        {
            switch (dataType)
            {
                case DataType.Bool:
                    {
                        return seriesData.BoolArray?.Values?[index];
                    }
                case DataType.Double:
                    {
                        return seriesData.DoubleArray?.Values?[index];
                    }
                case DataType.Duration:
                    {
                        var v = seriesData.DurationArray?.Values?[index];
                        return v?.ToTimeSpan();
                    }
                case DataType.Float:
                    {
                        return seriesData.FloatArray?.Values?[index];
                    }
                case DataType.Int32:
                    {
                        return seriesData.Int32Array?.Values?[index];
                    }
                case DataType.Int64:
                    {
                        return seriesData.Int64Array?.Values?[index];
                    }
                case DataType.String:
                    {
                        return seriesData.StringArray?.Values?[index];
                    }
                case DataType.Timestamp:
                    {
                        var v = seriesData.TimestampArray?.Values?[index];
                        return v?.ToDateTime();
                    }
                default:
                    throw new NotImplementedException($"{dataType} is not implemented");
            }
        }
    }

    public class Table
    {
        public List<Row> Rows { get; set; }

        public override string ToString()
        {
            return string.Join(Environment.NewLine, Rows);
        }
    }

    public class Row
    {
        public List<string> Cells { get; set; }

        public override string ToString()
        {
            return string.Join(",", Cells.Select(c => c.Replace(",", "")));
        }
    }
}

 

import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.poi.ss.formula.eval.NotImplementedException;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.factset.protobuf.stach.NullValues;
import com.factset.protobuf.stach.PackageProto.Package;
import com.factset.protobuf.stach.table.DataTypeProto.DataType;
import com.factset.protobuf.stach.table.SeriesDataProto.SeriesData;
import com.factset.protobuf.stach.table.SeriesDefinitionProto.SeriesDefinition;
import com.factset.protobuf.stach.table.TableProto.Table;

import com.google.protobuf.Duration;
import com.google.protobuf.Timestamp;

public class StachExtensions {
  // The purpose of this class is to provide the helper methods for converting
  // stach to Tabular format.

  public static void generateExcel(Package packageObj) {
    for (TableData table : convertToTableFormat(packageObj)) {
      writeDataToExcel(table, UUID.randomUUID().toString() + ".xlsx");
    }
  }

  public static List<TableData> convertToTableFormat(Package packageObj) {
    List<TableData> tables = new ArrayList<TableData>();
    for (String primaryTableId : packageObj.getPrimaryTableIdsList()) {
      tables.add(generateTable(packageObj, primaryTableId));
    }
    return tables;
  }

  private static TableData generateTable(Package packageObj, String primaryTableId) {
    Map<String, Table> tablesMap = packageObj.getTablesMap();
    Table primaryTable = tablesMap.get(primaryTableId);
    String headerId = primaryTable.getDefinition().getHeaderTableId();
    Table headerTable = tablesMap.get(headerId);
    int headerRowCount = headerTable.getData().getRowsCount();
    int rowsCount = primaryTable.getData().getRowsCount();

    TableData table = new TableData();

    // Construct the column headers by considering dimension columns and header
    // rows.
    List<SeriesDefinition> headerTableSeriesDefinitions = headerTable.getDefinition().getColumnsList();
    List<SeriesDefinition> primaryTableSeriesDefinitions = primaryTable.getDefinition().getColumnsList();

    Map<String, SeriesData> headerTableColumns = headerTable.getData().getColumnsMap();
    Map<String, SeriesData> primaryTableColumns = primaryTable.getData().getColumnsMap();

    for (SeriesDefinition headerTableseriesDefinition : headerTableSeriesDefinitions) {
      Row headerRow = new Row();
      for (SeriesDefinition primaryTableSeriesDefinition : primaryTableSeriesDefinitions) {
        if (primaryTableSeriesDefinition.getIsDimension()) {
          headerRow.Cells.add(primaryTableSeriesDefinition.getDescription());
        }
      }

      String headerColumnId = headerTableseriesDefinition.getId();
      String nullFormat = headerTableseriesDefinition.getFormat().getNullFormat();
      for (int i = 0; i < headerRowCount; i++) {
        headerRow.Cells.add(SeriesDataHelper.getValueHelper(headerTableColumns.get(headerColumnId),
            headerTableseriesDefinition.getType(), i, nullFormat).toString());
      }
      table.Rows.add(headerRow);
    }

    // Construct the column data
    for (int i = 0; i < rowsCount; i++) {
      Row dataRow = new Row();
      for (SeriesDefinition primaryTableSeriesDefinition : primaryTableSeriesDefinitions) {
        String nullFormat = primaryTableSeriesDefinition.getFormat().getNullFormat();
        String primaryTableColumnId = primaryTableSeriesDefinition.getId();
        dataRow.Cells.add(SeriesDataHelper.getValueHelper(primaryTableColumns.get(primaryTableColumnId),
            primaryTableSeriesDefinition.getType(), i, nullFormat).toString());
      }
      table.Rows.add(dataRow);
    }
    return table;
  }

  private static void writeDataToExcel(TableData table, String fileLocation) {
    XSSFWorkbook workbook = new XSSFWorkbook();
    XSSFSheet sheet = workbook.createSheet("PA Report");

    int rowsSize = table.Rows.size();
    for (int rowIndex = 0; rowIndex < rowsSize; rowIndex++) {
      XSSFRow xsswRow = sheet.createRow(rowIndex);
      List<String> cells = table.Rows.get(rowIndex).Cells;
      for (int cellIndex = 0; cellIndex < cells.size(); cellIndex++) {
        XSSFCell xssfCell = xsswRow.createCell(cellIndex);
        xssfCell.setCellValue(cells.get(cellIndex));
      }
    }

    try {
      FileOutputStream out = new FileOutputStream(new File(fileLocation));
      workbook.write(out);
      out.close();
      workbook.close();
    } catch (Exception e) {
      System.err.println("Failed to write data to excel");
      e.printStackTrace();
    }
  }
}

class SeriesDataHelper {
  public static Object getValueHelper(SeriesData seriesData, DataType dataType, int index, String nullFormat) {
    if (dataType == DataType.STRING) {
      String value = seriesData.getStringArray().getValues(index);
      return NullValues.STRING.equals(value) ? nullFormat : value;
    } else if (dataType == DataType.DOUBLE) {
      double value = seriesData.getDoubleArray().getValues(index);
      return Double.isNaN(value) ? nullFormat : value;
    } else if (dataType == DataType.BOOL) {
      return seriesData.getBoolArray().getValues(index);
    } else if (dataType == DataType.DURATION) {
      Duration value = seriesData.getDurationArray().getValues(index);
      return NullValues.DURATION.equals(value) ? nullFormat : value;
    } else if (dataType == DataType.FLOAT) {
      float value = seriesData.getFloatArray().getValues(index);
      return Float.isNaN(value) ? nullFormat : value;
    } else if (dataType == DataType.INT32) {
      int value = seriesData.getInt32Array().getValues(index);
      return NullValues.INT32 == value ? nullFormat : value;
    } else if (dataType == DataType.INT64) {
      long value = seriesData.getInt64Array().getValues(index);
      return NullValues.INT64 == value ? nullFormat : value;
    } else if (dataType == DataType.TIMESTAMP) {
      Timestamp value = seriesData.getTimestampArray().getValues(index);
      return NullValues.TIMESTAMP.equals(value) ? nullFormat : value;
    } else {
      throw new NotImplementedException(dataType + " is not implemented");
    }
  }
}

class TableData {
  List<Row> Rows = new ArrayList<Row>();

  public String toString() {
    return Rows.toString();
  }
}

class Row {
  List<String> Cells = new ArrayList<String>();

  public String toString() {
    return Cells.toString();
  }
}

 

import uuid
import math

import pandas as pd

from fds.protobuf.stach.Package_pb2 import Package
from fds.protobuf.stach.NullValues import NullValues
from fds.protobuf.stach.table.DataType_pb2 import DataType

class StachExtensions:
    """The purpose of this class is to provide the helper methods for converting Stach to Tabular format"""

    @staticmethod
    def generate_excel(package):
        for table in StachExtensions.convert_to_table_format(package):
            writer = pd.ExcelWriter(str(uuid.uuid1()) + ".xlsx")
            table.to_excel(excel_writer=writer)
            writer.save()
            writer.close()

    @staticmethod
    def convert_to_table_format(package):
        tables = list()
        for primary_table_id in package.primary_table_ids:
            tables.append(StachExtensions.generate_table(package, primary_table_id))
        return tables

    @staticmethod
    def generate_table(package_response, primary_table_id):

        if isinstance(package_response, Package):
            primary_table = package_response.tables[primary_table_id]
            header_id = primary_table.definition.header_table_id
            header_table = package_response.tables[header_id]
            dimension_columns = list(filter(lambda column_obj: column_obj.is_dimension, primary_table.definition.columns))
            dimension_columns_count = len(dimension_columns)
            row_count = len(primary_table.data.rows)
            header_row_count = len(header_table.data.rows)

            headers = list(list())
            # Constructs the column headers by considering dimension columns and header rows
            for series_definition_column in header_table.definition.columns:
                header_row = list()
                for i in range(0, dimension_columns_count, 1):
                    header_row.append(dimension_columns[i].description)

                for i in range(0, header_row_count, 1):
                    header_row.append(str(SeriesDataHelper.get_value_helper(header_table.data.columns[series_definition_column.id], series_definition_column.type, i, series_definition_column.format.null_format)))
                headers.append(header_row)

            data = list(list())
            # Constructs the column data
            for i in range(0, row_count, 1):
                data_row = list()
                for series_definition_column in primary_table.definition.columns:
                    data_row.append(str(SeriesDataHelper.get_value_helper(primary_table.data.columns[series_definition_column.id], series_definition_column.type, i, series_definition_column.format.null_format)))
                data.append(data_row)

            data_frame = pd.DataFrame(data=data)
            data_frame.columns = pd.MultiIndex.from_arrays(headers)
            return data_frame

        else:
            ValueError("Response data passed should be of package type.")


class SeriesDataHelper:

    @staticmethod
    def get_value_helper(series_data, datatype, index, null_format):
        if DataType.Name(datatype) == "STRING":
            return SeriesDataHelper.null_value_handler(datatype, series_data.string_array.values[index], null_format)
        elif DataType.Name(datatype) == "DOUBLE":
            return SeriesDataHelper.null_value_handler(datatype, series_data.double_array.values[index], null_format)
        elif DataType.Name(datatype) == "FLOAT":
            return SeriesDataHelper.null_value_handler(datatype, series_data.float_array.values[index], null_format)
        elif DataType.Name(datatype) == "INT32":
            return SeriesDataHelper.null_value_handler(datatype, series_data.int32_array.values[index], null_format)
        elif DataType.Name(datatype) == "INT64":
            return SeriesDataHelper.null_value_handler(datatype, series_data.int64_array.values[index], null_format)
        elif DataType.Name(datatype) == "BOOL":
            return SeriesDataHelper.null_value_handler(datatype, series_data.bool_array.values[index], null_format)
        elif DataType.Name(datatype) == "DURATION":
            return SeriesDataHelper.null_value_handler(datatype, series_data.duration_array.values[index], null_format)
        elif DataType.Name(datatype) == "TIMESTAMP":
            return SeriesDataHelper.null_value_handler(datatype, series_data.timestamp_array.values[index], null_format)
        else:
            ValueError("The datatype is not implemented")

    @staticmethod
    def null_value_handler(datatype, value, null_format):
        if DataType.Name(datatype) == "STRING":
            if NullValues.STRING == value:
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "DOUBLE":
            if math.isnan(value):
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "FLOAT":
            if math.isnan(value):
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "INT32":
            if NullValues.INT32 == value:
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "INT64":
            if NullValues.INT64 == value:
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "DURATION":
            if NullValues.DURATION.equals(value):
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "TIMESTAMP":
            if NullValues.TIMESTAMP.equals(value):
                return null_format
            else:
                return value
        else:
            return value

 

Building and running a calculation
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;

using FactSet.AnalyticsAPI.Engines.v2.Api;
using FactSet.AnalyticsAPI.Engines.v2.Client;
using FactSet.AnalyticsAPI.Engines.v2.Model;

using FactSet.Protobuf.Stach;
using Google.Protobuf;

namespace FactSet.AnalyticsAPI.Engines.v2.Example.Examples
{
    public class SPAREngineExample
    {
        private static Configuration _engineApiConfiguration;
        private const string BASE_PATH = "https://api.factset.com";
        private const string USER_NAME = "<username-serial>";
        private const string PASSWORD = "<apiKey>";
        private const string SPAR_DEFAULT_DOCUMENT = "pmw_root:/spar_documents/Factset Default Document";
        private const string SPAR_BENCHMARK_R_1000 = "R.1000";
        private const string SPAR_BENCHMARK_RUSSELL_PR_2000 = "RUSSELL_P:R.2000";
        private const string SPAR_BENCHMARK_RUSSELL_PREFIX = "RUSSELL";
        private const string SPAR_BENCHMARK_RUSSELL_RETURN_TYPE = "GTR";

        private static Configuration GetEngineApiConfiguration()
        {
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            if (_engineApiConfiguration != null)
            {
                return _engineApiConfiguration;
            }

            _engineApiConfiguration = new Configuration
            {
                BasePath = BASE_PATH,
                Username = USER_NAME,
                Password = PASSWORD
            };

            return _engineApiConfiguration;
        }

        public static void Main(string[] args)
        {
            try
            {
                var calculationParameters = new CalculationParameters
                {
                    Spar = new Dictionary<string, SPARCalculationParameters> { { "1", GetSparCalculationParameters() } }
                };

                var calculationApi = new CalculationsApi(GetEngineApiConfiguration());

                var runCalculationResponse = calculationApi.RunCalculationWithHttpInfo(calculationParameters);

                var calculationId = runCalculationResponse.Headers["Location"][0].Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).Last();
                ApiResponse<OutstandingCalculations> getStatus = null;

                while (getStatus == null || getStatus.Data.Status == OutstandingCalculations.StatusEnum.Queued || getStatus.Data.Status == OutstandingCalculations.StatusEnum.Executing)
                {
                    if (getStatus != null)
                    {
                        if (getStatus.Headers.ContainsKey("Cache-Control"))
                        {
                            var maxAge = getStatus.Headers["Cache-Control"][0];
                            if (string.IsNullOrWhiteSpace(maxAge))
                            {
                                Console.WriteLine("Sleeping for 2 seconds");
                                // Sleep for at least 2 seconds.
                                Thread.Sleep(2000);
                            }
                            else
                            {
                                var age = int.Parse(maxAge.Replace("max-age=", ""));
                                Console.WriteLine($"Sleeping for {age} seconds");
                                Thread.Sleep(age * 1000);
                            }
                        }
                    }

                    getStatus = calculationApi.GetCalculationByIdWithHttpInfo(calculationId);
                }
                Console.WriteLine("Calculation Completed");

                // Check for failed calculations
                foreach (var sparCalculationParameters in getStatus.Data.Spar)
                {
                    if (sparCalculationParameters.Value.Status == Calculation.StatusEnum.Failed)
                    {
                        Console.WriteLine($"CalculationId : {sparCalculationParameters.Key} Failed!!!");
                        Console.WriteLine($"Error message : {sparCalculationParameters.Value.Error}");
                    }
                }

                // Get result of successful calculations
                foreach (var sparCalculationParameters in getStatus.Data.Spar)
                {
                    PrintResult(sparCalculationParameters);
                }

                Console.ReadKey();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }

        private static SPARCalculationParameters GetSparCalculationParameters()
        {
            // Build SPAR Engine calculation parameters
            var componentsApi = new ComponentsApi(GetEngineApiConfiguration());

            var componentsResponse = componentsApi.GetSPARComponentsWithHttpInfo(SPAR_DEFAULT_DOCUMENT);

            if (componentsResponse.StatusCode != HttpStatusCode.OK)
            {
                LogError(componentsResponse);
                return null;
            }

            var sparComponentId = componentsResponse.Data.First().Key;
            Console.WriteLine($"SPAR Component Id : {sparComponentId}");


            var sparAccountIdentifier = new SPARIdentifier(SPAR_BENCHMARK_R_1000, SPAR_BENCHMARK_RUSSELL_RETURN_TYPE, SPAR_BENCHMARK_RUSSELL_PREFIX);
            var sparAccounts = new List<SPARIdentifier> { sparAccountIdentifier };
            var sparBenchmarkIdentifier = new SPARIdentifier(SPAR_BENCHMARK_RUSSELL_PR_2000, SPAR_BENCHMARK_RUSSELL_RETURN_TYPE, SPAR_BENCHMARK_RUSSELL_PREFIX);

            var sparCalculation = new SPARCalculationParameters(sparComponentId, sparAccounts, sparBenchmarkIdentifier);

            return sparCalculation;
        }

        private static void PrintResult(KeyValuePair<string, Calculation> calculation)
        {
            if (calculation.Value.Status == Calculation.StatusEnum.Success)
            {
                ApiResponse<string> resultResponse = null;

                var utilityApi = new UtilityApi(GetEngineApiConfiguration());
                resultResponse = utilityApi.GetByUrlWithHttpInfo(calculation.Value.Result);

                if (resultResponse.StatusCode != HttpStatusCode.OK)
                {
                    LogError(resultResponse);
                    return;
                }

                Console.WriteLine($"CalculationId : {calculation.Key} Succeeded!!!");
                Console.WriteLine($"CalculationId : {calculation.Key} Result");
                Console.WriteLine("/****************************************************************/");

                // converting the data to Package object
                var jpSettings = JsonParser.Settings.Default;
                var jp = new JsonParser(jpSettings.WithIgnoreUnknownFields(true));
                var package = jp.Parse<Package>(resultResponse.Data);

                // To convert package to 2D tables.
                var tables = package.ConvertToTableFormat();
                Console.WriteLine(tables[0]);

                // Uncomment the following line to generate an Excel file
                // package.GenerateCSV();
                Console.WriteLine("/****************************************************************/");
            }
        }

        private static void LogError<T>(ApiResponse<T> response)
        {
            Console.WriteLine("Error!!!");
            Console.WriteLine("Status Code: " + response.StatusCode);
            Console.WriteLine("Request Key: " + response.Headers["X-DataDirect-Request-Key"]);
            Console.WriteLine($"Reason: {response.Data}");
        }
    }
}

 

import java.util.List;
import java.util.Map;

import factset.analyticsapi.engines.v2.*;
import factset.analyticsapi.engines.v2.api.*;
import factset.analyticsapi.engines.v2.models.*;
import factset.analyticsapi.engines.v2.models.OutstandingCalculations.StatusEnum;

import com.google.protobuf.util.JsonFormat;
import com.google.protobuf.InvalidProtocolBufferException;
import com.factset.protobuf.stach.PackageProto.Package.Builder;
import com.factset.protobuf.stach.PackageProto.Package;

public class SPAREngineExample {
  private static ApiClient apiClient = null;
  private static final String BASE_PATH = "https://api.factset.com";
  private static final String USERNAME = "<username-serial>";
  private static final String PASSWORD = "<apiKey>";
  public static final String SPAR_DEFAULT_DOCUMENT = "pmw_root:/spar_documents/Factset Default Document";
  private static final String COMPONENT_NAME = "Returns Data";
  private static final String COMPONENT_CATEGORY = "Raw Data / Returns";

  public static void main(String[] args) throws InterruptedException {
    try {
      // Build SPAR Calculation Parameters List

      // Get all component from SPAR_DEFAULT_DOCUMENT with Name COMPONENT_NAME & category COMPONENT_CATEGORY
      ComponentsApi componentsApi = new ComponentsApi(getApiClient());
      Map<String, ComponentListEntity> components = componentsApi.getSPARComponents(SPAR_DEFAULT_DOCUMENT);
      String componentId = components.entrySet().stream().filter(
          c -> c.getValue().getName().equals(COMPONENT_NAME) && c.getValue().getCategory().equals(COMPONENT_CATEGORY))
          .iterator().next().getKey();
      System.out.println("ID of component with Name '" + COMPONENT_NAME + "' and category '" + COMPONENT_CATEGORY
          + "' : " + componentId);

      CalculationParameters parameters = new CalculationParameters();

      SPARCalculationParameters sparItem = new SPARCalculationParameters();

      sparItem.setComponentid(componentId);

      SPARIdentifier accountIdentifier1 = new SPARIdentifier();
      accountIdentifier1.setId("R.1000");
      accountIdentifier1.setPrefix("RUSSELL");
      accountIdentifier1.setReturntype("GTR");
      sparItem.addAccountsItem(accountIdentifier1);

      SPARIdentifier accountIdentifier2 = new SPARIdentifier();
      accountIdentifier2.setId("RUSSELL_P:R.2000");
      accountIdentifier2.setPrefix("RUSSELL");
      accountIdentifier2.setReturntype("GTR");
      sparItem.addAccountsItem(accountIdentifier2);

      SPARIdentifier benchmarkIdentifier = new SPARIdentifier();
      benchmarkIdentifier.setId("R.2000");
      benchmarkIdentifier.setPrefix("RUSSELL");
      benchmarkIdentifier.setReturntype("GTR");
      sparItem.setBenchmark(benchmarkIdentifier);

      SPARDateParameters dateParameters = new SPARDateParameters();
      dateParameters.setStartdate("20180101");
      dateParameters.setEnddate("20181231");
      dateParameters.setFrequency("Monthly");
      sparItem.setDates(dateParameters);

      parameters.putSparItem("1", sparItem);

      // Run Calculation Request
      CalculationsApi apiInstance = new CalculationsApi(getApiClient());
      ApiResponse<Void> createResponse = null;

      createResponse = apiInstance.runCalculationWithHttpInfo(parameters);

      String[] locationList = createResponse.getHeaders().get("Location").get(0).split("/");
      String requestId = locationList[locationList.length - 1];

      // Get Calculation Request Status
      ApiResponse<OutstandingCalculations> getStatus = null;

      while (getStatus == null || getStatus.getData().getStatus() == StatusEnum.QUEUED
          || getStatus.getData().getStatus() == StatusEnum.EXECUTING) {
        if (getStatus != null) {
          List<String> cacheControl = getStatus.getHeaders().get("Cache-Control");
          if (cacheControl != null) {
            int maxAge = Integer.parseInt(cacheControl.get(0).replaceAll("max-age=", ""));
            System.out.println("Sleeping for: " + maxAge + " seconds");
            Thread.sleep(maxAge * 1000);
          } else {
            System.out.println("Sleeping for: 2 seconds");
            Thread.sleep(2 * 1000);
          }
        }
        getStatus = apiInstance.getCalculationByIdWithHttpInfo(requestId);
      }

      System.out.println("Calculation Completed!!!");

      // Check for Failed Calculations
      for (Map.Entry<String, Calculation> calculationParameters : getStatus.getData().getSpar().entrySet()) {
        if (calculationParameters.getValue().getStatus() == Calculation.StatusEnum.FAILED) {
          System.out.println("CalculationId : " + calculationParameters.getKey() + " Failed!!!");
          System.out.println("Error message : " + calculationParameters.getValue().getError());
          return;
        }
      }

      // Get Result of Successful Caculations
      for (Map.Entry<String, Calculation> calculationParameters : getStatus.getData().getSpar().entrySet()) {
        if (calculationParameters.getValue().getStatus() == Calculation.StatusEnum.SUCCESS) {
          UtilityApi utilityApiInstance = new UtilityApi(apiClient);
          ApiResponse<String> resultResponse = utilityApiInstance
              .getByUrlWithHttpInfo(calculationParameters.getValue().getResult());
          System.out.println("CalculationId : " + calculationParameters.getKey() + " Succeeded!!!");
          System.out.println("CalculationId : " + calculationParameters.getKey() + " Result");

          Builder builder = Package.newBuilder();
          try {
            JsonFormat.parser().ignoringUnknownFields().merge(resultResponse.getData(), builder);
          } catch (InvalidProtocolBufferException e) {
            System.out.println("Error while deserializing the response");
            e.printStackTrace();
          }

          Package result = (Package) builder.build();
          // To convert result to 2D tables.
          List<TableData> tables = StachExtensions.convertToTableFormat(result);
          System.out.println(tables.get(0)); // Prints the result in 2D table format.
          // Uncomment the following line to generate an Excel file
          // StachExtensions.generateExcel(result);
        }
      }
    } catch (ApiException e) {
      handleException("SPAREngineExample#Main", e);
      return;
    }
  }

  private static ApiClient getApiClient() throws ApiException {
    if (apiClient != null) {
      return apiClient;
    }

    apiClient = new ApiClient();
    apiClient.setConnectTimeout(30000);
    apiClient.setReadTimeout(30000);
    apiClient.setBasePath(BASE_PATH);
    apiClient.setUsername(USERNAME);
    apiClient.setPassword(PASSWORD);

    return apiClient;
  }

  private static void handleException(String method, ApiException e) {
    System.err.println("Exception when calling " + method);
    if (e.getResponseHeaders() != null && e.getResponseHeaders().containsKey("x-datadirect-request-key")) {
      System.out.println("x-datadirect-request-key: " + e.getResponseHeaders().get("x-datadirect-request-key").get(0));
    }
    System.out.println("Status code: " + e.getCode());
    System.out.println("Reason: " + e.getResponseBody());
    e.printStackTrace();
  }
}

 

import time
import json

from google.protobuf import json_format
from google.protobuf.json_format import MessageToJson
from google.protobuf.json_format import MessageToDict
from fds.protobuf.stach.Package_pb2 import Package

from fds.analyticsapi.engines.v2.configuration import Configuration;
from fds.analyticsapi.engines.v2.api_client import ApiClient;
from fds.analyticsapi.engines.v2.api.components_api import ComponentsApi
from fds.analyticsapi.engines.v2.api.calculations_api import CalculationsApi
from fds.analyticsapi.engines.v2.api.utility_api import UtilityApi
from fds.analyticsapi.engines.v2.models.calculation_parameters import CalculationParameters
from fds.analyticsapi.engines.v2.models.spar_calculation_parameters import SPARCalculationParameters
from fds.analyticsapi.engines.v2.models.spar_identifier import SPARIdentifier
from fds.analyticsapi.engines.v2.models.spar_date_parameters import SPARDateParameters

from stach_extensions import StachExtensions

host = "https://api.factset.com"
username = "<username-serial>"
password = "<apiKey>"

spar_document_name = "pmw_root:/spar_documents/Factset Default Document";
spar_benchmark_r_1000 = "R.1000";
spar_benchmark_russell_pr_2000 = "RUSSELL_P:R.2000";
spar_benchmark_russell_prefix = "RUSSELL"
spar_benchmark_russell_return_type = "GTR"
startdate = "20180101"
enddate = "20181231"
frequency = "Monthly"

config = Configuration()
config.host = host
config.username = username
config.password = password
# add proxy and/or disable ssl verification according to your development environment
# config.proxy = "<proxyUrl>"
# config.verify_ssl = False

api_client = ApiClient(config)

components_api = ComponentsApi(api_client);

components = components_api.get_spar_components_with_http_info(spar_document_name)
component_id = list(components[0].keys())[0]

spar_account_identifier = SPARIdentifier(spar_benchmark_r_1000, spar_benchmark_russell_return_type, spar_benchmark_russell_prefix)
spar_accounts =[spar_account_identifier]
spar_benchmark_identifier = SPARIdentifier(spar_benchmark_russell_pr_2000, spar_benchmark_russell_return_type, spar_benchmark_russell_prefix);
spar_dates = SPARDateParameters(startdate, enddate, frequency)

spar_calculation_parameters = {"1": SPARCalculationParameters(component_id, spar_accounts, spar_benchmark_identifier, spar_dates)}
calculations = CalculationParameters(spar=spar_calculation_parameters)
print(calculations)

calculations_api = CalculationsApi(api_client)
run_calculation_response = calculations_api.run_calculation_with_http_info(calculations=calculations)

if(run_calculation_response[1] != 202):
    print(batch_api_post_result[2].get("x-datadirect-request-key"))
    quit()

calculation_id = run_calculation_response[2].get("location").split("/")[-1]
print("Calculation Id: " + calculation_id)

calculation_status = calculations_api.get_calculation_by_id_with_http_info(calculation_id)
while (calculation_status[1] == 200 and (calculation_status[0].status == "Queued" or calculation_status[0].status == "Executing")):
    age_value = calculation_status[2].get("cache-control")
    if(age_value != None):
        max_age = age_value.replace("max-age=", "")
        print('Sleeping: ' + max_age)
        time.sleep(int(max_age))
    calculation_status = calculations_api.get_calculation_by_id_with_http_info(calculation_id)

if(calculation_status[1] != 200):
    print(calculation_status[2].get("x-datadirect-request-key"))
    quit()

print("Calculation Completed!!!");

for calculation_key, calculation_item in calculation_status[0].spar.items():
    if calculation_item.status == "Failed":
        print("Spar Calculation : " + calculation_key + " Failed!!!")
        print("Error Message : " + calculation_item.error)
    elif calculation_item.status == "Success":
        utility_api = UtilityApi(api_client)
        calculation_result = utility_api.get_by_url_with_http_info(calculation_item.result)

        if(calculation_result[1] != 200):
            print(calculation_result[2].get('x-datadirect-request-key'))
            quit()

        # converting the data to Package object
        result =  json_format.Parse(json.dumps(calculation_result[0]), Package())
        # print(MessageToJson(result)) # To print the result object as a JSON
        # print(MessageToDict(result)) # To print the result object as a Dictionary
        tables = StachExtensions.convert_to_table_format(result) # To convert result to 2D tables.
        print(tables[0]) # Prints the result in 2D table format.
        # StachExtensions.generate_excel(result) # To get the result in table format exported to excel file.

 

Converting API output to Table format
using System;
using System.Collections.Generic;
using System.Linq;
using FactSet.Protobuf.Stach;
using FactSet.Protobuf.Stach.Table;

namespace FactSet.AnalyticsAPI.Engines.v2.Example.Examples
{
    public static class StachExtensions
    {
        public static void GenerateCSV(this Package package)
        {
            foreach (var table in package.ConvertToTableFormat())
            {
                System.IO.File.WriteAllText($"{Guid.NewGuid():N}.csv", table.ToString());
            }
        }

        public static List<Table> ConvertToTableFormat(this Package package)
        {
            var tables = new List<Table>();
            foreach (var primaryTableId in package.PrimaryTableIds)
            {
                tables.Add(GenerateTable(package, primaryTableId));
            }

            return tables;
        }

        private static Table GenerateTable(Package package, string primaryTableId)
        {
            var primaryTable = package.Tables[primaryTableId];
            var headerId = primaryTable.Definition.HeaderTableId;
            var headerTable = package.Tables[headerId];
            var columnIds = primaryTable.Definition.Columns.Select(c => c.Id).ToList();
            var headerColumnIds = headerTable.Definition.Columns.Select(c => c.Id).ToList();
            var dimensionColumnsCount = primaryTable.Definition.Columns.Count(c => c.IsDimension);
            var rowCount = primaryTable.Data.Rows.Count;
            var headerRowCount = headerTable.Data.Rows.Count;

            var table = new Table
            {
                Rows = new List<Row>()
            };
            // Constructs the column headers by considering dimension columns and header rows
            foreach (var columnId in headerColumnIds)
            {
                var headerRow = new Row { Cells = new List<string>() };
                for (int j = 0; j < dimensionColumnsCount; j++)
                {
                    headerRow.Cells.Add("");
                }

                for (int i = 0; i < headerRowCount; i++)
                {
                    headerRow.Cells.Add(Convert.ToString(headerTable.Data.Columns[columnId]
                        .GetValueHelper(headerTable.Definition.Columns.First(c => c.Id == columnId).Type, i)));
                }
                table.Rows.Add(headerRow);
            }
            // Constructs the column data
            for (int i = 0; i < rowCount; i++)
            {
                var dataRow = new Row { Cells = new List<string>() };
                foreach (var columnId in columnIds)
                {
                    dataRow.Cells.Add(Convert.ToString(primaryTable.Data.Columns[columnId]
                        .GetValueHelper(primaryTable.Definition.Columns.First(c => c.Id == columnId).Type, i)));
                }
                table.Rows.Add(dataRow);
            }

            return table;
        }
    }

    public static class SeriesDataHelper
    {
        public static object GetValueHelper(this SeriesData seriesData, DataType dataType, int index)
        {
            switch (dataType)
            {
                case DataType.Bool:
                    {
                        return seriesData.BoolArray?.Values?[index];
                    }
                case DataType.Double:
                    {
                        return seriesData.DoubleArray?.Values?[index];
                    }
                case DataType.Duration:
                    {
                        var v = seriesData.DurationArray?.Values?[index];
                        return v?.ToTimeSpan();
                    }
                case DataType.Float:
                    {
                        return seriesData.FloatArray?.Values?[index];
                    }
                case DataType.Int32:
                    {
                        return seriesData.Int32Array?.Values?[index];
                    }
                case DataType.Int64:
                    {
                        return seriesData.Int64Array?.Values?[index];
                    }
                case DataType.String:
                    {
                        return seriesData.StringArray?.Values?[index];
                    }
                case DataType.Timestamp:
                    {
                        var v = seriesData.TimestampArray?.Values?[index];
                        return v?.ToDateTime();
                    }
                default:
                    throw new NotImplementedException($"{dataType} is not implemented");
            }
        }
    }

    public class Table
    {
        public List<Row> Rows { get; set; }

        public override string ToString()
        {
            return string.Join(Environment.NewLine, Rows);
        }
    }

    public class Row
    {
        public List<string> Cells { get; set; }

        public override string ToString()
        {
            return string.Join(",", Cells.Select(c => c.Replace(",", "")));
        }
    }
}

 

import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.poi.ss.formula.eval.NotImplementedException;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.factset.protobuf.stach.NullValues;
import com.factset.protobuf.stach.PackageProto.Package;
import com.factset.protobuf.stach.table.DataTypeProto.DataType;
import com.factset.protobuf.stach.table.SeriesDataProto.SeriesData;
import com.factset.protobuf.stach.table.SeriesDefinitionProto.SeriesDefinition;
import com.factset.protobuf.stach.table.TableProto.Table;

import com.google.protobuf.Duration;
import com.google.protobuf.Timestamp;

public class StachExtensions {
  // The purpose of this class is to provide the helper methods for converting
  // stach to Tabular format.

  public static void generateExcel(Package packageObj) {
    for (TableData table : convertToTableFormat(packageObj)) {
      writeDataToExcel(table, UUID.randomUUID().toString() + ".xlsx");
    }
  }

  public static List<TableData> convertToTableFormat(Package packageObj) {
    List<TableData> tables = new ArrayList<TableData>();
    for (String primaryTableId : packageObj.getPrimaryTableIdsList()) {
      tables.add(generateTable(packageObj, primaryTableId));
    }
    return tables;
  }

  private static TableData generateTable(Package packageObj, String primaryTableId) {
    Map<String, Table> tablesMap = packageObj.getTablesMap();
    Table primaryTable = tablesMap.get(primaryTableId);
    String headerId = primaryTable.getDefinition().getHeaderTableId();
    Table headerTable = tablesMap.get(headerId);
    int headerRowCount = headerTable.getData().getRowsCount();
    int rowsCount = primaryTable.getData().getRowsCount();

    TableData table = new TableData();

    // Construct the column headers by considering dimension columns and header
    // rows.
    List<SeriesDefinition> headerTableSeriesDefinitions = headerTable.getDefinition().getColumnsList();
    List<SeriesDefinition> primaryTableSeriesDefinitions = primaryTable.getDefinition().getColumnsList();

    Map<String, SeriesData> headerTableColumns = headerTable.getData().getColumnsMap();
    Map<String, SeriesData> primaryTableColumns = primaryTable.getData().getColumnsMap();

    for (SeriesDefinition headerTableseriesDefinition : headerTableSeriesDefinitions) {
      Row headerRow = new Row();
      for (SeriesDefinition primaryTableSeriesDefinition : primaryTableSeriesDefinitions) {
        if (primaryTableSeriesDefinition.getIsDimension()) {
          headerRow.Cells.add(primaryTableSeriesDefinition.getDescription());
        }
      }

      String headerColumnId = headerTableseriesDefinition.getId();
      String nullFormat = headerTableseriesDefinition.getFormat().getNullFormat();
      for (int i = 0; i < headerRowCount; i++) {
        headerRow.Cells.add(SeriesDataHelper.getValueHelper(headerTableColumns.get(headerColumnId),
            headerTableseriesDefinition.getType(), i, nullFormat).toString());
      }
      table.Rows.add(headerRow);
    }

    // Construct the column data
    for (int i = 0; i < rowsCount; i++) {
      Row dataRow = new Row();
      for (SeriesDefinition primaryTableSeriesDefinition : primaryTableSeriesDefinitions) {
        String nullFormat = primaryTableSeriesDefinition.getFormat().getNullFormat();
        String primaryTableColumnId = primaryTableSeriesDefinition.getId();
        dataRow.Cells.add(SeriesDataHelper.getValueHelper(primaryTableColumns.get(primaryTableColumnId),
            primaryTableSeriesDefinition.getType(), i, nullFormat).toString());
      }
      table.Rows.add(dataRow);
    }
    return table;
  }

  private static void writeDataToExcel(TableData table, String fileLocation) {
    XSSFWorkbook workbook = new XSSFWorkbook();
    XSSFSheet sheet = workbook.createSheet("PA Report");

    int rowsSize = table.Rows.size();
    for (int rowIndex = 0; rowIndex < rowsSize; rowIndex++) {
      XSSFRow xsswRow = sheet.createRow(rowIndex);
      List<String> cells = table.Rows.get(rowIndex).Cells;
      for (int cellIndex = 0; cellIndex < cells.size(); cellIndex++) {
        XSSFCell xssfCell = xsswRow.createCell(cellIndex);
        xssfCell.setCellValue(cells.get(cellIndex));
      }
    }

    try {
      FileOutputStream out = new FileOutputStream(new File(fileLocation));
      workbook.write(out);
      out.close();
      workbook.close();
    } catch (Exception e) {
      System.err.println("Failed to write data to excel");
      e.printStackTrace();
    }
  }
}

class SeriesDataHelper {
  public static Object getValueHelper(SeriesData seriesData, DataType dataType, int index, String nullFormat) {
    if (dataType == DataType.STRING) {
      String value = seriesData.getStringArray().getValues(index);
      return NullValues.STRING.equals(value) ? nullFormat : value;
    } else if (dataType == DataType.DOUBLE) {
      double value = seriesData.getDoubleArray().getValues(index);
      return Double.isNaN(value) ? nullFormat : value;
    } else if (dataType == DataType.BOOL) {
      return seriesData.getBoolArray().getValues(index);
    } else if (dataType == DataType.DURATION) {
      Duration value = seriesData.getDurationArray().getValues(index);
      return NullValues.DURATION.equals(value) ? nullFormat : value;
    } else if (dataType == DataType.FLOAT) {
      float value = seriesData.getFloatArray().getValues(index);
      return Float.isNaN(value) ? nullFormat : value;
    } else if (dataType == DataType.INT32) {
      int value = seriesData.getInt32Array().getValues(index);
      return NullValues.INT32 == value ? nullFormat : value;
    } else if (dataType == DataType.INT64) {
      long value = seriesData.getInt64Array().getValues(index);
      return NullValues.INT64 == value ? nullFormat : value;
    } else if (dataType == DataType.TIMESTAMP) {
      Timestamp value = seriesData.getTimestampArray().getValues(index);
      return NullValues.TIMESTAMP.equals(value) ? nullFormat : value;
    } else {
      throw new NotImplementedException(dataType + " is not implemented");
    }
  }
}

class TableData {
  List<Row> Rows = new ArrayList<Row>();

  public String toString() {
    return Rows.toString();
  }
}

class Row {
  List<String> Cells = new ArrayList<String>();

  public String toString() {
    return Cells.toString();
  }
}

 

import uuid
import math

import pandas as pd

from fds.protobuf.stach.Package_pb2 import Package
from fds.protobuf.stach.NullValues import NullValues
from fds.protobuf.stach.table.DataType_pb2 import DataType

class StachExtensions:
    """The purpose of this class is to provide the helper methods for converting Stach to Tabular format"""

    @staticmethod
    def generate_excel(package):
        for table in StachExtensions.convert_to_table_format(package):
            writer = pd.ExcelWriter(str(uuid.uuid1()) + ".xlsx")
            table.to_excel(excel_writer=writer)
            writer.save()
            writer.close()

    @staticmethod
    def convert_to_table_format(package):
        tables = list()
        for primary_table_id in package.primary_table_ids:
            tables.append(StachExtensions.generate_table(package, primary_table_id))
        return tables

    @staticmethod
    def generate_table(package_response, primary_table_id):

        if isinstance(package_response, Package):
            primary_table = package_response.tables[primary_table_id]
            header_id = primary_table.definition.header_table_id
            header_table = package_response.tables[header_id]
            dimension_columns = list(filter(lambda column_obj: column_obj.is_dimension, primary_table.definition.columns))
            dimension_columns_count = len(dimension_columns)
            row_count = len(primary_table.data.rows)
            header_row_count = len(header_table.data.rows)

            headers = list(list())
            # Constructs the column headers by considering dimension columns and header rows
            for series_definition_column in header_table.definition.columns:
                header_row = list()
                for i in range(0, dimension_columns_count, 1):
                    header_row.append(dimension_columns[i].description)

                for i in range(0, header_row_count, 1):
                    header_row.append(str(SeriesDataHelper.get_value_helper(header_table.data.columns[series_definition_column.id], series_definition_column.type, i, series_definition_column.format.null_format)))
                headers.append(header_row)

            data = list(list())
            # Constructs the column data
            for i in range(0, row_count, 1):
                data_row = list()
                for series_definition_column in primary_table.definition.columns:
                    data_row.append(str(SeriesDataHelper.get_value_helper(primary_table.data.columns[series_definition_column.id], series_definition_column.type, i, series_definition_column.format.null_format)))
                data.append(data_row)

            data_frame = pd.DataFrame(data=data)
            data_frame.columns = pd.MultiIndex.from_arrays(headers)
            return data_frame

        else:
            ValueError("Response data passed should be of package type.")


class SeriesDataHelper:

    @staticmethod
    def get_value_helper(series_data, datatype, index, null_format):
        if DataType.Name(datatype) == "STRING":
            return SeriesDataHelper.null_value_handler(datatype, series_data.string_array.values[index], null_format)
        elif DataType.Name(datatype) == "DOUBLE":
            return SeriesDataHelper.null_value_handler(datatype, series_data.double_array.values[index], null_format)
        elif DataType.Name(datatype) == "FLOAT":
            return SeriesDataHelper.null_value_handler(datatype, series_data.float_array.values[index], null_format)
        elif DataType.Name(datatype) == "INT32":
            return SeriesDataHelper.null_value_handler(datatype, series_data.int32_array.values[index], null_format)
        elif DataType.Name(datatype) == "INT64":
            return SeriesDataHelper.null_value_handler(datatype, series_data.int64_array.values[index], null_format)
        elif DataType.Name(datatype) == "BOOL":
            return SeriesDataHelper.null_value_handler(datatype, series_data.bool_array.values[index], null_format)
        elif DataType.Name(datatype) == "DURATION":
            return SeriesDataHelper.null_value_handler(datatype, series_data.duration_array.values[index], null_format)
        elif DataType.Name(datatype) == "TIMESTAMP":
            return SeriesDataHelper.null_value_handler(datatype, series_data.timestamp_array.values[index], null_format)
        else:
            ValueError("The datatype is not implemented")

    @staticmethod
    def null_value_handler(datatype, value, null_format):
        if DataType.Name(datatype) == "STRING":
            if NullValues.STRING == value:
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "DOUBLE":
            if math.isnan(value):
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "FLOAT":
            if math.isnan(value):
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "INT32":
            if NullValues.INT32 == value:
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "INT64":
            if NullValues.INT64 == value:
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "DURATION":
            if NullValues.DURATION.equals(value):
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "TIMESTAMP":
            if NullValues.TIMESTAMP.equals(value):
                return null_format
            else:
                return value
        else:
            return value

 

Building and running a calculation
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;

using FactSet.AnalyticsAPI.Engines.v2.Api;
using FactSet.AnalyticsAPI.Engines.v2.Client;
using FactSet.AnalyticsAPI.Engines.v2.Model;

using FactSet.Protobuf.Stach;
using Google.Protobuf;

namespace FactSet.AnalyticsAPI.Engines.v2.Example.Examples
{
    public class SPAREngineExample
    {
        private static Configuration _engineApiConfiguration;
        private const string BASE_PATH = "https://api.factset.com";
        private const string USER_NAME = "<username-serial>";
        private const string PASSWORD = "<apiKey>";
        private const string SPAR_DEFAULT_DOCUMENT = "pmw_root:/spar_documents/Factset Default Document";
        private const string SPAR_BENCHMARK_R_1000 = "R.1000";
        private const string SPAR_BENCHMARK_RUSSELL_PR_2000 = "RUSSELL_P:R.2000";
        private const string SPAR_BENCHMARK_RUSSELL_PREFIX = "RUSSELL";
        private const string SPAR_BENCHMARK_RUSSELL_RETURN_TYPE = "GTR";

        private static Configuration GetEngineApiConfiguration()
        {
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            if (_engineApiConfiguration != null)
            {
                return _engineApiConfiguration;
            }

            _engineApiConfiguration = new Configuration
            {
                BasePath = BASE_PATH,
                Username = USER_NAME,
                Password = PASSWORD
            };

            return _engineApiConfiguration;
        }

        public static void Main(string[] args)
        {
            try
            {
                var calculationParameters = new CalculationParameters
                {
                    Spar = new Dictionary<string, SPARCalculationParameters> { { "1", GetSparCalculationParameters() } }
                };

                var calculationApi = new CalculationsApi(GetEngineApiConfiguration());

                var runCalculationResponse = calculationApi.RunCalculationWithHttpInfo(calculationParameters);

                var calculationId = runCalculationResponse.Headers["Location"][0].Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).Last();
                ApiResponse<OutstandingCalculations> getStatus = null;

                while (getStatus == null || getStatus.Data.Status == OutstandingCalculations.StatusEnum.Queued || getStatus.Data.Status == OutstandingCalculations.StatusEnum.Executing)
                {
                    if (getStatus != null)
                    {
                        if (getStatus.Headers.ContainsKey("Cache-Control"))
                        {
                            var maxAge = getStatus.Headers["Cache-Control"][0];
                            if (string.IsNullOrWhiteSpace(maxAge))
                            {
                                Console.WriteLine("Sleeping for 2 seconds");
                                // Sleep for at least 2 seconds.
                                Thread.Sleep(2000);
                            }
                            else
                            {
                                var age = int.Parse(maxAge.Replace("max-age=", ""));
                                Console.WriteLine($"Sleeping for {age} seconds");
                                Thread.Sleep(age * 1000);
                            }
                        }
                    }

                    getStatus = calculationApi.GetCalculationByIdWithHttpInfo(calculationId);
                }
                Console.WriteLine("Calculation Completed");

                // Check for failed calculations
                foreach (var sparCalculationParameters in getStatus.Data.Spar)
                {
                    if (sparCalculationParameters.Value.Status == Calculation.StatusEnum.Failed)
                    {
                        Console.WriteLine($"CalculationId : {sparCalculationParameters.Key} Failed!!!");
                        Console.WriteLine($"Error message : {sparCalculationParameters.Value.Error}");
                    }
                }

                // Get result of successful calculations
                foreach (var sparCalculationParameters in getStatus.Data.Spar)
                {
                    PrintResult(sparCalculationParameters);
                }

                Console.ReadKey();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }

        private static SPARCalculationParameters GetSparCalculationParameters()
        {
            // Build SPAR Engine calculation parameters
            var componentsApi = new ComponentsApi(GetEngineApiConfiguration());

            var componentsResponse = componentsApi.GetSPARComponentsWithHttpInfo(SPAR_DEFAULT_DOCUMENT);

            if (componentsResponse.StatusCode != HttpStatusCode.OK)
            {
                LogError(componentsResponse);
                return null;
            }

            var sparComponentId = componentsResponse.Data.First().Key;
            Console.WriteLine($"SPAR Component Id : {sparComponentId}");


            var sparAccountIdentifier = new SPARIdentifier(SPAR_BENCHMARK_R_1000, SPAR_BENCHMARK_RUSSELL_RETURN_TYPE, SPAR_BENCHMARK_RUSSELL_PREFIX);
            var sparAccounts = new List<SPARIdentifier> { sparAccountIdentifier };
            var sparBenchmarkIdentifier = new SPARIdentifier(SPAR_BENCHMARK_RUSSELL_PR_2000, SPAR_BENCHMARK_RUSSELL_RETURN_TYPE, SPAR_BENCHMARK_RUSSELL_PREFIX);

            var sparCalculation = new SPARCalculationParameters(sparComponentId, sparAccounts, sparBenchmarkIdentifier);

            return sparCalculation;
        }

        private static void PrintResult(KeyValuePair<string, Calculation> calculation)
        {
            if (calculation.Value.Status == Calculation.StatusEnum.Success)
            {
                ApiResponse<string> resultResponse = null;

                var utilityApi = new UtilityApi(GetEngineApiConfiguration());
                resultResponse = utilityApi.GetByUrlWithHttpInfo(calculation.Value.Result);

                if (resultResponse.StatusCode != HttpStatusCode.OK)
                {
                    LogError(resultResponse);
                    return;
                }

                Console.WriteLine($"CalculationId : {calculation.Key} Succeeded!!!");
                Console.WriteLine($"CalculationId : {calculation.Key} Result");
                Console.WriteLine("/****************************************************************/");

                // converting the data to Package object
                var jpSettings = JsonParser.Settings.Default;
                var jp = new JsonParser(jpSettings.WithIgnoreUnknownFields(true));
                var package = jp.Parse<Package>(resultResponse.Data);

                // To convert package to 2D tables.
                var tables = package.ConvertToTableFormat();
                Console.WriteLine(tables[0]);

                // Uncomment the following line to generate an Excel file
                // package.GenerateCSV();
                Console.WriteLine("/****************************************************************/");
            }
        }

        private static void LogError<T>(ApiResponse<T> response)
        {
            Console.WriteLine("Error!!!");
            Console.WriteLine("Status Code: " + response.StatusCode);
            Console.WriteLine("Request Key: " + response.Headers["X-DataDirect-Request-Key"]);
            Console.WriteLine($"Reason: {response.Data}");
        }
    }
}

 

import java.util.List;
import java.util.Map;

import factset.analyticsapi.engines.v2.*;
import factset.analyticsapi.engines.v2.api.*;
import factset.analyticsapi.engines.v2.models.*;
import factset.analyticsapi.engines.v2.models.OutstandingCalculations.StatusEnum;

import com.google.protobuf.util.JsonFormat;
import com.google.protobuf.InvalidProtocolBufferException;
import com.factset.protobuf.stach.PackageProto.Package.Builder;
import com.factset.protobuf.stach.PackageProto.Package;

public class SPAREngineExample {
  private static ApiClient apiClient = null;
  private static final String BASE_PATH = "https://api.factset.com";
  private static final String USERNAME = "<username-serial>";
  private static final String PASSWORD = "<apiKey>";
  public static final String SPAR_DEFAULT_DOCUMENT = "pmw_root:/spar_documents/Factset Default Document";
  private static final String COMPONENT_NAME = "Returns Data";
  private static final String COMPONENT_CATEGORY = "Raw Data / Returns";

  public static void main(String[] args) throws InterruptedException {
    try {
      // Build SPAR Calculation Parameters List

      // Get all component from SPAR_DEFAULT_DOCUMENT with Name COMPONENT_NAME & category COMPONENT_CATEGORY
      ComponentsApi componentsApi = new ComponentsApi(getApiClient());
      Map<String, ComponentListEntity> components = componentsApi.getSPARComponents(SPAR_DEFAULT_DOCUMENT);
      String componentId = components.entrySet().stream().filter(
          c -> c.getValue().getName().equals(COMPONENT_NAME) && c.getValue().getCategory().equals(COMPONENT_CATEGORY))
          .iterator().next().getKey();
      System.out.println("ID of component with Name '" + COMPONENT_NAME + "' and category '" + COMPONENT_CATEGORY
          + "' : " + componentId);

      CalculationParameters parameters = new CalculationParameters();

      SPARCalculationParameters sparItem = new SPARCalculationParameters();

      sparItem.setComponentid(componentId);

      SPARIdentifier accountIdentifier1 = new SPARIdentifier();
      accountIdentifier1.setId("R.1000");
      accountIdentifier1.setPrefix("RUSSELL");
      accountIdentifier1.setReturntype("GTR");
      sparItem.addAccountsItem(accountIdentifier1);

      SPARIdentifier accountIdentifier2 = new SPARIdentifier();
      accountIdentifier2.setId("RUSSELL_P:R.2000");
      accountIdentifier2.setPrefix("RUSSELL");
      accountIdentifier2.setReturntype("GTR");
      sparItem.addAccountsItem(accountIdentifier2);

      SPARIdentifier benchmarkIdentifier = new SPARIdentifier();
      benchmarkIdentifier.setId("R.2000");
      benchmarkIdentifier.setPrefix("RUSSELL");
      benchmarkIdentifier.setReturntype("GTR");
      sparItem.setBenchmark(benchmarkIdentifier);

      SPARDateParameters dateParameters = new SPARDateParameters();
      dateParameters.setStartdate("20180101");
      dateParameters.setEnddate("20181231");
      dateParameters.setFrequency("Monthly");
      sparItem.setDates(dateParameters);

      parameters.putSparItem("1", sparItem);

      // Run Calculation Request
      CalculationsApi apiInstance = new CalculationsApi(getApiClient());
      ApiResponse<Void> createResponse = null;

      createResponse = apiInstance.runCalculationWithHttpInfo(parameters);

      String[] locationList = createResponse.getHeaders().get("Location").get(0).split("/");
      String requestId = locationList[locationList.length - 1];

      // Get Calculation Request Status
      ApiResponse<OutstandingCalculations> getStatus = null;

      while (getStatus == null || getStatus.getData().getStatus() == StatusEnum.QUEUED
          || getStatus.getData().getStatus() == StatusEnum.EXECUTING) {
        if (getStatus != null) {
          List<String> cacheControl = getStatus.getHeaders().get("Cache-Control");
          if (cacheControl != null) {
            int maxAge = Integer.parseInt(cacheControl.get(0).replaceAll("max-age=", ""));
            System.out.println("Sleeping for: " + maxAge + " seconds");
            Thread.sleep(maxAge * 1000);
          } else {
            System.out.println("Sleeping for: 2 seconds");
            Thread.sleep(2 * 1000);
          }
        }
        getStatus = apiInstance.getCalculationByIdWithHttpInfo(requestId);
      }

      System.out.println("Calculation Completed!!!");

      // Check for Failed Calculations
      for (Map.Entry<String, Calculation> calculationParameters : getStatus.getData().getSpar().entrySet()) {
        if (calculationParameters.getValue().getStatus() == Calculation.StatusEnum.FAILED) {
          System.out.println("CalculationId : " + calculationParameters.getKey() + " Failed!!!");
          System.out.println("Error message : " + calculationParameters.getValue().getError());
          return;
        }
      }

      // Get Result of Successful Caculations
      for (Map.Entry<String, Calculation> calculationParameters : getStatus.getData().getSpar().entrySet()) {
        if (calculationParameters.getValue().getStatus() == Calculation.StatusEnum.SUCCESS) {
          UtilityApi utilityApiInstance = new UtilityApi(apiClient);
          ApiResponse<String> resultResponse = utilityApiInstance
              .getByUrlWithHttpInfo(calculationParameters.getValue().getResult());
          System.out.println("CalculationId : " + calculationParameters.getKey() + " Succeeded!!!");
          System.out.println("CalculationId : " + calculationParameters.getKey() + " Result");

          Builder builder = Package.newBuilder();
          try {
            JsonFormat.parser().ignoringUnknownFields().merge(resultResponse.getData(), builder);
          } catch (InvalidProtocolBufferException e) {
            System.out.println("Error while deserializing the response");
            e.printStackTrace();
          }

          Package result = (Package) builder.build();
          // To convert result to 2D tables.
          List<TableData> tables = StachExtensions.convertToTableFormat(result);
          System.out.println(tables.get(0)); // Prints the result in 2D table format.
          // Uncomment the following line to generate an Excel file
          // StachExtensions.generateExcel(result);
        }
      }
    } catch (ApiException e) {
      handleException("SPAREngineExample#Main", e);
      return;
    }
  }

  private static ApiClient getApiClient() throws ApiException {
    if (apiClient != null) {
      return apiClient;
    }

    apiClient = new ApiClient();
    apiClient.setConnectTimeout(30000);
    apiClient.setReadTimeout(30000);
    apiClient.setBasePath(BASE_PATH);
    apiClient.setUsername(USERNAME);
    apiClient.setPassword(PASSWORD);

    return apiClient;
  }

  private static void handleException(String method, ApiException e) {
    System.err.println("Exception when calling " + method);
    if (e.getResponseHeaders() != null && e.getResponseHeaders().containsKey("x-datadirect-request-key")) {
      System.out.println("x-datadirect-request-key: " + e.getResponseHeaders().get("x-datadirect-request-key").get(0));
    }
    System.out.println("Status code: " + e.getCode());
    System.out.println("Reason: " + e.getResponseBody());
    e.printStackTrace();
  }
}

 

import time
import json

from google.protobuf import json_format
from google.protobuf.json_format import MessageToJson
from google.protobuf.json_format import MessageToDict
from fds.protobuf.stach.Package_pb2 import Package

from fds.analyticsapi.engines.v2.configuration import Configuration;
from fds.analyticsapi.engines.v2.api_client import ApiClient;
from fds.analyticsapi.engines.v2.api.components_api import ComponentsApi
from fds.analyticsapi.engines.v2.api.calculations_api import CalculationsApi
from fds.analyticsapi.engines.v2.api.utility_api import UtilityApi
from fds.analyticsapi.engines.v2.models.calculation_parameters import CalculationParameters
from fds.analyticsapi.engines.v2.models.spar_calculation_parameters import SPARCalculationParameters
from fds.analyticsapi.engines.v2.models.spar_identifier import SPARIdentifier
from fds.analyticsapi.engines.v2.models.spar_date_parameters import SPARDateParameters

from stach_extensions import StachExtensions

host = "https://api.factset.com"
username = "<username-serial>"
password = "<apiKey>"

spar_document_name = "pmw_root:/spar_documents/Factset Default Document";
spar_benchmark_r_1000 = "R.1000";
spar_benchmark_russell_pr_2000 = "RUSSELL_P:R.2000";
spar_benchmark_russell_prefix = "RUSSELL"
spar_benchmark_russell_return_type = "GTR"
startdate = "20180101"
enddate = "20181231"
frequency = "Monthly"

config = Configuration()
config.host = host
config.username = username
config.password = password
# add proxy and/or disable ssl verification according to your development environment
# config.proxy = "<proxyUrl>"
# config.verify_ssl = False

api_client = ApiClient(config)

components_api = ComponentsApi(api_client);

components = components_api.get_spar_components_with_http_info(spar_document_name)
component_id = list(components[0].keys())[0]

spar_account_identifier = SPARIdentifier(spar_benchmark_r_1000, spar_benchmark_russell_return_type, spar_benchmark_russell_prefix)
spar_accounts =[spar_account_identifier]
spar_benchmark_identifier = SPARIdentifier(spar_benchmark_russell_pr_2000, spar_benchmark_russell_return_type, spar_benchmark_russell_prefix);
spar_dates = SPARDateParameters(startdate, enddate, frequency)

spar_calculation_parameters = {"1": SPARCalculationParameters(component_id, spar_accounts, spar_benchmark_identifier, spar_dates)}
calculations = CalculationParameters(spar=spar_calculation_parameters)
print(calculations)

calculations_api = CalculationsApi(api_client)
run_calculation_response = calculations_api.run_calculation_with_http_info(calculations=calculations)

if(run_calculation_response[1] != 202):
    print(batch_api_post_result[2].get("x-datadirect-request-key"))
    quit()

calculation_id = run_calculation_response[2].get("location").split("/")[-1]
print("Calculation Id: " + calculation_id)

calculation_status = calculations_api.get_calculation_by_id_with_http_info(calculation_id)
while (calculation_status[1] == 200 and (calculation_status[0].status == "Queued" or calculation_status[0].status == "Executing")):
    age_value = calculation_status[2].get("cache-control")
    if(age_value != None):
        max_age = age_value.replace("max-age=", "")
        print('Sleeping: ' + max_age)
        time.sleep(int(max_age))
    calculation_status = calculations_api.get_calculation_by_id_with_http_info(calculation_id)

if(calculation_status[1] != 200):
    print(calculation_status[2].get("x-datadirect-request-key"))
    quit()

print("Calculation Completed!!!");

for calculation_key, calculation_item in calculation_status[0].spar.items():
    if calculation_item.status == "Failed":
        print("Spar Calculation : " + calculation_key + " Failed!!!")
        print("Error Message : " + calculation_item.error)
    elif calculation_item.status == "Success":
        utility_api = UtilityApi(api_client)
        calculation_result = utility_api.get_by_url_with_http_info(calculation_item.result)

        if(calculation_result[1] != 200):
            print(calculation_result[2].get('x-datadirect-request-key'))
            quit()

        # converting the data to Package object
        result =  json_format.Parse(json.dumps(calculation_result[0]), Package())
        # print(MessageToJson(result)) # To print the result object as a JSON
        # print(MessageToDict(result)) # To print the result object as a Dictionary
        tables = StachExtensions.convert_to_table_format(result) # To convert result to 2D tables.
        print(tables[0]) # Prints the result in 2D table format.
        # StachExtensions.generate_excel(result) # To get the result in table format exported to excel file.

 

Converting API output to Table format
using System;
using System.Collections.Generic;
using System.Linq;
using FactSet.Protobuf.Stach;
using FactSet.Protobuf.Stach.Table;

namespace FactSet.AnalyticsAPI.Engines.v2.Example.Examples
{
    public static class StachExtensions
    {
        public static void GenerateCSV(this Package package)
        {
            foreach (var table in package.ConvertToTableFormat())
            {
                System.IO.File.WriteAllText($"{Guid.NewGuid():N}.csv", table.ToString());
            }
        }

        public static List<Table> ConvertToTableFormat(this Package package)
        {
            var tables = new List<Table>();
            foreach (var primaryTableId in package.PrimaryTableIds)
            {
                tables.Add(GenerateTable(package, primaryTableId));
            }

            return tables;
        }

        private static Table GenerateTable(Package package, string primaryTableId)
        {
            var primaryTable = package.Tables[primaryTableId];
            var headerId = primaryTable.Definition.HeaderTableId;
            var headerTable = package.Tables[headerId];
            var columnIds = primaryTable.Definition.Columns.Select(c => c.Id).ToList();
            var headerColumnIds = headerTable.Definition.Columns.Select(c => c.Id).ToList();
            var dimensionColumnsCount = primaryTable.Definition.Columns.Count(c => c.IsDimension);
            var rowCount = primaryTable.Data.Rows.Count;
            var headerRowCount = headerTable.Data.Rows.Count;

            var table = new Table
            {
                Rows = new List<Row>()
            };
            // Constructs the column headers by considering dimension columns and header rows
            foreach (var columnId in headerColumnIds)
            {
                var headerRow = new Row { Cells = new List<string>() };
                for (int j = 0; j < dimensionColumnsCount; j++)
                {
                    headerRow.Cells.Add("");
                }

                for (int i = 0; i < headerRowCount; i++)
                {
                    headerRow.Cells.Add(Convert.ToString(headerTable.Data.Columns[columnId]
                        .GetValueHelper(headerTable.Definition.Columns.First(c => c.Id == columnId).Type, i)));
                }
                table.Rows.Add(headerRow);
            }
            // Constructs the column data
            for (int i = 0; i < rowCount; i++)
            {
                var dataRow = new Row { Cells = new List<string>() };
                foreach (var columnId in columnIds)
                {
                    dataRow.Cells.Add(Convert.ToString(primaryTable.Data.Columns[columnId]
                        .GetValueHelper(primaryTable.Definition.Columns.First(c => c.Id == columnId).Type, i)));
                }
                table.Rows.Add(dataRow);
            }

            return table;
        }
    }

    public static class SeriesDataHelper
    {
        public static object GetValueHelper(this SeriesData seriesData, DataType dataType, int index)
        {
            switch (dataType)
            {
                case DataType.Bool:
                    {
                        return seriesData.BoolArray?.Values?[index];
                    }
                case DataType.Double:
                    {
                        return seriesData.DoubleArray?.Values?[index];
                    }
                case DataType.Duration:
                    {
                        var v = seriesData.DurationArray?.Values?[index];
                        return v?.ToTimeSpan();
                    }
                case DataType.Float:
                    {
                        return seriesData.FloatArray?.Values?[index];
                    }
                case DataType.Int32:
                    {
                        return seriesData.Int32Array?.Values?[index];
                    }
                case DataType.Int64:
                    {
                        return seriesData.Int64Array?.Values?[index];
                    }
                case DataType.String:
                    {
                        return seriesData.StringArray?.Values?[index];
                    }
                case DataType.Timestamp:
                    {
                        var v = seriesData.TimestampArray?.Values?[index];
                        return v?.ToDateTime();
                    }
                default:
                    throw new NotImplementedException($"{dataType} is not implemented");
            }
        }
    }

    public class Table
    {
        public List<Row> Rows { get; set; }

        public override string ToString()
        {
            return string.Join(Environment.NewLine, Rows);
        }
    }

    public class Row
    {
        public List<string> Cells { get; set; }

        public override string ToString()
        {
            return string.Join(",", Cells.Select(c => c.Replace(",", "")));
        }
    }
}

 

import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.poi.ss.formula.eval.NotImplementedException;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.factset.protobuf.stach.NullValues;
import com.factset.protobuf.stach.PackageProto.Package;
import com.factset.protobuf.stach.table.DataTypeProto.DataType;
import com.factset.protobuf.stach.table.SeriesDataProto.SeriesData;
import com.factset.protobuf.stach.table.SeriesDefinitionProto.SeriesDefinition;
import com.factset.protobuf.stach.table.TableProto.Table;

import com.google.protobuf.Duration;
import com.google.protobuf.Timestamp;

public class StachExtensions {
  // The purpose of this class is to provide the helper methods for converting
  // stach to Tabular format.

  public static void generateExcel(Package packageObj) {
    for (TableData table : convertToTableFormat(packageObj)) {
      writeDataToExcel(table, UUID.randomUUID().toString() + ".xlsx");
    }
  }

  public static List<TableData> convertToTableFormat(Package packageObj) {
    List<TableData> tables = new ArrayList<TableData>();
    for (String primaryTableId : packageObj.getPrimaryTableIdsList()) {
      tables.add(generateTable(packageObj, primaryTableId));
    }
    return tables;
  }

  private static TableData generateTable(Package packageObj, String primaryTableId) {
    Map<String, Table> tablesMap = packageObj.getTablesMap();
    Table primaryTable = tablesMap.get(primaryTableId);
    String headerId = primaryTable.getDefinition().getHeaderTableId();
    Table headerTable = tablesMap.get(headerId);
    int headerRowCount = headerTable.getData().getRowsCount();
    int rowsCount = primaryTable.getData().getRowsCount();

    TableData table = new TableData();

    // Construct the column headers by considering dimension columns and header
    // rows.
    List<SeriesDefinition> headerTableSeriesDefinitions = headerTable.getDefinition().getColumnsList();
    List<SeriesDefinition> primaryTableSeriesDefinitions = primaryTable.getDefinition().getColumnsList();

    Map<String, SeriesData> headerTableColumns = headerTable.getData().getColumnsMap();
    Map<String, SeriesData> primaryTableColumns = primaryTable.getData().getColumnsMap();

    for (SeriesDefinition headerTableseriesDefinition : headerTableSeriesDefinitions) {
      Row headerRow = new Row();
      for (SeriesDefinition primaryTableSeriesDefinition : primaryTableSeriesDefinitions) {
        if (primaryTableSeriesDefinition.getIsDimension()) {
          headerRow.Cells.add(primaryTableSeriesDefinition.getDescription());
        }
      }

      String headerColumnId = headerTableseriesDefinition.getId();
      String nullFormat = headerTableseriesDefinition.getFormat().getNullFormat();
      for (int i = 0; i < headerRowCount; i++) {
        headerRow.Cells.add(SeriesDataHelper.getValueHelper(headerTableColumns.get(headerColumnId),
            headerTableseriesDefinition.getType(), i, nullFormat).toString());
      }
      table.Rows.add(headerRow);
    }

    // Construct the column data
    for (int i = 0; i < rowsCount; i++) {
      Row dataRow = new Row();
      for (SeriesDefinition primaryTableSeriesDefinition : primaryTableSeriesDefinitions) {
        String nullFormat = primaryTableSeriesDefinition.getFormat().getNullFormat();
        String primaryTableColumnId = primaryTableSeriesDefinition.getId();
        dataRow.Cells.add(SeriesDataHelper.getValueHelper(primaryTableColumns.get(primaryTableColumnId),
            primaryTableSeriesDefinition.getType(), i, nullFormat).toString());
      }
      table.Rows.add(dataRow);
    }
    return table;
  }

  private static void writeDataToExcel(TableData table, String fileLocation) {
    XSSFWorkbook workbook = new XSSFWorkbook();
    XSSFSheet sheet = workbook.createSheet("PA Report");

    int rowsSize = table.Rows.size();
    for (int rowIndex = 0; rowIndex < rowsSize; rowIndex++) {
      XSSFRow xsswRow = sheet.createRow(rowIndex);
      List<String> cells = table.Rows.get(rowIndex).Cells;
      for (int cellIndex = 0; cellIndex < cells.size(); cellIndex++) {
        XSSFCell xssfCell = xsswRow.createCell(cellIndex);
        xssfCell.setCellValue(cells.get(cellIndex));
      }
    }

    try {
      FileOutputStream out = new FileOutputStream(new File(fileLocation));
      workbook.write(out);
      out.close();
      workbook.close();
    } catch (Exception e) {
      System.err.println("Failed to write data to excel");
      e.printStackTrace();
    }
  }
}

class SeriesDataHelper {
  public static Object getValueHelper(SeriesData seriesData, DataType dataType, int index, String nullFormat) {
    if (dataType == DataType.STRING) {
      String value = seriesData.getStringArray().getValues(index);
      return NullValues.STRING.equals(value) ? nullFormat : value;
    } else if (dataType == DataType.DOUBLE) {
      double value = seriesData.getDoubleArray().getValues(index);
      return Double.isNaN(value) ? nullFormat : value;
    } else if (dataType == DataType.BOOL) {
      return seriesData.getBoolArray().getValues(index);
    } else if (dataType == DataType.DURATION) {
      Duration value = seriesData.getDurationArray().getValues(index);
      return NullValues.DURATION.equals(value) ? nullFormat : value;
    } else if (dataType == DataType.FLOAT) {
      float value = seriesData.getFloatArray().getValues(index);
      return Float.isNaN(value) ? nullFormat : value;
    } else if (dataType == DataType.INT32) {
      int value = seriesData.getInt32Array().getValues(index);
      return NullValues.INT32 == value ? nullFormat : value;
    } else if (dataType == DataType.INT64) {
      long value = seriesData.getInt64Array().getValues(index);
      return NullValues.INT64 == value ? nullFormat : value;
    } else if (dataType == DataType.TIMESTAMP) {
      Timestamp value = seriesData.getTimestampArray().getValues(index);
      return NullValues.TIMESTAMP.equals(value) ? nullFormat : value;
    } else {
      throw new NotImplementedException(dataType + " is not implemented");
    }
  }
}

class TableData {
  List<Row> Rows = new ArrayList<Row>();

  public String toString() {
    return Rows.toString();
  }
}

class Row {
  List<String> Cells = new ArrayList<String>();

  public String toString() {
    return Cells.toString();
  }
}

 

import uuid
import math

import pandas as pd

from fds.protobuf.stach.Package_pb2 import Package
from fds.protobuf.stach.NullValues import NullValues
from fds.protobuf.stach.table.DataType_pb2 import DataType

class StachExtensions:
    """The purpose of this class is to provide the helper methods for converting Stach to Tabular format"""

    @staticmethod
    def generate_excel(package):
        for table in StachExtensions.convert_to_table_format(package):
            writer = pd.ExcelWriter(str(uuid.uuid1()) + ".xlsx")
            table.to_excel(excel_writer=writer)
            writer.save()
            writer.close()

    @staticmethod
    def convert_to_table_format(package):
        tables = list()
        for primary_table_id in package.primary_table_ids:
            tables.append(StachExtensions.generate_table(package, primary_table_id))
        return tables

    @staticmethod
    def generate_table(package_response, primary_table_id):

        if isinstance(package_response, Package):
            primary_table = package_response.tables[primary_table_id]
            header_id = primary_table.definition.header_table_id
            header_table = package_response.tables[header_id]
            dimension_columns = list(filter(lambda column_obj: column_obj.is_dimension, primary_table.definition.columns))
            dimension_columns_count = len(dimension_columns)
            row_count = len(primary_table.data.rows)
            header_row_count = len(header_table.data.rows)

            headers = list(list())
            # Constructs the column headers by considering dimension columns and header rows
            for series_definition_column in header_table.definition.columns:
                header_row = list()
                for i in range(0, dimension_columns_count, 1):
                    header_row.append(dimension_columns[i].description)

                for i in range(0, header_row_count, 1):
                    header_row.append(str(SeriesDataHelper.get_value_helper(header_table.data.columns[series_definition_column.id], series_definition_column.type, i, series_definition_column.format.null_format)))
                headers.append(header_row)

            data = list(list())
            # Constructs the column data
            for i in range(0, row_count, 1):
                data_row = list()
                for series_definition_column in primary_table.definition.columns:
                    data_row.append(str(SeriesDataHelper.get_value_helper(primary_table.data.columns[series_definition_column.id], series_definition_column.type, i, series_definition_column.format.null_format)))
                data.append(data_row)

            data_frame = pd.DataFrame(data=data)
            data_frame.columns = pd.MultiIndex.from_arrays(headers)
            return data_frame

        else:
            ValueError("Response data passed should be of package type.")


class SeriesDataHelper:

    @staticmethod
    def get_value_helper(series_data, datatype, index, null_format):
        if DataType.Name(datatype) == "STRING":
            return SeriesDataHelper.null_value_handler(datatype, series_data.string_array.values[index], null_format)
        elif DataType.Name(datatype) == "DOUBLE":
            return SeriesDataHelper.null_value_handler(datatype, series_data.double_array.values[index], null_format)
        elif DataType.Name(datatype) == "FLOAT":
            return SeriesDataHelper.null_value_handler(datatype, series_data.float_array.values[index], null_format)
        elif DataType.Name(datatype) == "INT32":
            return SeriesDataHelper.null_value_handler(datatype, series_data.int32_array.values[index], null_format)
        elif DataType.Name(datatype) == "INT64":
            return SeriesDataHelper.null_value_handler(datatype, series_data.int64_array.values[index], null_format)
        elif DataType.Name(datatype) == "BOOL":
            return SeriesDataHelper.null_value_handler(datatype, series_data.bool_array.values[index], null_format)
        elif DataType.Name(datatype) == "DURATION":
            return SeriesDataHelper.null_value_handler(datatype, series_data.duration_array.values[index], null_format)
        elif DataType.Name(datatype) == "TIMESTAMP":
            return SeriesDataHelper.null_value_handler(datatype, series_data.timestamp_array.values[index], null_format)
        else:
            ValueError("The datatype is not implemented")

    @staticmethod
    def null_value_handler(datatype, value, null_format):
        if DataType.Name(datatype) == "STRING":
            if NullValues.STRING == value:
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "DOUBLE":
            if math.isnan(value):
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "FLOAT":
            if math.isnan(value):
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "INT32":
            if NullValues.INT32 == value:
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "INT64":
            if NullValues.INT64 == value:
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "DURATION":
            if NullValues.DURATION.equals(value):
                return null_format
            else:
                return value
        elif DataType.Name(datatype) == "TIMESTAMP":
            if NullValues.TIMESTAMP.equals(value):
                return null_format
            else:
                return value
        else:
            return value

 

Change Logs

v2
Summary
  • v2.0.0 - Released on 08/15/19
Functionality Additions
  • Initial release [v2.0.0]
Changes
  • No changes
Bug Fixes
  • No changes
v1 (Retired)
Summary
  • v1.1.0 - Released on 07/25/19
  • v1.0.0 - Released on 06/13/19
Functionality Additions
  • Added format parameter to Get Result Endpoint to switch between different output formats [v1.1.0]
  • Added ability to create, fetch, and delete multiple SPAR Engine calculations [v1.0.0]
  • Initial release [v1.0.0]
Changes
  • No changes
Bug Fixes
  • No bug fixes