DSWS SOAP Tutorial

The purpose of this Tutorial is to explain the code used in the Quick Start, and demonstrate an example of one of the DSWS API delivery methods and in result help you discover how to use it.

DSWS provides a SOAP based web service, built using the Windows Communication Foundation (WCF) framework, to access Datastream content. The metadata is published through Web Service Definition Language (WSDL). This document describes the SOAP objects used in the product along with some sample requests.

You can use any platform that can access SOAP based web services for integration. You can also refer to our test page to see the SOAP request and response messages for various operations.

Table of contents

  • Basic Process Steps
  • Formatting Requests
  • Submitting Requests
  • Processing Responses

Basic Process Steps

The basic steps for retrieving data are:

  • Create a DSServiceClient instance.
    Importing the SOAP metadata from the WSDL reference will create a DSServiceClient class in the references.cs file. This class supports the methods for requesting a secure token and subsequent data requests.

  • Request a secure token.
    All data requests must be accompanied by a secure token identifying you as the client. You obtain a secure token by calling the GetToken method supplying your Datastream credentials. In addition, your Datastream account must be authorised for access to the API service.
    The returned token is valid for 24 hours and should be used for all subsequent requests with a new token being requested shortly before expiry of the current token.

  • Sending requests and processing the response.
    The API supports just two data methods: GetData and GetDataBundle. Both methods need a valid secure token supplied with each request.
    Both methods also use a common DSDataRequest object to request one or more sets of data from the system. Both methods return one or more DSDataResponse objects containing the result of each query.
    GetData is used to make a single request from the system using one DSDataRequest object. This single request can retrieve data for multiple instruments with a common set of datatypes and a common reporting period. This method returns one DSDataResponse object containing the data for all requested instruments.
    GetDataBundle is used to retrieve multiple datasets in one request using an array of DSDataRequest objects. Each DSDataRequest object is independent of any other DSDataRequest within the bundle. GetDataBundle returns a collection of DSDataResponse objects. While slightly more complex to construct and decode, GetDataBundle is more efficient than GetData because the API servers will perform parallel processing of bundled requests.

The DSServiceClient Object

The DSServiceClient class is the custom WCF client object used to connect to the Datastream ClientAPI service. It extends the .NET System.ServiceModel.ClientBase class and is generated from the WSDL file.

The class supports the GetToken, GetData and GetDataBundle methods for authentication and retrieving data. These methods are described in more detail below. In addition, the class supports a Ping method for basic connectivity checks.

The instantiated DSServiceClient object should be used for all subsequent token and data requests.

    	
            

<!-- App.config entry -->

<system.serviceModel>

  <bindings>

    <basicHttpBinding>

      <binding name="BasicHttpBinding_IDSService"

              maxBufferSize="60000000" maxReceivedMessageSize="60000000"

              receiveTimeout="00:11:00" sendTimeout="00:11:00">

        <security mode="Transport"></security>

      </binding>

    </basicHttpBinding>

  </bindings>

  <client>

    <endpoint address="https://product.datastream.com/DswsClient/V1/DSService.svc"

        binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IDSService"

        contract="DSWSReference.IDSService" name="BasicHttpBinding_IDSService" />

  </client>

</system.serviceModel>

 

// C# code

using (var dsClient = new DSServiceClient())

{

    //let's try a simple ping test

    bool gotPing = false;

    try

    {

        var pingResp = dsClient.Ping(null);

        gotPing = true; // success

    }

    catch (Exception e)

    {

        // process the error

    }

}

This class also provides constructors to supply the endpoint and binding details programmatically.

For any connectivity issues, the Ping method can be used to test the round trip connectivity to the ClientAPI servers. The Ping method simply replies immediately with null. The Ping method can also be easily tested using Powershell or Curl using the Rest\JSON interface.

    	
            

// Powershell should return a HTTP 200 status code or will display an error message

$T = Invoke-WebRequest -URI "https://product.datastream.com/dswsclient/V1/DSService.svc/rest/Ping"

$T.StatusCode

 

// Curl for Windows

curl https://product.datastream.com/dswsclient/V1/DSService.svc/rest/Ping

Token Retrieval

All data requests must be accompanied by a secure token identifying you as the client. You obtain a secure token by calling the GetToken method supplying your Datastream credentials. In addition, your Datastream account must be authorised for access to the API service.

    	
            

// Create a token request

var tokenRequest = new DSGetTokenRequest()

{

    UserName = "xxxxx", //add your Datastream ID and password here

    Password = "yyyyyy",

};

 

using (var dsClient = new DSServiceClient())

{

    string tokenValue = null;

    DateTime tokenExpiry = default(DateTime);

    // Issue a call to get the token

    try

    {

        var tokenResponse = dsClient.GetToken(tokenRequest);

 

        // Read the token from the response

        tokenValue = tokenResponse.TokenValue;

        tokenExpiry = tokenResponse.TokenExpiry;

    }

    catch (System.ServiceModel.FaultException<DSFault> tokenFault)

    {

        // Process the credentials error

        Console.WriteLine("Error retrieving token for user {0}. Code {1}, Message {2}.", 

                 tokenRequest.UserName, tokenFault.Code.Name, tokenFault.Message);

    }

    catch (Exception e)

    {

        // Process the network or endpoint error

        Console.WriteLine("Error retrieving token HRES 0x{1:X}, Message {2}.", 

                            e.HResult, e.Message);

    }

}

The GetToken method accepts an instance of a DSGetTokenRequest object as a parameter. This object has two fields of type string, UserName and Password, which accept your Datastream credentials. The object also contains a Properties field that accepts a collection of string-object pairs. This field is reserved for possible future enhancements and provides no current functionality.

For valid credentials, GetToken returns a DSGetTokenResponse object. This contains a TokenValue field of type string containing the secure token, and a TokenExpiry field of type DateTime specifying the timestamp (in UTC) when the token will expire. This token can be used for all subsequent data requests up until the time of expiry, when a new token will be required. In practice, the token is valid for 24 hours, and you should request the new token prior to the expiry of the old token.

DSGetTokenResponse also contains a Properties field that returns a collection of string-object pairs. This field is reserved for possible future enhancements and currently returns a null reference.

For invalid requests, GetToken returns a DSFault object specifying the error. This contains Code and Message fields of type string. For invalid input, the Code field will contain the value “InvalidArgument” and the Message field will specify the invalid input such as “UserName must have a value. (UserName)”. For invalid credentials, the Code field will contain the value “InvalidCredentials” and the Message field will contain an error message such as “Invalid credentials were supplied. ACF01012 PASSWORD NOT MATCHED” or “Invalid credentials were supplied. ACF01013 LOGONID xxxxxxx SUSPENDED BECAUSE OF PASSWORD VIOLATIONS”.

In addition to valid credentials, user accounts must be authorised for access to the API service. If your account has not been granted access, GetToken will return an “InvalidCredentials” error with the Message field containing an error message of the form “User 'xxxxxxx' not entitled to ClientApi service”. If you encounter this error, please contact your Datastream representative for authorisation.

Finally, for general network or endpoint errors, where a connection to our servers is not possible, a generic Exception error will occur. You also need to handle this type of error.

Formatting Requests

With a valid secure token, data can be retrieved using the GetData and GetDataBundle methods. Both methods require one or more DSDataRequest objects to define the set of data to be returned.

The DSDataRequest Object

A DSDataRequest object allows you to specify one or more instruments to be requested, a list of datatypes to return for each of these instruments, date information specifying the period to retrieve data for, and a user defined tag that is returned with the response.

A simple C# example of creating a DSDataRequest:

    	
            

// Create a data request

var req1 = new DSDataRequest()

{

    Instrument = new DSInstrument() { Value = "<VOD.L>" },

    DataTypes = new[] { new DSDataType() { Value = "PH" } },

    Date = new DSDate() { Kind = DSDateKind.Snapshot, Start = "-10D" },

    Tag = "SomeClientDefinedReference"

};

DSInstrument

The DSInstrument member of a DSDataRequest object is used to specify one or more instruments. It consists of a Value field of type string used to specify the required instruments, and an optional Properties field containing an array of string-object pairs used to further specify the content of the Value field.

C# examples creating DSInstrument objects with various request settings:

    	
            

// Create a data request specifying multiple instruments

var req1 = new DSDataRequest()

{

    Instrument = new DSInstrument()

    {

        Value = "<BLND.L>,GB0031348658,<VOD.L>",

        Properties = new DSStringObjectKVPair[] 

        { 

            new DSStringObjectKVPair() { Key = "ReturnName", Value = true }

        }

    },

    Date = new DSDate() { Kind = DSDateKind.TimeSeries, Start = "-7D" },

    // other members follow

};

 

// Create a data request containing expressions

var req2 = new DSDataRequest()

{

    Instrument = new DSInstrument()

    {

        Value = "PCH#(<VOD.L>(PH),1Y)",

        Properties = new DSStringObjectKVPair[] 

        { 

            new DSStringObjectKVPair() { Key = "IsExpression", Value = true }

        }

    },

    DataTypes = null,  // Expressions don’t use DSDataTypes

    // other members follow

};

 

// Create a data request requesting data for a constituent list

var req3 = new DSDataRequest()

{

    Instrument = new DSInstrument()

    {

        Value = "LFTSE100",

        Properties = new DSStringObjectKVPair[] 

        { 

            new DSStringObjectKVPair() { Key = "IsList", Value = true }

        }

    },

    DataTypes = new[] 

    { 

        new DSDataType() { Value = "NAME" },

        new DSDataType() { Value = "ISIN" },

        new DSDataType() { Value = "SECD" }

    },

    // other members follow

};

The Value field of DSInstrument accepts a comma separated list of instruments. Instruments can be defined in the following formats (where applicable) with Equities examples given for Vodafone, Microsoft, Daimler and Toyota:

  • Datastream Mnemonic (MNEM): This is a unique identification code assigned by Datastream. For all markets except the UK and Ireland, the first 1 or 2 characters plus a colon are a country identification prefix:
    e.g. VOD, @MSFT, D:DAI, J:TYMO

  • Datastream Code (DSCD): This is the unique six-character identification code allocated by Datastream for every instrument. This code can be used instead of a series mnemonic:
    e.g. 953133, 719643, 688700, 905289

  • ISIN (ISIN): The International Security Identification Number is a code that uniquely identifies a security:
    e.g. GB00BH4HKS39, US5949181045, DE0007100000, JP3633400001

  • Sedol (SECD): This is an identification code based on the code issued by the London Stock Exchange. Note UK and Ireland stocks need to be prefixed by “UK”:
    e.g. UKBH4HKS3, 2588173, 5529027, 6900643

  • RIC (RIC): The Reuters Instrument Code. Note: RICs must be decorated by RIC\T1C delimiters:
     e.g. <VOD.L>, < MSFT.O>, < DAIGn.F>, < 7203.T>

  • Thomson Ticker (T1C): The Thomson One Ticker: Note: T1Cs must be decorated by RIC\T1C delimiters:
    e.g. <VOD-LN>, < MSFT-US>, < DAI-FF>, < 7203-TO>

  • Local Code (LOC): This is an identification code based on the official local exchange code. It comprises up to 12 characters, prefixed by an alphabetic country code.
    e.g. UK:VOD, U59491810, D710000, J7203

In addition to Equities, Datastream also supports other financial data, such as Economics (e.g. UKGDP...D), Investment trusts (e.g. SMT), Corporate Bonds (e.g. 8393A1), Interest rates (e.g. TRUS10T), Exchange Rates (e.g. UKDOLLR), etc. The full range of instruments can be searched using our Datastream For Office (DFO), Eikon or ThomsonOne products. Alternatively, you can search for items directly in a browser using your Datastream credentials.

Datastream also supports Constituent Lists of instruments, e.g. LFTSE100, LS&PCOMP, LDAXINDX, LSTOKYOSE, etc. List instruments are only supported in Snapshot mode, and only one list is permitted per request. The datatypes supplied with the list request are applied to all the constituents of the list, and the response for each item returned in the DSDataResponse object.  Again, these lists can be searched for using DFO, EIKON, etc.

To retrieve TimeSeries data for the constituents of a list, it is necessary to make a Snapshot request for the ID of each of the constituents (e.g. MNEM, ISIN, etc as defined above), and to then make TimeSeries requests for the individual constituents using GetData or GetDataBundle.

