Last active
July 4, 2024 07:58
-
-
Save unrelentingfox/66e586fb2d397bf45d5291bea9adcaf7 to your computer and use it in GitHub Desktop.
A python script that queries all of your historic trades and calculates the average price you purchased coins at. This was a quick script based on the examples found here: https://docs.kraken.com/rest/. I am open to feedback!!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/local/bin/python3 | |
import base64 | |
import hashlib | |
import hmac | |
import json | |
import os | |
import requests | |
import time | |
import urllib.parse | |
# SAMPLE OUTPUT | |
# TICKER AVG COST LAST PRICE GAIN/LOSS | |
# XETHZUSD 4187.51 3911.61 -6.59% | |
# KAVAUSD 5.90 5.38 -8.88% | |
# DOTUSD 40.06 36.15 -9.78% | |
# XXBTZUSD 56039.83 49928.40 -10.91% | |
# XDGUSD 0.48 0.43 -9.75% | |
# Read Kraken API key and secret stored in environment variables | |
api_url = "https://api.kraken.com" | |
api_key = os.environ['api_key_KRAKEN'] | |
api_sec = os.environ['api_sec_KRAKEN'] | |
def get_kraken_signature(urlpath, data, secret): | |
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() | |
# Attaches auth headers and returns results of a POST request | |
def kraken_request(uri_path, data, api_key, api_sec): | |
headers = {} | |
headers['API-Key'] = api_key | |
# get_kraken_signature() as defined in the 'Authentication' section | |
headers['API-Sign'] = get_kraken_signature(uri_path, data, api_sec) | |
req = requests.post((api_url + uri_path), headers=headers, data=data) | |
return req | |
def check_errors(resp): | |
if resp["error"]: | |
print("There were errors with the request:") | |
print(resp["error"]) | |
exit(1) | |
def get_average_cost(): | |
resp = kraken_request('/0/private/TradesHistory', { | |
"nonce": str(int(1000*time.time())), | |
"trades": True | |
}, api_key, api_sec).json() | |
check_errors(resp) | |
trade_history = resp["result"]["trades"] | |
average_cost = {} | |
total_vol = {} | |
total_cost = {} | |
for trade_key in trade_history: | |
trade = trade_history[trade_key] | |
ttype = trade["type"] | |
currency_pair = trade["pair"] | |
volume = float(trade["vol"]) | |
cost = float(trade["cost"]) | |
fee = float(trade["fee"]) | |
if ttype == "buy": | |
total_vol[currency_pair] = total_vol.get(currency_pair, 0.0) + volume | |
total_cost[currency_pair] = total_cost.get(currency_pair, 0.0) + (cost + fee) | |
elif ttype == "sell": | |
total_vol[currency_pair] = total_vol.get(currency_pair, 0.0) - volume | |
total_cost[currency_pair] = total_cost.get(currency_pair, 0.0) - (cost - fee) | |
for currency_pair in total_vol: | |
if total_vol[currency_pair] > 0.0: | |
average_cost[currency_pair] = total_cost[currency_pair] / total_vol[currency_pair] | |
return average_cost | |
def get_last_price(currency_pairs): | |
last_price = {} | |
for currency_pair in currency_pairs: | |
resp = requests.get('https://api.kraken.com/0/public/Trades?pair=%s' % currency_pair).json() | |
check_errors(resp) | |
last_price[currency_pair] = float(resp["result"][currency_pair][-1][0]) | |
return last_price | |
def calc_gain_loss_percent(average_cost, last_price): | |
gain_loss_percent = {} | |
for currency_pair in average_cost: | |
gain_loss_percent[currency_pair] = (last_price[currency_pair] - average_cost[currency_pair]) / average_cost[currency_pair] * 100 | |
return gain_loss_percent | |
def display_info(average_cost, last_price, gain_loss_percent): | |
fcolumns = "{0:<12} {1:<12} {2:<12} {3:<12}" | |
ffloat = "{:.2f}" | |
fpercent = ffloat+"%" | |
print(fcolumns.format("TICKER", "AVG COST", "LAST PRICE", "GAIN/LOSS")) | |
for currency_pair in average_cost: | |
print(fcolumns.format( | |
currency_pair, | |
ffloat.format(average_cost[currency_pair]), | |
ffloat.format(last_price[currency_pair]), | |
fpercent.format(gain_loss_percent[currency_pair]) | |
)) | |
average_cost = get_average_cost() | |
last_price = get_last_price(average_cost.keys()) | |
gain_loss_percent = calc_gain_loss_percent(average_cost, last_price) | |
display_info(average_cost, last_price, gain_loss_percent) | |
Hello Dustin,
I am wondering if you can give me a tip how to fix this error:
Error: Invalid base64-encoded string: number of data characters (85) cannot be 1 more than a multiple of 4
It's happening when I try to execute the code.
Thanks Dustin for the good work!
I have added a few extra features (sorry for the sloppy code. Python is not my native language) here: https://gist.github.com/DVN237294/4f40133b79926dd598333580a9f5d82f
- Original script only fetched the previous 50 trades at most. This now loops through all trades in history (that kraken exposes)
- Added some basic api limiting to adhere to krakens limits (seemed like it was actually not necessary in my case. Not sure why)
- Prints the received trades and total trade count
- Changed from floats to decimals to avoid monetary rounding errors
- Added a few more columns to output:
TOTAL VOL
,TOTAL COST
,TOTAL FEES
,MIN PRICE
andMAX PRICE
@DVN237294 Thanks for the collaboration!
I want to note that I no longer use this script since there are services online that do this for free. I'm using Koinly currently, but there are other options too.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I use my fiat currency to invest into some coins and thus, the trade tab is empty. Any way to adapt this for the information under the kraken.com/u/history/ledger section? This looks like this: https://pasteboard.co/zXG7FEhc0WXL.png