function do_trade { # Info for log g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@" # needed vars local f_ASSET=$1 local f_CURRENCY=$2 local f_QUANTITY=$3 local f_ACTION=$4 # buy or sell local f_COMMENT=$5 local f_DATE=$(date '+%F_%H-%M-%S') local f_ASSET_HIST_FILE="asset-histories/${f_ASSET}${f_CURRENCY}.history.csv" local f_link="https://www.coingecko.com/de/munze/$(egrep -i ^${f_ASSET}, COINGECKO_IDS | cut -d, -f2)" # get stock exchange specific infos for trade (e.g. f_QUANTITY_LOT_CUT; f_MIN_NOTIONAL) $TOKEN_INFO_CMD $f_ASSET $f_CURRENCY $f_QUANTITY local f_QUANTITY=${f_QUANTITY_LOT_CUT} #### Workaround for f_QUANTITY_LOT_CUT by buy more and directly sell g_echo_note "Checking for need of QUANTITY_LOT_CUT Workaround (${f_QUANTITY_LOT_CUT} > ${f_MIN_NOTIONAL})" if [ $(echo "${f_QUANTITY_LOT_CUT} > ${f_MIN_NOTIONAL}" | bc -l) -eq 0 ] && [ ${f_ACTION} = sell ] then # add 0.5 to f_MIN_NOTIONAL and trading fee local f_MIN_NOTIONAL_WITH_FEE=$(echo "${f_MIN_NOTIONAL}+${FEE}+0.5" | bc -l) g_echo_note "Doing QUANTITY_LOT_CUT Workaround - buying ${f_MIN_NOTIONAL_WITH_FEE} ${f_ASSET} ${f_CURRENCY}" do_trade ${f_ASSET} ${f_CURRENCY} ${f_MIN_NOTIONAL_WITH_FEE} buy "Workaround for selling values under QUANTITY_LOT_CUT - buy +MIN_NOTIONAL" || return 1 local f_QUANTITY=$(echo "${f_QUANTITY}+${f_MIN_NOTIONAL}" | bc -l) fi if [ "${f_ACTION}" = "buy" ] then # check for enough balance for trade get_balances local f_CURRENCY_BALANCE=$(egrep "^${f_CURRENCY}," EXCHANGE_GET_BALANCES_CMD_OUT | cut -d"," -f2) g_echo_note "Checking for enough balance for trade (${f_CURRENCY_BALANCE} > ${f_QUANTITY})" if [ $(echo "${f_CURRENCY_BALANCE} > ${f_QUANTITY}" | bc -l) -eq 0 ] then local f_note="Not enough balance for trade (${f_CURRENCY_BALANCE} > ${f_QUANTITY}) :${f_COMMENT} ${FUNCNAME} $@" g_echo_note "$f_note" g_signal-notify "$f_note" return 1 fi fi # prepare trading command local f_CMDFILE="trade-histories/${f_DATE}-${f_CURRENCY}-${f_MIN_NOTIONAL}-TRADE_CMD" echo "${TRADE_CMD}" | perl -pe "s/ACTION/${f_ACTION}/; s/TOKEN/${f_ASSET}${f_CURRENCY}/; s/QUANTITY/${f_QUANTITY}/" >${f_CMDFILE} # trade g_echo_note "Command: $(cat ${f_CMDFILE})" #g_runcmd g_retrycmd sh ${f_CMDFILE} >${f_CMDFILE}_OUT . ${f_CMDFILE} cat ${g_tmp}/API_CMD_OUT >${f_CMDFILE}_OUT g_echo_note "Command Output: $(cat ${f_CMDFILE}_OUT)" # workaround for "insufficient balance" error. lower quantity in 0.1 steps and try again (for values loosing while selling) if [ "${f_ACTION}" = "sell" ] && grep -q "Account has insufficient balance for requested action." ${f_CMDFILE}_OUT then g_echo_note "workaround for \"insufficient balance\" error." local f_tries=10 local f_try=1 until (grep -q "FILLED" ${f_CMDFILE}_OUT) do sleep 1 f_QUANTITY=$(echo "$f_QUANTITY-0.1" | bc -l | sed 's/^\./0./;') g_echo_note "lower $f_QUANTITY by -0.1" echo "${TRADE_CMD}" | perl -pe "s/ACTION/${f_ACTION}/; s/TOKEN/${f_ASSET}${f_CURRENCY}/; s/QUANTITY/${f_QUANTITY}/" >${f_CMDFILE} #g_runcmd g_retrycmd sh ${f_CMDFILE} >${f_CMDFILE}_OUT . ${f_CMDFILE} cat ${g_tmp}/API_CMD_OUT >${f_CMDFILE}_OUT [ $f_try -eq $f_tries ] && break ((f_try=f_try+1)) done fi # Check return and log trade f_STATUS=$(cat ${f_CMDFILE}_OUT | grep '^{' | jq -r .status) local f_trade_info_msg="TRADE - ${f_ACTION} ${f_ASSET}${f_CURRENCY} ${f_link} Complete Overview: https://bot.ds9.dedyn.io/ Comment: ${f_COMMENT}" if [ "${f_STATUS}" = "FILLED" ] then g_echo_note "TRADE SUCCESSFUL!" local f_PRICE=$(cat ${f_CMDFILE}_OUT | grep '^{' | jq -r .fills[].price | head -n1) local f_COMMISSION=$(cat ${f_CMDFILE}_OUT | grep '^{' | jq -r .fills[].commission) | head -n1 local f_COMMISSIONASSET=$(cat ${f_CMDFILE}_OUT | grep '^{' | jq -r .fills[].commissionAsset | head -n1) echo "${f_DATE},${f_ACTION},${f_CMDFILE}_OUT,${f_QUANTITY} ${f_CURRENCY},${f_PRICE},${f_COMMISSION} ${f_COMMISSIONASSET},${f_COMMENT}" | head -n1 >>trade-histories/${f_ASSET}${f_CURRENCY}.history.csv if [ "${f_ACTION}" = "buy" ] then if echo ${f_COMMENT} | grep -q "Workaround for selling values under QUANTITY_LOT_CUT" then echo "${f_DATE},${f_ACTION},${f_CMDFILE}_OUT,${f_QUANTITY} ${f_CURRENCY},${f_PRICE},${f_COMMISSION} ${f_COMMISSIONASSET},${f_COMMENT}" | head -n1 >>trade-histories/trade-*${f_ASSET}${f_CURRENCY}-open.history.csv else echo "${f_DATE},${f_ACTION},${f_CMDFILE}_OUT,${f_QUANTITY} ${f_CURRENCY},${f_PRICE},${f_COMMISSION} ${f_COMMISSIONASSET},${f_COMMENT}" | head -n1 >>trade-histories/trade-$(date +%F.%T. | sed 's/:/_/g')${f_ASSET}${f_CURRENCY}-open.history.csv fi fi if [ "${f_ACTION}" = "sell" ] then f_tradehistfile="$(ls trade-histories/trade-*${f_ASSET}${f_CURRENCY}-open.history.csv | tail -n1)" echo "${f_DATE},${f_ACTION},${f_CMDFILE}_OUT,${f_QUANTITY} ${f_CURRENCY},${f_PRICE},${f_COMMISSION} ${f_COMMISSIONASSET},${f_COMMENT}" | head -n1 >>${f_tradehistfile} f_tradehistfileclosed=$(echo ${f_tradehistfile} | sed 's/open.history.csv/closed.history.csv/') mv ${f_tradehistfile} ${f_tradehistfileclosed} fi g_signal-notify "TRADE SUCCESSFUL! ${f_trade_info_msg} Command stored: ${f_CMDFILE}[_OUT]" [ -f DIFF_BUY_PRICE_${f_ASSET}${f_CURRENCY} ] && [ "${f_ACTION}" = "sell" ] && rm -f DIFF_BUY_PRICE_${f_ASSET}${f_CURRENCY} # get new balances get_balances else g_echo_note "TRADE FAILED! $(cat ${f_CMDFILE}_OUT)" g_signal-notify "TRADE FAILED! ${f_trade_info_msg} Command ${f_CMDFILE}: $0 $@ $(cat ${f_CMDFILE}) OUTPUT: $(cat ${f_CMDFILE}_OUT) " fi }