Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions data/trades/5_trades.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"timestamp": "2025-08-03 13:06:22.359621", "side": "BUY", "pair": "EURQ/USD", "quantity": 1.0074, "price": 1.1536, "total_value": 1.16213664, "account_id": 5, "base_currency": "EURQ", "quote_currency": "ZUSD", "balances_after": {"EURQ": 6.0074000000000005, "ZUSD": 48.1963899}}
23 changes: 23 additions & 0 deletions kraken_ws/kraken_ws.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,29 @@ def __init__(self, api_key: Optional[str] = None, api_secret: Optional[str] = No

self._running = False

def check_connection(self) -> bool:
"""
Check if the WebSocket connections are active.

Returns:
bool: True if public connection is active, False otherwise.
Also considers account connection status if account has credentials.
"""
# Check public connection
public_connected = (
self.public_ws is not None and
not self.public_ws.closed and
self.is_connected
)

# If no API credentials, only check public connection
if not (hasattr(self.account, 'api_key') and self.account.api_key):
return public_connected

# If API credentials exist, check both public and private connections
account_connected = self.account.connected() if hasattr(self.account, 'connected') else False

return public_connected and account_connected

async def connect(self, private: bool = False):
"""
Expand Down
8 changes: 7 additions & 1 deletion resources/data/settings/settings.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
program:
name: "TradeByte"
version: "2.2.0"
version: "2.2.1"
debug: false
version_notes:
- Version 2.2.1 8/2/2025
- Added check_connection() function to kraken_ws.py
- Added check_connection() function to account.py
- Added get_open_orders() function to kraken_python_client.py
- Added cancel_all_open_orders() function to kraken_python_client.py
14 changes: 14 additions & 0 deletions src/apps/subaccounts/data/accounts/account_5.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"account_id": 5,
"nick_name": "Sample Account",
"balance": {
"ZUSD": 0.0,
"ZEUR": 0.0
},
"created_date": "2025-08-03",
"active": true,
"balances": {
"ZUSD": 50.0,
"EURQ": 0.0
}
}
108 changes: 108 additions & 0 deletions src/clients/kraken_python_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
import pandas as pd
import requests
import time
import urllib.parse
import hashlib
import hmac
import base64
from typing import Dict

"""
This client is used to interact with the rust kraken API.
Expand All @@ -16,6 +21,7 @@ def __init__(self, asset='XBTUSD', error_message=False, api_key=None, api_secret
self.base_url = "https://api.kraken.com/0/public"
self.api_key = api_key
self.api_secret = api_secret
self.api_url = "https://api.kraken.com"

def test_connection(self):
try:
Expand Down Expand Up @@ -333,6 +339,108 @@ def get_my_recent_trades(self, pair=None, since=None, count=None):
if self.error_message:
print(f"KrakenPythonClient.get_my_recent_trades: {e}")
return False
def get_open_orders(self, pair: str = None) -> Dict:
"""Get open orders, optionally filtered by trading pair"""
params = {}
if pair:
params['pair'] = pair

return self._kraken_request("/0/private/OpenOrders", params, self.api_key, self.api_secret)

def _get_kraken_signature(self, urlpath: str, data: Dict, secret: str) -> str:
"""Generate Kraken API signature"""
postdata = urllib.parse.urlencode(data)
encoded = (str(data['nonce']) + postdata).encode()
message = urlpath.encode() + hashlib.sha256(encoded).digest()

mac = hmac.new(base64.b64decode(secret), message, hashlib.sha512)
sigdigest = base64.b64encode(mac.digest())
return sigdigest.decode()

def _kraken_request(self, uri_path: str, data: Dict, api_key: str, api_secret: str) -> Dict:
"""Make authenticated request to Kraken API"""
headers = {}
if api_key and api_secret:
data['nonce'] = str(int(1000 * time.time()))
headers['API-Key'] = api_key
headers['API-Sign'] = self._get_kraken_signature(uri_path, data, api_secret)

req = requests.post(f"{self.api_url}{uri_path}", headers=headers, data=data)
return req.json()

def cancel_all_open_orders(self, pair: str) -> Dict:
"""Cancel all open orders for a specific trading pair"""
# First get all open orders for the pair
open_orders_response = self.get_open_orders(pair)

# Check if the request was successful
if 'error' in open_orders_response and open_orders_response['error']:
return open_orders_response

# Extract order IDs from the response
open_orders = open_orders_response.get('result', {}).get('open', {})

if not open_orders:
return {
'error': [],
'result': {
'count': 0,
'message': f'No open orders found for pair {pair}'
}
}

# Collect all order IDs for the specified pair
order_ids = []
for order_id, order_data in open_orders.items():
# Double-check the pair matches (in case API filtering didn't work perfectly)
order_pair = order_data.get('descr', {}).get('pair', '')
if order_pair == pair or not pair: # Include all if pair filtering failed
order_ids.append(order_id)

if not order_ids:
return {
'error': [],
'result': {
'count': 0,
'message': f'No open orders found for pair {pair}'
}
}

# Cancel orders one by one (more reliable than batch)
cancelled_orders = []
failed_orders = []

for order_id in order_ids:
cancel_params = {
'txid': order_id
}

cancel_response = self._kraken_request(
"/0/private/CancelOrder",
cancel_params,
self.api_key,
self.api_secret
)

if 'error' in cancel_response and cancel_response['error']:
failed_orders.append({
'order_id': order_id,
'error': cancel_response['error']
})
else:
cancelled_orders.append(order_id)

# Return summary response
return {
'error': [],
'result': {
'cancelled_count': len(cancelled_orders),
'failed_count': len(failed_orders),
'cancelled_orders': cancelled_orders,
'failed_orders': failed_orders,
'pair': pair
}
}

def cancel_all_orders(self, asset=None):
"""
Expand Down
Loading