Skip to content

Commit

Permalink
Merge pull request #13 from olned/develop
Browse files Browse the repository at this point in the history
get_currencies and get_instruments
  • Loading branch information
olned committed Jun 5, 2020
2 parents 73305e3 + 4ca610c commit a447bab
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 32 deletions.
23 changes: 22 additions & 1 deletion examples/deribit_basic_example.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,30 @@
#!/usr/bin/env python
import asyncio
import json
from ssc2ce import Deribit

conn = Deribit()

pending = {}


async def handle_instruments(data: dict):
del pending[data["id"]]
print(json.dumps(data))
if not pending:
await subscribe()


async def handle_currencies(data: dict):
for currency in data["result"]:
symbol = currency["currency"]
id = await conn.get_instruments(symbol, callback=handle_instruments)
pending[id] = symbol


async def get_currencies():
await conn.get_currencies(handle_currencies)


async def subscribe():
await conn.send_public(request={
Expand All @@ -23,7 +44,7 @@ async def handle_subscription(data):
print(f" Deribit Price Index {index_name.upper()}: {price}")


conn.on_connect_ws = subscribe
conn.on_connect_ws = get_currencies
conn.method_routes += [("subscription", handle_subscription)]

loop = asyncio.get_event_loop()
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

setuptools.setup(
name='ssc2ce',
version="0.8.2",
version="0.9.0",
author='Oleg Nedbaylo',
author_email='olned64@gmail.com',
description='A Set of Simple Connectors for access To Cryptocurrency Exchanges',
Expand Down
196 changes: 166 additions & 30 deletions ssc2ce/deribit.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,15 @@ def __init__(self,
]

async def run_receiver(self):
"""
Establish a connection and start the receiver loop.
:return:
"""
self.ws = await self._session.ws_connect(self.ws_api)
if self.on_connect_ws:
await self.on_connect_ws()

# A receiver loop
while self.ws and not self.ws.closed:
message = await self.ws.receive()
self.receipt_time = time()
Expand All @@ -96,19 +101,49 @@ async def run_receiver(self):
if self.on_message:
await self.on_message(message)

async def send_public(self, request):
def close(self):
super()._close()

async def stop(self):
"""
Close connection and break the receiver loop
:return:
"""
await self.ws.close()

async def send_public(self, request: dict, callback=None) -> int:
"""
Send a public request
:param request: Request without jsonrpc and id fields
:param callback: The function that will be called after receiving the query result. Default is None
:return: Request Id
"""
request_id = self.get_id()
request = {
"jsonrpc": "2.0",
"id": request_id,
**request
}
self.requests[request_id] = request
self.logger.info(f"sending:{repr(hide_secret(request))}")
await self.ws.send_json(request)

if callback:
request["callback"] = callback

self.requests[request_id] = request

return request_id

async def send_private(self, request):
async def send_private(self, request: dict, callback=None) -> int:
"""
Send a private request
:param request: Request without jsonrpc and id fields
:param callback: The function that will be called after receiving the query result. Default is None
:return: Request Id
"""

request_id = self.get_id()
access_token = self.auth_params["access_token"]
request["params"]["access_token"] = access_token
Expand All @@ -118,21 +153,38 @@ async def send_private(self, request):
"id": request_id,
**request
}
self.requests[request_id] = request
self.logger.info(f"sending:{repr(hide_secret(request))}")
await self.ws.send_json(request)

if callback:
request["callback"] = callback

self.requests[request_id] = request

return request_id

async def send(self, request):
async def send(self, request: dict, callback=None) -> int:
"""
A wrapper for send_private and send_public, defines the type of request by content.
:param request: Request without jsonrpc and id fields
:param callback: The function that will be called after receiving the query result. Default is None
:return: Request Id
"""
method = request["method"]
if method.starts("public/"):
request_id = await self.send_public(request)
request_id = await self.send_public(request, callback)
else:
request_id = await self.send_private(request)
request_id = await self.send_private(request, callback)

return request_id

async def auth_login(self):
async def auth_login(self) -> int:
"""
Send an authentication request using parameters stored in the constructor
:return: Reuest id
"""
self.auth_type = AuthType.CREDENTIALS

msg = {
Expand All @@ -150,8 +202,9 @@ async def auth_login(self):
request_id = await self.send_public(msg)
return request_id

async def auth_client_credentials(self, client_id, client_secret, scope: str = None):
async def auth_client_credentials(self, client_id, client_secret, scope: str = None) -> int:
"""
Send a credentials authentication request
:param client_id: using the access key
:param client_secret: and access secret that can be found on the API page on the website
Expand All @@ -160,7 +213,7 @@ async def auth_client_credentials(self, client_id, client_secret, scope: str = N
trade:[read, read_write, none],
wallet:[read, read_write, none],
account:[read, read_write, none]
:return:
:return: Request Id
"""

self.auth_type = AuthType.CREDENTIALS
Expand All @@ -183,7 +236,20 @@ async def auth_client_credentials(self, client_id, client_secret, scope: str = N
request_id = await self.send_public(msg)
return request_id

async def auth_password(self, username, password, scope: str = None):
async def auth_password(self, username: str, password: str, scope: str = None) -> int:
"""
Send a password authentication request
:param username: User name
:param password: Password
:param scope:
connection, session, session:name,
trade:[read, read_write, none],
wallet:[read, read_write, none],
account:[read, read_write, none]
:return: Request Id
"""

self.auth_type = AuthType.PASSWORD
msg = {
"method": "public/auth",
Expand All @@ -203,7 +269,12 @@ async def auth_password(self, username, password, scope: str = None):
request_id = await self.send_public(msg)
return request_id

async def auth_refresh_token(self):
async def auth_refresh_token(self) -> int:
"""
Send a refresh token request
:return: Request Id
"""
msg = {
"method": "public/auth",
"params": {
Expand All @@ -215,7 +286,12 @@ async def auth_refresh_token(self):
request_id = await self.send_public(msg)
return request_id

async def auth_logout(self):
async def auth_logout(self) -> int:
"""
Send a logout request
:return: Request Id
"""
msg = {
"method": "private/logout",
"params": {}
Expand All @@ -224,15 +300,54 @@ async def auth_logout(self):
request_id = await self.send_private(msg)
return request_id

async def set_heartbeat(self, interval: int = 15):
async def set_heartbeat(self, interval: int = 15) -> int:
"""
:param interval:
:return:
"""
request_id = await self.send_public({"method": "public/set_heartbeat", "params": {"interval": interval}})
return request_id

async def disable_heartbeat(self):
async def disable_heartbeat(self) -> int:
"""
:return:
"""
request_id = await self.send_public({"method": "public/disable_heartbeat", "params": {}})
return request_id

async def handle_message(self, message: aiohttp.WSMessage):
async def get_currencies(self, callback=None):
"""
Send a request for a list of cryptocurrencies supported by the API
:param callback:
:return: Request Id
"""
return await self.send_public(request=dict(method="public/get_currencies", params={}), callback=callback)

async def get_instruments(self, currency: str, kind: str = None, callback=None) -> int:
"""
Send a request for a list available trading instruments
:param currency: The currency symbol: BTC or ETH
:param kind: Instrument kind: future or option, if not provided instruments of all kinds are considered
:param callback:
:return: Request Id
"""
request = {"method": "public/get_instruments",
"params": {
"currency": currency
}}
if kind:
request["kind"] = kind

return await self.send_public(request=request, callback=callback)

async def handle_message(self, message: aiohttp.WSMessage) -> None:
"""
:param message:
:return:
"""
if message.type == aiohttp.WSMsgType.TEXT:
data = message.json()
self.logger.debug(f"handling:{repr(hide_secret(data))}")
Expand All @@ -250,7 +365,11 @@ async def handle_message(self, message: aiohttp.WSMessage):
request_id = data["id"]
request = self.requests.get(request_id)
if request:
await self.handle_response(request=request, response=data)
if "callback" in request:
callback = request["callback"]
await callback(data)
else:
await self.handle_response(request=request, response=data)

del self.requests[request_id]
else:
Expand All @@ -266,36 +385,59 @@ async def handle_message(self, message: aiohttp.WSMessage):
else:
self.logger.warning(f"Unknown type of message {repr(message)}")

async def empty_handler(self, **kwargs):
async def empty_handler(self, **kwargs) -> None:
"""
A default handler
:param kwargs:
:return:
"""
self.logger.debug(f"{repr(kwargs)}")

async def handle_response(self, request, response):
async def handle_response(self, request, response) -> None:
"""
:param request:
:param response:
:return:
"""
method = request["method"]
handler = resolve_route(method, self.response_routes)

if handler:
return await handler(request=request, response=response)

self.logger.warning(f"Unhandled method:{method} response:{repr(response)} to request:{repr(request)}.")
return

async def handle_method_message(self, data):
async def handle_method_message(self, data) -> None:
"""
:param data:
:return:
"""
method = data["method"]
handler = resolve_route(method, self.method_routes)

if handler:
return await handler(data)

self.logger.warning(f"Unhandled message:{repr(data)}.")
return

async def handle_heartbeat(self, data):
"""
:param data:
:return:
"""
if data["params"]["type"] == "test_request":
await self.send_public({"method": "public/test", "params": {}})

return
async def handle_auth(self, request, response) -> None:
"""
async def handle_auth(self, request, response):
:param request:
:param response:
:return:
"""
self.auth_params = response["result"]
grant_type = request["params"]["grant_type"]
if grant_type == "":
Expand All @@ -311,9 +453,3 @@ async def handle_auth(self, request, response):
pass
else:
self.logger.error(f"Unknown grant_type {repr(hide_secret(request))} : {repr(hide_secret(response))}")

def close(self):
super()._close()

async def stop(self):
await self.ws.close()

0 comments on commit a447bab

Please sign in to comment.