Finally, Datastream also supports pre-defined functions that can be incorporated in formulas (known as Expressions) of the form Function#(Expression, Parameters), where:

  • Function# is a function code, for example, MAV#  (Moving Average).
  • Expression can be a series mnemonic, a combination of series using mathematical operators, a nested function, a built-in Datastream expression available to all users, or a stored custom expression created by a user via the Expression Builder window in DFO.
  • Parameters vary according to function, but generally relate to time e.g. Start date.

Example expressions are:

  • Simple mathematical functions such as LOG#(FTALLSH), LN#(FTALLSH)
  • Growth functions such as Percentage changes: PCH#(MKS, -1Y)
  • Rebasing functions such as rebasing a data series to 100 from a specified date or relative to the latest value:
  • e.g. REB#(VOD(P), 31/12/17) or REB#(VOD(P), TIME)
  • Complex nested functions such as a Historical Beta calculation
  • e.g. REGB#(LN#(U:HOG(LI)/LAG#(U:HOG(LI),1M)),LN#(U:HOG/LAG#(U:HOG,1M)),60M)
  • Built-in predefined Datastream expressions such as 897E which performs the same Historical Beta function given previously e.g. 897E(U:HOG)

The full range of functions can be searched using our Datastream For Office (DFO) or Eikon products. Alternatively, you can examine the functions directly in a browser. The available predefined Datastream functions can be reviewed using the Expressions Tool in DFO.

The DSInstrument member of a DSDataRequest object also contains a Properties field. This is a collection of string-object pairs. The primary purpose of this field is to provide hints to the servers as to how to process the contents of the Value field. Expressions and constituent lists require slightly different processing on the servers, so supplying a hint to identify these items, if you know they are lists or expressions, speeds up processing.

In addition, the Properties field can also be used to request the descriptive names of the requested instruments when requesting TimeSeries data.

