Skip to content

Commit 797600c

Browse files
author
Wasin Waeosri
committed
Merge branch 'notebook'
Add Jupyter Notebook code example
2 parents 2e9d1fb + c2efccc commit 797600c

4 files changed

Lines changed: 290 additions & 6 deletions

File tree

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
.vscode/
22
console_python/market_price.py
3-
result/
3+
result/
4+
notebook_python/test_ws_post.ipynb
5+
notebook_python/test_ws_post2.ipynb

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Data Contribution is a means to send your pricing data directly to Refinitiv , f
1212

1313
## Application Overview
1414

15-
This example shows how to writing an application to contribute your data to TRCC using [Elektron WebSocket API](https://developers.refinitiv.com/elektron/websocket-api) through Thomson Reuters Enterprise Platform (TREP). The example just connects to TREP via a WebSocket connection, then sends an off-stream post to contribute item to TRCC server via that TREP. The application is implemented with Python language, but the main concept and post message structures are the same for all technologies.
15+
This example shows how to writing an application to contribute your data to TRCC using [Elektron WebSocket API](https://developers.refinitiv.com/elektron/websocket-api) through Thomson Reuters Enterprise Platform (TREP). The example just connects to TREP via a WebSocket connection, then sends an off-stream post to contribute item to TRCC server via that TREP. The project are implemented with Python language for both console and Jupyter Notebook applications, but the main concept and post message structures are the same for all technologies.
1616

1717
If you are interested to contribute data using the RSSL connection (with or without TREP), please visit the following series of Elektron SDK and TRCC based on your prefer API:
1818
* [Contributing your data to Thomson Reuters article](https://developers.refinitiv.com/article/contributing-your-data-thomson-reuters).
@@ -37,6 +37,7 @@ This example requires the following dependencies softwares and libraries.
3737
2. [Python](https://www.python.org/) compiler and runtime
3838
3. Python's [requests 2.x](https://pypi.org/project/requests/) library.
3939
4. Python's [websocket-client](https://pypi.org/project/websocket-client/) library (*version 0.49 or greater*).
40+
5. [Jupyter Notebook](https://jupyter.org/) runtime (for the Notebook example application only)
4041
5. TRCC username, password and host list credentials. Please reach out to your Refinitiv sales associate to acquire TRCC access credentials.
4142

4243
*Note:*
@@ -49,11 +50,12 @@ This example requires the following dependencies softwares and libraries.
4950
This example project contains the following files and folders
5051
1. *console_python/trcc_posting.py*: The example application file
5152
2. *console_python/requirements.txt*: The application dependencies configurationf file
52-
3. *trep_config/rmds_trcc.cnf*: ADH TRCC configurations example file (*not a completed ADH configuration file*)
53-
4. LICENSE.md: Project's license file
54-
5. README.md: Project's README file
53+
3. *notebook_python/trcc_posting_notebook.ipynb*: The example Jupyter Notebook application file
54+
4. *trep_config/rmds_trcc.cnf*: ADH TRCC configurations example file (*not a completed ADH configuration file*)
55+
5. LICENSE.md: Project's license file
56+
6. README.md: Project's README file
5557

56-
## How to run this example
58+
## How to run this console example
5759

5860
Please be informed that your TREP server (ADS and ADH) should be applied the TRCC configurations and TRCC contribution service should be "Up" before running an example. The TRCC access credentials are required in the connection between ADH server and TRCC server only, not in the application level.
5961

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Ignore everything in this directory
2+
*
3+
# Except this file
4+
!.gitignore
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"metadata": {},
7+
"outputs": [],
8+
"source": [
9+
"# #uncomment if you do not have requests and websocket-client (version 0.49 and above) installed\n",
10+
"# #Install requests package in a current Jupyter kernal\n",
11+
"\n",
12+
"# import sys\n",
13+
"# !{sys.executable} -m pip install requests\n",
14+
"# !{sys.executable} -m pip install websocket-client"
15+
]
16+
},
17+
{
18+
"cell_type": "code",
19+
"execution_count": null,
20+
"metadata": {},
21+
"outputs": [],
22+
"source": [
23+
"# import required libraries\n",
24+
"\n",
25+
"import sys\n",
26+
"import time\n",
27+
"import getopt\n",
28+
"import socket\n",
29+
"import json\n",
30+
"import websocket\n",
31+
"import threading\n",
32+
"import os\n",
33+
"from threading import Thread, Event"
34+
]
35+
},
36+
{
37+
"cell_type": "code",
38+
"execution_count": null,
39+
"metadata": {},
40+
"outputs": [],
41+
"source": [
42+
"# TREP connection variables\n",
43+
"\n",
44+
"hostname = '127.0.0.1'\n",
45+
"port = '15000'\n",
46+
"user = 'root'\n",
47+
"app_id = '256'\n",
48+
"position = socket.gethostbyname(socket.gethostname())\n",
49+
"login_id = 1"
50+
]
51+
},
52+
{
53+
"cell_type": "code",
54+
"execution_count": null,
55+
"metadata": {},
56+
"outputs": [],
57+
"source": [
58+
"# TRCC contribution variables\n",
59+
"\n",
60+
"post_item_name = 'CONTRIBUTION_RIC'\n",
61+
"service_name = 'TRCC'\n",
62+
"\n",
63+
"post_id = 1\n",
64+
"bid_value = 34.25\n",
65+
"ask_value = 35.48\n",
66+
"primact_1_value = 116.50"
67+
]
68+
},
69+
{
70+
"cell_type": "code",
71+
"execution_count": null,
72+
"metadata": {},
73+
"outputs": [],
74+
"source": [
75+
"# WebSocket connections Variables\n",
76+
"\n",
77+
"web_socket_app = None\n",
78+
"web_socket_open = False"
79+
]
80+
},
81+
{
82+
"cell_type": "code",
83+
"execution_count": null,
84+
"metadata": {},
85+
"outputs": [],
86+
"source": [
87+
"# Create JSON Off-Stream Post message and sends it to ADS server.\n",
88+
"\n",
89+
"def send_market_price_post(ws):\n",
90+
" \"\"\" Send a post message contains a market-price content to TRCC \"\"\"\n",
91+
"\n",
92+
" \"\"\" Contribution fields \"\"\"\n",
93+
" contribution_fields = {\n",
94+
" \"BID\": bid_value,\n",
95+
" \"ASK\": ask_value,\n",
96+
" \"PRIMACT_1\": primact_1_value\n",
97+
" }\n",
98+
"\n",
99+
" \"\"\" OMM Post msg Key \"\"\"\n",
100+
" mp_post_key = {\n",
101+
" \"Name\": post_item_name,\n",
102+
" \"Service\": service_name\n",
103+
" }\n",
104+
"\n",
105+
" \"\"\" OMM Post Payload \"\"\"\n",
106+
" contribution_payload_json = {\n",
107+
" \"ID\": 0,\n",
108+
" \"Type\": \"Update\",\n",
109+
" \"Domain\": \"MarketPrice\",\n",
110+
" \"Fields\": contribution_fields,\n",
111+
" \"Key\": {}\n",
112+
" }\n",
113+
"\n",
114+
" \"\"\" OMM Off-Stream Post message \"\"\"\n",
115+
" mp_post_json_offstream = {\n",
116+
" \"Domain\": \"MarketPrice\",\n",
117+
" \"Ack\": True,\n",
118+
" \"PostID\": post_id,\n",
119+
" \"PostUserInfo\": {\n",
120+
" \"Address\": position,\n",
121+
" \"UserID\": int(app_id)\n",
122+
" },\n",
123+
" \"Key\": {},\n",
124+
" \"Message\": {},\n",
125+
" \"Type\": \"Post\",\n",
126+
" \"ID\": login_id #Off-Stream post, sending the Post message on the Loing stream.\n",
127+
" }\n",
128+
"\n",
129+
" contribution_payload_json[\"Key\"] = mp_post_key\n",
130+
" mp_post_json_offstream[\"Key\"] = mp_post_key\n",
131+
" mp_post_json_offstream[\"Message\"] = contribution_payload_json\n",
132+
"\n",
133+
" ws.send(json.dumps(mp_post_json_offstream))\n",
134+
" print(\"SENT:\")\n",
135+
" print(json.dumps(mp_post_json_offstream, sort_keys=True, indent=2, separators=(',', ':')))\n"
136+
]
137+
},
138+
{
139+
"cell_type": "code",
140+
"execution_count": null,
141+
"metadata": {},
142+
"outputs": [],
143+
"source": [
144+
"# JSON-OMM Login and Process messages\n",
145+
"\n",
146+
"def process_message(ws, message_json): # Process all incoming messages.\n",
147+
" \"\"\" Parse at high level and output JSON of message \"\"\"\n",
148+
" message_type = message_json['Type']\n",
149+
"\n",
150+
" if message_type == \"Refresh\":\n",
151+
" if 'Domain' in message_json:\n",
152+
" message_domain = message_json['Domain']\n",
153+
" if message_domain == \"Login\":\n",
154+
" process_login_response(ws, message_json)\n",
155+
" elif message_type == \"Ping\":\n",
156+
" pong_json = {'Type': 'Pong'}\n",
157+
" ws.send(json.dumps(pong_json))\n",
158+
" print(\"SENT:\")\n",
159+
" print(json.dumps(pong_json, sort_keys=True,\n",
160+
" indent=2, separators=(',', ':')))\n",
161+
" \n",
162+
"# Process incoming Login Refresh Response message.\n",
163+
"def process_login_response(ws, message_json):\n",
164+
" \"\"\" Send Off-Stream Post \"\"\"\n",
165+
" print(\"Sending Off-Stream Post to TREP Server\")\n",
166+
" send_market_price_post(ws) \n",
167+
" \n",
168+
"# Create JSON Login request message and sends it to ADS server.\n",
169+
"def send_login_request(ws):\n",
170+
" \"\"\" Generate a login request from command line data (or defaults) and send \"\"\"\n",
171+
" login_json = {\n",
172+
" 'ID': login_id,\n",
173+
" 'Domain': 'Login',\n",
174+
" 'Key': {\n",
175+
" 'Name': '',\n",
176+
" 'Elements': {\n",
177+
" 'ApplicationId': '',\n",
178+
" 'Position': ''\n",
179+
" }\n",
180+
" }\n",
181+
" }\n",
182+
"\n",
183+
" login_json['Key']['Name'] = user\n",
184+
" login_json['Key']['Elements']['ApplicationId'] = app_id\n",
185+
" login_json['Key']['Elements']['Position'] = position\n",
186+
"\n",
187+
" ws.send(json.dumps(login_json))\n",
188+
" print(\"SENT:\")\n",
189+
" print(json.dumps(login_json, sort_keys=True, indent=2, separators=(',', ':')))"
190+
]
191+
},
192+
{
193+
"cell_type": "code",
194+
"execution_count": null,
195+
"metadata": {},
196+
"outputs": [],
197+
"source": [
198+
"# WebSocket connection process\n",
199+
"\n",
200+
"def on_message(ws, message):\n",
201+
" \"\"\" Called when message received, parse message into JSON for processing \"\"\"\n",
202+
" print(\"RECEIVED: \")\n",
203+
" message_json = json.loads(message)\n",
204+
" print(json.dumps(message_json, sort_keys=True, indent=2, separators=(',', ':')))\n",
205+
"\n",
206+
" for singleMsg in message_json:\n",
207+
" process_message(ws, singleMsg)\n",
208+
" \n",
209+
"def on_error(ws, error):\n",
210+
" \"\"\" Called when websocket error has occurred \"\"\"\n",
211+
" print(error)\n",
212+
" \n",
213+
"def on_close(ws):\n",
214+
" \"\"\" Called when websocket is closed \"\"\"\n",
215+
" global web_socket_open\n",
216+
" print(\"WebSocket Closed\")\n",
217+
" web_socket_open = False\n",
218+
" \n",
219+
"def on_open(ws):\n",
220+
" \"\"\" Called when handshake is complete and websocket is open, send login \"\"\"\n",
221+
"\n",
222+
" print(\"WebSocket successfully connected!\")\n",
223+
" global web_socket_open\n",
224+
" web_socket_open = True\n",
225+
" send_login_request(ws)\n",
226+
"\n",
227+
"if __name__ == \"__main__\":\n",
228+
" # Start websocket handshake\n",
229+
" ws_address = \"ws://{}:{}/WebSocket\".format(hostname, port)\n",
230+
" print(\"Connecting to WebSocket \" + ws_address + \" ...\")\n",
231+
" web_socket_app = websocket.WebSocketApp(ws_address, header=['User-Agent: Python'],\n",
232+
" on_message=on_message,\n",
233+
" on_error=on_error,\n",
234+
" on_close=on_close,\n",
235+
" subprotocols=['tr_json2'])\n",
236+
" web_socket_app.on_open = on_open\n",
237+
"\n",
238+
" # Event loop\n",
239+
" #wst = threading.Thread(target=web_socket_app.run_forever)\n",
240+
" wst = threading.Thread(target=web_socket_app.run_forever, kwargs={'sslopt': {'check_hostname': False}})\n",
241+
" wst.start()\n",
242+
"\n",
243+
" time.sleep(10)\n",
244+
" web_socket_app.close()\n"
245+
]
246+
},
247+
{
248+
"cell_type": "code",
249+
"execution_count": null,
250+
"metadata": {},
251+
"outputs": [],
252+
"source": []
253+
}
254+
],
255+
"metadata": {
256+
"kernelspec": {
257+
"display_name": "Python 3",
258+
"language": "python",
259+
"name": "python3"
260+
},
261+
"language_info": {
262+
"codemirror_mode": {
263+
"name": "ipython",
264+
"version": 3
265+
},
266+
"file_extension": ".py",
267+
"mimetype": "text/x-python",
268+
"name": "python",
269+
"nbconvert_exporter": "python",
270+
"pygments_lexer": "ipython3",
271+
"version": "3.7.3"
272+
}
273+
},
274+
"nbformat": 4,
275+
"nbformat_minor": 2
276+
}

0 commit comments

Comments
 (0)