Binance stream trade via websocket problem - python

I am getting no response from the Binance api when executing the following code, is there anything that I could have missed here? do I need to create an account in order to get stream data through the api?
import json
import websocket
socket='wss://stream.binance.com:9443'
def on_open(ws):
print("opened")
subscribe_message = {
"method": "SUBSCRIBE",
"params":
[
"btcusdt#trade",
"btcusdt#depth"
],
"id": 1
}
ws.send(json.dumps(subscribe_message))
def on_message(ws, message):
print("received a message")
print(json.loads(message))
def on_close(ws):
print("closed connection")
ws = websocket.WebSocketApp(socket, on_open=on_open, on_message=on_message, on_close=on_close)
ws.run_forever()

In order to make your code work you just need to add /ws at the end of the websocket url:
socket = 'wss://stream.binance.com:9443/ws'

What I can see is, that you are not using the path after the hostname and port!
See here what is missing:
https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#general-wss-information
Raw streams are accessed at /ws/streamName>
Combined streams are accessed at /stream?streams=streamName1/streamName2/streamName3
If you want to subscribe to streams via websocket.send() then you have to create a combined stream first and then send the payload to subscribe the streams.
But you dont have to reinvent the wheel. There are different ready implementations for python.
I recommend you this lib I have written: https://github.com/oliver-zehentleitner/unicorn-binance-websocket-api
This will save you a lot of work :)
Best regards,
Oliver

Related

Python/Quart: how to send while awaiting a response?