The Properties field currently supports the following settings (see the C# examples section above for instances of their use):

  • IsExpression: When set to True, indicates to the server that the instrument field contains one or more expressions such as LOG#(VOD), VOD + BARC, etc. When this flag is set, the server performs different processing of the instrument field. Expressions can be very complex; setting this flag acts as an instruction to the server to pass the full instrument through to the mainframe without detailed pre-processing.
  • IsList: List instruments are only supported in Snapshot mode, and only one list is permitted per request. If you know the instrument is a constituent list, please set this flag to simplify post-processing of the response.
  • IsSymbolSet (Deprecated): In earlier versions of DSWS, users had to set this flag True if the Value field contained more than one instrument, especially if the Value field contained multiple complex expressions each with nested sub-expressions. If set, DSWS performed analysis of the Value field, searching for nested expressions. DSWS now performs this check as standard, and this field is now deprecated.
  • ReturnName: For Snapshot requests, the NAME datatype can be requested to return the display name for any requested instrument (e.g. for VOD, the NAME datatype will return “VODAFONE GROUP”).
  • For TimeSeries requests, however, simply requesting the NAME datatype will always return an error (“$$ER: E100,INVALID CODE OR EXPRESSION ENTERED”) as static datatypes are not supported in TimeSeries requests. For TimeSeries requests only, setting the ReturnName flag to True in the Properties field will return a collection of key-value pairs (e.g. “VOD” : ”VODAFONE GROUP“) in the SymbolNames member of the DSDataResponse object (see DSDataResponse section later for an example).

ReturnCurrency and ReturnDates (Deprecated): These flags originally supported a prototype dataset that was never released into production and are now deprecated.

DSDataTypes

The DSDataTypes member of a DSDataRequest object is used to specify a collection of one or more DSDataType objects specifying the datatypes to be returned for each of the specified instruments. The DSDataType object consists of a Value field of type string used to specify the required datatype, and an optional Properties field containing an array of string-object pairs used to further specify the content of the Value field.

C# examples creating a DSDataType objects with various request settings:

    	
            

// Creating a data request specifying no datatypes returns just the default

// datatype (X) for each requested item

var req1 = new DSDataRequest()

{

    Instrument = new DSInstrument() { Value = "U:HOG,VOD" },

    DataTypes = null,  // Default datatype X assumed

    // other members follow

};

 

// You can specify the default datatype explicitly

var req2 = new DSDataRequest()

{

    Instrument = new DSInstrument() { Value = "U:HOG,VOD" },

    DataTypes = new[] { new DSDataType() { Value = "X" } },

    // other members follow

};

 

// You can request multiple datatypes including built-in Datastream

// expressions such as 897E (Historical Beta)

var req3 = new DSDataRequest()

{

    Instrument = new DSInstrument() { Value = "U:HOG,VOD" },

    DataTypes = new[] 

    { 

        new DSDataType() { Value = "NAME" },

        new DSDataType() { Value = "ISIN" },

        new DSDataType() { Value = "897E" }

    },

    // other members follow

};

 

// You can simplify the use of expressions using the DSDataType and

// the “symbol substitution” feature where each requested instrument is 

// substituted for X in any expression

// e.g. LN#(X(RI)) and VOD will be substituted as LN#(VOD(RI))

var req4 = new DSDataRequest()

{

    Instrument = new DSInstrument() { Value = "U:HOG,VOD" },

    DataTypes = new[] 

    { 

        new DSDataType() { Value = "LN#(X(RI))" },

        new DSDataType() { Value = "PCH#(X(PH), 1Y)" }

    },

    // other members follow

};

 

// You can use the Properties member of DSDataType to request

// the return of the descriptive name for each datatype

var req5 = new DSDataRequest()

{

    Instrument = new DSInstrument() { Value = "U:HOG,VOD" },

    DataTypes = new[] 

    { 

        new DSDataType()

        {

            Value = "PH",

            Properties = new DSStringObjectKVPair[] 

            { 

                new DSStringObjectKVPair() { Key = "ReturnName", Value = true }

            }

        },

        new DSDataType()

        {

            Value = "PL",

            Properties = new DSStringObjectKVPair[] 

            { 

                new DSStringObjectKVPair() { Key = "ReturnName", Value = true }

            }

        }

    },

    // other members follow

};

Currently, the Properties field only supports one option, ReturnName. When set True for a datatype, this will return a full display name for the datatype if available. The display names are returned as a collection of key-value pairs (e.g. “PH” : ”PRICE HIGH“) in the DataTypeNames member of the DSDataResponse object (see DSDataResponse section later for an example).

The Value field of DSDataType accepts a single datatype. Examples of the range of datatypes available on Datastream are (the actual datatypes to request are given in parentheses):

  • Pricing data for equities: e.g. Official Closing Price (P), closing Bid and Ask Prices (PB, PA), intraday high and lows (PH, PL), Earnings data (EPS), Dividend data (DPS), etc.
  • Worldscope data for equities: e.g. Net Debt (WC18199), Operating Income (WC01250), etc.
  • IBES earnings forecasts:  e.g. 12 Month Forward EPS data (EPS1FD12, EPS1MN), etc.
  • Economics data: e.g. Next Dates of Release (DS.NDOR1, DS.NDOR2), etc.
  • Bond data: e.g. Coupon Rate (C), Redemption Date (RD), Yield To Redemption (RY), etc.

The DSDataType can also be used to simplify requesting expressions. If you have a range of instruments you need to use in an expression, rather than constructing a unique expression for each required instrument such as (e.g. Exchange Rates):

PCH#(MAV#(UKDOLLR,1M),1M)

PCH#(MAV#(USEURSP,1M),1M)

PCH#(MAV#(CHIYUA$,1M),1M)

The expression can be simplified using the DSDataType field and the “Symbol Substitution” feature, where any single, isolated X character is replaced with the supplied instruments. For the previous instruments, we can construct a common expression in a datatype of the form PCH#(MAV#(X,1M),1M):

    	
            

var req4 = new DSDataRequest()

{

    Instrument = new DSInstrument() { Value = "UKDOLLR,USEURSP,CHIYUA$" },

    DataTypes = new[] { new DSDataType() { Value = "PCH#(MAV#(X,1M),1M)" } },

    // other members follow

};

Finally, if you don’t supply any datatype when making a standard request, a default datatype, X, is sent to the mainframe. This default datatype is interpolated by the mainframe as “return the default value for the given instrument”. The default value varies depending on the requested instrument type. For example, for equities and ETFs, the default is the official closing price (P). For exchange rates the default is the ER datatype; the midpoint between the bid and offered rates.

Note: for constituent lists, if the IsList property is supplied and set to True in the DSInstrument object, then the datatype NAME is sent as the default to the mainframe and returned as the default response field for each constituent of the list.

The full range of datatypes can be searched using our Datastream For Office (DFO), Eikon or ThomsonOne products. Alternatively, you can search for datatypes directly in a browser using your Datastream credentials.

DSDate

The DSDate member of a DSDataRequest object is used to specify the period to retrieve data from for each of the specified instruments. The DSDate object consists of a DSDateKind field specifying the request as a Snapshot or TimeSeries request, Start and Stop dates, and a Frequency string used when requesting TimeSeries data.

C# examples creating a DSDate objects with various request settings:

    	
            

// Creating a data request specifying snapshot data with relative date of -10 days

// Relative dates can be specified in days, weeks, months, quarters or years

// e.g. -5W, -12M, -3Q, -5Y

var req1 = new DSDataRequest()

{

    Instrument = new DSInstrument() { Value = "VOD"},

    Date = new DSDate() { Kind = DSDateKind.Snapshot, Start = "-10D" },

    // other members follow

};

 

// Creating a data request specifying snapshot data with an absolute date

// Absolute dates can be specified in YYYY-MM-DD or YYYYMMDD formats

var req2 = new DSDataRequest()

{

    Instrument = new DSInstrument() { Value = "VOD"},

    Date = new DSDate() { Kind = DSDateKind.Snapshot, Start = "2018-06-01" },

    // other members follow

};

 

// Creating a data request specifying snapshot data with latest date

// that has data available

var req3 = new DSDataRequest()

{

    Instrument = new DSInstrument() { Value = "VOD"},

    Date = new DSDate() { Kind = DSDateKind.Snapshot, Start = "LATESTDATE" },

    // other members follow

};

 

// Creating a timeseries request for daily data between 01 and 20 June 2018

var req4 = new DSDataRequest()

{

    Instrument = new DSInstrument() { Value = "VOD"},

    Date = new DSDate()

    {

        Kind = DSDateKind.TimeSeries,

        Start = "2018-06-01",

        End = "2018-06-20",

        Frequency = "D" 

    },

    // other members follow

};

 

// Creating a timeseries request for monthly data from the birth date of the stock

// on Datastream until the latest date

var req4 = new DSDataRequest()

{

    Instrument = new DSInstrument() { Value = "VOD"},

    Date = new DSDate()

    {

        Kind = DSDateKind.TimeSeries, 

        Start = "BDATE", 

        End = "",

        Frequency = "M"

    },

    // other members follow

};

 

// Creating a timeseries request for quarterly data (mid-quarter dates) for

// the last 12 quarters

var req4 = new DSDataRequest()

{

    Instrument = new DSInstrument() { Value = "VOD"},

    Date = new DSDate()

    {

        Kind = DSDateKind.TimeSeries, 

        Start = "-12QTM",

        End = "-1QTM",

        Frequency = "Q"

    },

    // other members follow

};

The DSDateKind member of DSDate is a simple enumerated type with value either Snapshot or TimeSeries.

The Start and End members of DSDate specify the start and end dates for data retrieval. These are string values and can accept the following input formats:

  • Absolute dates in the format “YYYY-MM-DD” or “YYYYMMDD”. e.g. “2018-06-01” or “20160601”.
  • Relative dates using day, week, month, quarter or year offsets: e.g. “-0D”, “-10D”, “-5W”, “-3M”, “-8Q”, “-50Y”, etc. The offsets are relative to the current date.
  • The Birth Date, BDATE, specifying the first date that Datastream has recorded data for the given item. E.g. for VOD this would be the equivalent of specifying “1998-10-25”.
  • The latest value date, LATESTDATE, specifying the latest date data was filed. For instruments that update daily, this is the same as specifying “-0D”. However, for instruments such as Economics or Worldscope data, where data is only filed periodically, specifying “-0D” may not return any valid data. Specifying LATESTDATE, requests data from the last filing date for the specified instrument.
  • Literal dates specifying the start of the current week, month, quarter and year:
    SWDATE: The date representing Monday in the current week.
    SMDATE: The date representing start of the current month.
    SQDATE: The date representing start of the current quarter.
    SYDATE: The date representing start of the current calendar year.
  • Relative offsets with specific starting dates specifying the start, mid and end periods of given weeks, months, quarters and years. The offsets are relative to the current date (week, month, quarter or year):
    WKS, WKM & WKE: literals representing the start, mid and end dates of specific weeks, respectively.
    e.g. “-5WKM” – The date representing Wednesday 5 weeks previous to the current week.
    MTS, MTM & MTE: literals representing the first, mid (15th) and last trading dates (weekdays) of specific months, respectively.
    e.g. “-3MTS” – The first weekday of the third month prior to the current month.
    QTS, QTM & QTE: literals representing the first, mid (15th of second month in the quarter) and last trading dates (weekdays) of specific quarters, respectively.
    e.g. “-8QTE” – The last weekday of the eighth quarter prior to the current quarter.
    YRS, YRM & YRE: literals representing the start, mid (15th June) and end dates of specific years, respectively.
    e.g. “-4YRM” – The date representing 15th June 4 years prior to the current year.

The Frequency field is only relevant for TimeSeries requests and specifies the frequency of the returned data. The Frequency field supports the following values:

  • D: Daily data. Note, only weekday data and dates are returned.
  • W: Weekly data
  • M: Monthly data
  • Q: Quarterly data
  • Y: Annual data
  • 7D: Daily data. Weekend dates are returned but the data fields contain the undefined double value NaN (Not a Number).
  • 7DPAD: Daily data. Weekend dates are returned with the price on the Friday also returned for the Saturday and Sunday.
  • 7DME: Daily data using the Middle East working week of Sunday through to Thursday. Dates are returned for Friday and Saturday but the data fields contain the undefined double value NaN (Not a Number). Any instrument that had data for the Friday will have the value returned on the Sunday.
  • 7DMEPAD: Daily data as for 7DME but the values for the Friday and Saturday are padded with the value for the previous Thursday.

The following table gives a comparison of the differences in output between the daily frequencies. The X represents dates and values that are not returned.

The Start, End and Frequency settings have the following defaults if not specified:

  • Start: For Snapshot requests, the default value is assumed to be “-0D”, returning data for the previous weekday; i.e. requesting -0D on a Saturday, Sunday or Monday will return you data for the previous Friday. For TimeSeries requests, the default value is assumed to be “-1Y”.
  • End: The default value is assumed to be “-0D” for the latest date.
  • Frequency: The default value is assumed to be “D” for daily data.

The End and Frequency settings are ignored if the request type is Snapshot.

DSDataRequest Tag Property

The Tag member of a DSDataRequest object is simply an optional client specified string. This string can be used to uniquely identify each request, e.g. a hash key, and is returned in the Tag field of the corresponding DSDataResponse object.

DSDataRequest: The Complete Request

A full DSDataRequest combines all the above elements:

    	
            

DSDataRequest testRequest = new DSDataRequest()

{

    Instrument = new DSInstrument()

    {

        // Vodafone as Mnemonic, MSFT as ISIN, Daimler as RIC, Toyota as Local code

        Value = "VOD,US5949181045,<DAIGn.F>,J7203",

        // Request full symbol names

        Properties = new DSStringObjectKVPair[]  

        { 

            new DSStringObjectKVPair() { Key = "ReturnName", Value = true }

        }

    },

    DataTypes = new[] 

    {

        // Request full datatype names in response 

        new DSDataType()

        {

            Value = "PH",

            Properties = new DSStringObjectKVPair[] 

            { 

                new DSStringObjectKVPair() { Key = "ReturnName", Value = true }

            }

        },

        new DSDataType()

        {

            Value = "DD",

            Properties = new DSStringObjectKVPair[] 

            { 

                new DSStringObjectKVPair() { Key = "ReturnName", Value = true }

            }

        },

        new DSDataType()

        {

            Value = "PYD",

            Properties = new DSStringObjectKVPair[] 

            { 

                new DSStringObjectKVPair() { Key = "ReturnName", Value = true }

            }

        }

    },

    Date = new DSDate()

    {

        Kind = DSDateKind.TimeSeries,

        Start = "2017-01-01",

        End = "2017-12-31",

        Frequency = "D"

    },

    Tag = "myUniqueTag"

};

DSDataRequest Limits

Whilst each DSDataRequest object supports multiple instruments and datatypes, request limits are imposed by the system.

Prior to the following new limits being imposed, clients were allowed to request up to 2000 items in any one request; where the number of items is defined as the number of instruments requested multiplied by the number of datatypes. If your Datastream credentials were authorised for accessing the API prior to 01 August 2018, the new limits will not be applied to your account in order to maintain compatibility with your existing requests. However, we would recommend that all clients try and adhere to the following new limits.

Clients granted access to the API after 01 August 2018 will be restricted to the following limits in any one DSDataRequest:

  • The maximum number of instruments that can be requested: 50
  • The maximum number of datatypes that can be requested: 50
  • The maximum number of items (instruments x datatypes) that can be requested: 100

The above limits permit the following example permutations in any one DSDataRequest:

  • 50 instruments x 2 datatypes
  • 2 instruments x 50 datatypes
  • 1 constituent list x 50 datatypes (you can never request more than one constituent list)
  • 10 instruments x 10 datatypes

When used with GetDataBundle requests, where a collection of DSDataRequest objects can be supplied, there are additional limits imposed on the number of items that can be requested across the bundle. Please see the GetDataBundle section for details.

Submitting Requests

With a valid secure token and one or more DSDataRequest objects defined, data can be retrieved using the GetData and GetDataBundle methods.

The GetData Request

GetData is used to make a single request from the system using one DSDataRequest object. This single request can retrieve data for multiple instruments with a common set of datatypes and a common reporting period. This method returns one DSDataResponse object containing the data for all requested instruments.

The GetData method takes one parameter, a DSGetDataRequest object, to wrap the token and DSDataRequest items, and returns a DSGetDataResponse object upon success. Upon failure, a DSFault exception object is thrown.

    	
            

/* This code snippet assumes the previous creation of the DSServiceClient

 * instance (dsClient), successfull retrieval of a token (tokenValue), and

 * the creation of a DSDataRequest instance (testRequest).

 * See the relevant previous sections for examples of how to create these instances.

 * */

 

// The token and DSDataRequest instance must be wrapped in a DSGetDataRequest instance.

var dataReq = new DSGetDataRequest()

{

    TokenValue = tokenValue,

    DataRequest = testRequest,

};

 

try

{

    // Issue the GetData request.

    DSGetDataResponse myGetDataResp = dsClient.GetData(dataReq);

 

    // Retrieve the DSDataResponse object.

    DSDataResponse response = myGetDataResp.DataResponse;

 

    // Process the response DSDataResponse.

    // See the DSDataResponse section 

 

}

catch (System.ServiceModel.FaultException<DSFault> reqFault)

{

    // Process any request error

    Console.WriteLine("Error requesting GetData for user {0}. Code {1}, Message {2}.", 

                tokenRequest.UserName, reqFault.Code.Name, reqFault.Message);

}

catch (Exception e)

{

    // Process any network or endpoint error

    Console.WriteLine("Error requesting GetData HRES 0x{1:X}, Message {2}.", 

                        e.HResult, e.Message);

}

The DSGetDataRequest object, in addition to the token and DSDataRequest parameters, also contains a Properties field that accepts a collection of string-object pairs. This field is reserved for possible future enhancements and provides no current functionality.

The section describing the returned DSDataResponse object explains how to process a successful response.

For invalid requests, GetData returns a DSFault object specifying the error. This contains Code and Message fields of type string. For invalid input, the Code field will contain the value “InvalidArgument” and the Message field will specify the invalid input such as “tokenValue cannot be empty. (tokenValue)”. The parameters of the supplied DSDataRequest are also validated and any errors returned, e.g. “Instrument cannot be null (Instrument)”.

For invalid or expired tokens, the Code field will contain the value “InvalidToken” and the Message field will contain a descriptive error message such as “Invalid token string.” or “Token has expired”.

Finally, for general network or endpoint errors, where a connection to our servers is not possible, a generic Exception error will occur. You also need to handle this type of error.

The GetDataBundle Request

GetDataBundle is used to retrieve multiple datasets in one request using an array of DSDataRequest objects.

Whilst each DSDataRequest object can be independent of any other DSDataRequest within the bundle, bundled request usually have a common request and response processing formats:

    	
            

// Simulating constructing a batch of instruments read from a database into a collection

string[] reqInstruments = new string[] { "VOD", "@MSFT", "D:DAI", "J:TYMO", "BARC", 

                                         "MKS", "LGEN", "RBS", "BLND", "LLOY" }; 

 

// In a bundled request we usually want to request the same datatypes

DSDataType[] reqDataTypes = new[] 

    new DSDataType() { Value = "PH" },

    new DSDataType() { Value = "PCH#(X(PH), 1Y)" }

};

 

