Getting Kraken tickers
This commit is contained in:
292
API/Krakenfutures_api.py
Normal file
292
API/Krakenfutures_api.py
Normal file
@@ -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'))
|
||||
0
API/__init__.py
Normal file
0
API/__init__.py
Normal file
BIN
API/__pycache__/Krakenfutures_api.cpython-313.pyc
Normal file
BIN
API/__pycache__/Krakenfutures_api.cpython-313.pyc
Normal file
Binary file not shown.
BIN
API/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
API/__pycache__/__init__.cpython-313.pyc
Normal file
Binary file not shown.
3
conf/config.ini
Normal file
3
conf/config.ini
Normal file
@@ -0,0 +1,3 @@
|
||||
[KRAKEN]
|
||||
api_key = i2fnn1LqzTqfoChwdoak/JbrpNytaCb6OAAvkgvdMbB+f9yR+mY7b49H
|
||||
api_secret = 8UgJ4fYIs2BIBAHuy0f2kRBWF+4qcrxcMtF9bAQAA/7u+dZzqbZskNxsM9pWDQGELx2wq67Bqx+QdphHvCYitg==
|
||||
77
main.py
Normal file
77
main.py
Normal file
@@ -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)
|
||||
Reference in New Issue
Block a user