From 79e784fb734e5ac4be7bd2e292309529e1fed64d Mon Sep 17 00:00:00 2001 From: Arnaud Barth Date: Thu, 1 Jan 2026 19:46:07 +0100 Subject: [PATCH] Getting Kraken tickers --- API/Krakenfutures_api.py | 292 ++++++++++++++++++ API/__init__.py | 0 .../Krakenfutures_api.cpython-313.pyc | Bin 0 -> 13434 bytes API/__pycache__/__init__.cpython-313.pyc | Bin 0 -> 140 bytes conf/config.ini | 3 + main.py | 77 +++++ 6 files changed, 372 insertions(+) create mode 100644 API/Krakenfutures_api.py create mode 100644 API/__init__.py create mode 100644 API/__pycache__/Krakenfutures_api.cpython-313.pyc create mode 100644 API/__pycache__/__init__.cpython-313.pyc create mode 100644 conf/config.ini create mode 100644 main.py diff --git a/API/Krakenfutures_api.py b/API/Krakenfutures_api.py new file mode 100644 index 0000000..2737996 --- /dev/null +++ b/API/Krakenfutures_api.py @@ -0,0 +1,292 @@ +import time +import base64 +import hashlib +import hmac +import json +import urllib.request as urllib2 +import urllib.parse as urllib +import ssl + + +class KrakenFutureClient(object): + def __init__(self, api_key="", api_secret="", timeout=10, checkCertificate=True, useNonce=False): + self.apiPath = 'https://futures.kraken.com' + self._api_key = api_key + self._api_secret = api_secret + self.timeout = timeout + self.nonce = 0 + self.checkCertificate = checkCertificate + self.useNonce = useNonce + + ''' public endpoints ''' + + # returns all instruments with specifications + def get_instruments(self): + endpoint = "/derivatives/api/v3/instruments" + return self.make_request("GET", endpoint)['instruments'] + + # returns market data for all instruments + def get_tickers(self): + endpoint = "/derivatives/api/v3/tickers" + return self.make_request("GET", endpoint) + + # returns the entire order book of a futures + def get_orderbook(self, symbol): + endpoint = "/derivatives/api/v3/orderbook" + postUrl = "symbol=%s" % symbol + return self.make_request("GET", endpoint, postUrl=postUrl) + + # returns historical data for futures and indices + def get_history(self, symbol, lastTime=""): + endpoint = "/derivatives/api/v3/history" + if lastTime != "": + postUrl = "symbol=%s&lastTime=%s" % (symbol, lastTime) + else: + postUrl = "symbol=%s" % symbol + return self.make_request("GET", endpoint, postUrl=postUrl) + + ''' private endpoints ''' + + # returns key account information + # Deprecated because it returns info about the Futures margin account + # Use get_accounts instead + def get_account(self): + endpoint = "/derivatives/api/v3/account" + return self.make_request("GET", endpoint) + + # returns key account information + def get_accounts(self): + endpoint = "/derivatives/api/v3/accounts" + return self.make_request("GET", endpoint)['accounts'] + + # places an order + def send_order(self, orderType, symbol, side, size, limitPrice, stopPrice=None, clientOrderId=None): + endpoint = "/derivatives/api/v3/sendorder" + postBody = "orderType=%s&symbol=%s&side=%s&size=%s&limitPrice=%s" % ( + orderType, symbol, side, size, limitPrice) + + if orderType == "stp" and stopPrice is not None: + postBody += "&stopPrice=%s" % stopPrice + + if clientOrderId is not None: + postBody += "&cliOrdId=%s" % clientOrderId + + return self.make_request("POST", endpoint, postBody=postBody) + + # places an order + def send_order_1(self, order): + endpoint = "/derivatives/api/v3/sendorder" + postBody = urllib.urlencode(order) + return self.make_request("POST", endpoint, postBody=postBody) + + # edit an order + def edit_order(self, edit): + endpoint = "/derivatives/api/v3/editorder" + postBody = urllib.urlencode(edit) + return self.make_request("POST", endpoint, postBody=postBody) + + # cancels an order + def cancel_order(self, order_id=None, cli_ord_id=None): + endpoint = "/derivatives/api/v3/cancelorder" + + if order_id is None: + postBody = "cliOrdId=%s" % cli_ord_id + else: + postBody = "order_id=%s" % order_id + + return self.make_request("POST", endpoint, postBody=postBody) + + # cancel all orders + def cancel_all_orders(self, symbol=None): + endpoint = "/derivatives/api/v3/cancelallorders" + if symbol is not None: + postbody = "symbol=%s" % symbol + else: + postbody = "" + + return self.make_request("POST", endpoint, postBody=postbody) + + # cancel all orders after + def cancel_all_orders_after(self, timeoutInSeconds=60): + endpoint = "/derivatives/api/v3/cancelallordersafter" + postbody = "timeout=%s" % timeoutInSeconds + + return self.make_request("POST", endpoint, postBody=postbody) + + # places or cancels orders in batch + def send_batchorder(self, jsonElement): + endpoint = "/derivatives/api/v3/batchorder" + postBody = "json=%s" % jsonElement + return self.make_request("POST", endpoint, postBody=postBody) + + # returns all open orders + def get_openorders(self): + endpoint = "/derivatives/api/v3/openorders" + return self.make_request("GET", endpoint) + + # returns filled orders + def get_fills(self, lastFillTime=""): + endpoint = "/derivatives/api/v3/fills" + if lastFillTime != "": + postUrl = "lastFillTime=%s" % lastFillTime + else: + postUrl = "" + return self.make_request("GET", endpoint, postUrl=postUrl) + + # returns all open positions + def get_openpositions(self): + endpoint = "/derivatives/api/v3/openpositions" + return self.make_request("GET", endpoint) + + # sends an xbt withdrawal request + def send_withdrawal(self, targetAddress, currency, amount): + endpoint = "/derivatives/api/v3/withdrawal" + postBody = "targetAddress=%s¤cy=%s&amount=%s" % ( + targetAddress, currency, amount) + return self.make_request("POST", endpoint, postBody=postBody) + + # returns xbt transfers + def get_transfers(self, lastTransferTime=""): + endpoint = "/derivatives/api/v3/transfers" + if lastTransferTime != "": + postUrl = "lastTransferTime=%s" % lastTransferTime + else: + postUrl = "" + return self.make_request("GET", endpoint, postUrl=postUrl) + + # returns all notifications + def get_notifications(self): + endpoint = "/derivatives/api/v3/notifications" + return self.make_request("GET", endpoint) + + # makes an internal transfer + def transfer(self, fromAccount, toAccount, unit, amount): + endpoint = "/derivatives/api/v3/transfer" + postBody = "fromAccount=%s&toAccount=%s&unit=%s&amount=%s" % ( + fromAccount, toAccount, unit, amount) + return self.make_request("POST", endpoint, postBody=postBody) + + # accountlog csv + def get_accountlog(self): + endpoint = "/api/history/v2/accountlogcsv" + return self.make_request("GET", endpoint) + + def _get_partial_historical_elements(self, elementType, since=None, contToken=None): + endpoint = "/api/history/v2/%s" % elementType + + if contToken is not None: + return self.make_request_raw("GET", endpoint, postUrl="continuationToken=%s" % contToken) + else: + if since is not None: + return self.make_request_raw("GET", endpoint, postUrl="since=%s" % since) + + return self.make_request_raw("GET", endpoint) + + def _get_historical_elements(self, elementType, since=None): + elements = [] + + more = True + contToken = None + + while more: + res = self._get_partial_historical_elements(elementType, since, contToken) + body = json.loads(res.read().decode('utf-8')) + elements = elements + body['elements'] + + if res.headers['is-truncated'] is None or res.headers['is-truncated'] == "false": + more = False + contToken = None + else: + contToken = res.headers['next-continuation-token'] + + elements.sort(key=lambda el: el['timestamp'], reverse=True) + return elements + + # historical orders after a certain point in reverse chronological order + def get_historical_orders(self, since=None): + return self._get_historical_elements('orders', since) + + # recent orders in reverse chronological order + def get_recent_orders(self): + return self.get_historical_orders(None) + + # historical executions after a certain point in reverse chronological order + def get_historical_executions(self, since=None): + return self._get_historical_elements('executions', since) + + # recent executions in reverse chronological order + def get_recent_executions(self): + return self.get_historical_executions(None) + + # signs a message + def sign_message(self, endpoint, postData, nonce=""): + if endpoint.startswith('/derivatives'): + endpoint = endpoint[len('/derivatives'):] + + # step 1: concatenate postData, nonce + endpoint + message = postData + nonce + endpoint + + # step 2: hash the result of step 1 with SHA256 + sha256_hash = hashlib.sha256() + sha256_hash.update(message.encode('utf8')) + hash_digest = sha256_hash.digest() + + # step 3: base64 decode apiPrivateKey + secretDecoded = base64.b64decode(self._api_secret) + + # step 4: use result of step 3 to has the result of step 2 with HMAC-SHA512 + hmac_digest = hmac.new(secretDecoded, hash_digest, + hashlib.sha512).digest() + + # step 5: base64 encode the result of step 4 and return + return base64.b64encode(hmac_digest) + + # creates a unique nonce + def get_nonce(self): + # https://en.wikipedia.org/wiki/Modulo_operation + self.nonce = (self.nonce + 1) & 8191 + return str(int(time.time() * 1000)) + str(self.nonce).zfill(4) + + # sends an HTTP request + def make_request_raw(self, requestType, endpoint, postUrl="", postBody=""): + # create authentication headers + postData = postUrl + postBody + + if self.useNonce: + nonce = self.get_nonce() + signature = self.sign_message(endpoint, postData, nonce=nonce) + authentHeaders = {"APIKey": self._api_key, + "Nonce": nonce, "Authent": signature} + else: + signature = self.sign_message(endpoint, postData) + authentHeaders = { + "APIKey": self._api_key, "Authent": signature} + + authentHeaders["User-Agent"] = "cf-api-python/1.0" + + # create request + if postUrl != "": + url = self.apiPath + endpoint + "?" + postUrl + else: + url = self.apiPath + endpoint + + request = urllib2.Request(url, str.encode(postBody), authentHeaders) + request.get_method = lambda: requestType + + # read response + if self.checkCertificate: + response = urllib2.urlopen(request, timeout=self.timeout) + else: + ctx = ssl.create_default_context() + ctx.check_hostname = False + ctx.verify_mode = ssl.CERT_NONE + response = urllib2.urlopen( + request, context=ctx, timeout=self.timeout) + + # return + return response + + # sends an HTTP request and read response body + def make_request(self, requestType, endpoint, postUrl="", postBody=""): + output = self.make_request_raw(requestType, endpoint, postUrl, postBody) + return json.loads(output.read().decode('utf-8')) \ No newline at end of file diff --git a/API/__init__.py b/API/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/API/__pycache__/Krakenfutures_api.cpython-313.pyc b/API/__pycache__/Krakenfutures_api.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dcdebd1ec41c7786064a12f84f1acdf8451f7925 GIT binary patch literal 13434 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 literal 0 HcmV?d00001 diff --git a/conf/config.ini b/conf/config.ini new file mode 100644 index 0000000..e1aa6b7 --- /dev/null +++ b/conf/config.ini @@ -0,0 +1,3 @@ +[KRAKEN] +api_key = i2fnn1LqzTqfoChwdoak/JbrpNytaCb6OAAvkgvdMbB+f9yR+mY7b49H +api_secret = 8UgJ4fYIs2BIBAHuy0f2kRBWF+4qcrxcMtF9bAQAA/7u+dZzqbZskNxsM9pWDQGELx2wq67Bqx+QdphHvCYitg== \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..73ab97e --- /dev/null +++ b/main.py @@ -0,0 +1,77 @@ +import configparser +import os +import sys + +# ------------------------------------------------------------------ +# 1. Gestion des imports depuis le dossier ./API +# ------------------------------------------------------------------ +sys.path.append(os.path.join(os.path.dirname(__file__), 'API')) + +try: + from API.Krakenfutures_api import KrakenFutureClient +except ImportError: + # Alternative si le dossier API n'est pas vu comme un module + from Krakenfutures_api import KrakenFutureClient + +# ------------------------------------------------------------------ +# 2. Lecture de la configuration +# ------------------------------------------------------------------ +config = configparser.ConfigParser() +config_path = os.path.join(os.path.dirname(__file__), 'conf', 'config.ini') + +# Vérification que le fichier existe +if not os.path.exists(config_path): + raise FileNotFoundError(f"Le fichier de configuration est introuvable ici : {config_path}") + +config.read(config_path) + +# Récupération des clés +try: + api_key = config['KRAKEN']['api_key'] + api_secret = config['KRAKEN']['api_secret'] +except KeyError as e: + raise ValueError(f"Erreur de lecture du config.ini. La clé ou la section est manquante : {e}") + +# ------------------------------------------------------------------ +# 3. Initialisation du Client et Test +# ------------------------------------------------------------------ +if __name__ == "__main__": + print("Initialisation du client Kraken Futures...") + + # Création de l'instance du client + kraken_client = KrakenFutureClient( + api_key=api_key, + api_secret=api_secret + ) + + try: + print("Tentative de connexion à l'API...") + response = kraken_client.get_tickers() + + # Vérification si la clé 'tickers' existe + if 'tickers' in response: + tickers_list = response['tickers'] + print("Connexion réussie !") + + if len(tickers_list) > 0: + # On prend le premier élément de la liste + first_ticker = tickers_list[0] + + # On affiche le contenu de ce premier ticker + print("\n--- Exemple de premier ticker reçu ---") + print(first_ticker) + + # Si vous voulez afficher spécifiquement le nom du symbole (souvent 'symbol' ou 'pair') + # Vous pouvez faire : print(f"Symbole : {first_ticker.get('symbol', 'Inconnu')}") + else: + print("La liste des tickers est vide.") + + else: + print("Réponse reçue, mais format inattendu (pas de clé 'tickers') :", response) + + except Exception as e: + print(f"Une erreur est survenue lors de l'appel API : {e}") + + # Pour tester un appel PRIVÉ (nécessite que les clés soient valides) + # accounts = kraken_client.get_accounts() + # print(accounts) \ No newline at end of file