// and a common date range for each instrument in the batch

DSDate reqDateRange = new DSDate()

{

    Kind = DSDateKind.TimeSeries,

    Start = "2018-06-01",

    End = "2018-06-20",

    Frequency = "D"

};

 

 

// Build an array of DSDataRequest items from the collection of instruments

// One request for each instrument in this example

DSDataRequest[] dataReqs = new DSDataRequest[reqInstruments.Count()];

int nindex = 0;

foreach (string inst in reqInstruments)

{

    dataReqs[nindex++] = new DSDataRequest()

    {

        Instrument = new DSInstrument() { Value = inst },  // Set the instrument

        DataTypes = reqDataTypes,   // Assign the list of datatypes we created earlier

        Date = reqDateRange,   // Assign the common date range 

        Tag = inst   // You can assign a unique identifier to each request.

    };

}

The GetDataBundle method takes one parameter, a DSGetDataBundleRequest object, to wrap the token and the array of DSDataRequest items, returning a DSGetDataBundleResponse object upon success. Upon failure, a DSFault exception object is thrown.

 

The DSGetDataBundleRequest object, in addition to the token and DSDataRequests parameters, also contains a Properties field that accepts a collection of string-object pairs. This field is reserved for possible future enhancements and provides no current functionality.

    	
            

