cryptos.sh

Same as stocks.sh but for cryptocurrency
-list_coint.txt list of existing cryptocurrency
This commit is contained in:
2025-01-13 21:02:33 +01:00
parent 85362cacda
commit cae388ac91
2 changed files with 5447 additions and 0 deletions

447
cryptos.sh Executable file
View File

@@ -0,0 +1,447 @@
#!/usr/bin/env bash
#set -e
### https://coinmarketcap.com/api/documentation/v1/#operation/getV2CryptocurrencyQuotesLatest
VERSION="v1.0"
### TODO
# Locale compliant
# Localization
redbold="\033[1;31m"
red="\033[0;31m"
greenbold="\033[1;32m"
green="\033[0;32m"
yellowbold="\033[1;33m"
yellow="\033[0;33m"
bgd="\033[1;4;31m"
bold="\033[1m"
#bold_under="\033[1;4m"
italic="\033[3m"
ita_under="\033[3;4m"
underline="\033[4m"
reset="\033[0m"
### Variables
ScriptArgs=( "$@" )
ScriptPath="$(readlink -f "$0")" # /Users/user/Documents/Scripts/stocks/crypto.sh
ScriptWorkDir="$(dirname "$ScriptPath")" # /Users/user/Documents/Scripts/stocks
####### Configurations ######
### Credentials
### Put the CMC_API_KEY= in .env file
dotenv () {
set -a
# shellcheck disable=SC1091
[ -f "$ScriptWorkDir/.env" ] && . "$ScriptWorkDir/.env" || echo -e "${red}\nNo .env file found ! CMC_API_KEY needed !!${reset}"
set +a
}
dotenv
### or in the script
#CMC_API_KEY=
if [ -z $CMC_API_KEY ]; then
echo -e "\n${red}No CMC_API_KEY key found !${reset}"
help
exit
fi
### Config file
cryptos_list=$HOME/.cryptos.yaml
# Free version does not support more than 1 currency.
# So, 2 requests for Euro and Dollar exchange rates
# Default currency (MUST BE THE SAME as unit_cost in ~/.cryptos.yaml)
currency="EUR"
symb_currency="€"
# Secondary currency (optionnal)
currency2="USD"
symb_currency2="$"
color_display=true # (true/false)
####### /Configurations ######
### Requierements
if ! $(type jq >/dev/null 2>&1); then
echo -e "${red}'jq' is not in the PATH. (See: https://stedolan.github.io/jq/)${reset}"
exit 1
fi
if ! $(type yq >/dev/null 2>&1); then
echo -e "${red}'yq' is not in the PATH. (See: https://github.com/kislyuk/yq)${reset}"
exit 1
fi
cat < /dev/null > /dev/tcp/1.1.1.1/53
if [[ $? -ne 0 ]]; then
echo -e "\n${red}No Internet connection !${reset}"
echo -e "Exit !"
exit 1
fi
####### Functions ######
# Help
Help() {
echo -e "${bold}cryptos $VERSION${reset}\n"
echo "Syntax: cryptos.sh [<coin>]"
echo
echo "Examples: cryptos.sh BTC ETH SOLE"
echo " cryptos.sh (need ~/.cryptos.yaml file)"
echo
echo "Options:"
echo "-h Print this Help."
echo
echo "Requires a CoinMarketCap API key"
echo "https://coinmarketcap.com/api/"
echo "Requires jq and yq installed"
echo
echo "\$currency variable (default)(line 39) must be the same as unit_cost in ~/.cryptos.yaml"
}
# Check if number is positive (or 0) or negative
CheckSign() {
local n="$1" # Capture the number passed as a parameter.
if [ $(echo "$n < 0" | bc -l) -eq 1 ] ; then
#printf "%+17.13f : %s\n" "$n" "negative"
p="-"
else
#printf "%+17.13f : %s\n" "$n" "positive or zero"
p="+"
fi
echo "$p"
}
LANG=C
LC_NUMERIC=C
### API
URLPREFIX="https://"
URLBASE="pro-api.coinmarketcap.com/"
URLPOSTFIX="v1/cryptocurrency/"
DATAURL=${URLPREFIX}${URLBASE}${URLPOSTFIX}
### Load (or download) a list of existing cryptos
#list_coins=$(curl --silent -H "X-CMC_PRO_API_KEY: $CMC_API_KEY" -H "Accept: application/json" -d "start=1&limit=5&convert=USD" -G "${DATAURL}listings"/latest)
#echo "$list_coins" | jq -r '.data[].name, .data[].symbol'
#echo "$list_coins" | jq -r '.data[] | {name: .name, symbol: .symbol}'
#list_coins=$(curl --silent -H "X-CMC_PRO_API_KEY: $CMC_API_KEY" -H "Accept: application/json" -d "start=1&limit=5&convert=USD" -G "${DATAURL}listings"/latest | jq -r '.data[] | .symbol')
get_list_coins (){
START_TIME=`echo $(($(date +%s%N)/1000000))`
curl --silent -H "X-CMC_PRO_API_KEY: $CMC_API_KEY" -H "Accept: application/json" -d "start=1&limit=5000&convert=USD" -G "${DATAURL}listings"/latest | jq -r '.data[] | .symbol' > "$ScriptWorkDir/list_coins.txt"
status=$?
END_TIME=`echo $(($(date +%s%N)/1000000))`
ELAPSED_TIME=$(($END_TIME - $START_TIME))
[ $status -eq 0 ] && echo -e "${green}Request to CMC API listings $currency successfull in $ELAPSED_TIME ms !${reset}" || echo -e "${red}Request to CMC API listing $currency failed !${reset}"
}
echo -e "${greenbold}Bash Crypto${reset} $VERSION"
echo -e "Using CoinMarketCap API ($DATAURL)\n"
if [ -f "$ScriptWorkDir/list_coins.txt" ]; then
timestamp_current=$(date +"%s")
timestamp_file=$(date -r list_coins.txt +"%s")
since=$(($((timestamp_current - timestamp_file))/(60*60*24)))
# Re-Download coins list every 15 days
((since > 15)) && { echo -e "${green}Download coins list...${reset}"; get_list_coins; }
list_coins=$(cat "$ScriptWorkDir/list_coins.txt")
[ $? -eq 0 ] && echo -e "${green}Load coins list...${reset}" || echo -e "${red}Fail to load coins list...${reset}"
else
get_list_coins
list_coins=$(cat "$ScriptWorkDir/list_coins.txt")
[ $? -eq 0 ] && echo -e "${green}Load coins list...${reset}" || echo -e "${red}Fail to load coins list...${reset}"
fi
### Read cryptos from ~/.cryptos.yaml config file
cryptos=()
# from arguments
if [ -n "$ScriptArgs" ]; then
REGEXP='^[a-zA-Z0-9,_ ]+$'
q="$@"
if [[ "$q" =~ $REGEXP ]]; then
q=${q//,/\ }
q=${q//_/\ }
cryptos+=($q)
else
Help
exit 1
fi
# Check if crypto passed as argument really exist
for val in ${!cryptos[@]}
do
k="${cryptos[$val]}"
#echo $val # index
#echo $k # value
if [[ ! "$list_coins" == *"$k"* ]]; then
echo -e "${red}$k is not a crypto. Remove it !${reset}"
unset cryptos[$val]
fi
done
# Recreate the array, because the gaps have to disappear
cryptos=("${cryptos[@]}")
echo -e "${green}Found ${#cryptos[@]} coins to display: ${cryptos[@]} ...${reset}"
# from ~/.cryptos.yaml config file
else
if [ -f "$cryptos_list" ]; then
cl=$(cat $cryptos_list)
a=$(yq '.watchlist' <<< $cl)
#a=$(cat $cryptos_list | yq '.watchlist') # Cryptos to display
status=$?
#[ $? -eq 0 ] && echo -e "${green}Load coins list to display...${reset}" || echo -e "${red}Fail to load coins list to display...${reset}"
b=$(yq '.lot' <<< $cl)
#b=$(cat $cryptos_list | yq '.lots') # Cryptos i've purchased
c=$((yq '.lots[] | select(.quantity != 0) | .symbol' | tr '\n' ' ') <<< $cl)
#c=$(cat $cryptos_list | yq '.lots[] | select(.quantity != 0) | .symbol' | tr '\n' ' ')
u=$(echo "$c" | wc -w)
[ $? -eq 0 ] && echo -e "${green}Found $u coins purchased: $c ...${reset}" || echo -e "${red}Fail to load coins list purchased...${reset}"
else
echo -e "${red}$cryptos_list not present !${reset}"
echo ""
fi
while IFS= read -r obj; do
stock=${obj:2}
cryptos+=("$stock")
done < <(echo "$a")
[ $status -eq 0 ] && echo -e "${green}Found ${#cryptos[@]} coins to display: ${cryptos[@]} ...${reset}" || echo -e "${red}No coins to display...${reset}"
if [ -z "$cryptos" ]; then
echo "Usage: ./crypto.sh"
echo " - add coins to ~/.cryptos.yaml file"
exit 1
fi
fi
nb_cryptos=${#cryptos[@]}
symbols=$(echo ${cryptos[@]} | tr [:space:] ',' | awk '{ print substr( $0, 1, length($0)-1 ) }')
# Free version does not support more than 1 currency.
# So, 2 requests for Euro and Dollar exchange rates
if [ -n "$currency2" ]; then
# 2 currency
START_TIME=`echo $(($(date +%s%N)/1000000))`
request=$(curl --silent -H "X-CMC_PRO_API_KEY: $CMC_API_KEY" -H "Accept: application/json" -d "convert=$currency" -G "${DATAURL}quotes"/latest?symbol=$symbols)
status=$?
END_TIME=`echo $(($(date +%s%N)/1000000))`
ELAPSED_TIME=$(($END_TIME - $START_TIME))
[ $status -eq 0 ] && echo -e "${green}Request to CMC API with currency $currency successfull in $ELAPSED_TIME ms !${reset}" || echo -e "${red}Request to CMC API with currency $currency failed !${reset}"
START_TIME=`echo $(($(date +%s%N)/1000000))`
request2=$(curl --silent -H "X-CMC_PRO_API_KEY: $CMC_API_KEY" -H "Accept: application/json" -d "convert=$currency2" -G "${DATAURL}quotes"/latest?symbol=$symbols)
status2=$?
END_TIME=`echo $(($(date +%s%N)/1000000))`
ELAPSED_TIME=$(($END_TIME - $START_TIME))
[ $status2 -eq 0 ] && echo -e "${green}Request to CMC API with currency $currency2 successfull in $ELAPSED_TIME ms !${reset}" || echo -e "${red}Request to CMC API with currency $currency2 failed !${reset}"
echo -e "${green}Displaying quotes for ${cryptos[@]} ...${reset}\n"
printf "${bold}| %-15s | %-4s | %-9s | %-9s | %-14s | %-7s | %-7s | %-7s | %-7s | %-7s | %-25s ${reset}\n" "Nom" "Symb" " Prix ($symb_currency)" " Prix ($symb_currency2)" " Volume" " % 24h" " % 7j" " % 30j" " % 60j" " % 90j" "Dernière mise-à-jour"
printf "${bold}%141s${reset}\n" " " | tr ' ' '-'
else
# 1 currency
START_TIME=`echo $(($(date +%s%N)/1000000))`
request=$(curl --silent -H "X-CMC_PRO_API_KEY: $CMC_API_KEY" -H "Accept: application/json" -d "convert=$currency" -G "${DATAURL}quotes"/latest?symbol=$symbols)
status=$?
END_TIME=`echo $(($(date +%s%N)/1000000))`
ELAPSED_TIME=$(($END_TIME - $START_TIME))
[ $status -eq 0 ] && echo -e "${green}Request to CMC API with currency $currency successfull in $ELAPSED_TIME ms !${reset}" || echo -e "${red}Request to CMC API with currency $currency failed !${reset}"
echo -e "${green}Displaying quotes for ${cryptos[@]} ...${reset}\n"
printf "${bold}| %-15s | %-4s | %-9s | %-14s | %-7s | %-7s | %-7s | %-7s | %-7s | %-25s ${reset}\n" "Nom" "Symb" " Prix ($symb_currency)" " Volume" " % 24h" " % 7j" " % 30j" " % 60j" " % 90j" "Dernière mise-à-jour"
printf "${bold}%141s${reset}\n" " " | tr ' ' '-'
fi
# Check if NO_COLOR is set to disable colorization
if [ -z "$NO_COLOR" ]; then
: "${COLOR_GREEN:=$'\e[32m'}"
: "${COLOR_RED:=$'\e[31m'}"
: "${COLOR_RESET:=$'\e[00m'}"
fi
#b=$(cat $cryptos_list | yq '.lots')
#echo "$b"
#d=$(cat $cryptos_list | yq '.lots[]')
#echo "$d"
#c=$(cat $cryptos_list | yq '.lots[] | select(.quantity != 0) | .symbol')
counter=0
while [ $counter -lt $nb_cryptos ]; do
c=$(echo "${cryptos[counter]}")
filter=".$c"
#echo "value (crypto): $c"
# devise 1 (EUR)
coin=$(echo "$request" | jq -r '.data' | jq -r $filter)
if [ "$coin" == null ]; then
echo -e "${red}$c n'est pas une crypto !${reset}"
((counter++))
continue
fi
name=$(echo "$coin" | jq -r '.name')
symbol=$(echo "$coin" | jq -r '.symbol')
slug=$(echo "$coin" | jq -r '.slug')
max_supply=$(echo "$coin" | jq -r '.max_supply') # Volume (Mrd) ($2,07 Mrd)
circulating_supply=$(echo "$coin" | jq -r '.circulating_supply') # Supply en circulation (Mio BNB) (144,01 Mio BNB)
total_supply=$(echo "$coin" | jq -r '.total_supply') # Montant total fourni (Mio BNB) (144,01 Mio BNB)
cmc_rank=$(echo "$coin" | jq -r '.cmc_rank') # Rang (N°5)
filter2=".$currency"
quote=$(echo "$coin" | jq -r '.quote'| jq -r $filter2)
price=$(echo "$quote" | jq -r '.price')
volume_24h=$(echo "$quote" | jq -r '.volume_24h')
percent_change_24h=$(echo "$quote" | jq -r '.percent_change_24h')
percent_change_7d=$(echo "$quote" | jq -r '.percent_change_7d')
percent_change_30d=$(echo "$quote" | jq -r '.percent_change_30d')
percent_change_60d=$(echo "$quote" | jq -r '.percent_change_60d')
percent_change_90d=$(echo "$quote" | jq -r '.percent_change_90d')
last_updated=$(echo "$quote" | jq -r '.last_updated') # 2025-01-07T16:35:00.000Z UTC (ZULU)
last_updated_fr=$(date --date="$last_updated" +"%d/%m/%Y %H:%M:%S %Z")
market_cap=$(echo "$quote" | jq -r '.market_cap') # Capitalisation (Mrd) ($103,47 Mrd ~= €95,81 Mrd)
market_cap_dominance=$(echo "$quote" | jq -r '.market_cap_dominance') # Dominance sur le marché (%) (2,94%)
fully_diluted_market_cap=$(echo "$quote" | jq -r '.fully_diluted_market_cap') # Cap. du marché totlalement diluée (Mrd) ($103,47 Mrd ~= €95,81 Mrd)
# devise 2 (USD)
if [ -n "$currency2" ]; then
coin2=$(echo "$request2" | jq -r '.data' | jq -r $filter)
filter3=".$currency2"
quote2=$(echo "$coin2" | jq -r '.quote' | jq -r $filter3)
price2=$(echo "$quote2" | jq -r '.price')
fi
: <<'END_COMMENT'
blabla
END_COMMENT
# Check cryptos we have (from .cryptos.yaml)
z=$(cat $cryptos_list | yq '.lots[] | select(.symbol == "'${c}'")')
### OK ###
#z=$(yq '.[] | select(.symbol == "'${c}'")' <<< "$b")
#echo "z: $z"
if [ ! -z "$z" ]; then
quantity=$(yq '.quantity' <<< $z)
else
quantity=0
fi
### /OK ###
# Côté variables
#COLOR_24h=$([ $(CheckSign "$percent_change_24h") == "+" ] && echo ${COLOR_GREEN} || echo ${COLOR_RED})
#COLOR_7d=$([ $(CheckSign "$percent_change_7d") == "+" ] && echo ${COLOR_GREEN} || echo ${COLOR_RED})
#COLOR_30d=$([ $(CheckSign "$percent_change_30d") == "+" ] && echo ${COLOR_GREEN} || echo ${COLOR_RED})
#COLOR_60d=$([ $(CheckSign "$percent_change_60d") == "+" ] && echo ${COLOR_GREEN} || echo ${COLOR_RED})
#COLOR_90d=$([ $(CheckSign "$percent_change_90d") == "+" ] && echo ${COLOR_GREEN} || echo ${COLOR_RED})
# Côté mise-en-page
COLOR_24h=$([ $(CheckSign "$percent_change_24h") == "+" ] && echo ${green} || echo ${red})
COLOR_7d=$([ $(CheckSign "$percent_change_7d") == "+" ] && echo ${green} || echo ${red})
COLOR_30d=$([ $(CheckSign "$percent_change_30d") == "+" ] && echo ${green} || echo ${red})
COLOR_60d=$([ $(CheckSign "$percent_change_60d") == "+" ] && echo ${green} || echo ${red})
COLOR_90d=$([ $(CheckSign "$percent_change_90d") == "+" ] && echo ${green} || echo ${red})
if [ -n "$currency2" ]; then
# 2 currency
if [ "$color_display" == true ];then
# With % colors
printf "${yellowbold}| %-15s | %-4s | %'9.2f | %'9.2f | %'14d |${reset}${COLOR_24h} %+6.1f%% ${COLOR_RESET}${yellowbold}|${COLOR_RESET}${COLOR_7d} %+6.1f%% ${COLOR_RESET}${yellowbold}|${COLOR_RESET}${COLOR_30d} %+6.1f%% ${COLOR_RESET}${yellowbold}|${COLOR_RESET}${COLOR_60d} %+6.1f%% ${COLOR_RESET}${yellowbold}|${COLOR_RESET}${COLOR_90d} %+6.1f%% ${COLOR_RESET}${yellowbold}| %-25s ${reset}\n" \
"$name" "$symbol" "$price" "$price2" "$volume_24h" "$percent_change_24h" "$percent_change_7d" "$percent_change_30d" "$percent_change_60d" "$percent_change_90d" "$last_updated_fr" 2>/dev/null
else
# Without colors
printf "| %-15s | %-4s | %'9.2f | %'9.2f | %'14d | %+6.1f%% | %+6.1f%% | %+6.1f%% | %+6.1f%% | %+6.1f%% | %-25s \n" "$name" "$symbol" "$price" "$price2" "$volume_24h" "$percent_change_24h" "$percent_change_7d" "$percent_change_30d" "$percent_change_60d" "$percent_change_90d" "$last_updated_fr" 2>/dev/null
fi
else
# 1 currency
if [ "$color_display" == true ];then
# With % colors
printf "${yellowbold}| %-15s | %-4s | %'9.2f | %'14d |${reset}${COLOR_24h} %+6.1f%% ${COLOR_RESET}${yellowbold}|${COLOR_RESET}${COLOR_7d} %+6.1f%% ${COLOR_RESET}${yellowbold}|${COLOR_RESET}${COLOR_30d} %+6.1f%% ${COLOR_RESET}${yellowbold}|${COLOR_RESET}${COLOR_60d} %+6.1f%% ${COLOR_RESET}${yellowbold}|${COLOR_RESET}${COLOR_90d} %+6.1f%% ${COLOR_RESET}${yellowbold}| %-25s ${reset}\n" \
"$name" "$symbol" "$price" "$volume_24h" "$percent_change_24h" "$percent_change_7d" "$percent_change_30d" "$percent_change_60d" "$percent_change_90d" "$last_updated_fr" 2>/dev/null
else
# Without colors
printf "| %-15s | %-4s | %'9.2f | %'14d | %+6.1f%% | %+6.1f%% | %+6.1f%% | %+6.1f%% | %+6.1f%% | %-25s \n" "$name" "$symbol" "$price" "$volume_24h" "$percent_change_24h" "$percent_change_7d" "$percent_change_30d" "$percent_change_60d" "$percent_change_90d" "$last_updated_fr" 2>/dev/null
fi
fi
: <<'END_COMMENT2'
END_COMMENT2
if (( $(bc <<< "$quantity > 0") )); then
quantity=$(yq '.quantity' <<<$z)
unit_cost=$(yq '.unit_cost' <<<$z) # EUR
purchased=$(echo "$quantity * $unit_cost" | bc -l)
valuations=$(echo "$quantity * $price" | bc -l)
profit=$(echo "$valuations - $purchased" | bc -l)
performance=$(echo "($valuations / $purchased - 1) * 100" | bc -l)
# quantity -> Disponible
# unit_cost -> Coût moyen
# purchased -> Acheté
# valuations -> Valoris.
# profit -> +/- value
# performance -> Perf.
printf "| %-11s | %-9s | %-10s | %-9s | %-9s | %-8s \n" "Disponible" "Coût moyen" "Acheté" "Valoris." "+/- value" "Perf." 2>/dev/null
if (( $(bc <<< "$performance > 0") )); then
printf "${green}| %11s | %10.2f | %9.2f | %9.2f | %9.2f | %8.2f%% ${reset}\n\n" "$quantity" "$unit_cost" "$purchased" "$valuations" "$profit" "$performance" 2>/dev/null
else
printf "${red}| %11s | %10.2f | %9.2f | %9.2f | %9.2f | %8.2f%% ${reset}\n\n" "$quantity" "$unit_cost" "$purchased" "$valuations" "$profit" "$performance" 2>/dev/null
fi
else
quantity=0
unit_cost=0
purchased=0
valuations=0
profit=0
fi
((counter++))
done
echo -e "\n${italic}Script finished in $SECONDS seconds.${reset}"