WebSocket API
The WebSocket API provides a bidirectional connection between client and marketplace where clients receive live updates from the market. Time sensistive updates including trading and market information are delivered through a WebSocket connection to the client immediately.
WebSocket Reference¶
The WebSocket API provides streaming connections to the marketplace for real-time messaging. Trading and market data endpoints are available to receive live updates from the marketplace.
The Trading API allows client to receive all order and trading related updates that are connected to the specific user account.
The Market Data API allows all clients to receive market data updates such as ticker messages or orderbook updates.
Websocket API base URL: wss://glocalflexmarket.com/api/v1/ws/ e.g.: wss://glocalflexmarket.com/api/v1/ws/trade
WebSocket API Endpoints¶
| Endpoint URL | Description | Message Types |
|---|---|---|
/trade |
Trading events | receive all order and contract updates |
/orderbook |
Orderbook events | subscribe to orderbook live events |
/ticker |
Price and flexibility events | subscribe tick live events |
Info
The data object of the WebSocket events uses mostly the message format described in the REST API reference. To check units or description of specific fields please consult the REST API reference for further information.
Control Messages¶
During the initial successful connection, the WebSocket server sends a control message to the client to confirm the connection.
control_message
Trading¶
/trade¶
The trading endpoint sends order and trade updates to the client. The user sends the access token during the initial connection to authenticate the user. Based on the access token the client receives all order and trade updates that are connected to the specific user account.
Note
The user only receives updates connected to its user id.
| Event Type | Description |
|---|---|
order_status_update |
Status of an existing order has changed |
contract_status_update |
Status updates for the contract associated with your orders |
| Status name | Description |
|---|---|
awaiting_baseline_data |
Order is waiting for baseline data |
accepted |
Order has been accepted |
matching_active |
Order is active in the matching engine |
filled |
Order has been fully filled |
order_status_update
{
"type": "order_status_update",
"name": str,
"created_at": date-time,
"data": {
// order object
}
}
contract_status_update
| Status name | Description |
|---|---|
verification_initiated |
Contract verification started |
verification_completed_success |
Contract verification succeeded |
settlement_initiated |
Contract settlement started |
settlement_completed_success |
Contract settlement succeeded |
{
"type": "order_status_update",
"name": str,
"created_at": date-time,
"data": {
// contract object
}
}
Market Data¶
/ticker¶
The ticker endpoint streams market updates of the last matched orders to all connected clients. The message contains the last price and basic information about the flexibility event. After connecting to the WebSocket endpoint the updates are streamed to the client.
| Event Type | Description |
|---|---|
ticker_update |
Information about the last trade closed in the marketplace |
expired_order_update |
Order that has been expired inside the orderbook |
ticker_update
{
"type": "ticker_update",
"created_at": date-time,
"data": {
"closed_at": date-time, // "2024-05-02T12:06:45.842304Z",
"price": float,
"delivery_start": date-time, // "2024-05-02T13:15:00.000Z",
"delivery_end": date-time, //"2024-05-02T14:15:00.000Z",
"energy": float,
"power": float,
"location": {
"location_id": [str],
"country_code": str,
"coordinates": {
"latitude": float,
"longitude": float
}
}
}
}
{
"type": "expired_order_update",
"created_at": date-time,
"data": {
"expired_at": data-time, // "2024-05-02T12:06:45.842304Z",
"price": float,
"delivery_start": date-time, // "2024-05-02T13:15:00.000Z",
"delivery_end": date-time, //"2024-05-02T14:15:00.000Z",
"energy": float,
"power": float,
"location": {
"location_id": [str],
"country_code": str,
"coordinates": {
"latitude": float,
"longitude": float
}
}
}
/orderbook¶
The orderbook endpoint streams the orderbook updates to all connected clients. The message contains the current orderbook state with bids and asks sort by price and time priority. The bids are sorted by price descending and the asks are sorted by price ascending.
orderbook_update
{
"type": "orderbook_update",
"created_at": date-time,
"data": {
"bids": {
"100": [
{
"side": str, // buy
"power": float,
"price": float,
"delivery_start": date-time,
"delivery_end": date-time,
"location": {
"location_id": [
str
],
"country_code": str
},
"energy": float
},
{
"side": str, // buy
"power": float,
"price": float,
"delivery_start": date-time,
"delivery_end": date-time,
"location": {
"location_id": [
str
],
},
"energy": float
},
{
"side": str, // buy
"power": float,
"price": float,
"delivery_start": date-time,
"delivery_end": date-time,
"location": {
"location_id": [
str
],
"country_code": str
},
"energy": float
}
]
},
"asks": {
"11": [
{
"side": str, // sell
"power": float,
"price": float,
"delivery_start": date-time,
"delivery_end": date-time,
"location": {
"location_id": [
str
],
"country_code": str
},
"energy": float
},
{
"side": str, // sell
"power": float,
"price": float,
"delivery_start": date-time,
"delivery_end": date-time,
"location": {
"location_id": [
str
],
"country_code": str
},
"energy": float
}
]
}
}
}
WebSocket Client Example¶
WebSocket Example - Listen to all trading messages and price updates¶
This example demonstrates how to listen to all trading messages and price updates using the WebSocket API.
If you use this example together with the previous Submit Order through the REST API, you can see the order status updates in real-time.
Info
Prerequisite:
- User created account on https://glocalflexmarket.com
- Python version: >= 3.10
Dependencies:
- pip install "websocket-client>=1.7.0" "requests>=2.31.0"
"""
usage: ws_api_listener.py [-h] [--host] [-u] [-p] [-t]
WebSocket Example Client Listener
options:
-h, --help show this help message and exit
--host Host url, DEFAULT: glocalflexmarket.com
-u , --username Username for authentication, default: <username>
-p , --password Password for authentication, default: <password>
-t , --endpoint Order API endpoint, default: /api/v1/ws/trade
Python version: >= 3.10
Dependencies:
pip install websocket-client requests
"""
import argparse
import json
import multiprocessing
import os
import ssl
import threading
from dataclasses import dataclass
from time import sleep
import requests
import websocket
HOST = os.getenv("GFLEX_URL", "glocalflexmarket.com")
USERNAME = os.getenv("GFLEX_USER", "<username>")
PASSWORD = os.getenv("GFLEX_PASSWORD", "<password>")
CLIENT_ID = "glocalflexmarket_public_api"
AUTH_ENDPOINT = "/auth/oauth/v2/token"
ORDER_ENDPOINT = "/api/v1/ws/trade/"
SSL_VERIFY = True
PORT = 443
USER_MESSAGE = "Listen for messages, press Ctrl + c to quit): \n"
class WebSocketClient:
def __init__(self, url, ssl_enabled=True, token=None):
self.ws_url = url
self.ssl_enabled = ssl_enabled
self.token = token
self.received_messages = []
self.shutdown_pipe, self.shutdown_pipe2 = multiprocessing.Pipe()
if self.token:
headers = {
"Authorization": f"Bearer {self.token}",
}
self.sslopt = (
{
"cert_reqs": ssl.CERT_NONE,
"check_hostname": False,
"ssl_context": ssl._create_unverified_context(),
}
if ssl_enabled
else None
)
self.ws = websocket.WebSocketApp(
url=self.ws_url,
header=headers,
on_message=self.on_message,
on_ping=self.on_ping,
on_close=self.on_close,
)
self.receive_thread = threading.Thread(target=self.receive_message, daemon=True)
self.receive_thread.start()
def receive_message(self):
err = self.ws.run_forever(ping_interval=1, sslopt=self.sslopt)
if err:
# send exit message to shutdown the mmain thread
self.shutdown_pipe.send("exit")
print(f"WebSocket connection error: {err}\n")
def on_close(self, ws):
print("WebSocket closed by server")
self.shutdown_pipe.send("exit")
def on_message(self, ws, message):
parsed_message = json.loads(message)
print(f"Received message:\n {json.dumps(parsed_message, indent=4)} \n")
print(USER_MESSAGE)
self.received_messages.append(parsed_message)
def on_ping(self, ws, data):
ws.pong()
def send_message(self, message):
self.ws.send(message)
def run(self):
try:
print(USER_MESSAGE)
while True:
# Check if shutdown signal is received from receive_message thread
if self.shutdown_pipe2.poll():
if self.shutdown_pipe2.recv() == "exit":
print("Exiting...")
break
sleep(0.1)
except KeyboardInterrupt:
pass
print("Closing connection...")
self.ws.close()
@dataclass
class Token:
access_token: str
refresh_token: str
expires_in: int
def request_token(
client_id: str,
username: str,
password: str,
token_url: str,
ssl_verify: bool = True,
) -> Token | None:
payload = {
"client_id": client_id,
"grant_type": "password",
"username": username,
"password": password,
}
response = request_access_token(token_url, payload, ssl_verify=ssl_verify)
return check_response(response)
def request_access_token(
token_url: str, payload: dict, ssl_verify=True
) -> requests.Response:
response = requests.post(
token_url,
data=payload,
headers={"Content-Type": "application/x-www-form-urlencoded"},
verify=ssl_verify,
)
return response
def check_response(response):
if response.status_code != 200:
print(f"Failed to get token from response {response}")
return None
oauth_resp = response.json()
token = Token(
oauth_resp["access_token"],
oauth_resp["refresh_token"],
oauth_resp["expires_in"],
)
return token
def cli_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="WebSocket Example Client Listener")
parser.add_argument("--host", default=HOST, dest="host", metavar="", help=f"Host url, DEFAULT: {HOST}")
parser.add_argument("-u", "--username", dest="username", metavar="", default=USERNAME, help=f"Username for authentication, default: {USERNAME}")
parser.add_argument("-p", "--password", dest="password", metavar="", default=PASSWORD, help=f"Password for authentication, default: {PASSWORD}")
parser.add_argument("-t", "--endpoint", dest="endpoint", default=ORDER_ENDPOINT, metavar="", help=f"Order API endpoint, default: {ORDER_ENDPOINT}")
return parser.parse_args()
def main():
args = cli_args()
host = args.host
user = args.username
secret = args.password
ws_endpoint = args.endpoint
auth_url = f"https://{host}:{PORT}{AUTH_ENDPOINT}"
ws_url = f"wss://{host}:{PORT}{ws_endpoint}"
token = request_token(CLIENT_ID, user, secret, auth_url, ssl_verify=SSL_VERIFY)
if token is None:
print("Failed to get token")
return
# token is used for authencation with the websocket endpoint
access_token = token.access_token
print("#############################################################")
print(f"Connecting to Websocket endpoint {ws_url}")
print("#############################################################")
ws_client = WebSocketClient(ws_url, token=access_token)
ws_client.run()
if __name__ == "__main__":
main()