/* This code snippet assumes the previous creation of the DSServiceClient

 * instance (dsClient), successfull retrieval of a token (tokenValue), and

 * the creation of a DSDataRequest array (dataReqs).

 

 * See the relevant previous sections for examples of how to create these instances.

 * */

 

// The token and DSDataRequest array must be wrapped in a DSGetDataBundleRequest

var dataReq = new DSGetDataBundleRequest()

{

    TokenValue = tokenValue,

    DataRequests = dataReqs

};

 

try

{

    // Issue the GetDataBundle request.

    DSGetDataBundleResponse myGetDataBundleResp = dsClient.GetDataBundle(dataReq);

 

    // Retrieve the DSDataResponse array.

    DSDataResponse[] myResps = myGetDataBundleResp.DataResponses;

 

    // Process the response for each request

    foreach (var response in myResps)

    {

        // Get the unique request identifier from the Tag field if needed.

        string reqIdentifier = response.Tag;  

 

        // Process the response DSDataResponse.

        // See the DSDataResponse section 

 

    }

}

catch (System.ServiceModel.FaultException<DSFault> reqFault)

{

    // Process any request error

    Console.WriteLine("Error in GetDataBundle for user {0}. Code {1}, Message {2}.", 

                tokenRequest.UserName, reqFault.Code.Name, reqFault.Message);

}

catch (Exception e)

{

    // Process any network or endpoint error

    Console.WriteLine("Error in GetDataBundle HRES 0x{1:X}, Message {2}.", 

                        e.HResult, e.Message);

}

The returned DSGetDataBundleResponse object contains a DataResponses property, a simple array of DSDataResponse objects corresponding to the supplied requests. This collection can simply be iterated and each individual DSDataResponse processed. The section describing DSDataResponse objects explains how to process a response.

The DSGDataBundleResponse also supports a Properties field that returns a collection of string-object pairs. Like the Properties Field of the DSGetDataBundleRequest object, this field is reserved for possible future enhancements and provides no current functionality.

For invalid requests, GetDataBundle returns a DSFault object specifying the error. This contains Code and Message fields of type string. For invalid input, the Code field will contain the value “InvalidArgument” and the Message field will specify the invalid input such as “tokenValue cannot be empty. (tokenValue)”.

For invalid or expired tokens, the Code field will contain the value “InvalidToken” and the Message field will contain a descriptive error message such as “Invalid token string.” or “Token has expired.”. The parameters of each of the supplied DSDataRequests items are also validated and any errors returned, e.g. “Instrument cannot be null (Instrument)”.

