project ready
This commit is contained in:
parent
3b06bc307e
commit
1d34619e7e
4 changed files with 177 additions and 2 deletions
32
README.md
32
README.md
|
@ -1,3 +1,31 @@
|
||||||
# cryptfolio
|
# Crypto Portfolio
|
||||||
|
|
||||||
Quick view of crypto assets...
|
This is a basic script to use `bash | jq` to process the contents of a `.json` "configuration" file and deliver the current status of a portfolio of crypto-currencies based on data retrieved from the [Kucoin API](https://www.kucoin.com/api) (which *requires no key*).
|
||||||
|
|
||||||
|
Results are delivered via an encoded [itty.bitty](https://about.bitty.site) url and can be downloaded as `csv` records.
|
||||||
|
|
||||||
|
[**Here is an example.**](https://itty.bitty.site/#Portfolio/XQAAAAT//////////wAeCEUG0O+oKBdZ2an16qclP3ZWSMUzhiDsEZ6qy1sgvhIq6Hr2L4YPd7IJhqr4o8AZqF9O9RftB9GDuVd2SlkYO7UY2awqwmBdB6MalZZnLcYV3O8NcFqO7TrHGf5CHNaQh3RY3FDPWDwhpMAQixOrVtPbWsnuwOKfsQtPTVqBibnT3EgSReJIx+p7vNOMDKV5s29g6OWtMkpuKgGXpwYnQtx3+8VrHAbsKHgM2MYHKk8sL6rdDCIPZQUWOW19GSrBC629KYV3J6BNWjcXhgW+B64age7uWmielfhcrbFdHJTt9P8PjQuYsHoLt6CELj/qKkzaaGn7ellVvKKm3VMSQx0zI0SGg328iuW6yDF0FNeS3S6sw8PovseMmn6nIg0M31y2WnvDylZVIVVjEXrEsV27XyVWpXiOGeLhmg5aYUqPlrqxBjiKbKUWpEwyoGIYLRXT1Tf2HYQQjXXICXACt69bI8+kHFkG3qyGlVXlZhKqcfa9gDUY9d3aB4OciyuZcy3cJTHZ0jQxqF9xO/Oqrg9RbSYTLsQQYdPyZpj9YprCNak7WcS+AwlyaMuEoNSE+/kq7vlKu9wcC7GRnirrFD12ydrvasGdHPsMFndVWuuKFq4jO7GCSrK6KzPi1yAkZYMsbhm132fgiCY4rBlEQFTwOqHn0TSqgpVFsfGCm7SwUldSHy3zzv0fLRsC9BTTEtbBU2ODylCMKVufr5EcHey76YvhumCd3YCqXf5zXpzPbFRLvi2HkL8Q8nb6Se4mfa5WYyh5hNaQLtyPb3X55iyvvnJmttyjTEhosbW5ucUCzYzb55n7kcImt+srD+YnjDEaERccGLNiFXJT0UUCo5LdUrViU1DbJTFpEEuA+5avLmw3KVmsR1jOdncSmYJ9oeBFpPp2h+Pl1zCDy4igbzKzsC+WJ0A2HM5ODjxfb/Sq5ULPxi+qZg51gmuLldJUofxYxekYESgEIwcL3zH5nqG5DcSlIX0Jtn1OD+7Xgp/NeT0rO97KTVy0yeeEpDytv8hUAkd8exAWtXOS/AfTAxrltVNPwx0ljsmBfWvLFaf+/Cl8jw==)
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
### Update Portfolio
|
||||||
|
|
||||||
|
Update the `wallet.json` file with an array of objects each containing the **token ID**, **amount you have invested**, and **balance** for each of your currencies.
|
||||||
|
|
||||||
|
> Make sure your token IDs match what is expected by the API. ([https://api.kucoin.com/api/v3/currencies](https://www.kucoin.com/docs/rest/spot-trading/market-data/get-currency-list))
|
||||||
|
|
||||||
|
### Execute Script
|
||||||
|
|
||||||
|
Simply run `portfolio.sh` manually or via `cron` as you like.
|
||||||
|
|
||||||
|
The script will read `wallet.json` for the tokens it needs to check and then make calls to the Kucoin API to determine prices, comparing that to your indicated balances and evaluating whether or not you are profiting.
|
||||||
|
|
||||||
|
The results are inserted into `template.html` using placeholders (via `sed`), which is then [encoded in itty.bitty](https://github.com/alcor/itty-bitty/wiki/#generating-links-programmatically) to be generated as a unique but constant webpage.
|
||||||
|
|
||||||
|
> You can bookmark the link, or click the "Download CSV" button (which uses some light JavaScript) to save the results.
|
||||||
|
|
||||||
|
## ntfy Alerts
|
||||||
|
|
||||||
|
While one can simply click on the generated link (or have it delivered any way, really), the `portfolio.sh` script comes pre-built with the functionality to deliver the results via a [ntfy](https://ntfy.sh) service.
|
||||||
|
|
||||||
|
The `wallet.json` file contains configuration options to specify the server and topic for delivery, and a message will be sent making the notification clickable, taking you directly to the results page.
|
||||||
|
|
68
portfolio.sh
Executable file
68
portfolio.sh
Executable file
|
@ -0,0 +1,68 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# current dir
|
||||||
|
dir="$(dirname $(realpath $0))"
|
||||||
|
|
||||||
|
# get files
|
||||||
|
wallet="${dir}/wallet.json"
|
||||||
|
template="${dir}/template.html"
|
||||||
|
|
||||||
|
# list tokens
|
||||||
|
tokens=$(jq -r '.tokens | map(.token) | join(",")' $wallet)
|
||||||
|
|
||||||
|
# fetch prices
|
||||||
|
prices=$(curl "https://api.kucoin.com/api/v1/prices?base=USD¤cies=${tokens}" | \
|
||||||
|
jq '[.data | to_entries[] | {token: .key, price: .value} | .price |= tonumber]')
|
||||||
|
|
||||||
|
# date stamp
|
||||||
|
dts=$(echo -n "As of $(date '+%F %T %:::z')")
|
||||||
|
|
||||||
|
# build portfolio
|
||||||
|
portfolio=$(jq -s '[ .[0] + .[1] | group_by(.token)[] | add ]' \
|
||||||
|
<(echo "$(jq '.tokens' $wallet)") <(echo "$prices"))
|
||||||
|
|
||||||
|
# calculate value
|
||||||
|
calc=$(jq '[.[] | .["value"] = .balance * .price | .["margin"] = .value - .investment | .["movement"] = .margin / .investment]' \
|
||||||
|
<(echo "$portfolio"))
|
||||||
|
|
||||||
|
# create rows
|
||||||
|
readarray -t tokens < <(jq -c '.[]' <(echo $calc))
|
||||||
|
|
||||||
|
for t in "${tokens[@]}"; do
|
||||||
|
tok=$(echo $t | jq '.token' | tr -d '"');
|
||||||
|
bal=$(echo $t | jq '.balance|tonumber');
|
||||||
|
prc=$(echo $t | jq '.price|tonumber');
|
||||||
|
inv=$(echo $t | jq '.investment|tonumber');
|
||||||
|
val=$(echo $t | jq '.value|tonumber');
|
||||||
|
mar=$(echo $t | jq '.margin|tonumber');
|
||||||
|
mov=$(echo $t | jq '.movement|tonumber');
|
||||||
|
|
||||||
|
row=$(echo "${row}<tr><td class=\"left\">${tok}</td><td>${bal}</td><td>"$(printf "$%.2f\n" $prc)"</td><td>"$(printf "$%.2f\n" $inv)"</td><td>"$(printf "$%.2f\n" $val)"</td><td>"$(printf "$%.2f\n" $mar)"</td><td>"$(printf "%.3f\n" $mov)"</td></tr>");
|
||||||
|
csv=$(echo "${csv}"$(echo -n $(date +",['"%F"','"%T"','"%:::z"'"))",'${tok}','${bal}','${prc}','${inv}','${val}','${mar}','${mov}']");
|
||||||
|
|
||||||
|
# Sum up
|
||||||
|
tot_inv=$(echo "${tot_inv:-0}+$inv" | bc);
|
||||||
|
tot_val=$(echo "${tot_val:-0}+$val" | bc);
|
||||||
|
tot_mar=$(echo "${tot_mar:-0}+$mar" | bc);
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
# format array
|
||||||
|
csv=$(echo $csv | sed 's|^,||g')
|
||||||
|
|
||||||
|
# calculate movement
|
||||||
|
tot_mov=$(echo "scale=3 ; $tot_mar / $tot_inv" | bc)
|
||||||
|
|
||||||
|
# fill template
|
||||||
|
page=$(cat $template | sed "s|%row%|$row|g;s|%inv%|"$(printf "$%.2f\n" $tot_inv)"|g;s|%val%|"$(printf "$%.2f\n" $tot_val)"|g;s|%mar%|"$(printf "$%.2f\n" $tot_mar)"|g;s|%mov%|"$(printf "%.4f\n" $tot_mov)"|g;s|%dts%|$dts|g;s|%csv_data%|$csv|g;s|%dts_fln%|"$(echo -n $(date '+%F_%T%:::z'))"|g")
|
||||||
|
|
||||||
|
# encode link
|
||||||
|
itty=$(echo -n $page | lzma -9 | base64 -w0 | xargs -0 printf "https://itty.bitty.site/#Portfolio/%s\n")
|
||||||
|
|
||||||
|
# send signal
|
||||||
|
ntfy=$(jq -r '.ntfy | "\(.server)/\(.topic)"' $wallet)
|
||||||
|
|
||||||
|
curl \
|
||||||
|
-H "title: Portfolio Update" \
|
||||||
|
-H "tags: coin" -H "click: ${itty}" \
|
||||||
|
-d "Click Here" $ntfy
|
60
template.html
Normal file
60
template.html
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Crypto Portfolio</title>
|
||||||
|
<style>
|
||||||
|
table {
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
td, th {
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 2px;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
td.left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Token</th><th>Balance</th><th>Price</th><th>Investment</th><th>Value</th><th>Margin</th><th>Movement</th>
|
||||||
|
</tr>
|
||||||
|
%row%
|
||||||
|
<tr>
|
||||||
|
<td class="left"><b>Total</b></td><td></td><td></td><td><b>%inv%</b></td><td><b>%val%</b></td><td><b>%mar%</b></td><td><b>%mov%</b></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p><i>%dts%</i></p>
|
||||||
|
<button onclick="download_csv_file()"> Download CSV </button>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
var csvFileData = [
|
||||||
|
%csv_data%
|
||||||
|
];
|
||||||
|
|
||||||
|
function download_csv_file() {
|
||||||
|
|
||||||
|
var csv = 'Date,Time,Zone,Token,Balance,Price,Investment,Value,Margin,Movement\n';
|
||||||
|
|
||||||
|
csvFileData.forEach(function(row) {
|
||||||
|
csv += row.join(',');
|
||||||
|
csv += "\n";
|
||||||
|
});
|
||||||
|
|
||||||
|
document.write(csv);
|
||||||
|
|
||||||
|
var hiddenElement = document.createElement('a');
|
||||||
|
hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv);
|
||||||
|
hiddenElement.target = '_blank';
|
||||||
|
|
||||||
|
hiddenElement.download = 'CSV_Portfolio_%dts_fln%.csv';
|
||||||
|
hiddenElement.click();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</html>
|
19
wallet.json
Normal file
19
wallet.json
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"tokens": [
|
||||||
|
{
|
||||||
|
"token": "BTC",
|
||||||
|
"investment": 50,
|
||||||
|
"balance": 0.0008
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"token": "ETH",
|
||||||
|
"investment": 35,
|
||||||
|
"balance": 0.012
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ntfy": {
|
||||||
|
"server": "https://ntfy.sh",
|
||||||
|
"topic": "topic123"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue