Using Datafeed we can upload Market data into SAP automatically from different Market data providers.
I want to show you an example how you can use Datafeed.
Input data
I have a web site of National Bank of the Republic of Belarus ( Exchange Rates, Refinancing Rate, News | National Bank of the Republic of Belarus) from where i can get information about:
- Refinancing Rate | National Bank of the Republic of Belarus
- Official Exchange Rate of the Belarusian Ruble Against Foreign Currencies Set on a Daily Basis | National Bank of the …
- Accounting Prices on Precious Metals in Standard Bars, Set By the National Bank of the Republic of Belarus | National B…
Each of mentioned Market data has API which can retrieve information. API is the URL with parameters. API returns a string with information.
- For Refinaning Rate – http://www.nbrb.by/API/RefinancingRate?onDate=2016-7-8.
Parameter “onDate” is the date on which we want to get information.
- For Exchange rates – http://www.nbrb.by/API/ExRates/Rates/Dynamics/190?startDate=2016-6-1&endDate=2016-6-30.
Parameters: “startDate”, “endDate” are the date on which we want to get information and “XXX” – external codes for currencies.
- For precious metals – http://www.nbrb.by/API/BankIngots/Prices/0?startDate=2016-6-1&endDate=2016-7-30
Parameters “startDate” and “endDate” makes period for each we want to get information.
As a result we need to get information into SAP and parse it into the special table “Answer”.
Before we can use Datafeed, we need to configure the system.
Configuration
Create Market Data Provider
IMG -> Financial Supply Chain Management -> Treasury and Risk Management -> Basic Functions -> Market Data Management -> Datafeed -> Technical Settings -> Define Datafeed Name (tr. S_ALR_87007834)
Here we create Market Data provider in order to separate the different sources of information:
- Data provider – name of data provider.
- Usage log – If you need to log all data retrievals. SAP Menu -> Accounting -> Financial Supply Chain Management -> Treasury and Risk Management -> Basic Functions -> Market Data Management -> Datafeed -> Usage Log -> …
- Feed active? – distinguish active and inactive feeds.
- Quotation source – Quotation source for commodity.
RFC Settings for External Partner Program
We can contact external partners in two different ways:
- Using RFC (remote function call) and calling external funciton.
- Web Access (URL or Web Services).
Let’s start with Web Access.
In my case i will use Web Acces.
IMG -> Financial Supply Chain Management -> Treasury and Risk Management -> Basic Functions -> Market Data Management -> Datafeed -> Technical Settings -> RFC Settings for External Partner Program -> Assign Datafeed RFC Destination (tr. SM30 -> V_VTB_DFD)
- Datafeed operating mode:
- •’1′ synchronous: SAP waits until the external partner program has delivered all the data.
- •’2′ asynchronous: SAP does not wait until the external partner program has delivered all the data but immediately switches control back to the calling program. The data is delivered from the external partner program at a later date (possibly in separate blocks).
For Web Access we choose Synchronous operation mode.
- Function: There is a standard SAP function module TB_DATAFEED_INTERNET_ACCESS to get information from web. But as i described earlier my data provider has special API – so i need to modify standard FM. So i created ZTB_DATAFEED_INTERNET_ACCESS
- RFC destination, Back-up RFC destination: For Web Access in my case i do not need RFC connection.
FUNCTION ztb_datafeed_internet_access.
*"----------------------------------------------------------------------
*"*"Локальный интерфейс:
*" IMPORTING
*" VALUE(FEEDNAME) LIKE VTB_DFDEST-RFEEDNAME
*" VALUE(HISTORY) LIKE VTB_DFCU-RUPDHIST
*" VALUE(UPDATE) LIKE VTB_DFCU-RUPDHIST
*" VALUE(BLANKSTOCRLF) TYPE VTB_DFDEST-BLANKSTOCRLF DEFAULT 'X'
*" VALUE(CLEAR_REQUEST_ENTITY_BODY) TYPE BOOLEAN DEFAULT 'X'
*" EXPORTING
*" VALUE(E_MESSAGE_BUFFER) LIKE VTB_MARKET-ERROR
*" TABLES
*" ANSWER STRUCTURE VTB_DFANS
*" REQUEST STRUCTURE VTB_DFREQ
*" EXCEPTIONS
*" DATAFEED_FAILURE
*"----------------------------------------------------------------------
************************************************************************
* Declarations
CONSTANTS: rworkmodus LIKE vtb_dfdest-rworkmodus VALUE '1'.
DATA: zresponse_body TYPE TABLE OF zchar9000 WITH HEADER LINE, " STRING TYPE
zstr TYPE zchar9000,
zsplit TYPE STANDARD TABLE OF char200 WITH HEADER LINE,
zresponse_headers TYPE TABLE OF char50 WITH HEADER LINE,
text_to_be_scanned TYPE char200, " String of market data
regular_expression_pattern TYPE char200, " REGEXP to find data in String of market data
res TYPE match_result, " Found result in String of market data
text TYPE char200, " Temporary variable to pass market data into answer table
zuri TYPE tb_dfuri, " URL from VTB_DFDEST table. We will modify URL to match requests.
zmetal TYPE char15,
zcur TYPE tb_key1_ex, " External data provider currency code
zmet TYPE tb_prpty. " External data provider metal code
TABLES: vtb_dfdest.
* Temp answer table
DATA: BEGIN OF temp_answer OCCURS 100.
INCLUDE STRUCTURE vtb_dfans.
DATA: END OF temp_answer.
DATA: hlp_message_buffer(50) TYPE c.
* Request tables
DATA: BEGIN OF request_headers OCCURS 100,
line LIKE tline-tdline.
DATA: END OF request_headers.
DATA: BEGIN OF request_entity_body OCCURS 100,
line LIKE vtbdfin-line.
DATA: END OF request_entity_body.
* Response tables
DATA: BEGIN OF response_headers OCCURS 10,
line LIKE tline-tdline.
DATA: END OF response_headers.
DATA: BEGIN OF response_entity_body OCCURS 10,
line LIKE vtb_dfans,
newlinechar(2) TYPE c,
END OF response_entity_body.
* status code RFC1945
DATA: status_code(3) TYPE c.
* length of response body
DATA: response_entity_body_length TYPE i.
DATA: request_entity_body_length TYPE i.
************************************************************************
* Initialization
CLEAR: e_message_buffer, hlp_message_buffer.
REFRESH: request_headers, response_headers, request_entity_body,
response_entity_body, temp_answer.
* read table vtb_dfdest for URI and PROXY Information.
SELECT SINGLE * FROM vtb_dfdest CLIENT SPECIFIED
WHERE mandt = sy-mandt
AND rfeedname = feedname
AND rworkmodus = rworkmodus.
* fill HTTP request page header
request_headers-line = "/ HTML version 3.2
'content-type: text/plain'. "#EC *
APPEND request_headers.
IF clear_request_entity_body IS NOT INITIAL.
CLEAR request_entity_body.
REFRESH request_entity_body.
ENDIF.
************************************************************************
* Retrieving market data from Data Provider
" Save the initial URL. We will modify vtb_dfdest-uri for different market data classes.
zuri = vtb_dfdest-uri.
" Loop at 'Data source' to get data
LOOP AT request.
CASE request-rinid2. "'Data source'
" Refinance rate
WHEN 'REFINANCE'.
" Create the right API URL for Refinance rate.
" If we have From (zreq-dfromdate) and To (zreq-dtodate) fields initial - then we request data on curren date (tr. TBD4).
" If we have From (zreq-dfromdate) and To (zreq-dtodate) fields NOT initial - then we requst history data (tr. TBDJ).
CLEAR vtb_dfdest-uri.
IF request-dfromdate IS INITIAL OR request-dtodate IS INITIAL.
CONCATENATE zuri '/RefinancingRate?onDate=' sy-datum+0(4) '-' sy-datum+4(2) '-' sy-datum+6(2) INTO vtb_dfdest-uri.
ELSE.
CONCATENATE zuri '/RefinancingRate' INTO vtb_dfdest-uri.
ENDIF.
CLEAR zresponse_body.
REFRESH zresponse_body.
CLEAR zresponse_headers.
REFRESH zresponse_headers.
CLEAR zstr.
CLEAR zsplit.
REFRESH zsplit.
CLEAR text_to_be_scanned.
WAIT UP TO 2 SECONDS.
" Requesting information.
CALL FUNCTION 'HTTP_GET'
EXPORTING
absolute_uri = vtb_dfdest-uri
user = vtb_dfdest-foreign_user
password = vtb_dfdest-foreign_passwd
blankstocrlf = blankstocrlf "VTB_DFDEST-BLANKSTOCRLF
IMPORTING
status_code = status_code
response_entity_body_length = response_entity_body_length
TABLES
request_entity_body = request_entity_body
request_headers = request_headers
response_entity_body = zresponse_body[]
response_headers = zresponse_headers[]
EXCEPTIONS
connect_failed = 1
timeout = 2
internal_error = 3
tcpip_error = 4
OTHERS = 5.
" error handling!!!
IF sy-subrc <> 0. "/ no connection
CASE sy-subrc.
WHEN '1'.
e_message_buffer =
'Сonnect_failed'(890).
WHEN '2'.
e_message_buffer =
'Timeout'(891).
WHEN '3'.
e_message_buffer =
'Internal_error'(892).
WHEN '4'.
e_message_buffer =
'TCP/IP error'(893).
WHEN OTHERS.
e_message_buffer =
'HTTP-GET error'(894).
ENDCASE.
EXIT.
" error handling!!!
ELSEIF status_code <> '200'. "/ connection ok, other problems
LOOP AT response_headers.
hlp_message_buffer = response_headers-line.
"/ first line contains error
EXIT.
ENDLOOP.
" concatenate 'Fehler: '(910) status_code hlp_message_buffer
MOVE hlp_message_buffer TO e_message_buffer.
CONDENSE e_message_buffer.
EXIT.
ELSE.
" everything was fine...
CLEAR answer.
LOOP AT zresponse_body INTO zstr.
" All data is diveded by '},{'. Let's split it into 1 string - 1 market data.
SPLIT zstr AT '},{' INTO TABLE zsplit IN CHARACTER MODE.
" Loop through and retrieve data that we need.
LOOP AT zsplit INTO text_to_be_scanned.
" Searching for date.
regular_expression_pattern = '\d{4}-\d{2}-\d{2}'.
FIND REGEX regular_expression_pattern IN text_to_be_scanned RESULTS res.
IF sy-subrc = 0.
CLEAR text.
text = text_to_be_scanned+res-offset(res-length).
CONCATENATE text+0(4) text+5(2) text+8(2) INTO answer-ddate.
ENDIF.
" Searching for time.
regular_expression_pattern = '\d{2}:\d{2}:\d{2}'.
FIND REGEX regular_expression_pattern IN text_to_be_scanned RESULTS res.
IF sy-subrc = 0.
CLEAR text.
text = text_to_be_scanned+res-offset(res-length).
CONCATENATE text+0(2) text+3(2) text+6(2) INTO answer-ttime.
ENDIF.
" Searching for value.
regular_expression_pattern = '\d{1,}\.\d{1,5}'.
FIND REGEX regular_expression_pattern IN text_to_be_scanned RESULTS res.
IF sy-subrc = 0.
answer-value = text_to_be_scanned+res-offset(res-length).
ENDIF.
" Other parameters (tr. SM30 -> V_DFCU03)
answer-rinid1 = 'REFINANCE'. "Instrument
answer-rinid2 = 'REFINANCE'. "Data Source
answer-sprpty = 'REFINANCE'. "Instrument property
answer-uname = sy-uname.
" Save market data into Answer table.
APPEND answer.
ENDLOOP.
ENDLOOP.
ENDIF.
" Exchange rate
WHEN 'CURRENCY'.
CLEAR vtb_dfdest-uri.
" Get external codes for currency codes.
SELECT SINGLE rkey1 FROM mducr INTO zcur WHERE vendor = 'NBRB.by' AND source = 'F' AND waers = request-rinid1+3(3).
IF sy-subrc <> 0.
CONCATENATE 'Error: Convert Codes for Currency Names: ' request-rinid1+3(3) 'SM30 -> V_MDUDFCR' INTO e_message_buffer.
EXIT.
ENDIF.
" Create the right API URL for Exchange rates.
" If we have From (zreq-dfromdate) initial or ( From (zreq-dfromdate) and To (zreq-dtodate) fields initial - then we request data on curren date (tr. TBD4).
" Otherwise - we requst history data on zreq-dfromdate (tr. TBDJ).
IF request-dfromdate IS INITIAL OR ( request-dtodate IS INITIAL AND request-dfromdate IS INITIAL ). " tr. TBD4
CONCATENATE zuri " http://www.nbrb.by/API
'/ExRates/Rates/Dynamics/'
zcur
'?startDate='
sy-datum+0(4) '-'
sy-datum+4(2) '-'
sy-datum+6(2)
'&endDate='
sy-datum+0(4) '-'
sy-datum+4(2) '-'
sy-datum+6(2)
INTO vtb_dfdest-uri.
sy-tcode = 'TBD4'.
ELSE. " tr. TBDJ
CONCATENATE zuri " http://www.nbrb.by/API
'/ExRates/Rates/Dynamics/'
zcur
'?startDate='
request-dfromdate+0(4) '-'
request-dfromdate+4(2) '-'
request-dfromdate+6(2)
'&endDate='
request-dtodate+0(4) '-'
request-dtodate+4(2) '-'
request-dtodate+6(2)
INTO vtb_dfdest-uri.
sy-tcode = 'TBDJ'.
ENDIF.
CLEAR zresponse_body.
REFRESH zresponse_body.
CLEAR zresponse_headers.
REFRESH zresponse_headers.
CLEAR zstr.
CLEAR zsplit.
REFRESH zsplit.
CLEAR text_to_be_scanned.
WAIT UP TO 2 SECONDS.
" Requesting information.
CALL FUNCTION 'HTTP_GET'
EXPORTING
absolute_uri = vtb_dfdest-uri
user = vtb_dfdest-foreign_user
password = vtb_dfdest-foreign_passwd
blankstocrlf = blankstocrlf "VTB_DFDEST-BLANKSTOCRLF
IMPORTING
status_code = status_code
response_entity_body_length = response_entity_body_length
TABLES
request_entity_body = request_entity_body
request_headers = request_headers
response_entity_body = zresponse_body[]
response_headers = zresponse_headers[]
EXCEPTIONS
connect_failed = 1
timeout = 2
internal_error = 3
tcpip_error = 4
OTHERS = 5.
" error handling!!!
IF sy-subrc <> 0. "/ no connection
CASE sy-subrc.
WHEN '1'.
e_message_buffer =
'Сonnect_failed'(890).
WHEN '2'.
e_message_buffer =
'Timeout'(891).
WHEN '3'.
e_message_buffer =
'Internal_error'(892).
WHEN '4'.
e_message_buffer =
'TCP/IP error'(893).
WHEN OTHERS.
e_message_buffer =
'HTTP-GET error'(894).
ENDCASE.
EXIT.
ELSEIF status_code <> '200'. "/ connection ok, other problems
" error handling!!!
LOOP AT response_headers.
hlp_message_buffer = response_headers-line.
"/ first line contains error
EXIT.
ENDLOOP.
" concatenate 'Fehler: '(910) status_code hlp_message_buffer
MOVE hlp_message_buffer TO e_message_buffer.
CONDENSE e_message_buffer.
EXIT.
ELSE.
" everything was fine...
CLEAR answer.
READ TABLE zresponse_body INTO zstr INDEX 1.
" All data is diveded by '},{'. Let's split it into 1 string - 1 market data.
SPLIT zstr AT '},{' INTO TABLE zsplit IN CHARACTER MODE.
" Loop through and retrieve data that we need.
LOOP AT zsplit INTO text_to_be_scanned.
" Searching for date.
regular_expression_pattern = '\d{4}-\d{2}-\d{2}'.
FIND REGEX regular_expression_pattern IN text_to_be_scanned RESULTS res.
IF sy-subrc = 0.
CLEAR text.
text = text_to_be_scanned+res-offset(res-length).
CONCATENATE text+0(4) text+5(2) text+8(2) INTO answer-ddate.
ENDIF.
" Searching for time.
regular_expression_pattern = '\d{2}:\d{2}:\d{2}'.
FIND REGEX regular_expression_pattern IN text_to_be_scanned RESULTS res.
IF sy-subrc = 0.
CLEAR text.
text = text_to_be_scanned+res-offset(res-length).
CONCATENATE text+0(2) text+3(2) text+6(2) INTO answer-ttime.
ENDIF.
" Searching for echange rate.
regular_expression_pattern = '\d{1,}\.\d{1,5}'.
FIND REGEX regular_expression_pattern IN text_to_be_scanned RESULTS res.
IF sy-subrc = 0.
answer-value = text_to_be_scanned+res-offset(res-length).
ENDIF.
" Other parameters
answer-currency = request-rinid1+3(3).
answer-rinid1 = request-rinid1.
answer-rinid2 = 'CURRENCY'.
answer-sprpty = 'M'.
answer-uname = sy-uname.
" Save market data into Answer table.
APPEND answer.
ENDLOOP.
ENDIF.
WHEN 'METALS'.
CLEAR vtb_dfdest-uri.
" Get external codes for commodities.
SELECT SINGLE sprpty FROM mducmv INTO zmet WHERE vendor = 'NBRB.by' AND source = 'F' AND quotyp = request-rinid1.
IF sy-subrc <> 0.
CONCATENATE 'Error: Convert Codes for Metal: ' request-rinid1+3(3) 'SM30 -> V_MDUCMV' INTO e_message_buffer.
EXIT.
ENDIF.
" URL for tr. TBD4
IF request-dfromdate IS INITIAL OR ( request-dtodate IS INITIAL AND request-dfromdate IS INITIAL ).
CONCATENATE zuri "http://www.nbrb.by/API
'/BankIngots/Prices/'
zmet
'?startDate='
sy-datum+0(4) '-' sy-datum+4(2) '-' sy-datum+6(2)
'&endDate='
sy-datum+0(4) '-' sy-datum+4(2) '-' sy-datum+6(2)
INTO vtb_dfdest-uri.
" URL for tr. TBDJ
ELSEIF request-dfromdate IS NOT INITIAL AND request-dtodate IS INITIAL.
CONCATENATE zuri "http://www.nbrb.by/API
'/BankIngots/Prices/'
zmet
'?startDate='
request-dfromdate+0(4) '-' request-dfromdate+4(2) '-' request-dfromdate+6(2)
'&endDate='
request-dfromdate+0(4) '-' request-dfromdate+4(2) '-' request-dfromdate+6(2)
INTO vtb_dfdest-uri.
" URL for tr. TBDJ
ELSE.
CONCATENATE zuri "http://www.nbrb.by/API
'/BankIngots/Prices/'
zmet
'?startDate='
request-dfromdate+0(4) '-'
request-dfromdate+4(2) '-'
request-dfromdate+6(2)
'&endDate='
request-dtodate+0(4) '-'
request-dtodate+4(2) '-'
request-dtodate+6(2)
INTO vtb_dfdest-uri.
ENDIF.
CLEAR zresponse_body.
REFRESH zresponse_body.
CLEAR zresponse_headers.
REFRESH zresponse_headers.
CLEAR zstr.
CLEAR zsplit.
REFRESH zsplit.
CLEAR text_to_be_scanned.
WAIT UP TO 2 SECONDS.
" Requesting information.
CALL FUNCTION 'HTTP_GET'
EXPORTING
absolute_uri = vtb_dfdest-uri
user = vtb_dfdest-foreign_user
password = vtb_dfdest-foreign_passwd
blankstocrlf = blankstocrlf "VTB_DFDEST-BLANKSTOCRLF
IMPORTING
status_code = status_code
response_entity_body_length = response_entity_body_length
TABLES
request_entity_body = request_entity_body
request_headers = request_headers
response_entity_body = zresponse_body[]
response_headers = zresponse_headers[]
EXCEPTIONS
connect_failed = 1
timeout = 2
internal_error = 3
tcpip_error = 4
OTHERS = 5.
" error handling!!!
IF sy-subrc <> 0. "/ no connection
CASE sy-subrc.
WHEN '1'.
e_message_buffer =
'Сonnect_failed'(890).
WHEN '2'.
e_message_buffer =
'Timeout'(891).
WHEN '3'.
e_message_buffer =
'Internal_error'(892).
WHEN '4'.
e_message_buffer =
'TCP/IP error'(893).
WHEN OTHERS.
e_message_buffer =
'HTTP-GET error'(894).
ENDCASE.
EXIT.
ELSEIF status_code <> '200'. "/ connection ok, other problems
" error handling!!!
LOOP AT response_headers.
hlp_message_buffer = response_headers-line.
"/ first line contains error
EXIT.
ENDLOOP.
" concatenate 'Fehler: '(910) status_code hlp_message_buffer
MOVE hlp_message_buffer TO e_message_buffer.
CONDENSE e_message_buffer.
EXIT.
ELSE.
" everything was fine...
CLEAR answer.
READ TABLE zresponse_body INTO zstr INDEX 1.
" All data is diveded by '},{'. Let's split it into 1 string - 1 market data.
SPLIT zstr AT '},{' INTO TABLE zsplit IN CHARACTER MODE.
" Loop through and retrieve data that we need.
LOOP AT zsplit INTO text_to_be_scanned. "response_entity_body.
" Search for date
regular_expression_pattern = '\d{4}-\d{2}-\d{2}'.
FIND REGEX regular_expression_pattern IN text_to_be_scanned RESULTS res.
IF sy-subrc = 0.
CLEAR text.
text = text_to_be_scanned+res-offset(res-length).
CONCATENATE text+0(4) text+5(2) text+8(2) INTO answer-ddate.
ENDIF.
" Search for time
regular_expression_pattern = '\d{2}:\d{2}:\d{2}'.
FIND REGEX regular_expression_pattern IN text_to_be_scanned RESULTS res.
IF sy-subrc = 0.
CLEAR text.
text = text_to_be_scanned+res-offset(res-length).
CONCATENATE text+0(2) text+3(2) text+6(2) INTO answer-ttime.
ENDIF.
" Search for commodity rate
regular_expression_pattern = '\d{1,}\.\d{1,5}'.
FIND REGEX regular_expression_pattern IN text_to_be_scanned RESULTS res.
IF sy-subrc = 0.
answer-value = text_to_be_scanned+res-offset(res-length).
ENDIF.
" Search for external commodity code
regular_expression_pattern = '"MetalId":[0-9]{1}'.
FIND REGEX regular_expression_pattern IN text_to_be_scanned RESULTS res.
IF sy-subrc = 0.
zmetal = text_to_be_scanned+res-offset(res-length).
ENDIF.
" Other parameters
CASE zmetal+10(1).
WHEN '0'.
answer-rinid1 = 'GOLD'.
WHEN '1'.
answer-rinid1 = 'SILVER'.
WHEN '2'.
answer-rinid1 = 'PLATINUM'.
WHEN '3'.
answer-rinid1 = 'PALADIUM'.
ENDCASE.
answer-rinid2 = 'METALS'.
answer-sprpty = 'METALS'.
answer-uname = sy-uname.
" Save market data into Answer table.
APPEND answer.
ENDLOOP.
ENDIF.
WHEN OTHERS.
ENDCASE.
ENDLOOP.
" Delete empty lines
LOOP AT answer WHERE rinid1 IS INITIAL
AND rinid2 IS INITIAL
AND sprpty IS INITIAL.
DELETE answer.
ENDLOOP.
" Find missing requests and build up error answer
LOOP AT request.
LOOP AT answer WHERE rinid1 = request-rinid1
AND rinid2 = request-rinid2
AND sprpty = request-sprpty.
ENDLOOP.
IF sy-subrc NE 0. "/ no answer for reques
MOVE-CORRESPONDING request TO temp_answer.
temp_answer-sstats = '99'.
CONCATENATE 'There is no answer from DataFeed: ' e_message_buffer INTO temp_answer-error .
APPEND temp_answer.
ENDIF.
ENDLOOP.
" add missing entries to answer
LOOP AT temp_answer.
MOVE-CORRESPONDING temp_answer TO answer.
APPEND answer.
ENDLOOP.
" that´s it
ENDFUNCTION.
The code also attached to this article in TXT file.
Using RFC
For RFC we need to Enter our RFC destionation (tr. SM59, RFC with type T (TCP/IP) ) and indicate partner’s function. For example, with RFC we connect to Data Provider and the SAP calls special partners function in order to get Market data. Usually, you can get description of RFC configuration and list of function from your partner (Reuters, Blumberg, Teletrade, etc). Using RFC we can retrieve information in Real-time if your provider allows it.
Internet settings for WEB Server Access
IMG -> Financial Supply Chain Management -> Treasury and Risk Management -> Basic Functions -> Market Data Management -> Datafeed -> Technical Settings -> Internet Settings for External Partner Program -> Define Internet Settings for WEB Server Access (tr. SM30 -> V_VTB_DFD2)
Here we define URL (required) and User name and Password (optional) if your Data Provider requeres it.
As you can see earlier in URL we have constant part (http://www.nbrb.by/API/) and variable part depending on market data class.
So in this configuration i will put constant part. Variable part is added inside of FM ZTB_DATAFEED_INTERNET_ACCESS.
Proxy Configuration
IMG -> Financial Supply Chain Management -> Treasury and Risk Management -> Basic Functions -> Market Data Management -> Datafeed -> Technical Settings -> Internet Settings for External Partner Program -> HTTP Proxy Configuration -> Define Proxy Configuration (SM30 -> THTTP)
If according to your companie’s policy you use Proxy to enter to internet, then you can configure your proxy with Proxy user and Proxy password.
Define Data Sources for Datafeed
IMG -> Financial Supply Chain Management -> Treasury and Risk Management -> Basic Functions -> Market Data Management -> Datafeed -> Translation Table -> Define Data Sources for Datafeed (tr. S_ALR_87007888)
Here we define different Data Sources of our Data Provider.
Translation Table
Translation tables can be filled in two ways:
- Automatically. You need to configure Datafeed Conversion Codes
- Manually.
Translation Table: automatically
Create Tables for Code Conversion
This operation fills Converstion tables with SAP data: Exchange rate types, Currency names, etc.
IMG -> Financial Supply Chain Management -> Treasury and Risk Management -> Basic Functions -> Market Data Management -> Datafeed -> Translation Table -> Define Datafeed Conversion Codes -> Create Tables for Code Conversion (tr. TBDK)
Convert Codes for Exchange Rate Types
IMG -> Financial Supply Chain Management -> Treasury and Risk Management -> Basic Functions -> Market Data Management -> Datafeed -> Translation Table -> Define Datafeed Conversion Codes -> Convert Codes for Exchange Rate Types (tr. SM30 -> V_MDUDFCV)
Before creating tables for Code Conversion, the table was empty. After creating tables – it will be filled with SAP data. All you need to map SAP Data with External Providers’ data.
In our case SAP data is equal to External data.
Adjust converstion tables to your need: IMG -> Financial Supply Chain Management -> Treasury and Risk Management -> Basic Functions -> Market Data Management -> Datafeed -> Translation Table -> Define Datafeed Conversion Codes -> …
For my purpse i created the following talbes:
Convert Codes for Currency Names: tr. SM30 -> V_MDUDFCR
Convert Commodity Price Types: tr. SM30 -> V_MDUCMV
I will use these tables to get external codes for currencies and commodities.
Import R/3 Master Data
Now it’s turn to create Translation tables Automatically.
- First select Master data: for example Currency.
- Then select Quantity. If you leave these fields empty then all combination of currency 1, currency 2 and rate type will be uploaded into translation tables. I will use combination of BYN-USD, BYN-EUR, BYN-RUB with rate type M. So, field “1 key definition” is filled with BYN, field “2 key definition” if filled with USD, EUR, RUB. Rate type is M. For mentioned field there is a help, data inside these fields depends on Master data: currency, security, etc.
- Datafeed: “Name” is NBRB.by, “Data source” is Currency.
- Test run – to test if transaction works perfect.
- Save market data – if you want to save data into Translation tables.
Start transaction.
Now we see, that SAP selected what we requested on selection screen. If you uncheck Test field, SAP will fill translation table for Currency. Let’s see this translation talbe.
Translation Table: Currency
IMG -> Financial Supply Chain Management -> Treasury and Risk Management -> Basic Functions -> Market Data Management -> Datafeed -> Translation Table -> Define Currencies (tr. S_ALR_87007920)
Select you data provider.
SAP created translation tables for currency. Make a double click on any parameters in the table.
Most of fields are entered by SAP, selected fields with red box – you have to enter yourself.
- Save markter data permanently in system: tell your system to save data into SAP tables. For example, Exhange rates – tr. OB08, Reference Interest rates – tr. JBIRM, etc.
- Instrument – ask you data provider about this data or create your own. I created my own Instrument – combination of currencies.
- External data feed currency settings: according to external data.
If you didn’t use Automatic creation of Translation tables then you have to fill these tables manually.
Translation Table: Interse rates
IMG -> Financial Supply Chain Management -> Treasury and Risk Management -> Basic Functions -> Market Data Management -> Datafeed -> Translation Table -> Define Reference Interest Rates (tr. S_ALR_87007812)
Translation table for Refinance rate.
Translation Table: Commodity
IMG -> Financial Supply Chain Management -> Treasury and Risk Management -> Basic Functions -> Market Data Management -> Datafeed -> Translation Table -> Define Commodities (tr. S_ALR_87007868)
Translation table for Commodity.
That’s all. For configuration.
Conclusion
If your provider is Reuters (or Bloombers, or Teletrade, or similar services) – it’s very good. Reuters, for example, is licensed with SAP to provide market data. All you need is to configure RFC connection, list of Reuters functions to call and translation tables.
If your data provider has Web-Services or APIs – it’s also not a problem to get data. You have to retrieve simple data structures and parse them into the SAP tables.
Even if you have access to data which is presented as a web page – you can get this information also (as HTML), but you have to find out how to parse this information.
Now it’s time to process datafeed market data: TRM Market Data Management: Datafeed: Processing market data.
————————————————————————————
More information about Market data management – Index.
Hi Grigoriy ,
Thank you very much for the sharing.
Regards,
Biao
Hi Grigoriy,
Thank you very much !
Cheers,
Jain
Dear Grigoriy,
Good Job.. Comprehensive Blog 🙂
Appreciate your help on the below queries.
We are using Reuters DATA SCOPE SELECT API.. after executing TBD4 how the request is passed to Reuters.. is there any JAVA program we need to write? how to invoke that program from TBD4?
Reuters Data Scope select API is called as Reuters SSL or ReutersWeb?
Hello Former Member,
I don’t have experience to work with Reuters, so i am unable to answer your question. I think you have to request such information from Reuters.
My thoughts about it.
1. IMG -> SAP Customizing Implementation Guide -> Financial Supply Chain Management -> Treasury and Risk Management -> Basic Functions -> Market Data Management -> Datafeed -> Technical Settings -> RFC Settings for External Partner Program
a) Define RFC Destination (tr. SM59) here you have to create RFC connection to Reuters system.
b) Assign Datafeed RFC Destination – here either Reuters function to call, or to use FM TB_DATAFEED_INTERNET_ACCESS or your ZTB_DATAFEED_INTERNET_ACCESS to request info.
2. OR IMG -> SAP Customizing Implementation Guide -> Financial Supply Chain Management -> Treasury and Risk Management -> Basic Functions -> Market Data Management -> Datafeed -> Technical Settings -> Internet Settings for External Partner Program
a) Define Internet Settings for WEB Server Access
I have this file about Reuters, it might be helpfull to you. https://drive.google.com/file/d/0B6CvOxs6tAv7RUJzMVl0ZTB2bjg/view?usp=sharing
Thanks Grigority 🙂 ... for the information .. We have achieved the solution through PI.
Hello Naresh,
Could you please give me some clue about how you solved it via PI?
Im using HTTP_AAE receiver comm channel but I´m not able to sort out the issue.
I really appreaciate your help.
Kind regards!
Carlos
Hi Grigoriy, very clear your post!
I have a question regarding the function ZTB_DATAFEED_INTERNET_ACCESS. When I try to set up "Internet settings for web server access" and to complet the URI,
I get the message "No entries found that match selection criteria" (Msg SV004).
When I debug, I see that this is beacuse in the code of this transaccion it is hardcoded "TB_DATAFEED_INTERNET_ACCESS". Do you know if we have to implement any note or do some modification?
Thanks in advance,
Oscar
Hello Oscar, i haven't met any note about this situation. If i want to add URI into this confi, i always use debug.
Thanks Grigory!
For obtainig information from other countries, you can visit http://www.sap-ob08.com
Thank you, Adrian Wilder.
I will try!
Very nicely described and illustrated. It was very helpful.
I had a follow up question- we have two different exchange rate types (M -average and ZB - Balance sheet rate) that we intend to update at different frequency and time of a month.by scheduling a batch job The transaction TBD4 does not have a selection field for exchange rate type. So if I schedule a batch job then it will update the rates for both the exchange rate types whereas I will want to update M rates weekly and ZB once a month only.
please recommend a solution.
Code link is not active.
You are my Super Hero of the Month! It’s such a detailed document that even I (an ABAP Developer) was able to import market data into our system. Double Thumbs Up for this Blog!
pk
You are welcome. I am happy this article helped you!
Can you repost the ztb_datafeed_access.txt, the link is broken. It looks like SAP has moved it. Can you also post the changes to the function group, otherwise the code gets an error when you try to compile (e.g.. referenced objects zchar9000, etc).
Good Morning Aaron,
Here is the link to txt file: https://drive.google.com/file/d/1lmxyjWy0mHQPuTtMAsuJXtgtDMt0193D/view?usp=sharing
zchar9000 is Data element with domain zchar9000 – Data Type CHAR, No. Characters 9000
Also pay attention, that this function module was writen when i didn't have enough knowledge about ABAP and JSON. So this code can be refactored in order to read JSON file with special functions or classes like this: https://blogs.sap.com/2017/08/03/parsing-json-in-abap/