Using Python 3.9 and Quart 0.15.1, I'm trying to create a websocket route that will listen on a websocket for incoming request data, parse it, and send outbound response data to a client, over and over in a loop - until and unless the client sends a JSON struct with a given key "key" in the payload, at which point we can move on to further processing.
I can receive the initial inbound request from the client, parse it, and send outbound responses in a loop, but when I try to gather the second payload to parse for the presence of "key", things fall apart. It seems I can either await websocket.send_json() or await websocket.receive(), but not both at the same time.
The Quart docs suggest using async-timeout to (https://pgjones.gitlab.io/quart/how_to_guides/request_body.html?highlight=timeout) to timeout if the body of a request isn't received in the desired amount of time, so I thought I'd try to send messages in a while loop, with a brief period of time spent in await websocket.receive() before timing out if a response wasn't receive()'d:
#app.websocket('/listen')
async def listen():
payload_requested = await websocket.receive()
parsed_payload_from_request = json.loads(payload_requested)
while "key" not in parsed_payload_from_request:
response = "response string"
await websocket.send_json(response)
async with timeout (1):
payload_requested = await websocket.receive()
parsed_payload_from_request = json.loads(payload_requested)
if "key" == "present":
do_stuff()
...but that doesn't seem to work, an asyncio.exceptions.CancelledError is thrown by the timeout.
I suspect there's a better way to accomplish this using futures and asyncio, but it's not clear to me from the docs.
I think your code is timing out waiting for a message from the client. You may not need it in this case.
I've tried to write out code as you've described your needs and got this,
#app.websocket('/listen')
async def listen():
while True:
data = await websocket.receive_json()
if "key" in data:
await websocket.send_json({"key": "response"})
else:
do_stuff()
return # websocket closes
does it do what you want, if not what goes wrong?

how to send video stream using webrtc

I'm new to webrtc,i liked to make simple application where client send video and audio stream to server using webrtc and from server i will use the video frame for detecting object in the video using opencv, i have implemented simple server side code using docs of aiortc package,but i was stuck,because the on_track never called i dont know whats wrong with my code
Client code
const { RTCPeerConnection, RTCSessionDescription } = window;
socket = io()
const peerConnection = new RTCPeerConnection()
const offerAsync = peerConnection.createOffer();
offerAsync.then(async offer=>{
await peerConnection.setLocalDescription(new RTCSessionDescription(offer));
socket.emit("connect_to_server", {
offer
});
})
socket.on("connect_to_server_response",async function(data){
navigator.mediaDevices.getUserMedia({
video:true,
audio:true
}).then(async stream=>{
const video = document.getElementById("video")
await peerConnection.setRemoteDescription(
data
);
console.log(data)
stream.getTracks().forEach(track => {
console.log("this is track")
peerConnection.addTrack(track, stream)
});
console.log(video)
video.srcObject = stream
video.play()
}).catch(err=>{
console.log(err)
console.log("something went wrong please connect administrator, error code = [100]")
})
})
console.log("working");
Server code
async def res(data):
offer = RTCSessionDescription(sdp=data["offer"]["sdp"], type=data["offer"]["type"])
pc = RTCPeerConnection()
#pc.on("track")
def on_track(track):
print("on Track")
print(track.kind)
await pc.setRemoteDescription(offer)
answer = await pc.createAnswer()
await pc.setLocalDescription(answer)
emit("connect_to_server_response", {"sdp": pc.localDescription.sdp, "type": pc.localDescription.type})
#socketio.on("connect_to_server")
def connect_to_server(data):
asyncio.set_event_loop(asyncio.SelectorEventLoop())
asyncio.get_event_loop().run_until_complete(res(data))
print(data)
print(request.sid)
print("new user joint")
It looks like you are exchanging the SDP messages fine and in the right order.
Your issue is because you are never exchanging ICE candidates. In order to establish a connection, you will need to emit ice candidate messages from the js client to the python client as well as from the python client to the js client.
You need to define an event handler for RTCPeerConnection.onicecandidate (this will start getting fired once you call createOffer) on both sides and emit these candidates that you're receiving. Then you have to RTCPeerConnection.addIceCandidate once you receive the candidates.
Once you successfully do that, you should be able to get the on_track event.
Check out these links for reference:
What are ICE Candidates and how do the peer connection choose between them?
RTCIceCandidate
Simple webrtc workflow sample code

Return JSON Array Websockets data feed

I am trying to get the message that is being returned by and apparently it is more of a
<function on_message at 0x00000138D6488F28>
How can I get it to return json message instead of the one above?
Below is my code.
from websocket import WebSocketApp
from json import dumps, loads
from pprint import pprint
URL = "wss://ws-feed.gdax.com"
def on_message(_, message):
pprint(loads(message))
print
def on_open(socket):
params = {
"type": "subscribe",
"channels": [{"name": "ticker", "product_ids": ["BTC-EUR"]}]
}
socket.send(dumps(params))
def main():
ws = WebSocketApp(URL, on_open=on_open, on_message=on_message)
while True:
print(ws.on_message)
time.sleep(1)
if __name__ == '__main__':
main()
def on_message(_, message): # this will be called everytime a message is recieved
pprint(loads(message))
print
def main():
ws = WebSocketApp(URL, on_open=on_open, on_message=on_message)
ws.run_forever() # this will run the ws main_loop that is builtin and listen for the connection and messages
ps thats a cool ws service ... I always enjoy finding new public ws services
Well, it prints function, because you literally are printing out the function, not calling it. But that function is not meant to be called by you, but it will be called by the WebSocketApp when you actually have a message and someone has connected to your socket.
If you, however, really want to call it, you can probably just do it by changing print(ws.on_message) to ws.on_message(None, 'your message').

Websocket to useable data in Python - get price from GDAX websocket feed

I am trying to get the last price data to use which is easy enough using polling on /ticker endpoint i.e.
rawticker = requests.get('https://api.gdax.com/products/BTC-EUR/ticker')
json_data = json.loads(rawticker.text)
price = json_data['price']
but the GDAX API discourages polling. How could I get the same information using websocket. How could I get the following code to run just once and then extract the price information.
from websocket import WebSocketApp
from json import dumps, loads
from pprint import pprint
URL = "wss://ws-feed.gdax.com"
def on_message(_, message):
"""Callback executed when a message comes.
Positional argument:
message -- The message itself (string)
"""
pprint(loads(message))
print
def on_open(socket):
"""Callback executed at socket opening.
Keyword argument:
socket -- The websocket itself
"""
params = {
"type": "subscribe",
"channels": [{"name": "ticker", "product_ids": ["BTC-EUR"]}]
}
socket.send(dumps(params))
def main():
"""Main function."""
ws = WebSocketApp(URL, on_open=on_open, on_message=on_message)
ws.run_forever()
if __name__ == '__main__':
main()
Thanks for any help.
Pulling is discouraged when you want to have real-time updates. In that case, it is recommended to use Web Sockets. In your case, however, running the code once and exiting, it is fine to use the pull endpoint.
To answer your question anyway. on_message's first argument is the WebSocketApp you can simply add this line to close it after receiving the first message.
def on_message(ws, message):
"""Callback executed when a message comes.
Positional argument:
message -- The message itself (string)
"""
pprint(loads(message))
ws.close()
Tip
Requests library has built-in .json() that you can use directly on the .get() return
import requests
rawticker = requests.get('https://api.gdax.com/products/BTC-EUR/ticker').json()
price = rawticker['price']
print(price)

Waiting for websocket.receive consumer in django-channels

How to wait for a response from client after sending the client something using django-channels?
Whenever Group.send() is called from function send_to_client() and upon receiving the message by client, send_to_client() is expecting a response back from client which is getting received on websocket.receive channel.
Is there a way to return the response_msg in send_to_client() function?
Now I have reached here
Sample Code for consumers.py:
def ws_receive(message):
response_msg = message.content['text']
return response_msg
def send_to_client(param1, param2, param3):
Group.send({
"text" : json.dumps({
"First" : param1,
"Second" : param2,
})
})
So once the message reaches at the client side, the client will send a response back to the server which will be received by the ws_receive(message) function through the websocket.receive channel which is defined in the urls.py file,
channel_patterns = [
route("websocket.receive", ws_receive),
...
]
Is there a way to do this so that my function would look like this?
def send_to_client(...):
Group.send(...)
response_msg = #response message from client
Since you are recieving via a websocket, I am not sure if you would be able to even tell if the recieving thing is directly as a response for your request. I would rather put an id variable or something in the ongoing request, and maybe ask the client to put that id in the response as well. That might require both the sender and reciever to know the value of id as well (probably store in the db?)
Also, it do not seem logical to be blocked waiting for the response from websocket as well.

Categories