Finally, for general network or endpoint errors, where a connection to our servers is not possible, a generic Exception error will occur. You also need to handle this type of error.

GetDataBundle Limits

As for the new limits imposed on individual DSDataRequest objects (see the DSDataRequest Limits section previously), there are also limits imposed by the servers on bundled requests. Prior to 01 August 2018, bundled requests could request up to a maximum of 2000 items, where the number of items is defined as the number of instruments requested multiplied by the number of datatypes. This 2000 item limit could be requested in any combination, from one constituent DSDataRequest containing 2000 items, to 2000 constituent DSDataRequests each containing just one item per request.

If your Datastream credentials were authorised for accessing the API prior to 01 August 2018, the following new limits will not be applied to your account in order to maintain compatibility with your existing requests.

Clients granted access to the API after 01 August 2018 will have the following limits imposed on a bundled request in addition to the individual limits imposed on any one DSDataRequest,:

  • The maximum number of DSDataRequests per bundled request: 20
  • The maximum number of items (instruments x datatypes) across all DSDataRequests: 500

The above limits permit the following example permutations in any one GetDataBundle request:

  • Up to 5 DSDataRequests each requesting 100 items
  • 10 DSDataRequests each requesting 50 items
  • 20 DSDataRequests each requesting 25 items

Processing Responses

Both the GetData and GetDataBundle requests return one or more DSDataResponse objects. For multiple response objects returned in GetDataBundle, the collection can be processed in turn using a simple array iterator.

    	
            

    // Retrieve the DSDataResponse array.

    DSDataResponse[] myResps = myGetDataBundleResp.DataResponses;

 

    // Process the response for each request

    foreach (var response in myResps)

    {

        // Get the unique request identifier from the Tag field if needed.

        string reqIdentifier = response.Tag;  

 

        // Process the response DSDataResponse.

        // See later example code for processing a single DSDataResponse

 

    }

The DSDataResponse object

Responses from the API service are primarily represented as an array of Datatype responses, each containing a result for every instrument requested.

The DSDataResponse object has two key properties; namely, the Dates property containing an array of DateTime objects representing the set of dates for which data is returned, and the DataTypeValues property, an array of DSDataTypeResponseValue objects describing the response for each requested datatype. The DSDataTypeResponseValue contains the set of responses for each requested instrument for the given datatype.

The DSDataResponse object also contains 4 optional response properties; namely, the Tag, AdditionalResponses, SymbolNames and DataTypeNames members.

DSDataResponse: The Dates Property

The Dates property returns an array of DateTime objects. This is a common set of UTC timezone dates corresponding to the set of values returned for each returned datatype. As each DSDataTypeResponseValue is processed, every valid instrument that returns data for the given datatype will return a corresponding collection of values matching the size of the DateTime array.

For valid Snapshot requests, which return a set of single response values for each requested datatype, the Dates property returns an array containing only one DateTime element. For valid TimeSeries requests, there will one or more DateTime elements returned in the array depending on the time period and frequency requested.

For invalid requests, where no response data is available, the Dates property will contain a null value rather than an array of DateTime objects. For TimeSeries requests, a null Dates response will be returned only if all instruments are invalid, all datatypes are invalid, or the specified date range is not supported by the system. For Snapshot requests, a null Dates response is sent if any one datatype is invalid or the requested date is not supported by the system. Although the Dates property will be null for invalid requests, the DataTypeValues property will detail the error condition. The error condition will be common across all responses; only the first response datatype needs to be processed in order to retrieve the general error message.

    	
            

// This snippet assumes the DSDataResponse object has previously been retrieved 

// into the variable response.

 

// Get the collection of dates corresponding with the responses to be processed.

DateTime[] respDates = response.Dates;

 

if (respDates == null) // No valid responses returned for any item. 

{

    // get the first SymbolValue that is of type DSSymbolResponseValueType.Error

    // from the first datatype and process the general error

    DSDataTypeResponseValue firstType = response.DataTypeValues.FirstOrDefault();

    if (firstType != null)

    {

        DSSymbolResponseValue respErrorSymbol = firstType.SymbolValues.FirstOrDefault(

                                      x => x.Type == DSSymbolResponseValueType.Error);

        if (respErrorSymbol != null)

        {

            string errMsg = respErrorSymbol.Value.ToString();

            // process this general error message

        }

    }

}

else

{

    // There is some valid data (note, not all responses may have valid data.)

    // Process the response for each requested datatype.

 

    // See next section.... 

}

DSDataResponse: The DataTypeValues Property

The DataTypeValues property contains an array of DSDataTypeResponseValue objects describing the response for each requested datatype. Each DSDataTypeResponseValue object consists of a DataType property containing the returned datatype’s name, and a SymbolValues property containing a collection of DSSymbolResponseValue objects; one for each instrument requested.

    	
            

foreach (var datatypeValue in resp.DataTypeValues)

{

    string datatype = datatypeValue.DataType; // the current dataype being processed

 

    // Each response datatype will have a list of responses for the symbols requested.

    // Process the response for each requested symbol in turn

    foreach (var symbolValue in datatypeValue.SymbolValues)

    {

        string symbolID = symbolValue.Symbol;

        string curr = symbolValue.Currency;

 

        // Process the DSSymbolResponseValue type and value.

    }

}

The DSSymbolResponseValue object returns the data for the given symbol and datatype. It provides the 4 following properties:

  • The Symbol property: The instrument or expression requested.
  • The Currency property: Should the response contain pricing information, this field will specify the currency in a string format such as £, U$, E, Y, etc.
  • The Value property: a value of type object containing the result for the requested datatype and instrument.
  • The Type property: an object of type DSSymbolResponseValueType, an enumeration specifying the type of the object returned in the Value property.

For valid Snapshot responses, the Type property will specify a DSSymbolResponseValueType  enumeration value of either Bool, DateTime, Double, Int or String, and the Value property will be an object of the specified type. If the requested datatype and instrument produce an error result, the type will be Error, and the Value property will contain a string specifying the error.

    	
            

// Each response datatype will have a list of responses for the symbols requested.

// Process the datatype response for each requested symbol in turn.

foreach (var symbolValue in datatypeValue.SymbolValues)

{

    string symbolID = symbolValue.Symbol;

    string curr = symbolValue.Currency;

 

    // did an error occur for this symbol and datatype?

    if (symbolValue.Type == DSSymbolResponseValueType.Error) 

    {

        // Process the request failure.

        string strErr = (symbolValue.Value == null ? string.Empty :

                                                (string)symbolValue.Value);

    }

    else

    {

        // Process the data for this symbol and datatype.

        // You can process differently based on returned type

        switch (symbolValue.Type)

        {

            case DSSymbolResponseValueType.Bool:

                { bool boolRes = (bool)symbolValue.Value; }

                break;

            case DSSymbolResponseValueType.DateTime:

                { DateTime dateRes = (DateTime)symbolValue.Value; }

                break;

            case DSSymbolResponseValueType.Double:

                { Double dblRes = (double)symbolValue.Value; }

                break;

            case DSSymbolResponseValueType.Int:

                { int intRes = (int)symbolValue.Value; }

                break;

            case DSSymbolResponseValueType.String:

                { string strRes = (string)symbolValue.Value; }

                break;

            default: // Snapshots shouldn't return any other type

                break;

        }

    }

}

For valid TimeSeries requests, the Type property will specify a DSSymbolResponseValueType  enumeration value of one of DoubleArray, DateTimeArray or ObjectArray. If the requested datatype and instrument produce an error result, the type will be Error, and the Value property will contain a string specifying the error.

    	
            

// Each response datatype will have a list of responses for the symbols requested.

// Process the datatype response for each requested symbol in turn

foreach (var symbolValue in datatypeValue.SymbolValues)

{

    string symbolID = symbolValue.Symbol;

    string curr = symbolValue.Currency;

 

    // Did an error occur for this symbol and datatype?

    if (symbolValue.Type == DSSymbolResponseValueType.Error) 

    {

        // Process the request failure. Here we just crop for display purposes

        string strErr = (symbolValue.Value == null ? string.Empty : 

                                                    (string)symbolValue.Value);

    }

    else

    {

        // Process the data for this symbol and datatype. 

        // You can process differently based on returned type

        switch (symbolValue.Type)

        {

            case DSSymbolResponseValueType.DateTimeArray:

                {

                    DateTime[] trimDates = (DateTime[])symbolValue.Value;

                    break;

                }

            case DSSymbolResponseValueType.DoubleArray:

                {

                    double[] trimDbls = (double[])symbolValue.Value;

                    break;

                }

            case DSSymbolResponseValueType.ObjectArray:

            default: //TimeSeries shouldn't return any other type other than above

                {

                    object[] trimObjs = (object[])symbolValue.Value;

                    break;

                }

        }

    }

}

DSDataResponse: Miscellaneous Properties

Whilst the Dates and DataTypeValues are key properties of any response, the DSDataResponse object also contains 4 optional response properties:

  • The Tag member: Each DSDataRequest object supports a Tag member that can be optionally used to supply a reference string uniquely identifying each request. Any supplied tag is simply returned in the Tag member of the corresponding DSDataResponse object.
  • The AdditionalResponses member: This property returns a collection of string-object pairs and is reserved for possible future enhancements. Currently, for TimeSeries requests only, this property only returns one item with key “Frequency” and value one of “D”, “W”, “M”, “Q” or “Y”, representing the frequency of the collection of dates returned in the Dates response. For Snapshot requests, which only ever return a single date, the AdditionalResponses member will always contain a null response.
  • The SymbolNames member: The DSInstrument member of any DSDataRequest contains a Properties field for supplying optional hints as to how to process the content of its Value field (e.g. IsExpression, IsList, etc. – see the DSInstrument section for more details). One option is to also specify the ReturnName property (see the first request example code under the DSInstrument section). When specified, the SymbolNames member in the response will contain a collection of string key-value pairs mapping each requested instrument code (key) to its NAME datatype (value element).
    This collection can be used for name expansion when displaying or storing the requested instruments’ results. Example key-value responses for valid instruments are “VOD”-“VODAFONE GROUP”, “@MSFT”-”MICROSOFT”, “D:DAI”-”DAIMLER” and “J:TYMO”-“TOYOTA MOTOR”. For any invalid instruments requested, the corresponding key and value elements will be identical to the requested invalid instrument code. E.g. “VODXX”-“VODXX”
    The SymbolNames member is only supported for TimeSeries requests. For Snapshot requests, this member will always return a collection of key-value pairs that match the requested instrument code (e.g. “VOD”-“VOD”). To retrieve the display name for Snapshot requests, the NAME datatype can be requested as part of the request’s DataTypes collection and processed as per any other requested datatype.
  • The DataTypeNames member: As for symbol names, the expanded name of the requested datatypes can also be returned. Setting ReturnName in the Properties member of each DSDataType object will return the expanded datatype name as key-value string pairs (see the last example request in the DSDataType section). Example key-value pairs are “PH”-“PRICE HIGH”, “DD”-”DIV RATE ADJUSTED”, “PYD”-“DIV PAY DATE”, etc. For invalid datatypes, a null string will be returned.

The following is sample code for processing the above optional fields:

    	
            

// Retrieve the DSDataResponse object.

DSDataResponse response = myGetDataResp.DataResponse;

 

// Get the unique request identifier from the Tag field if needed.

string reqIdentifier = response.Tag;  

 

// If request was a Timeseries request, the Additionalresponses collection 

// will contain a Frequency member with value "D", "W", "M", "Q" or "Y"

if (response.AdditionalResponses != null 

           && response.AdditionalResponses[0].Key == "Frequency")

{

    string responseFreq = response.AdditionalResponses[0].Value.ToString();

}

 

// Process any SymbolValues mapping requested instruments 

// to full symbol names (e.g. "VOD" to "VODAFONE GROUP")

if (response.SymbolNames != null)

{

    foreach (var kvSymbol in response.SymbolNames)

    {

        string reqCode = kvSymbol.Key;

        string symbolName = kvSymbol.Value;

    }

}

 

// Process any DataTypeNames mapping requested datatypes 

// to full name (e.g. "PH" to "PRICE HIGH")

if (response.DataTypeNames != null)

{

    foreach (var kvDataType in response.DataTypeNames)

    {

        string reqDatatype = kvDataType.Key;

        string typeName = kvDataType.Value;

    }

}