Initial commit
This commit is contained in:
174
kraken.py
Normal file
174
kraken.py
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
import http.client
|
||||||
|
import urllib.request
|
||||||
|
import urllib.parse
|
||||||
|
import hashlib
|
||||||
|
import hmac
|
||||||
|
import base64
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
API_KEY = "q1QjOkt6S0oOmmknkuh2MSyBqKE1suEGfNb6DlRm9mUpAhZsz7GFpnx7"
|
||||||
|
API_SECRET = "ZhIrO4Sh5e6khajbXmfGEYvnPE91EerdYXdDiPcJlBAUYNq5G4qr+tF6dwIH8vN/wTlBXCJyAJVZ3RkH4HaVfA=="
|
||||||
|
ASSET_MAP = {
|
||||||
|
"XETH": "ETH",
|
||||||
|
"XXBT": "BTC"
|
||||||
|
}
|
||||||
|
ANSI_RESET = "\033[0m"
|
||||||
|
ANSI_BOLD = "\033[1m"
|
||||||
|
ANSI_GREEN = "\033[32m"
|
||||||
|
ANSI_RED = "\033[31m"
|
||||||
|
ANSI_CYAN = "\033[36m"
|
||||||
|
INTERVAL = 10
|
||||||
|
|
||||||
|
def main():
|
||||||
|
previous_trade_balance = None
|
||||||
|
previous_portfolio = None
|
||||||
|
while True:
|
||||||
|
trade_balance, portfolio = get_account_overview()
|
||||||
|
os.system("clear")
|
||||||
|
print(f"{ANSI_RESET}{ANSI_BOLD}Kraken Pro Portfolio{ANSI_RESET}")
|
||||||
|
print("Currency\tBalance\t\tRate\t\tValue")
|
||||||
|
for investment in portfolio:
|
||||||
|
if previous_portfolio and previous_portfolio[investment] and previous_portfolio[investment]['value'] <= portfolio[investment]['value']:
|
||||||
|
print(f"{ANSI_GREEN}{investment}\t\t{portfolio[investment]['balance']:010.8f}\t${portfolio[investment]['exchange_rate']:010.4f}\t${portfolio[investment]['value']:010.4f}{ANSI_RESET}")
|
||||||
|
elif previous_portfolio and previous_portfolio[investment] and previous_portfolio[investment]['value'] > portfolio[investment]['value']:
|
||||||
|
print(f"{ANSI_RED}{investment}\t\t{portfolio[investment]['balance']:010.8f}\t${portfolio[investment]['exchange_rate']:010.4f}\t${portfolio[investment]['value']:010.4f}{ANSI_RESET}")
|
||||||
|
else:
|
||||||
|
print(f"{ANSI_RESET}{investment}\t\t{portfolio[investment]['balance']:010.8f}\t${portfolio[investment]['exchange_rate']:010.4f}\t${portfolio[investment]['value']:010.4f}{ANSI_RESET}")
|
||||||
|
print(f"{ANSI_RESET}------------------------------------------------------------")
|
||||||
|
if previous_trade_balance and previous_trade_balance <= trade_balance:
|
||||||
|
print(f"{ANSI_GREEN}Total\t\t\t\t\t\t${trade_balance:010.4f}{ANSI_RESET}")
|
||||||
|
elif previous_trade_balance and previous_trade_balance > trade_balance:
|
||||||
|
print(f"{ANSI_RED}Total\t\t\t\t\t\t${trade_balance:010.4f}{ANSI_RESET}")
|
||||||
|
else:
|
||||||
|
print(f"{ANSI_RESET}Total\t\t\t\t\t\t${trade_balance:010.4f}{ANSI_RESET}")
|
||||||
|
time.sleep(INTERVAL)
|
||||||
|
previous_trade_balance = trade_balance
|
||||||
|
previous_portfolio = portfolio
|
||||||
|
|
||||||
|
def get_account_overview():
|
||||||
|
account_balance = get_account_balance()
|
||||||
|
if account_balance['error'] != []:
|
||||||
|
for error in account_balance['error']:
|
||||||
|
raise Exception(error)
|
||||||
|
else:
|
||||||
|
account_balance = account_balance['result']
|
||||||
|
investments = [each for each in account_balance if float(account_balance[each]) > 0]
|
||||||
|
portfolio = {}
|
||||||
|
for currency in investments:
|
||||||
|
if currency in ASSET_MAP:
|
||||||
|
pair = f"{ASSET_MAP[currency]}/USD"
|
||||||
|
else:
|
||||||
|
pair = f"{currency}/USD"
|
||||||
|
ohlc = get_ohlc_data(pair)
|
||||||
|
if ohlc['error'] != []:
|
||||||
|
for error in ohlc['error']:
|
||||||
|
print(f"{error}: {pair}")
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
ohlc = ohlc['result']
|
||||||
|
for pair in ohlc:
|
||||||
|
portfolio[currency] = {
|
||||||
|
'balance': float(account_balance[currency]),
|
||||||
|
'exchange_rate': float(ohlc[pair][-2][4]),
|
||||||
|
'value': float(account_balance[currency]) * float(ohlc[pair][-2][4])
|
||||||
|
}
|
||||||
|
if portfolio[currency]['value'] < 0.01:
|
||||||
|
portfolio.pop(currency)
|
||||||
|
break
|
||||||
|
trade_balance = get_trade_balance()
|
||||||
|
if trade_balance['error'] != []:
|
||||||
|
for error in trade_balance['error']:
|
||||||
|
raise Exception(error)
|
||||||
|
else:
|
||||||
|
trade_balance = float(trade_balance['result']['eb'])
|
||||||
|
return trade_balance, portfolio
|
||||||
|
|
||||||
|
|
||||||
|
def get_ohlc_data(pair):
|
||||||
|
response = request(
|
||||||
|
method="GET",
|
||||||
|
path="/0/public/OHLC",
|
||||||
|
query={
|
||||||
|
"pair": pair,
|
||||||
|
"interval": 5,
|
||||||
|
},
|
||||||
|
environment="https://api.kraken.com",
|
||||||
|
)
|
||||||
|
return json.loads(response.read().decode())
|
||||||
|
|
||||||
|
def get_account_balance():
|
||||||
|
response = request(
|
||||||
|
method="POST",
|
||||||
|
path="/0/private/Balance",
|
||||||
|
public_key=API_KEY,
|
||||||
|
private_key=API_SECRET,
|
||||||
|
environment="https://api.kraken.com",
|
||||||
|
)
|
||||||
|
return json.loads(response.read().decode())
|
||||||
|
|
||||||
|
def get_trade_balance():
|
||||||
|
response = request(
|
||||||
|
method="POST",
|
||||||
|
path="/0/private/TradeBalance",
|
||||||
|
public_key=API_KEY,
|
||||||
|
private_key=API_SECRET,
|
||||||
|
environment="https://api.kraken.com",
|
||||||
|
)
|
||||||
|
return json.loads(response.read().decode())
|
||||||
|
|
||||||
|
def request(method: str = "GET", path: str = "", query: dict | None = None, body: dict | None = None, public_key: str = "", private_key: str = "", environment: str = "") -> http.client.HTTPResponse:
|
||||||
|
url = environment + path
|
||||||
|
query_str = ""
|
||||||
|
if query is not None and len(query) > 0:
|
||||||
|
query_str = urllib.parse.urlencode(query)
|
||||||
|
url += "?" + query_str
|
||||||
|
nonce = ""
|
||||||
|
if len(public_key) > 0:
|
||||||
|
if body is None:
|
||||||
|
body = {}
|
||||||
|
nonce = body.get("nonce")
|
||||||
|
if nonce is None:
|
||||||
|
nonce = get_nonce()
|
||||||
|
body["nonce"] = nonce
|
||||||
|
headers = {}
|
||||||
|
body_str = ""
|
||||||
|
if body is not None and len(body) > 0:
|
||||||
|
body_str = json.dumps(body)
|
||||||
|
headers["Content-Type"] = "application/json"
|
||||||
|
if len(public_key) > 0:
|
||||||
|
headers["API-Key"] = public_key
|
||||||
|
headers["API-Sign"] = get_signature(private_key, query_str+body_str, nonce, path)
|
||||||
|
req = urllib.request.Request(
|
||||||
|
method=method,
|
||||||
|
url=url,
|
||||||
|
data=body_str.encode(),
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
return urllib.request.urlopen(req)
|
||||||
|
|
||||||
|
def get_nonce() -> str:
|
||||||
|
return str(int(time.time() * 1000))
|
||||||
|
|
||||||
|
def get_signature(private_key: str, data: str, nonce: str, path: str) -> str:
|
||||||
|
return sign(
|
||||||
|
private_key=private_key,
|
||||||
|
message=path.encode() + hashlib.sha256(
|
||||||
|
(nonce + data)
|
||||||
|
.encode()
|
||||||
|
).digest()
|
||||||
|
)
|
||||||
|
|
||||||
|
def sign(private_key: str, message: bytes) -> str:
|
||||||
|
return base64.b64encode(
|
||||||
|
hmac.new(
|
||||||
|
key=base64.b64decode(private_key),
|
||||||
|
msg=message,
|
||||||
|
digestmod=hashlib.sha512,
|
||||||
|
).digest()
|
||||||
|
).decode()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user