-
-
Save dncgst/2beccff999fd29ad4e14f42d3d2f4c42 to your computer and use it in GitHub Desktop.
Giacenza Media Annua for Revolut accounts
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
#!/bin/bash | |
# Compute the Giacenza Media Annua (GMA) of a Revolut account, required by the Italian INPS. | |
# Dependencies: awk, GNU date, getopts, xargs | |
# Computation method: https://bit.ly/3avDLu3 | |
# Thread on Revolut forum: https://bit.ly/3511e5h | |
# Assumptions: | |
# 1. Dates are in YYYY-MM-DD format. The Revolut app uses your locale, so if this is set | |
# to it-IT, then this assumption is already satisfied. Otherwise, convert the dates in | |
# your CSV to ISO 8601 before using the script. | |
# 2. The time interval considered is between January 1 and December 31 of the same year | |
# (since it is an annual value). | |
# 3. Transactions are in ascending date order. | |
# 4. The actual balance of day D is the last registered during D. This is because the GMA | |
# is a weighted arithmetic mean, and the entries of the CSV are sorted by date. Hence, | |
# if T is an array of transactions registered during D, with |T| > 1, then all entries | |
# in T except the last one have null weight, because they have been on the account for | |
# less than one day. Thus, they do not affect the GMA, and can be safely skipped. | |
version="2022.05" | |
completed_date=4 | |
balance=10 | |
separator="," | |
use_decimal_point=false | |
print_usage() { | |
printf "Usage: `basename "$0"` [options]\n%-2sOptions:\n" | |
printf "%-4s-c \n%-6s'Completed Date' column number\n" | |
printf "%-6sDefault: $completed_date\n" | |
printf "%-4s-a \n%-6s'Balance' column number\n%-6sDefault: $balance\n" | |
printf "%-4s-s \n%-6sSeparator character of the input CSV\n" | |
printf "%-6sDefault: '$separator'\n" | |
printf "%-4s-d \n%-6sUse point instead of comma as decimal separator\n" | |
printf "%-6sDefault: $use_decimal_point\n" | |
} | |
if [[ $# -lt 1 ]] | |
then | |
print_usage | |
exit 1 | |
fi | |
while getopts "cbs:dvh" flag; do | |
case "${flag}" in | |
c) completed_date="${OPTARG}" ;; | |
b) balance="${OPTARG}" ;; | |
s) separator="${OPTARG}" ;; | |
d) use_decimal_point=true ;; | |
v) printf "Version: $version\n" | |
exit 0 ;; | |
*) print_usage | |
exit 0 ;; | |
esac | |
done | |
result=0 | |
prev_date="" | |
year="" | |
get_days() { | |
# input values are in seconds, and there are 60 * 60 * 24 = 86400 seconds in a day | |
days=$((($1 - $2) / 86400)) | |
days=${days#-} | |
days=$(($days + 1)) | |
printf $days | |
} | |
mycmd="awk -F '$separator' '(!unique[\$$completed_date]++ && NR > 1) {print \$$completed_date,\$$balance}' '$1'" | |
while read curr_date | |
do | |
d1="" | |
d2s="" | |
if [[ ! $prev_date ]] | |
then | |
year=$(date -d "${curr_date% *}" "+%Y") | |
d1=$(date -d "$year-01-01" +%s) | |
d1s="1 Jan $year" | |
prev_date="$year-01-01" | |
printf "Calculating the Giacenza Media Annua of the year $year\n\n" | |
fi | |
if [[ ! $d1 ]] | |
then | |
d1=$(date -d "${prev_date%% *}" +%s) | |
fi | |
d2=$(date -d "${curr_date%% *}" +%s) | |
days="$(get_days $d1 $d2)" | |
money=`echo ${curr_date##* } | xargs` | |
# approximated to 2 decimal values for ease of reading, comment to see exact values | |
money=$(awk "BEGIN {printf(\"%.2f\", $money); exit}") | |
p=$(awk "BEGIN {print $money*$days; exit}") | |
result=$(awk "BEGIN {print $result+$p; exit}") | |
d1s=`echo ${prev_date%% *} | xargs` | |
if [[ ! $d2s ]] | |
then | |
d2s=`echo ${curr_date%% *} | xargs` | |
fi | |
printf "$d1s to $d2s: $money x $days = $p\n" | |
prev_date=$curr_date | |
done <<< `eval $mycmd` | |
if [[ ! "$d2s" = "$year-12-31" ]] # last date is not the last day of the year | |
then | |
days="$(get_days $(date -d "$year-12-31" +%s) $d2)" | |
p=$(awk "BEGIN {print $money*$days; exit}") | |
result=$(awk "BEGIN {print $result+$p; exit}") | |
printf "$d2s to $year-12-31: $money x $days days = $p\n" | |
fi | |
result=`awk "BEGIN {print $result/365; exit}"` | |
if !$use_decimal_point | |
then | |
result=${result/\./\,} | |
fi | |
if [[ "$result" -lt 0 ]] # if the GMA is negative, the value to declare must be 0 | |
then | |
result_ceil=0 | |
else | |
result_ceil=${result%.*} | |
result_ceil=$((result_ceil + 1)) | |
fi | |
printf "\nResult: $result, to be rounded up to $result_ceil\n" | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment