initial version

This commit is contained in:
olli 2023-04-28 17:09:15 +02:00
parent 74755a16e5
commit 51d959891d
29 changed files with 2623 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
docker-compose.override.yml
htdocs/botdata
htdocs/index.html
tests
.binance-secrets
.bitpanda-secrets

12
Dockerfile Normal file
View File

@ -0,0 +1,12 @@
FROM debian:latest
RUN apt-get update \
&& apt-get install -y npm node-commander git \
&& git clone https://github.com/binance/binance-cli \
&& cd binance-cli \
&& npm install @binance/connector \
&& npm install -g \
&& ln -s /usr/local/lib/node_modules/\@binance/ /usr/lib/nodejs/
ENV LANG en_US.utf8
COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]

5
analyze.conf Normal file
View File

@ -0,0 +1,5 @@
ANALYZE_TIME="^2023-04-17"
. bot.conf

129
analyze.sh Executable file
View File

@ -0,0 +1,129 @@
#!/bin/bash
. /etc/bash/gaboshlib.include
g_nice
function g_echo_note {
[ -z "$1" ] && return 0
echo -en "\033[97m$(tail -n1 ${g_tmp}/$tmpfile | cut -d, -f1) \033[36mNOTE:"
cat <<< "$@"
echo -en "\033[0m"
}
function analyze {
local file=$1
tmpfile=$(basename "${file}")
. /etc/bash/gaboshlib/g_percentage-diff.bashfunc
. functions/check_buy_conditions.sh
. functions/check_sell_conditions.sh
. functions/get_vars_from_csv.sh
. bot.conf
. analyze.conf
#g_echo "Analyzing file: $file"
# cleanup
f_SELL=1
f_BUY=""
>${g_tmp}/${tmpfile}
>${g_tmp}/result-${tmpfile}
rm -f ${g_tmp}/open-${tmpfile}
rm -f ${g_tmp}/interim-${tmpfile}
rm -f ${g_tmp}/output-${tmpfile}
ORIGIFS="$IFS"
IFS=$'\n'
for line in $(egrep "^${ANALYZE_TIME}" "$file")
do
IFS="$ORIGIFS"
current=$(echo $line | cut -d, -f2)
time=$(echo $line | cut -d, -f1 | cut -d: -f1,2)
echo "$line" >>${g_tmp}/${tmpfile}
if [ -f "${g_tmp}/open-${tmpfile}" ]
then
check_sell_conditions ${g_tmp}/${tmpfile} >>${g_tmp}/output-${tmpfile} 2>&1
fi
if ! [ -f "${g_tmp}/open-${tmpfile}" ]
then
f_market_performance=$(grep "^$time" htdocs/botdata/MARKET_PERFORMANCE | tail -n1 | cut -d: -f4 | cut -d"%" -f1 | sed 's/ *//')
[ -z "${f_market_performance}" ] && continue
if [ $(echo "${f_market_performance} < ${GOOD_MARKET_PERFORMANCE_INDEX}" | bc -l) -eq 0 ]
then
check_buy_conditions ${g_tmp}/${tmpfile} >>${g_tmp}/output-${tmpfile} 2>&1 || break
else
g_echo_note "bad market (${f_market_performance} < ${GOOD_MARKET_PERFORMANCE_INDEX}) - Price: $current" >>${g_tmp}/output-${tmpfile} 2>&1
fi
fi
done
# sell at the end to have a final result.
if [ -f ${g_tmp}/open-${tmpfile} ]
then
f_SELL="SELL ${f_ASSET}: End of file/data"
echo "SELL: $(tail -n1 ${g_tmp}/${tmpfile} | cut -d, -f1) === ${f_SELL}" >>${g_tmp}/output-${tmpfile} 2>&1
result=$(g_percentage-diff ${BUY_PRICE} ${current})
result=$(echo "${result}-${FEE}" | bc | sed 's/^\./0./; s/^-\./-0./')
echo "$result" >>${g_tmp}/result-${tmpfile}
echo "RESULT: ${result}% (${BUY_PRICE} -> ${current})" >>${g_tmp}/output-${tmpfile}
rm -f ${g_tmp}/open-${tmpfile}
rm -f ${g_tmp}/interim-${tmpfile}
fi
complete_result=0
for result in $(cat ${g_tmp}/result-${tmpfile})
do
complete_result=$(echo "$complete_result+$result" | bc -l | sed 's/^\./0./; s/^-\./-0./' | xargs printf "%.2f")
done
echo "COMPLETE RESULT $file analyze-${analyzedate}/${tmpfile}.log: ${complete_result}%" | tee -a ${g_tmp}/output-${tmpfile}
echo "=====================================" >>${g_tmp}/output-${tmpfile}
echo "${complete_result}" >>${g_tmp}/overall-result-${tmpfile}
cat ${g_tmp}/output-${tmpfile} >"analyze-${analyzedate}/${tmpfile}.log"
}
. bot.conf
. analyze.conf
set | grep ^[A-Z].*=[-0-9]
cores=$(cat /proc/cpuinfo | grep "^processor.*:" | tail -n1 | perl -pe 's/processor.*: //')
echo -n "parallel -j${cores} bash -c --" >/tmp/parallel-$$
analyzedate="$(date +%Y-%m-%d--%H-%M-%S)"
mkdir "analyze-${analyzedate}"
cp bot.conf analyze.conf analyze-${analyzedate}/
for file in $@
do
echo "${file}" | grep -q "BALANCE" && continue
echo -n " \"analyze ${file}\"" >>/tmp/parallel-$$
done
export -f g_echo_note
export g_tmp
export analyzedate
. /tmp/parallel-$$
echo "OVERALL RESULT: $(cat ${g_tmp}/overall-result-* | awk '{ SUM += $1 } END { printf("%2.2f", SUM) }')%" | tee analyze-${analyzedate}/overall-result.log
cat analyze-${analyzedate}/*.history.csv.log >analyze-${analyzedate}/analyze-overall.log
echo Trades: "$(grep "BUY: " analyze-${analyzedate}/analyze-overall.log | wc -l)" | tee -a analyze-${analyzedate}/overall-result.log
echo Interim Results: "$(grep "INTERIM RESULT: " analyze-${analyzedate}/analyze-overall.log | wc -l)" | tee -a analyze-${analyzedate}/overall-result.log
echo Interim Results Positive: "$(grep "INTERIM RESULT: [0-9]" analyze-${analyzedate}/analyze-overall.log | wc -l)" | tee -a analyze-${analyzedate}/overall-result.log
echo Interim Results Negative: "$(grep "INTERIM RESULT: -" analyze-${analyzedate}/analyze-overall.log | wc -l)" | tee -a analyze-${analyzedate}/overall-result.log
echo "
Complete Results" >>analyze-${analyzedate}/overall-result.log
grep "COMPLETE RESULT " analyze-${analyzedate}/analyze-overall.log | grep -v ": 0%" >>analyze-${analyzedate}/overall-result.log
echo "
Trades" >>analyze-${analyzedate}/overall-result.log
egrep "BUY: |SELL: " analyze-${analyzedate}/analyze-overall.log >>analyze-${analyzedate}/overall-result.log

130
dabo-bot.conf Normal file
View File

@ -0,0 +1,130 @@
# The exchange we use for using the correct API
STOCK_EXCHANGE="BINANCE"
# fee per trade in percentage on exchange (taker and maker added)
FEE="0.4"
# Interval in seconds
INTERVAL="150"
## Currency used for trading
CURRENCY="USDT"
TRANSFER_CURRENCY="EUR"
# Only use currencies under the first X currencies sorted by market capitalization
LARGEST_MARKETCAP="250"
# Blacklist Currencies
BLACKLIST="^DAI${CURRENCY}|^BUSD${CURRENCY}|^USDC${CURRENCY}|^USDP${CURRENCY}|^TUSD${CURRENCY}|^USDD${CURRENCY}|^GUSD${CURRENCY}|^FEI${CURRENCY}|^USTC${CURRENCY}|^FRAX${CURRENCY}|^USDJ${CURRENCY}|^LUSD${CURRENCY}|^EURS${CURRENCY}|^TRIBE${CURRENCY}|^BNB${CURRENCY}"
## Signal Group for Notifications
SIGNAL_GROUP="Krypto-Bot"
## Percent from balance per invest.
# Overwritten by MIN_NOTIONAL+X% from stock if lower
INVEST="5"
# GOOD_MARKET_PERFORMANCE_INDEX defines from fwhich growth the market is considered good/favorable for investment.
# The market performance is calculated from the average percentage development of various indicators such as development MSCI World, Bitcoin and Ethereum as well as forecasts.
# for details see functions/market_performance.sh
# If the market performance is under this value no buying will be done
GOOD_MARKET_PERFORMANCE_INDEX="0.3"
# Stop all trading and sell everything if the complete balance shrinks under this value in ${CURRENCY}
EMERGENCY_STOP="190"
###### BUY CONDITIONS ######
### RSI Indicator checks
# Don't buy if the RSI-XX value is >= BUY_RSIXX_BUY_SIGNAL_UNTIL
BUY_RSI5_SIGNAL_UNTIL="99"
BUY_RSI14_SIGNAL_UNTIL="99"
BUY_RSI21_SIGNAL_UNTIL="99"
BUY_RSI60_SIGNAL_UNTIL="99"
BUY_RSI120_SIGNAL_UNTIL="99"
BUY_RSI240_SIGNAL_UNTIL="99"
BUY_RSI420_SIGNAL_UNTIL="99"
BUY_RSI720_SIGNAL_UNTIL="99"
# Don't buy if the RSI-XX value is <= BUY_RSIXX_BUY_SIGNAL_FROM
BUY_RSI5_SIGNAL_FROM="0"
BUY_RSI14_SIGNAL_FROM="0"
BUY_RSI21_SIGNAL_FROM="0"
BUY_RSI60_SIGNAL_FROM="0"
BUY_RSI120_SIGNAL_FROM="0"
BUY_RSI240_SIGNAL_FROM="0"
BUY_RSI420_SIGNAL_FROM="0"
BUY_RSI720_SIGNAL_FROM="0"
### MACD Indicator Checks
# Don't buy if MACD Histogram Relation is not between this values.
# The ratio is calculated by the difference between the maximum positive Histogram value (of the defined time period) and the current value.
# Here you can specify a percentage range.
# If only the buy signal should be considered, simply specify the range 0 and 100.
# decimal numbers are not allowed here.
BUY_MACD_RELATION_FROM="60"
BUY_MACD_RELATION_TO="95"
# Don't buy if price change is under this percentage values
BUY_MIN_PRICE_CHANGE_LAST_1_DAY="0.25"
BUY_MIN_PRICE_CHANGE_LAST_7_DAY="-1"
BUY_MIN_PRICE_CHANGE_LAST_14_DAY="-2"
BUY_MIN_PRICE_CHANGE_LAST_30_DAY="-5"
# Dont buy if growth in the last defined time period <= BUY_MINGROWTH
BUY_MINGROWTH_PERIOD="30"
BUY_MINGROWTH="-10"
###### SELL CONDITIONS ######
# Force hold if result negative expect SELL_PERCENTAGE_FROM_LAST_PURCHASE_NEGATIVE. Boolean 1 for true 0 for false.
SELL_HOLD_IF_RESULT_NEGATIVE="1"
# If the price falls by this percentage value from the purchase price, then sell in any case
SELL_PERCENTAGE_FROM_LAST_PURCHASE_NEGATIVE="-10"
# from here only if SELL_HOLD_IF_RESULT_NEGATIVE doesn't match
# If the price falls by this percentage value from the last rate
SELL_IF_LAST_RATE_LOWER_THEN="-0.25"
### RSI Indicator checks
# SELL if the RSI-XX value is <= SELL_RSIXX_SELL_SIGNAL_UNTIL
SELL_RSI5_SIGNAL_UNTIL="99"
SELL_RSI14_SIGNAL_UNTIL="99"
SELL_RSI21_SIGNAL_UNTIL="99"
SELL_RSI60_SIGNAL_UNTIL="99"
SELL_RSI120_SIGNAL_UNTIL="99"
SELL_RSI240_SIGNAL_UNTIL="99"
SELL_RSI420_SIGNAL_UNTIL="99"
SELL_RSI720_SIGNAL_UNTIL="99"
# SELL if the RSI-XX value is >= SELL_RSIXX_SELL_SIGNAL_FROM
SELL_RSI5_SIGNAL_FROM="90"
SELL_RSI14_SIGNAL_FROM="90"
SELL_RSI21_SIGNAL_FROM="90"
SELL_RSI60_SIGNAL_FROM="70"
SELL_RSI120_SIGNAL_FROM="50"
SELL_RSI240_SIGNAL_FROM="50"
SELL_RSI420_SIGNAL_FROM="50"
SELL_RSI720_SIGNAL_FROM="50"
# If the price after this time periods is lower the the trading fee, then sell if SELL_HOLD_IF_RESULT_NEGATIVE is fine with it
SELL_IF_LOWER_THEN_FEE_AFTER_PERIOD="9999999"
### MACD Indicator Checks
# Sell if MACD Histogram relation is < this value
# The ratio is calculated by the difference between the maximum negative Histogram value (of the defined time period) and the current value.
# Here you can specify a percentage range.
# If only the sell signal should be considered, simply specify 0
# decimal numbers are not allowed here.
SELL_MACD_RELATION_FROM="25"

82
dabo-bot.sh Executable file
View File

@ -0,0 +1,82 @@
#!/bin/bash
. /etc/bash/gaboshlib.include
g_lockfile
### CONFIG ###
BASEPATH=/dabo
g_tries=3
g_tries_delay=5
### FUNCTIONS ###
for bashfunc in $(find ${BASEPATH}/../functions -type f -name "*.sh")
do
. "$bashfunc"
done
### MAIN ###
# prepare directories
mkdir -p ${BASEPATH}/botdata/asset-histories
mkdir -p ${BASEPATH}/botdata/trade-histories
cd ${BASEPATH}/botdata
touch firstloop
# am I the bot (important for functions used by analyze.sh
echo $0 | grep -q "dabo-bot\.sh" && BOT=1
# run endless loop
while true
do
# wait until next full minute in the beginning to be able to work with continue in this loop
if [ -f firstloop ]
then
rm -f firstloop
else
g_echo_note "NEXT LOOP - sleping until next full ${INTERVAL} seconds"
sleep $((${INTERVAL} - $(date +%s) % ${INTERVAL}))
fi
# reload config
. ../../dabo-bot.conf
# stock data
if [ ${STOCK_EXCHANGE} = "BINANCE" ]
then
#BINANCE_CLI_CMD="docker-compose -f /home/docker/binance-cli/docker-compose.yml exec -T binance-cli binance-cli"
# command for current token infos (function for setting var QUANTITY_LOT_CUT
TOKEN_INFO_CMD="binance_get_token_info"
# command for buying/selling a token
#TRADE_CMD="$BINANCE_CLI_CMD ACTION -s TOKEN -u QUANTITY -t market"
TRADE_CMD='binance-api-call POST /api/v3/order "&symbol=TOKEN&quoteOrderQty=QUANTITY&side=ACTION&type=MARKET"'
fi
# Get current assets
get_assets || continue
# Get current balances
get_balances || continue
# Check the situation on the market
if ! market_performance
then
f_market_performance=$(cat MARKET_PERFORMANCE_LATEST)
fi
##### Sell something? ####
check_for_sell
##### Buy something? ####
check_for_buy
##### Update webpage
webpage &
done

35
docker-compose.yml Normal file
View File

@ -0,0 +1,35 @@
version: '3.6'
services:
bot.ds9.dedyn.io:
image: nginx:latest
restart: unless-stopped
volumes:
- ./htdocs:/usr/share/nginx/html:ro
- /etc/localtime:/etc/localtime:ro
networks:
- traefik
labels:
- traefik.enable=true
# HTTPS
- traefik.http.routers.bot-ds9.rule=Host(`bot.ds9.dedyn.io`) || Host(`autodiscover.ds9.dedyn.io`)
- traefik.http.routers.bot-ds9.entrypoints=https
- traefik.http.routers.bot-ds9.tls=true
# Proxy to service-port
- traefik.http.services.bot-ds9.loadbalancer.server.port=80
- traefik.http.routers.bot-ds9.service=bot-ds9
# cert via letsencrypt
- traefik.http.routers.bot-ds9.tls.certresolver=letsencrypt
# Traefik network
- traefik.docker.network=traefik
binance-cli:
build: .
restart: unless-stopped
environment:
- BINANCE_API_KEY="docker-compose.override.yml"
- BINANCE_API_SECRET="docker-compose.override.yml"
networks:
traefik:
external: true

4
docker-entrypoint.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
sleep 999999999
binance-cli $@

14
functions/api-calls.sh Normal file
View File

@ -0,0 +1,14 @@
function EXCHANGE_GET_ASSETS_CMD {
if [ ${STOCK_EXCHANGE} = "BINANCE" ]
then
binance-api-call GET /api/v3/ticker/price || return 1
# parse API output
cat ${g_tmp}/API_CMD_OUT | jq -r '.[] | .symbol + "," + .price' | grep "${CURRENCY}," | egrep -v "${TRANSFER_CURRENCY},|,0[\.][0]*$" | sort >${f_filename}_OUT.tmp
fi
}

View File

@ -0,0 +1,36 @@
#!/bin/bash
function binance-api-call {
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
local method=$1
local call=$2
local params=$3
if [ -s /home/docker/binance-cli/.binance-secrets ]
then
. /home/docker/binance-cli/.binance-secrets
else
g_echo_error "No secrets file found"
return 1
fi
call=$(echo "$call" | sed "s/^\///")
if echo "${call}" | egrep -q "^sapi/|^api/v3/order"
then
params="recvWindow=60000${params}"
local timestamp=$(date +%s000)
params="${params}&timestamp=${timestamp}"
local signature=$(echo -n "${params}" | openssl dgst -sha256 -hmac "${API_SECRET}" | cut -d" " -f2)
params="?${params}&signature=$signature"
fi
echo "curl -s -H \"X-MBX-APIKEY: $API_KEY\" -X \"$method\" \"https://api.binance.com/${call}${params}\"" >${g_tmp}/API_CMD
echo "curl -s -H \"X-MBX-APIKEY: API_KEY\" -X \"$method\" \"https://api.binance.com/${call}${params}\"" >${g_tmp}/API_CMD_WO_KEY
g_runcmd g_retrycmd sh ${g_tmp}/API_CMD >${g_tmp}/API_CMD_OUT 2>&1
if egrep -q -i '^{"code":|error' ${g_tmp}/API_CMD_OUT
then
g_echo_error "$(cat ${g_tmp}/API_CMD_WO_KEY): $(cat ${g_tmp}/API_CMD_OUT)"
return 1
fi
}

View File

@ -0,0 +1,118 @@
function binance_convert {
# 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_QUANTITY_CURRENCY=$6
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)"
local f_CMDFILE="trade-histories/${f_DATE}-${f_CURRENCY}-BINANCE_CONVERT-TRADE_CMD"
local f_num_converts=$(find trade-histories/*-*-BINANCE_CONVERT-TRADE_CMD -type f -mmin 60 | wc -l)
if [ $f_num_converts -ge 99 ]
then
g_echo_note "Already did 99 or more binance converts last hour."
return 1
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
# get quote on buy
echo "binance-api-call POST /sapi/v1/convert/getQuote '&fromAsset=${f_CURRENCY}&toAsset=${f_ASSET}&fromAmount=${f_QUANTITY}&walletType=SPOT&validTime=10s'" >${f_CMDFILE}
fi
if [ "${f_ACTION}" = "sell" ]
then
# get quote on sell
echo "binance-api-call POST /sapi/v1/convert/getQuote '&fromAsset=${f_ASSET}&toAsset=${f_CURRENCY}&fromAmount=${f_QUANTITY}&walletType=SPOT&validTime=10s'" >${f_CMDFILE}
fi
echo "cat ${g_tmp}/API_CMD_OUT >${f_CMDFILE}_QUOTE_OUT
local f_quoteid=\$(cat ${g_tmp}/API_CMD_OUT | jq -r '.quoteId')
binance-api-call POST /sapi/v1/convert/acceptQuote \"&quoteId=\${f_quoteid}\"
cat ${g_tmp}/API_CMD_OUT >${f_CMDFILE}_OUT
" >>${f_CMDFILE}
# convert/trade
g_echo_note "Command: $(cat ${f_CMDFILE})"
. ${f_CMDFILE}
cat ${g_tmp}/API_CMD_OUT >${f_CMDFILE}_OUT
g_echo_note "Command Output: $(cat ${f_CMDFILE}_OUT)"
# Check return and log trade
f_STATUS=$(cat ${f_CMDFILE}_OUT | grep '^{' | jq -r .orderStatus)
local f_trade_info_msg="CONVERT/TRADE - ${f_ACTION} ${f_ASSET}${f_CURRENCY}
${f_link}
Complete Overview: https://bot.ds9.dedyn.io/
Comment: ${f_COMMENT}"
if echo "${f_STATUS}" | egrep -q "PROCESS|ACCEPT_SUCCESS|SUCCESS"
then
g_echo_note "CONVERT/TRADE SUCCESSFUL!"
[ "${f_ACTION}" = "buy" ] && local f_PRICE=$(cat ${f_CMDFILE}_QUOTE_OUT | grep '^{' | jq -r .inverseRatio | head -n1)
[ "${f_ACTION}" = "sell" ] && local f_PRICE=$(cat ${f_CMDFILE}_QUOTE_OUT | grep '^{' | jq -r .ratio | head -n1)
local f_COMMISSION="0"
local f_COMMISSIONASSET="${f_CURRENCY}"
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
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
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_CURRENCY} ${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 "CONVERT/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
return 0
else
g_echo_note "CONVERT/TRADE FAILED!
$(cat ${f_CMDFILE}_OUT)"
g_signal-notify "CONVERT/TRADE FAILED!
${f_trade_info_msg}
Command ${f_CMDFILE}:
$0 $@
$(cat ${f_CMDFILE})
OUTPUT:
$(cat ${f_CMDFILE}_OUT)
"
return 1
fi
}

View File

@ -0,0 +1,46 @@
#!/bin/bash
function binance_convert_dust {
# find BNB Balance of an conversion which ran before - Balance takes a while to be shown on BNB
# get BNB balance
binance-api-call GET sapi/v1/capital/config/getall
local f_bnb_balance=$(cat ${g_tmp}/API_CMD_OUT | jq -r '.[] | .coin + "," + .free' | grep "^BNB," | cut -d, -f2)
# convert BNB to $CURRENCY
#if echo "${f_bnb_balance}" | egrep -q "[0-9]\.[0-9]"
if [ $(echo "${f_bnb_balance} > 0.004" | bc -l) -ne 0 ]
then
binance-api-call POST /sapi/v1/convert/getQuote "&fromAsset=BNB&toAsset=${CURRENCY}&fromAmount=${f_bnb_balance}&walletType=SPOT&validTime=30s"
local f_quoteid=$(cat ${g_tmp}/API_CMD_OUT | jq -r '.quoteId')
g_signal-notify "Converting dust from ${f_bnb_balance} BNB to ${CURRENCY}
$(cat ${g_tmp}/API_CMD_OUT)"
binance-api-call POST /sapi/v1/convert/acceptQuote "&quoteId=${f_quoteid}"
fi
# Only run every 6 houres - binance doesn't allow to do it more often
[ -s BINANCE_LAST_DUST_RUN ] || date >BINANCE_LAST_DUST_RUN
find BINANCE_LAST_DUST_RUN -mmin +362 -delete
[ -s BINANCE_LAST_DUST_RUN ] && return 0
date >BINANCE_LAST_DUST_RUN
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
# find dust
local f_dust_assets=""
local f_dust
binance-api-call POST /sapi/v1/asset/dust-btc
# ignore $CURRENCY and assets in open trades
for f_dust in $(cat ${g_tmp}/API_CMD_OUT | jq -r '.details[].asset' | egrep -v "${CURRENCY}")
do
ls trade-histories/trade-*.${f_dust}${CURRENCY}-open.history.csv >/dev/null 2>&1 && continue
f_dust_assets="${f_dust_assets},$f_dust"
done
f_dust_assets=$(echo ${f_dust_assets} | sed 's/^,//')
# convert dust to BNB
if [ -n "${f_dust_assets}" ]
then
g_signal-notify "Converting dust from ${f_dust_assets} to BNB"
binance-api-call POST /sapi/v1/asset/dust "&asset=${f_dust_assets}"
fi
}

View File

@ -0,0 +1,38 @@
function binance_get_token_info {
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
local f_ASSET=$1
local f_CURRENCY=$2
local f_QUANTITY=$3
# cleanup cache
[ -s BINANCE_TOKEN_INFO_CMD_OUT ] && find BINANCE_TOKEN_INFO_CMD_OUT -mmin +60 -or -empty -delete
#echo "$BINANCE_CLI_CMD info" >BINANCE_TOKEN_INFO_CMD
#[ -s BINANCE_TOKEN_INFO_CMD_OUT ] || g_runcmd g_retrycmd sh BINANCE_TOKEN_INFO_CMD >BINANCE_TOKEN_INFO_CMD_OUT
if ! [ -s BINANCE_TOKEN_INFO_CMD_OUT ]
then
binance-api-call GET /api/v3/exchangeInfo >BINANCE_TOKEN_INFO_CMD_OUT
cat ${g_tmp}/API_CMD_OUT >BINANCE_TOKEN_INFO_CMD_OUT
fi
# cut quantity by lot-step-size
if ! [ -z "$f_QUANTITY" ]
then
local f_LOT_STEP_SIZE=$(cat BINANCE_TOKEN_INFO_CMD_OUT | jq -c "[ .symbols[] | select( .symbol==\"${f_ASSET}${f_CURRENCY}\") ]" | jq -c '.[].filters[] | select( .filterType=="LOT_SIZE")' | jq -r '.stepSize' | perl -pe 's/0+$//; s/\.$//')
if [ -z "${f_LOT_STEP_SIZE}" ]
then
g_echo "Got no LOT_STEP_SIZE from BINANCE_TOKEN_INFO_CMD_OUT for ${f_ASSET} - Assuming 0.01"
f_LOT_STEP_SIZE="0.01"
fi
local f_LOT_DIV=$(echo "scale=0; ${f_QUANTITY}/${f_LOT_STEP_SIZE}" | bc -l)
f_QUANTITY_LOT_CUT=$(echo "${f_LOT_DIV}*${f_LOT_STEP_SIZE}" | bc -l | sed 's/^\./0./;')
fi
# get min CURRENCY
f_MIN_NOTIONAL=$(cat BINANCE_TOKEN_INFO_CMD_OUT | jq -c "[ .symbols[] | select( .symbol==\"${f_ASSET}${f_CURRENCY}\") ]" | jq -c '.[].filters[] | select( .filterType=="MIN_NOTIONAL")' | jq -r '.minNotional' | perl -pe 's/0+$//; s/\.$//')
if [ -z "${f_MIN_NOTIONAL=}" ]
then
g_echo "Got no LOT_STEP_SIZE from BINANCE_TOKEN_INFO_CMD_OUT for ${f_ASSET} - Assuming 10.00000000"
f_MIN_NOTIONAL="10.00000000"
fi
}

View File

@ -0,0 +1,173 @@
function check_buy_conditions {
local f_ASSET_HIST_FILE="$1"
f_ASSET=$(basename ${f_ASSET_HIST_FILE} | cut -d\. -f1)
if [ -n "${BOT}" ]
then
# ignore already invested asset
if ls trade-histories/trade-*${f_ASSET}-open.history.csv >/dev/null 2>&1
then
g_echo_note "BUY ${f_ASSET}@${CURRENCY}: $f_ASSET Already invested - ignoring for more diversification"
return 0
fi
fi
get_vars_from_csv "${f_ASSET_HIST_FILE}" || return 1
### from here: check for defined state to buy
f_BUY="${f_last_line}"
local f_priceXago=$(tail -n${BUY_MINGROWTH_PERIOD} ${f_ASSET_HIST_FILE} | grep ^[0-9] | head -n1 | cut -d, -f2)
local f_pricenow=$(echo ${f_last_line} | grep ^[0-9] | cut -d, -f2)
local f_pricediff=$(g_percentage-diff "$f_priceXago" "$f_pricenow")
if [ $(echo "${f_pricediff} < ${BUY_MINGROWTH}" | bc -l) -ne 0 ]
then
g_echo_note "BUY ${f_ASSET}@${CURRENCY}:${f_price}: With ${f_pricediff} under ${BUY_MINGROWTH}% growth in the last ${BUY_MINGROWTH_PERIOD} time periods"
return 0
fi
#local f_macd_histogram_max=$(tail -n26 "${f_ASSET_HIST_FILE}" | cut -d"," -f8 | egrep "^[0-9]|^-[0-9]" | sed 's/^-//' | sort -n | tail -n1)
#local f_macd_histogram_relation=$(echo "100+$(g_percentage-diff ${f_macd_histogram_max} ${f_macd_histogram})" | bc | cut -d\. -f1)
# MACD
# no negative or empty values
echo "${f_macd_histogram_relation}" | grep -q "^[0-9]" || return 0
# check for conditions
if [ ${f_macd_histogram_relation} -le ${BUY_MACD_RELATION_FROM} ] || [ ${f_macd_histogram_relation} -ge ${BUY_MACD_RELATION_TO} ]
then
g_echo_note "BUY ${f_ASSET}@${CURRENCY}:${f_price}: MACD conditions NOT met"
return 0
fi
# RSI
if \
[ ${f_rsi5} -le ${BUY_RSI5_SIGNAL_UNTIL} ] && \
[ ${f_rsi14} -le ${BUY_RSI14_SIGNAL_UNTIL} ] && \
[ ${f_rsi21} -le ${BUY_RSI21_SIGNAL_UNTIL} ] && \
[ ${f_rsi60} -le ${BUY_RSI60_SIGNAL_UNTIL} ] && \
[ ${f_rsi120} -le ${BUY_RSI120_SIGNAL_UNTIL} ] && \
[ ${f_rsi240} -le ${BUY_RSI240_SIGNAL_UNTIL} ] && \
[ ${f_rsi420} -le ${BUY_RSI420_SIGNAL_UNTIL} ] && \
[ ${f_rsi720} -le ${BUY_RSI720_SIGNAL_UNTIL} ] && \
[ ${f_rsi5} -ge ${BUY_RSI5_SIGNAL_FROM} ] && \
[ ${f_rsi14} -ge ${BUY_RSI14_SIGNAL_FROM} ] && \
[ ${f_rsi21} -ge ${BUY_RSI21_SIGNAL_FROM} ] && \
[ ${f_rsi60} -ge ${BUY_RSI60_SIGNAL_FROM} ] && \
[ ${f_rsi120} -ge ${BUY_RSI120_SIGNAL_FROM} ] && \
[ ${f_rsi240} -ge ${BUY_RSI240_SIGNAL_FROM} ] && \
[ ${f_rsi420} -ge ${BUY_RSI420_SIGNAL_FROM} ] && \
[ ${f_rsi720} -ge ${BUY_RSI720_SIGNAL_FROM} ]
then
echo "BUY ${f_ASSET}@${CURRENCY}:${f_price}: RSI conditions met" >/dev/null
else
g_echo_note "BUY ${f_ASSET}@${CURRENCY}:${f_price}: RSI conditions NOT met"
return 0
fi
# Price change
if \
[ $(echo "${f_price_change_1_day} > ${BUY_MIN_PRICE_CHANGE_LAST_1_DAY}" | bc -l) -ne 0 ] && \
[ $(echo "${f_price_change_7_day} > ${BUY_MIN_PRICE_CHANGE_LAST_7_DAY}" | bc -l) -ne 0 ] && \
[ $(echo "${f_price_change_14_day} > ${BUY_MIN_PRICE_CHANGE_LAST_14_DAY}" | bc -l) -ne 0 ] && \
[ $(echo "${f_price_change_30_day} > ${BUY_MIN_PRICE_CHANGE_LAST_30_DAY}" | bc -l) -ne 0 ]
then
echo "BUY ${f_ASSET}@${CURRENCY}:${f_price}: Price change conditions met" >/dev/null
else
g_echo_note "BUY ${f_ASSET}@${CURRENCY}:${f_price}: Price change conditions NOT met"
return 0
fi
if [ -n "$f_BUY" ]
then
# Check for beginning MACD Trend
if ! tail -n3 ${f_ASSET_HIST_FILE} | grep -q '|buy,'
then
g_echo_note "BUY ${f_ASSET}@${CURRENCY}:${f_price}: MACD Trend not near (3 timeframes) the beginning buy signal"
return 0
fi
# Check for growing MACD trend
local f_macd_histogram_before=$(tail -n2 ${f_ASSET_HIST_FILE} | head -n1 | cut -d, -f8)
local f_macd_histogram_2before=$(tail -n3 ${f_ASSET_HIST_FILE} | head -n1 | cut -d, -f8)
local f_macd_histogram_3before=$(tail -n4 ${f_ASSET_HIST_FILE} | head -n1 | cut -d, -f8)
local f_macd_histogram_4before=$(tail -n5 ${f_ASSET_HIST_FILE} | head -n1 | cut -d, -f8)
local f_macd_histogram_5before=$(tail -n6 ${f_ASSET_HIST_FILE} | head -n1 | cut -d, -f8)
if \
[ $(echo "${f_macd_histogram} < ${f_macd_histogram_before}" | bc -l) -ne 0 ] && \
[ $(echo "${f_macd_histogram_before} < ${f_macd_histogram_2before}" | bc -l) -ne 0 ] && \
[ $(echo "${f_macd_histogram_2before} < ${f_macd_histogram_3before}" | bc -l) -ne 0 ] && \
[ $(echo "${f_macd_histogram_3before} < ${f_macd_histogram_4before}" | bc -l) -ne 0 ] && \
[ $(echo "${f_macd_histogram_4before} < ${f_macd_histogram_5before}" | bc -l) -ne 0 ]
then
g_echo_note "BUY ${f_ASSET}@${CURRENCY}:${f_price} MACD Histogram not rising (now ${f_macd_histogram} < 1 before ${f_macd_histogram_before} < 2 before ${f_macd_histogram_2before} < 3 before ${f_macd_histogram_3before} < 4 before ${f_macd_histogram_4before} < 5 before ${f_macd_histogram_5before}) - trend loses strength / not growing - don't buy"
return 0
fi
fi
### Buy or not buy?
# BOT
if [ -n "$f_BUY" ] && [ -n "${BOT}" ]
then
echo "${f_last_line},${f_ASSET}" >>trade.log
f_BUY="BUY ${f_ASSET}@${CURRENCY}:${f_price}: All BUY conditions met!!!
${f_BUY}"
g_echo_note "${f_BUY}"
# calculate quantity from balance for potentially invest
local f_INVEST_QUANTITY=$(echo "scale=2; ${CURRENCY_BALANCE}/100*${INVEST}" | bc -l | sed 's/^\./0./;' | cut -d\. -f1)
g_echo_note "BUY current investment quantity is ${f_INVEST_QUANTITY} ${CURRENCY}"
# remove CURRENCY from asset
f_ASSET=$(echo ${f_ASSET} | sed "s/${CURRENCY}//")
# get stock exchange specific infos for trade (e.g. MIN_NOTIONAL)
$TOKEN_INFO_CMD ${f_ASSET} ${CURRENCY}
# use MIN_NOTIONAL+5% as INVEST_QUANTITY if INVEST_QUANTITY is under MIN_NOTIONAL
# +5% in spite of MIN_NOTIONAL to be able to sell when the price falls a little bit
[ $(echo "${f_INVEST_QUANTITY} < ${f_MIN_NOTIONAL}" | bc -l) -eq 0 ] || f_INVEST_QUANTITY=$(echo "scale=2; $f_MIN_NOTIONAL/100*105" | bc -l)
# if there is not enough balance for buying because ${f_MIN_NOTIONAL} needed for buying to sell (workaround)
if [ $(echo "${CURRENCY_BALANCE} < ${f_MIN_NOTIONAL}*2" | bc -l) -ne 0 ]
then
g_echo_note "BUY ${f_ASSET} not enough balance ${CURRENCY_BALANCE} for buying because of MIN_NOTIONAL (${f_MIN_NOTIONAL}*2) needed for buying-to-sell (workaround)"
return 1
fi
# continue if not balance enough for lowest quantity (MIN_NOTIONAL)
if [ $(echo "${CURRENCY_BALANCE} > ${f_INVEST_QUANTITY}" | bc -l) -eq 0 ]
then
g_echo_note "BUY ${f_ASSET} not enough balance (${CURRENCY_BALANCE}) for lowest quantity (MIN_NOTIONAL - ${f_INVEST_QUANTITY})"
return 1
fi
#g_echo_note "BUY BUY BUY ${f_ASSET} ${CURRENCY} ${f_INVEST_QUANTITY} buy \"$f_BUY\""
if [ ${STOCK_EXCHANGE} = "BINANCE" ]
then
binance_convert ${f_ASSET} ${CURRENCY} ${f_INVEST_QUANTITY} buy "$f_BUY" || \
do_trade ${f_ASSET} ${CURRENCY} ${f_INVEST_QUANTITY} buy "$f_BUY"
else
do_trade ${f_ASSET} ${CURRENCY} ${f_INVEST_QUANTITY} buy "$f_BUY"
fi
f_BUY=""
fi
# ANALYZE
if [ -n "$f_BUY" ] && [ -z "${BOT}" ]
then
echo "BUY: $(echo ${f_last_line} | cut -d, -f1) === $f_BUY"
echo "$f_BUY" >${g_tmp}/open-${tmpfile}
BUY_PRICE=$current
fi
}

View File

@ -0,0 +1,54 @@
function check_for_buy {
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
g_echo_ok "Investmentbudget: $CURRENCY_BALANCE $CURRENCY"
# check for emergency stop
local f_COMPLETE_BALANCE=$(tail -n1 "asset-histories/BALANCECOMPLETE${CURRENCY}.history.csv" | cut -d, -f2)
if [ $(echo "${f_COMPLETE_BALANCE} < ${EMERGENCY_STOP}" | bc -l) -ne 0 ]
then
g_echo_note "BUY ATTENTION! EMERGENCY STOP DUE TO POOR PERFORMANCE: BALANCE (${f_COMPLETE_BALANCE}) LOWER THEN EMERGENCY_STOP-VALUE (${EMERGENCY_STOP})"
return 0
fi
## Generate grep regex for already invested assets
#f_investedassets_regex=$(cat EXCHANGE_GET_BALANCES_CMD_OUT | cut -d, -f1 | perl -pe 's/^/\^/; s/\n/\|/' | perl -pe 's/\|$//')
if ! [ -s ASSETS ]
then
g_echo_note "BUY file ASSETS empty $(ls -l ASSETS)"
return 0
fi
## use BUY_CONDITION_RISK if market is bad
if [ $(echo "${f_market_performance} > ${GOOD_MARKET_PERFORMANCE_INDEX}" | bc -l) -eq 0 ]
then
#g_echo_note "BUY market performance ${f_market_performance}% looks bad - Using BUY_CONDITION_RISK (${BUY_CONDITION_RISK}) as BUY_CONDITION"
#BUY_CONDITION=${BUY_CONDITION_RISK}
g_echo_note "BUY market performance ${f_market_performance}% looks bad - Dont buy anything"
return 0
else
g_echo_note "BUY market performance ${f_market_performance}% looks ok - going on buying with BUY_CONDITION (${BUY_CONDITION})"
fi
# go through highest assets
local f_line
for f_ASSET in $(cat ASSETS | egrep -v "${BLACKLIST}")
do
f_ASSET_HIST_FILE="asset-histories/${f_ASSET}.history.csv"
if [ $(tail -n 6 "$f_ASSET_HIST_FILE" | egrep -v ",,|,$" | wc -l) -ge 5 ]
then
check_buy_conditions "$f_ASSET_HIST_FILE"
else
g_echo_note "BUY $f_ASSET_HIST_FILE not enough data - waiting for complete values"
fi
done
}

230
functions/check_for_sell.sh Normal file
View File

@ -0,0 +1,230 @@
function check_for_sell {
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
## sell earlier if market is bad
if [ $(echo "${f_market_performance} > ${GOOD_MARKET_PERFORMANCE_INDEX}" | bc -l) -eq 0 ]
then
g_echo_note "SELL market performance ${f_market_performance}% bad - sell earlier"
#SELL_PERCENTAGE_FROM_LAST_PURCHASE_NEGATIVE="${SELL_PERCENTAGE_FROM_LAST_PURCHASE_NEGATIVE_BAD_MARKET}"
#SELL_PERCENTAGE_FROM_LAST_PURCHASE_POSITIVE="${SELL_PERCENTAGE_FROM_LAST_PURCHASE_POSITIVE_BAD_MARKET}"
else
g_echo_note "SELL market performance ${f_market_performance}% ok"
fi
# Check all balances
for f_EXCHANGE_GET_BALANCES_CMD_OUT in $(cat EXCHANGE_GET_BALANCES_CMD_OUT | egrep -v "^${CURRENCY},")
do
f_ASSET=$(echo ${f_EXCHANGE_GET_BALANCES_CMD_OUT} | cut -d, -f1)
f_QUANTITY=$(echo ${f_EXCHANGE_GET_BALANCES_CMD_OUT} | cut -d, -f2)
f_QUANTITY_CURRENCY=$(echo ${f_EXCHANGE_GET_BALANCES_CMD_OUT} | cut -d, -f3)
f_LAST_EXCHANGE_RATE=$(echo ${f_EXCHANGE_GET_BALANCES_CMD_OUT} | cut -d, -f4)
f_ASSET_HIST_FILE="asset-histories/${f_ASSET}${CURRENCY}.history.csv"
# State for currency
g_echo "SELL ${f_ASSET}: Balance: $f_QUANTITY ($f_QUANTITY_CURRENCY $CURRENCY)"
# check for emergency stop
local f_COMPLETE_BALANCE=$(tail -n1 "asset-histories/BALANCECOMPLETE${CURRENCY}.history.csv" | cut -d, -f2)
if [ $(echo "${f_COMPLETE_BALANCE} < ${EMERGENCY_STOP}" | bc -l) -ne 0 ]
then
local f_msg="ATTENTION! EMERGENCY STOP DUE TO POOR PERFORMANCE: BALANCE (${f_COMPLETE_BALANCE}) LOWER THEN EMERGENCY_STOP-VALUE (${EMERGENCY_STOP})"
g_echo_error "$f_msg"
do_trade ${f_ASSET} ${CURRENCY} ${f_QUANTITY_CURRENCY} sell "${f_msg}"
continue
fi
check_sell_conditions ${f_ASSET_HIST_FILE}
#local f_perf
#for f_perf in ${f_perf_week} ${f_perf_month}
#do
# [ -z "${f_perf}" ] && continue
# if [ $(echo "${f_perf} < ${EMERGENCY_STOP}" | bc -l) -ne 0 ]
# then
# local f_msg="ATTENTION! EMERGENCY STOP DUE TO POOR PERFORMANCE: LOWER THEN EMERGENCY_STOP-VALUE (${EMERGENCY_STOP}) (WEEK: ${f_perf_week}; MONTH: ${f_perf_month})"
# g_echo_error "$f_msg"
# do_trade ${f_ASSET} ${CURRENCY} ${f_QUANTITY_CURRENCY} sell "${f_msg}"
# continue 2
# fi
#done
## check for DONT_SELL_IF_GROWTH_OVER
#local f_condition
#for f_condition in $DONT_SELL_IF_GROWTH_OVER
#do
# local f_min=$(echo ${f_condition} | cut -d'>' -f1)
# local f_percentage=$(echo ${f_condition} | cut -d'>' -f1)
# get_rate_percentage_min_before_and_now ${f_ASSET} ${CURRENCY} ${f_min} || continue
# if [ $(echo "${f_exchange_rate_diff_percentage} > ${f_percentage}" | bc -l) -ne 0 ]
# then
# g_echo_note "SELL ${f_ASSET}: growth rate last ${f_min} minute(s) was over ${f_percentage}% (${f_exchange_rate_diff_percentage})"
# continue 2
# fi
#done
### from here: check for defined state to sell
# Reset g_SELL for next round
# f_SELL=""
#
#
# ## check current result
# f_TRADE_HIST_FILE="trade-histories/${f_ASSET}${CURRENCY}.history.csv"
# if [ -s "${f_TRADE_HIST_FILE}" ]
# then
# f_BUY_PRICE=$(grep ",buy," $f_TRADE_HIST_FILE | tail -n1 | cut -d, -f5)
# f_BUY_PRICE_LAST_RATE_DIFF=$(g_percentage-diff $f_BUY_PRICE $f_LAST_EXCHANGE_RATE)
# # Store for overview
# echo ${f_BUY_PRICE_LAST_RATE_DIFF} >DIFF_BUY_PRICE_${f_ASSET}${CURRENCY}
#
#
# # check for SELL_PERCENTAGE_FROM_LAST_PURCHASE_NEGATIVE
# if [ $(echo "${f_BUY_PRICE_LAST_RATE_DIFF} < ${SELL_PERCENTAGE_FROM_LAST_PURCHASE_NEGATIVE}" | bc -l) -ne 0 ]
# then
# f_SELL="Selling ${f_QUANTITY_CURRENCY} ${CURRENCY} - SELL_PERCENTAGE_FROM_LAST_PURCHASE_NEGATIVE(${SELL_PERCENTAGE_FROM_LAST_PURCHASE_NEGATIVE}%) > Last rate (${f_BUY_PRICE_LAST_RATE_DIFF}%)"
# do_trade ${f_ASSET} ${CURRENCY} ${f_QUANTITY_CURRENCY} sell "${f_SELL}"
# continue
# else
# g_echo_note "SELL ${f_ASSET}: compare current price $f_LAST_EXCHANGE_RATE and price at the time of purchase $f_BUY_PRICE (${f_BUY_PRICE_LAST_RATE_DIFF}): over SELL_PERCENTAGE_FROM_LAST_PURCHASE_NEGATIVE(${SELL_PERCENTAGE_FROM_LAST_PURCHASE_NEGATIVE}%)"
# fi
# # check for SELL_PERCENTAGE_FROM_LAST_PURCHASE_POSITIVE
# if [ $(echo "${f_BUY_PRICE_LAST_RATE_DIFF} < ${SELL_PERCENTAGE_FROM_LAST_PURCHASE_POSITIVE}" | bc -l) -ne 0 ]
# then
# g_echo_note "SELL ${f_ASSET}: Not doing further checking - compare current price $f_LAST_EXCHANGE_RATE and price at the time of purchase $f_BUY_PRICE (${f_BUY_PRICE_LAST_RATE_DIFF}): under SELL_PERCENTAGE_FROM_LAST_PURCHASE_POSITIVE(${SELL_PERCENTAGE_FROM_LAST_PURCHASE_POSITIVE}%)"
# continue
# elif [ $(echo "${f_market_performance} > ${GOOD_MARKET_PERFORMANCE_INDEX}" | bc -l) -eq 0 ]
# then
# # check for SELL_PERCENTAGE_FROM_LAST_PURCHASE_POSITIVE if on bad market
# local f_msg="SELL ${f_ASSET}: Sell because over SELL_PERCENTAGE_FROM_LAST_PURCHASE_POSITIVE_BAD_MARKET (${SELL_PERCENTAGE_FROM_LAST_PURCHASE_POSITIVE_BAD_MARKET}) $f_BUY_PRICE (${f_BUY_PRICE_LAST_RATE_DIFF} in bad market"
# g_echo_note "$f_msg"
# do_trade ${f_ASSET} ${CURRENCY} ${f_QUANTITY_CURRENCY} sell "${f_msg}"
# continue
# fi
# # check for SELL_PERCENTAGE_FROM_LAST_PURCHASE_SOFT
# if [ $(echo "${f_BUY_PRICE_LAST_RATE_DIFF} > ${SELL_PERCENTAGE_FROM_LAST_PURCHASE_SOFT}" | bc -l) -ne 0 ]
# then
# f_SELL="Selling ${f_QUANTITY_CURRENCY} ${CURRENCY} - SELL_PERCENTAGE_FROM_LAST_PURCHASE_SOFT(${SELL_PERCENTAGE_FROM_LAST_PURCHASE_SOFT}%) > Last rate (${f_BUY_PRICE_LAST_RATE_DIFF}%)"
# else
# g_echo_note "SELL ${f_ASSET}: compare current price $f_LAST_EXCHANGE_RATE and price at the time of purchase $f_BUY_PRICE (${f_BUY_PRICE_LAST_RATE_DIFF}) not over SELL_PERCENTAGE_FROM_LAST_PURCHASE_SOFT(${SELL_PERCENTAGE_FROM_LAST_PURCHASE_SOFT}%)"
# fi
# else
# g_echo_warn "SELL ${f_ASSET}: Missing TRADE_HIST_FILE (${f_TRADE_HIST_FILE})"
# fi
# ## check for SELL_PERCENTAGE_HARD
# get_rate_percentage_min_before_and_now $f_ASSET $CURRENCY 15 || continue
# if [ $(echo "${f_exchange_rate_diff_percentage} < ${SELL_PERCENTAGE_HARD}" | bc -l) -ne 0 ]
# then
# f_SELL="SELLING ${f_QUANTITY_CURRENCY} ${CURRENCY} - SELL_PERCENTAGE_HARD(${SELL_PERCENTAGE_HARD}%) > 15 minutes rate (${f_exchange_rate_diff_percentage}%)"
# else
# g_echo_note "SELL ${f_ASSET}: Rate change 15 minutes ago (${f_exchange_rate_diff_percentage}) not over SELL_PERCENTAGE_HARD(${SELL_PERCENTAGE_HARD}%)"
# fi
## check for SELL_PERCENTAGE_SOFT
# go through time intervals
# for f_min in ${MINUTE_STEPS_SELL}
# do
# # calculate rate change last defined minutes
# get_rate_percentage_min_before_and_now $f_ASSET $CURRENCY $f_min || continue
# if [ $(echo "${f_exchange_rate_diff_percentage} < ${SELL_PERCENTAGE_SOFT}" | bc -l) -ne 0 ]
# then
# f_SELL="SELLING ${f_QUANTITY_CURRENCY} ${CURRENCY} - SELL_PERCENTAGE_SOFT(${SELL_PERCENTAGE_SOFT}%) > $f_min minutes rate (${f_exchange_rate_diff_percentage}%)"
# break
# else
# g_echo_note "SELL ${f_ASSET}: Rate change $f_min ago (${f_exchange_rate_diff_percentage}) not over SELL_PERCENTAGE_SOFT(${SELL_PERCENTAGE_SOFT}%)"
# fi
# done
# dont sell if lock exists
#if [ -s "${f_ASSET}${CURRENCY}-sell.lock" ]
#then
# g_echo_note "SELL ${f_ASSET}: Not doing further checking - ${f_ASSET}${CURRENCY}-sell.lock exists and not older then 30 minutes"
# continue
#fi
# check last 5 minutes - if growth over 0.5% then hold (important for rally prices
#get_rate_percentage_min_before_and_now ${f_ASSET} ${CURRENCY} 5 || continue
#[ $(echo "${f_exchange_rate_diff_percentage} > 0.5" | bc -l) -ne 0 ] && continue
# # check last 10 minutes - if loss over -1% then sell
# get_rate_percentage_min_before_and_now ${f_ASSET} ${CURRENCY} 10
# if [ $(echo "${f_exchange_rate_diff_percentage} < -1" | bc -l) -ne 0 ]
# then
# f_SELL="SELL ${f_ASSET}: 10min Loss ${f_exchange_rate_diff_percentage} higher then -1%"
# g_echo_note "$f_SELL"
# fi
#
# # Sell on RSI higher then RSI_SELL_SIGNAL_FROM_FORCE
# local f_rsi=$(tail -n1 ${f_ASSET_HIST_FILE} | cut -d, -f3)
# if [ ${f_rsi} -ge ${RSI_SELL_SIGNAL_FROM_FORCE} ] && [ ${f_rsi} -lt 100 ]
# then
# f_SELL="SELL ${f_ASSET}: RSI: $f_rsi"
# g_echo_note "$f_SELL"
# fi
#
#
# # check MACD and RSI
# local f_macd=$(tail -n1 ${f_ASSET_HIST_FILE} | cut -d, -f7)
# g_echo_note "SELL ${f_ASSET}: Checking for indicators: RSI $f_rsi ; MACD: $f_macd"
# if [ $(echo "${f_macd} < 0" | bc -l) -ne 0 ]
# then
# g_echo_note "SELL ${f_ASSET}: trend change RSI $f_rsi ; MACD: $f_macd"
# if [ $(echo "${f_rsi} > 60" | bc -l) -ne 0 ]
# then
# f_SELL="SELL ${f_ASSET}: RSI: $f_rsi ; MACD: $f_macd"
# g_echo_note "$f_SELL"
# fi
# fi
# # check for SELL_CONDITION and RSI Indicator
# local f_condition
# local f_loopcount=0
# local f_conditioncount=0
# for f_condition in $SELL_CONDITION
# do
# local f_min=$(echo ${f_condition} | cut -d'<' -f1)
# local f_percentage=$(echo ${f_condition} | cut -d'<' -f2)
# get_rate_percentage_min_before_and_now ${f_ASSET} ${CURRENCY} ${f_min} || continue 2
# if [ $(echo "${f_exchange_rate_diff_percentage} < ${f_percentage}" | bc -l) -ne 0 ]
# then
# g_echo_note "SELL ${f_ASSET}: Price change met SELL_CONDITION (decrease of ${f_exchange_rate_diff_percentage}% higher then ${f_percentage}% in ${f_min} minutes."
# ((f_conditioncount=f_conditioncount+1))
# else
# g_echo_note "SELL ${f_ASSET}: Price change didn't meet SELL_CONDITION (decrease of ${f_exchange_rate_diff_percentage}% lower then ${f_percentage}% in ${f_min} minutes."
# fi
# ((f_loopcount=f_loopcount+1))
# done
# if [ $f_conditioncount -eq $f_loopcount ]
# then
# if [ ${f_rsi} -ge ${RSI_SELL_SIGNAL_FROM} ]
# then
# f_SELL="SELL ${f_ASSET}: Price change met all SELL_CONDITIONs ${SELL_CONDITION} ($f_conditioncount of $f_loopcount) with RSI ${f_rsi}"
# g_echo_note "$f_SELL"
# fi
# else
# g_echo_note "SELL ${f_ASSET}: Price change didn't meet SELL_CONDITIONs ${SELL_CONDITION} ($f_conditioncount of $f_loopcount)"
# fi
# # Sell or not sell?
# if [ -n "$f_SELL" ]
# then
# do_trade ${f_ASSET} ${CURRENCY} ${f_QUANTITY_CURRENCY} sell "${f_SELL}"
# fi
done
}

View File

@ -0,0 +1,143 @@
function check_sell_conditions {
local f_ASSET_HIST_FILE="$1"
f_ASSET=$(basename ${f_ASSET_HIST_FILE} | cut -d\. -f1)
### from here: check for defined state to sell
f_SELL=""
# get data
get_vars_from_csv ${f_ASSET_HIST_FILE} || return 1
### check current result
if [ -n "${BOT}" ]
then
f_TRADE_HIST_FILE="$(ls -1tr trade-histories/trade-*${f_ASSET}-open.history.csv | tail -n1)"
if ! [ -s "${f_TRADE_HIST_FILE}" ]
then
g_echo_note "SELL ${f_ASSET}: No trade history file (${f_TRADE_HIST_FILE}) found - ignoring"
return 0
fi
f_TRADE_HIST_FILE_INTERIM=$(echo ${f_TRADE_HIST_FILE} | sed 's/-open\.history\.csv$/-interim.history.csv/')
local f_BUY_PRICE=$(grep ',BUY' $f_TRADE_HIST_FILE | tail -n1 | cut -d, -f5)
local f_BUY_PRICE_LAST_RATE_DIFF=$(g_percentage-diff ${f_BUY_PRICE} ${f_price})
# Store for overview
echo ${f_BUY_PRICE_LAST_RATE_DIFF} >DIFF_BUY_PRICE_${f_ASSET}
else
f_TRADE_HIST_FILE="${g_tmp}/open-${tmpfile}"
f_TRADE_HIST_FILE_INTERIM="${g_tmp}/interim-${tmpfile}"
f_BUY_PRICE_LAST_RATE_DIFF=$(g_percentage-diff ${BUY_PRICE} ${f_price})
f_BUY_PRICE=${BUY_PRICE}
result=${f_BUY_PRICE_LAST_RATE_DIFF}
echo "${f_last_line}"
echo "INTERIM RESULT: ${f_BUY_PRICE_LAST_RATE_DIFF}%"
fi
# check if the result (profit/loss until now) is lowering and sell if too low ()
if [ -f ${f_TRADE_HIST_FILE_INTERIM} ]
then
local f_BUY_PRICE_2ND_LAST_RATE_DIFF=$(tail -n1 ${f_TRADE_HIST_FILE_INTERIM})
local f_diff_result=$(echo "${f_BUY_PRICE_LAST_RATE_DIFF} - (${f_BUY_PRICE_2ND_LAST_RATE_DIFF})" | bc | sed 's/^\./0./; s/^-\./-0./')
if [ $(echo "${f_diff_result} < ${SELL_IF_LAST_RATE_LOWER_THEN}" | bc -l) -ne 0 ] && [ $(echo "${f_BUY_PRICE_LAST_RATE_DIFF} > ${FEE}" | bc -l) -ne 0 ]
then
f_SELL="Loss between last (${f_BUY_PRICE_LAST_RATE_DIFF}%) and 2nd last (${f_BUY_PRICE_2ND_LAST_RATE_DIFF}%) rate/result more then ${SELL_IF_LAST_RATE_LOWER_THEN}% (${f_diff_result}%)"
fi
# Sell if the last X time units is lower then FEE
if [ $(cat ${f_TRADE_HIST_FILE_INTERIM} | wc -l) -ge ${SELL_IF_LOWER_THEN_FEE_AFTER_PERIOD} ]
then
local f_BUY_PRICE_XND_LAST_RATE_DIFF=$(tail -n${SELL_IF_LOWER_THEN_FEE_AFTER_PERIOD} ${f_TRADE_HIST_FILE_INTERIM} | head -n1)
local f_diff_result=$(echo "${f_BUY_PRICE_LAST_RATE_DIFF} - (${f_BUY_PRICE_XND_LAST_RATE_DIFF})" | bc)
if [ $(echo "${f_diff_result} < ${FEE}" | bc -l) -ne 0 ]
then
f_SELL="Loss between last rate (${f_BUY_PRICE_LAST_RATE_DIFF}%) in ${SELL_IF_LOWER_THEN_FEE_AFTER_PERIOD} time units before more then ${FEE} (${f_diff_result}%)"
fi
fi
fi
# store new interim result
echo ${f_BUY_PRICE_LAST_RATE_DIFF} >>${f_TRADE_HIST_FILE_INTERIM}
# Sell on MACD Condition
if [ $(echo "${f_macd_histogram_relation} < ${SELL_MACD_RELATION_FROM}" | bc -l) -ne 0 ]
then
f_SELL="MACD condition met"
fi
# Sell on RSI conditions
if \
[ ${f_rsi5} -le ${SELL_RSI5_SIGNAL_UNTIL} ] && \
[ ${f_rsi14} -le ${SELL_RSI14_SIGNAL_UNTIL} ] && \
[ ${f_rsi21} -le ${SELL_RSI21_SIGNAL_UNTIL} ] && \
[ ${f_rsi60} -le ${SELL_RSI60_SIGNAL_UNTIL} ] && \
[ ${f_rsi120} -le ${SELL_RSI120_SIGNAL_UNTIL} ] && \
[ ${f_rsi240} -le ${SELL_RSI240_SIGNAL_UNTIL} ] && \
[ ${f_rsi420} -le ${SELL_RSI420_SIGNAL_UNTIL} ] && \
[ ${f_rsi720} -le ${SELL_RSI720_SIGNAL_UNTIL} ]&& \
[ ${f_rsi5} -ge ${SELL_RSI5_SIGNAL_FROM} ] && \
[ ${f_rsi14} -ge ${SELL_RSI14_SIGNAL_FROM} ] && \
[ ${f_rsi21} -ge ${SELL_RSI21_SIGNAL_FROM} ] && \
[ ${f_rsi60} -ge ${SELL_RSI60_SIGNAL_FROM} ] && \
[ ${f_rsi120} -ge ${SELL_RSI120_SIGNAL_FROM} ] && \
[ ${f_rsi240} -ge ${SELL_RSI240_SIGNAL_FROM} ] && \
[ ${f_rsi420} -ge ${SELL_RSI420_SIGNAL_FROM} ] && \
[ ${f_rsi720} -ge ${SELL_RSI720_SIGNAL_FROM} ]
then
f_SELL="RSI conditions met"
fi
# hold on negative result
if [ "${SELL_HOLD_IF_RESULT_NEGATIVE}" -gt 0 ]
then
if [ $(echo "(${f_BUY_PRICE_LAST_RATE_DIFF} - ${FEE}) < 0" | bc -l) -ne 0 ]
then
g_echo_note "Result negative - holding (INTERIM RESULT ${f_BUY_PRICE_LAST_RATE_DIFF}% - FEE ${FEE}% < 0"
f_SELL=""
fi
fi
# check for SELL_PERCENTAGE_FROM_LAST_PURCHASE_NEGATIVE
if [ $(echo "${f_BUY_PRICE_LAST_RATE_DIFF} < ${SELL_PERCENTAGE_FROM_LAST_PURCHASE_NEGATIVE}" | bc -l) -ne 0 ]
then
f_SELL="SELL_PERCENTAGE_FROM_LAST_PURCHASE_NEGATIVE(${SELL_PERCENTAGE_FROM_LAST_PURCHASE_NEGATIVE}%) > Last rate (${f_BUY_PRICE_LAST_RATE_DIFF}%)"
fi
[ -n "$f_SELL" ] && f_SELL="SELL ${f_ASSET}@${CURRENCY}:${f_price}: $f_SELL"
### Sell or not sell?
# BOT
if [ -n "$f_SELL" ] && [ -n "${BOT}" ]
then
g_echo_note "$f_SELL"
echo "${f_last_line},${f_ASSET}" >>trade.log
f_ASSET=$(echo ${f_ASSET} | sed "s/${CURRENCY}//")
# binance_convert ${f_ASSET} ${CURRENCY} ${f_QUANTITY} sell "${f_SELL}"
if [ ${STOCK_EXCHANGE} = "BINANCE" ]
then
binance_convert ${f_ASSET} ${CURRENCY} ${f_QUANTITY} sell "${f_SELL}" ${f_QUANTITY_CURRENCY} || \
do_trade ${f_ASSET} ${CURRENCY} ${f_QUANTITY_CURRENCY} sell "${f_SELL}"
else
do_trade ${f_ASSET} ${CURRENCY} ${f_QUANTITY_CURRENCY} sell "${f_SELL}"
fi
fi
# ANALYZE
if [ -n "${f_SELL}" ] && [ -z "${BOT}" ]
then
echo "SELL: $(tail -n1 ${f_ASSET_HIST_FILE} | cut -d, -f1) === $f_SELL"
result=$(g_percentage-diff ${BUY_PRICE} ${current})
result=$(echo "${result}-${FEE}" | bc | sed 's/^\./0./; s/^-\./-0./')
echo "${result}" >>${g_tmp}/result-${tmpfile}
rm -f "${f_TRADE_HIST_FILE}"
rm -f "${f_TRADE_HIST_FILE_INTERIM}"
echo "RESULT: ${result}% (${BUY_PRICE} -> ${current})"
fi
}

134
functions/do_trade.sh Normal file
View File

@ -0,0 +1,134 @@
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
}

83
functions/get_asset.sh Normal file
View File

@ -0,0 +1,83 @@
function get_asset {
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
local f_ASSET="$1"
# write asset hist file with macd and rsi
local f_ASSET_HIST_FILE="asset-histories/${f_ASSET}.history-raw.csv"
[ -f "${f_ASSET_HIST_FILE}" ] || echo "Date and Time,Price" >"${f_ASSET_HIST_FILE}"
if ! grep -q "^$(echo "${f_timestamp}" | cut -d: -f1,2)" "${f_ASSET_HIST_FILE}"
then
local f_line="${f_timestamp},$(egrep "^${f_ASSET}," EXCHANGE_GET_ASSETS_CMD_OUT | cut -d, -f2)"
echo "${f_line}" >>${f_ASSET_HIST_FILE}
local f_linecount=0
local f_last_price=0
local f_lines="$(tail -n 51 "${f_ASSET_HIST_FILE}" | wc -l)"
for f_price in $(tail -n 50 "${f_ASSET_HIST_FILE}" | grep "^[0-9]" | cut -d, -f2)
do
if [ "$f_last_price" == "$f_price" ]
then
continue
fi
let "f_linecount+=1"
f_last_price=$f_price
done
if [ ${f_linecount} -le 3 ] && [ ${f_lines} -ge 50 ]
then
g_echo_note "${f_ASSET_HIST_FILE}: price seems not to change - ignoring"
return 0
fi
f_ASSET_HIST_FILE="asset-histories/${f_ASSET}.history.csv"
if [ ${f_linecount} -lt 30 ] && [ ${f_lines} -ge 50 ]
then
g_echo_note "${f_ASSET_HIST_FILE}: set price to 5 minute period"
if ! echo "${f_timestamp}" | egrep -q ":[0-5]0:|:[0-5]5:"
then
return 0
fi
fi
# headline
[ -s "${f_ASSET_HIST_FILE}" ] || echo 'Date and Time,Price,Price Change,EMA12,EMA26,MACD,EMA9 MACD (Signal),MACD Histogram,MACD Signal,RSI5,RSI14,RSI21,RSI720,RSI60,RSI120,RSI240,RSI420,Price Change 24h,Price Change 7d,Price Change 14d,Price Change 30d' >"${f_ASSET_HIST_FILE}"
# date and price
echo -n "${f_line}" >>${f_ASSET_HIST_FILE}
# calculate price change percentage
f_last_price=$(tail -n2 ${f_ASSET_HIST_FILE} | head -n1 | cut -d, -f2)
if echo $f_last_price | grep -q "^[0-9]"
then
f_price=$(tail -n1 ${f_ASSET_HIST_FILE} | cut -d, -f2)
local f_price_change=$(g_percentage-diff ${f_last_price} ${f_price})
else
local f_price_change=""
fi
echo -n ",${f_price_change}" >>"${f_ASSET_HIST_FILE}"
# calculate macd and rsi
get_macd_indicator ${f_ASSET_HIST_FILE}
get_rsi_indicator ${f_ASSET_HIST_FILE} 5
get_rsi_indicator ${f_ASSET_HIST_FILE} 14
get_rsi_indicator ${f_ASSET_HIST_FILE} 21
get_rsi_indicator ${f_ASSET_HIST_FILE} 720
get_rsi_indicator ${f_ASSET_HIST_FILE} 60
get_rsi_indicator ${f_ASSET_HIST_FILE} 120
get_rsi_indicator ${f_ASSET_HIST_FILE} 240
get_rsi_indicator ${f_ASSET_HIST_FILE} 480
# get coingecko price change
local f_asset=$(echo ${f_ASSET} | sed "s/${CURRENCY}\$//" | tr '[:upper:]' '[:lower:]')
echo -n ,$(jq -r ".[] |select(.symbol==\"${f_asset}\")|\"\\(.price_change_percentage_24h_in_currency)\"" COINGECKO_GET_ASSETS_CMD_OUT) >>${f_ASSET_HIST_FILE}
echo -n ,$(jq -r ".[] |select(.symbol==\"${f_asset}\")|\"\\(.price_change_percentage_7d_in_currency)\"" COINGECKO_GET_ASSETS_CMD_OUT) >>${f_ASSET_HIST_FILE}
echo -n ,$(jq -r ".[] |select(.symbol==\"${f_asset}\")|\"\\(.price_change_percentage_14d_in_currency)\"" COINGECKO_GET_ASSETS_CMD_OUT) >>${f_ASSET_HIST_FILE}
echo -n ,$(jq -r ".[] |select(.symbol==\"${f_asset}\")|\"\\(.price_change_percentage_30d_in_currency)\"" COINGECKO_GET_ASSETS_CMD_OUT) >>${f_ASSET_HIST_FILE}
# end with newline
echo "" >>${f_ASSET_HIST_FILE}
fi
}

150
functions/get_assets.sh Normal file
View File

@ -0,0 +1,150 @@
function get_assets {
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
## determine assets with prices
local f_filename="EXCHANGE_GET_ASSETS_CMD"
# Try to collect assets
# get data from API
if [ ${STOCK_EXCHANGE} = "BINANCE" ]
then
binance-api-call GET /api/v3/ticker/price || return 1
# parse API output
cat ${g_tmp}/API_CMD_OUT | jq -r '.[] | .symbol + "," + .price' | grep "${CURRENCY}," | egrep -v "${TRANSFER_CURRENCY},|,0[\.][0]*$" >${f_filename}_OUT.tmp
fi
# timestamp for data
f_timestamp=$(g_date_print)
# check output
if [ -s ${f_filename}_OUT.tmp ] && egrep -q "^[A-Z]+${CURRENCY},[0-9]*\.[0-9]+$" ${f_filename}_OUT.tmp
then
mv ${f_filename}_OUT.tmp ${f_filename}_OUT
else
g_echo_warn "${f_filename}_OUT.tmp has wrong Syntax. - Not updating ${f_filename}_OUT $(tail -n 10 ${f_filename}_OUT.tmp)"
return 2
fi
## write assets list and filter by marketcap and sort by price
# get krypto symbol list sorted by marketcap
echo "curl -s -X 'GET' \"https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=250&page=1&sparkline=false&price_change_percentage=1h,24h,7d,14d,30d\" -H 'accept: application/json'" >COINGECKO_GET_ASSETS_CMD
g_runcmd g_retrycmd sh COINGECKO_GET_ASSETS_CMD >COINGECKO_GET_ASSETS_CMD_OUT || return 1
#ASSET_MARKETCAP_OUT.tmp || return 1
if [ -s COINGECKO_GET_ASSETS_CMD_OUT ] && grep -q "market_cap_rank" COINGECKO_GET_ASSETS_CMD_OUT
then
# get marketcap sort
jq -r '.[].symbol' COINGECKO_GET_ASSETS_CMD_OUT | tr [:lower:] [:upper:] | head -n $LARGEST_MARKETCAP >ASSET_MARKETCAP_OUT.tmp-sort
if [ -s ASSET_MARKETCAP_OUT.tmp-sort ] && egrep -q "^[A-Z0-9]+$" ASSET_MARKETCAP_OUT.tmp-sort
then
mv ASSET_MARKETCAP_OUT.tmp-sort SORTMARKETCAP
else
g_echo_warn "ASSET_MARKETCAP_OUT.tmp-sort has wrong Syntax. - Not updating ASSET_MARKETCAP_OUT.tmp-sort $(tail -n 10 ASSET_MARKETCAP_OUT.tmp-sort)"
return 2
fi
# write down 24h pricechange
cat COINGECKO_GET_ASSETS_CMD_OUT | jq -r '.[] | .symbol + "," + (.price_change_percentage_24h|tostring)' | tr [:lower:] [:upper:] >ASSET_PRICE_CHANGE_PERCENTAGE_24H
# store coingecko symbolids for coingecko info URLs
jq -r '.[] | .symbol + "," + .id' COINGECKO_GET_ASSETS_CMD_OUT >COINGECKO_IDS.tmp
if [ -s COINGECKO_IDS.tmp ]
then
mv COINGECKO_IDS.tmp COINGECKO_IDS
else
g_echo_warn "COINGECKO_IDS.tmp has wrong Syntax. - Not updating COINGECKO_IDS $(tail -n 10 COINGECKO_IDS.tmp)"
return 2
fi
fi
# Write file with asset list and ignore marketcap under LARGEST_MARKETCAP
cat EXCHANGE_GET_ASSETS_CMD_OUT | cut -d"," -f1 | while read f_ASSET
do
# ignore marketcap under LARGEST_MARKETCAP
f_assetwocurrency=$(echo ${f_ASSET} | sed "s/$CURRENCY$//")
if ! egrep -q "^${f_assetwocurrency}$" SORTMARKETCAP
then
#g_echo_note "Ignoring $f_ASSET because of lower marketcap then Top ${LARGEST_MARKETCAP}"
continue
fi
echo ${f_ASSET} >>ASSETS.tmp
done
mv ASSETS.tmp ASSETS
## write histfiles by having a look on marketcap
#>ASSETS_HIGHEST.tmp
# get alread invested assets
#f_investedassets_regex=$(cat EXCHANGE_GET_BALANCES_CMD_OUT | cut -d, -f1 | perl -pe 's/^/\^/; s/\n/\|/' | perl -pe 's/\|$//')
local f_ASSET
local f_parallel_arg
echo -n "parallel -j3 bash -c --" >/tmp/parallel
for f_ASSET in $(cat ASSETS | egrep -v "${BLACKLIST}")
do
#get_asset "${f_ASSET}"
echo -n " \"get_asset ${f_ASSET}\"" >>/tmp/parallel
done
export -f get_asset
export f_timestamp
. /tmp/parallel
# cleanup trashlines (possibly generated by kill further of this progress)
sed -i "/[0-9]$(date +%Y)-/d" asset-histories/*
#cat ASSETS | while read f_ASSET
#do
# # write asset hist file with macd and rsi
# local f_ASSET_HIST_FILE="asset-histories/${f_ASSET}.history.csv"
# [ -f "${f_ASSET_HIST_FILE}" ] || touch "${f_ASSET_HIST_FILE}"
# if ! grep -q "^$(echo "${f_timestamp}" | cut -d: -f1,2)" "${f_ASSET_HIST_FILE}"
# then
# local f_line="${f_timestamp},$(egrep "^${f_ASSET}," EXCHANGE_GET_ASSETS_CMD_OUT | cut -d, -f2)"
# #g_echo_note "Writing new line (${f_line}) to history ${ASSET_HIST_FILE}"
# echo -n "${f_line}" >>${f_ASSET_HIST_FILE}
# get_macd_indicator ${f_ASSET_HIST_FILE}
# get_rsi_indicator ${f_ASSET_HIST_FILE} 30
# echo ",${f_macd},${f_rsi}" >>${f_ASSET_HIST_FILE}
# fi
# cat ASSETS | while read f_ASSET
# do
# # ignore already invested asset
# if echo "$f_ASSET" | egrep -q "$f_investedassets_regex"
# then
# g_echo_note "Already invested in $f_ASSET - ignoring for more diversification"
# continue
# fi
#
# # sort latest assets prices by highest in last timeframe (ignore - or 0)
# get_rate_percentage_min_before_and_now $(echo ${f_ASSET} | sed "s/${CURRENCY}\$//") ${CURRENCY} 1 || continue
# local f_ASSET_PERCENTAGE=${f_exchange_rate_diff_percentage}
# echo "$f_ASSET_PERCENTAGE" | egrep -q '^-|^0.0' && continue
# g_echo "adding ${f_ASSET}({$f_ASSET_PERCENTAGE}) to ASSETS_HIGHEST because marketcap in Top ${LARGEST_MARKETCAP}"
# echo "${f_ASSET_PERCENTAGE},${f_ASSET}" >>ASSETS_HIGHEST.tmp
# done
# cat ASSETS_HIGHEST.tmp | sort -r >ASSETS_HIGHEST.tmp2
# mv ASSETS_HIGHEST.tmp2 ASSETS_HIGHEST
# rm ASSETS_HIGHEST.tmp
# get MSCI World Index for analysis
echo "wget -q -O - https://www.boerse.de/realtime-kurse/MSCI-World/XC0009692739 | egrep 'itemprop=\"price\" content=\"[0-9]+\.[0-9]+\"' | cut -d\\\" -f6" >MSCI_WORLD_CMD
g_runcmd g_retrycmd sh MSCI_WORLD_CMD >MSCI_WORLD_CMD_OUT.tmp
# check output
if [ -s MSCI_WORLD_CMD_OUT.tmp ] && egrep -q "^[0-9]*\.[0-9]+$" MSCI_WORLD_CMD_OUT.tmp
then
if egrep -q "^0\.00$" MSCI_WORLD_CMD_OUT.tmp
then
g_echo_note "Ignoring MSCI World $(tail -n 10 MSCI_WORLD_CMD_OUT.tmp) - maybe out of business day"
else
mv MSCI_WORLD_CMD_OUT.tmp MSCI_WORLD_CMD_OUT
fi
else
g_echo_warn "MSCI_WORLD_CMD_OUT.tmp has wrong Syntax. - Not updating MSCI WORLD Index $(tail -n 10 MSCI_WORLD_CMD_OUT.tmp)"
fi
echo "${f_timestamp},$(cat MSCI_WORLD_CMD_OUT)" >>asset-histories/MSCI-WORLD-INDEX.history.csv
}

126
functions/get_balances.sh Normal file
View File

@ -0,0 +1,126 @@
function get_balances {
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
local f_filename="EXCHANGE_GET_BALANCES_CMD"
# get data from API
if [ ${STOCK_EXCHANGE} = "BINANCE" ]
then
binance_convert_dust
binance-api-call GET sapi/v1/capital/config/getall || return 1
# parse outout
cat ${g_tmp}/API_CMD_OUT | jq -r '.[] | .coin + "," + .free' | egrep -v ",0$|,0[\.][0]*$|${TRANSFER_CURRENCY}" | sort >${f_filename}_OUT.tmp_raw
fi
if ! [ -s ${f_filename}_OUT.tmp_raw ] && egrep -q "^[A-Z]+,[0-9]*\.[0-9]+$" ${f_filename}_OUT.tmp_raw
then
g_echo_warn "${f_filename}_OUT.tmp_raw has wrong Syntax or is empty. - Not updating ${f_filename}_OUT $(tail -n 10 ${f_filename}_OUT.tmp_raw)"
return 2
fi
# CURRENCY is defined
if [ -n "${CURRENCY}" ]
then
# put balance of (main) currency in global CURRENCY_BALANCE
local f_CURRENCY_BALANCE=$(egrep "^${CURRENCY}," ${f_filename}_OUT.tmp_raw | cut -d"," -f2)
if echo "${f_CURRENCY_BALANCE}" | egrep -q "^[0-9]*\.[0-9]*"
then
CURRENCY_BALANCE=${f_CURRENCY_BALANCE}
g_echo_note "Investmentbudget: $CURRENCY_BALANCE $CURRENCY"
else
g_echo_warn "Could not determine CURRENCY_BALANCE (${f_CURRENCY_BALANCE} ${CURRENCY}) from file ${f_filename}_OUT.tmp_raw $(cat ${f_filename}_OUT.tmp_raw)"
return 3
fi
# add balance in CURRNCY
local f_line
for f_line in $(cat ${f_filename}_OUT.tmp_raw)
do
local f_ASSET=$(echo ${f_line} | cut -d, -f1)
local f_QUANTITY=$(echo ${f_line} | cut -d, -f2)
if [ "${f_ASSET}" = "${CURRENCY}" ]
then
g_echo_note "own currency line $f_line"
echo "${f_ASSET},${f_QUANTITY},$f_QUANTITY,1.00000000" >>${f_filename}_OUT.tmp
continue
fi
local f_ASSET_HIST_FILE="asset-histories/${f_ASSET}${CURRENCY}.history.csv"
if ! [ -s ${f_ASSET_HIST_FILE} ]
then
g_echo_note "No history file (${f_ASSET_HIST_FILE}) found for asset (${f_ASSET}) - ignoring $f_line."
continue
fi
# ignore non traded currencies by bot
ls trade-histories/trade-*.${f_ASSET}${CURRENCY}-open.history.csv >/dev/null 2>&1 || continue
# get last prices
local f_LAST_EXCHANGE_PRICE=$(tail -n1 ${f_ASSET_HIST_FILE} | head -n1 | cut -d, -f2)
if ! echo "$f_LAST_EXCHANGE_PRICE" | egrep -q "^[0-9]"
then
g_echo_warn "didn't get latest price from ${f_ASSET_HIST_FILE}"
continue
fi
# calculate quantity in CURRENCY
local f_QUANTITY_CURRENCY=$(echo "scale=8; $f_LAST_EXCHANGE_PRICE*$f_QUANTITY" | bc -l | sed 's/^\./0./;')
if ! echo "$f_QUANTITY_CURRENCY" | egrep -q "^[0-9]"
then
g_echo_warn "could not calculate quantity in ${CURRENCY}"
continue
fi
# ignore low values
if [ $(echo "$f_QUANTITY_CURRENCY < 2" | bc -l) -ne 0 ]
then
g_echo_note "${f_ASSET}: Ignore low quantity asset ${f_ASSET}(${f_QUANTITY})"
continue
else
g_echo_note "${f_ASSET}: Going on with non-low quantity (>1) asset ${f_ASSET}(${f_QUANTITY})"
fi
echo "${f_ASSET},${f_QUANTITY},${f_QUANTITY_CURRENCY},${f_LAST_EXCHANGE_PRICE}" >>${f_filename}_OUT.tmp
done
fi
if [ -s ${f_filename}_OUT.tmp ] && egrep -q "^[A-Z]+,[0-9]*\.[0-9]+,[0-9]*\.[0-9]+,[0-9]*\.[0-9]+$" ${f_filename}_OUT.tmp
then
mv ${f_filename}_OUT.tmp ${f_filename}_OUT
else
g_echo_warn "${f_filename}_OUT.tmp has wrong Syntax or is empty. - Not updating ${f_filename}_OUT $(tail -n 10 ${f_filename}_OUT.tmp)"
return 2
fi
# get complete spot balance
local f_SPOT_BALANCE=0
local f_EXCHANGE_GET_BALANCES_CMD_OUT
for f_EXCHANGE_GET_BALANCES_CMD_OUT in $(cat EXCHANGE_GET_BALANCES_CMD_OUT | grep -v ^$CURRENCY,)
do
#local f_ASSET=$(echo ${f_EXCHANGE_GET_BALANCES_CMD_OUT} | cut -d"," -f1)
local f_QUANTITY_CURRENCY=$(echo ${f_EXCHANGE_GET_BALANCES_CMD_OUT} | cut -d"," -f3)
local f_SPOT_BALANCE=$(echo "scale=2; $f_SPOT_BALANCE+$f_QUANTITY_CURRENCY" | bc -l)
done
# calculate complete balance
local f_COMPLETE_BALANCE=$(echo "scale=2; $CURRENCY_BALANCE+$f_SPOT_BALANCE" | bc -l)
local f_timestamp=$(g_date_print)
# write balance history
echo "$f_timestamp,$f_COMPLETE_BALANCE" >>"asset-histories/BALANCECOMPLETE${CURRENCY}.history.csv"
echo "$f_timestamp,$f_SPOT_BALANCE" >>"asset-histories/BALANCESPOT${CURRENCY}.history.csv"
echo "$f_timestamp,$CURRENCY_BALANCE" >>"asset-histories/BALANCE${CURRENCY}.history.csv"
### global vars for overall performance last day, week, month
#get_rate_percentage_min_before_and_now BALANCECOMPLETE ${CURRENCY} 1440
#f_perf_day=${f_exchange_rate_diff_percentage}
#get_rate_percentage_min_before_and_now BALANCECOMPLETE ${CURRENCY} 10080
#f_perf_week=${f_exchange_rate_diff_percentage}
#get_rate_percentage_min_before_and_now BALANCECOMPLETE ${CURRENCY} 43200
#f_perf_month=${f_exchange_rate_diff_percentage}
}

27
functions/get_ema.sh Normal file
View File

@ -0,0 +1,27 @@
function get_ema {
local f_hist_file="$1"
local f_hist_file_column="$2"
local f_period="$3"
local f_last_ema="$4"
local f_lastvalue="$5"
f_ema=""
# calculate EMA if last EMA is given
if [ -n "$f_last_ema" ]
then
f_ema=$(echo "scale=10; ${f_lastvalue}*(2/(${f_period}+1))+${f_last_ema}*(1-(2/(${f_period}+1)))" | bc | sed 's/^\./0./; s/^-\./-0./' )
# calculate SMA12 only for first time as base for EMA and call it EMA if there are enough value periods
else
local f_period_sum=$(tail -n${f_period} "${f_hist_file}" | cut -d, -f${f_hist_file_column} | egrep "^[0-9]|-[0-9]" | wc -l)
if [ ${f_period_sum} -eq ${f_period} ]
then
f_ema=$(tail -n ${f_period} "${f_hist_file}" | cut -d"," -f${f_hist_file_column} | awk "{ SUM += \$1} END { printf(\"%10.10f\", SUM/${f_period}) }")
else
g_echo_note "${FUNCNAME} $@: Not enough data - waiting for more values. (${f_period} needed; ${f_period_sum} given)"
return 0
fi
fi
}

View File

@ -0,0 +1,118 @@
function get_macd_indicator {
#g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
# get histfile
local f_hist_file="$1"
# define or clean gloval macdvars
f_macd_ema12=""
f_macd_ema26=""
f_macd=""
f_macd_ema9_signal=""
f_macd_signal=""
if ! [ -s "$f_hist_file" ]
then
g_echo_warn "${FUNCNAME} $@: Histfile $f_hist_file does not exist or is empty"
return 1
fi
# read last two lines
local f_lastline=$(tail -n1 "$f_hist_file" | grep ^2)
local f_second_lastline=$(tail -n2 "$f_hist_file" | head -n1 | grep ^2)
# Try to get current MACD values
local f_macd_lastprice=$(echo "$f_lastline" | cut -d, -f2)
f_macd_ema12=$(echo "$f_lastline" | cut -d, -f4)
f_macd_ema26=$(echo "$f_lastline" | cut -d, -f5)
f_macd=$(echo "$f_lastline" | cut -d, -f6)
f_macd_ema9_signal=$(echo "$f_lastline" | cut -d, -f7)
# if data is complete
if [ -n "${f_macd_ema12}" ] && [ -n "${f_macd_ema26}" ] && [ -n "${f_macd}" ] && [ -n "${f_macd_ema9_signal}" ]
then
g_echo_note "${FUNCNAME} $@: Looks like current MACD was already calculated"
return 1
fi
# Try to get last MACD values
f_macd_last_ema12=$(echo "$f_second_lastline" | cut -d, -f4)
f_macd_last_ema26=$(echo "$f_second_lastline" | cut -d, -f5)
f_macd_last=$(echo "$f_second_lastline" | cut -d, -f6)
f_macd_last_ema9_signal=$(echo "$f_second_lastline" | cut -d, -f7)
f_macd_last_histogram=$(echo "$f_second_lastline" | cut -d, -f8)
# calc EMA12
get_ema "${f_hist_file}" 2 12 "${f_macd_last_ema12}" "${f_macd_lastprice}"
if [ -z "${f_ema}" ]
then
g_echo_note "${FUNCNAME} $@: Not enough data for calculating EMA12 - waiting for more values"
echo -n ",,,,,," >>"${f_hist_file}"
return 0
fi
f_macd_ema12=${f_ema}
echo -n ",${f_macd_ema12}" >>"${f_hist_file}"
# calc EMA26
if [ -z "${f_macd_last_ema12}" ]
then
echo -n ",,,,," >>"${f_hist_file}"
return 0
fi
get_ema "${f_hist_file}" 2 26 "${f_macd_last_ema26}" "${f_macd_lastprice}"
if [ -z "${f_ema}" ]
then
g_echo_note "${FUNCNAME} $@: Not enough data for calculating EMA26 - waiting for more values"
echo -n ",,,,," >>"${f_hist_file}"
return 0
fi
f_macd_ema26=${f_ema}
echo -n ",${f_macd_ema26}" >>"${f_hist_file}"
# calc MACD
if [ -z "${f_macd_ema26}" ]
then
echo -n ",,,," >>"${f_hist_file}"
return 0
fi
#[ -z "${f_macd_ema12}" ] && return 0
f_macd=$(echo "scale=8; ${f_macd_ema12}-${f_macd_ema26}" | bc | sed 's/^\./0./; s/^-\./-0./')
echo -n ",${f_macd}" >>"${f_hist_file}"
# calc MACD Signal
if [ -z "${f_macd}" ]
then
echo -n ",,," >>"${f_hist_file}"
return 0
fi
get_ema "${f_hist_file}" 6 9 "${f_macd_last_ema9_signal}" "${f_macd}"
if [ -z "${f_ema}" ]
then
g_echo_note "${FUNCNAME} $@: Not enough data for calculating EMA9 Signal - waiting for more values"
echo -n ",,," >>"${f_hist_file}"
return 0
fi
f_macd_ema9_signal=${f_ema}
echo -n ",${f_macd_ema9_signal}" >>"${f_hist_file}"
# calc MACD Histogram
f_macd_histogram=$(echo "scale=10; ${f_macd}-(${f_macd_ema9_signal})" | bc | sed 's/^\./0./; s/^-\./-0./')
echo -n ",${f_macd_histogram}" >>"${f_hist_file}"
# check for MACD buy or sell signal
echo ${f_macd_histogram} | grep -q "^-" && echo ${f_macd_last_histogram} | grep -q "^[0-9]" && f_macd_signal="sell"
echo ${f_macd_histogram} | grep -q "^[0-9]" && echo ${f_macd_last_histogram} | grep -q "^-" && f_macd_signal="buy"
# calculate MACD Histogram relation
if [ $(tail -n36 "${f_hist_file}" | wc -l) -ge 35 ]
then
local f_macd_histogram_max=$(tail -n60 "${f_hist_file}" | cut -d"," -f8 | egrep "^[0-9]|^-[0-9]" | sed 's/^-//' | sort -n | tail -n1)
local f_macd_histogram_relation=$(echo "100+$(g_percentage-diff ${f_macd_histogram_max} ${f_macd_histogram})" | bc | sed 's/^\./0./; s/^-\./-0./' | cut -d\. -f1)
fi
echo -n ",${f_macd_histogram_relation}|${f_macd_signal}" >>"${f_hist_file}"
}

View File

@ -0,0 +1,63 @@
function get_rate_percentage_min_before_and_now {
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
# get vars
local f_asset=$1
local f_currency=$2
local f_min=$3
# Optional time from min before sould be calculated (to be able to calculate from 5 min before to 10 minutes before)
local f_min_from=$4
# clean up global variable (maybe used in runs before)
f_exchange_rate_diff_percentage=""
local f_asset_hist_file="asset-histories/${f_asset}${f_currency}.history.csv"
if [ -s "f_asset_hist_file" ]
then
g_echo_note "${f_asset}: No or empty histfile(${f_asset_hist_file}) found"
return 1
fi
# prepare date
if [ -n "${f_min_from}" ]
then
local f_min_date_from=$(date "+%F %H:%M:" --date="-${f_min_from} minutes")
f_min=$((f_min+f_min_from))
else
local f_min_date_from=$(date "+%F %H:%M:")
fi
local f_min_date=$(date "+%F %H:%M:" --date="-${f_min} minutes")
if [ -z "${f_min_date}" ]
then
g_echo_warn "${f_asset}: Error while calculating date ${f_min} before"
return 1
fi
# get current exchange rate
local f_current_exchange_rate=$(egrep "^${f_min_date_from}" ${f_asset_hist_file} | cut -d, -f2)
if [ -z "${f_current_exchange_rate}" ]
then
g_echo_note "${f_asset}: From rate $f_min_from ${f_min_date_from} not found in ${f_asset_hist_file}"
return 1
fi
# get exchange rate defined minutes before
local f_min_before_exchange_rate=$(egrep "^${f_min_date}" ${f_asset_hist_file} | cut -d, -f2)
if [ -z "${f_min_before_exchange_rate}" ]
then
g_echo_note "${f_asset}: Rate ${f_min} minutes ago not found in ${f_asset_hist_file}"
return 2
fi
# calculate difference in percentage between current rate and rate defined minutes before
f_exchange_rate_diff_percentage=$(g_percentage-diff ${f_min_before_exchange_rate} ${f_current_exchange_rate})
if [ -z "$f_exchange_rate_diff_percentage" ]
then
g_echo_warn "${f_asset}: Calculating difference between rate ${f_min} minutes ago (${min_before_exchange_rate}) and current (${m_current_exchange_rate}) in percentage failed"
return 3
fi
# give back percentage
g_echo_note "${f_asset}: difference from ${f_current_exchange_rate} from ${f_min_date_from} and ${f_min_date} ${f_min_before_exchange_rate}: ${f_exchange_rate_diff_percentage}%"
return 0
}

View File

@ -0,0 +1,79 @@
function get_rsi_indicator {
#g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
# get histfile
local f_hist_file="$1"
local f_last_minutes="$2"
# calculate change of lastest f_last_minutes+1 prices for calculating rsi over the last f_last_minutes periods
local f_price
local f_last_price
local f_positive_sum=0
local f_negative_sum=0
f_rsi=""
local f_period=$((f_last_minutes+1))
local f_period_sum=$(tail -n${f_period} "${f_hist_file}" | cut -d, -f2 | grep "^[0-9]" | wc -l)
if ! [ ${f_period_sum} -ge ${f_period} ]
then
g_echo_note "${FUNCNAME} $@: Not enough data - waiting for more values. (${f_period} needed; ${f_period_sum} given)"
echo -n ",${f_rsi}" >>"${f_hist_file}"
return 0
fi
# for f_price in $(tail -n${f_period} "${f_hist_file}" | cut -d"," -f2)
# do
# # not for the first line because a comparative value is missing
# if [ -z "${f_last_price}" ]
# then
# f_last_price=${f_price}
# continue
# fi
#
# # calculate each change
# local f_price_change=$(g_percentage-diff ${f_last_price} ${f_price})
# f_last_price=${f_price}
#
# # add positive/negative changes
# if echo "${f_price_change}" | grep -q '^-'
# then
# f_negative_sum=$(echo "${f_negative_sum}+${f_price_change}" | bc -l)
# else
# f_positive_sum=$(echo "${f_positive_sum}+${f_price_change}" | bc -l)
# fi
# done
f_positive_sum=$(tail -n${f_period} "${f_hist_file}" | cut -d"," -f3 | grep "^[0-9]" | awk "{ SUM += \$1} END { printf(\"%10.10f\", SUM/${f_period}) }")
f_negative_sum=$(tail -n${f_period} "${f_hist_file}" | cut -d"," -f3 | grep "^-[0-9]" | awk "{ SUM += \$1} END { printf(\"%10.10f\", SUM/${f_period}) }")
# if one of both is "0" then fix results
if [ ${f_negative_sum} == "0.0000000000" ]
then
f_rsi=100
#g_echo_note "RSI-Indicator RSI: ${f_rsi}%"
echo -n ",${f_rsi}" >>"${f_hist_file}"
return 0
fi
if [ ${f_positive_sum} == "0.0000000000" ]
then
f_rsi=0
#g_echo_note "RSI-Indicator RSI: ${f_rsi}%"
echo -n ",${f_rsi}" >>"${f_hist_file}"
return 0
fi
# calculate positive/negative change averages
local f_negative_sum_average=$(echo "${f_negative_sum}/${f_last_minutes}" | bc -l | sed 's/-//')
local f_positive_sum_average=$(echo "${f_positive_sum}/${f_last_minutes}" | bc -l)
# calculate RS and RSI
local f_rs=$(echo "${f_positive_sum_average}/${f_negative_sum_average}" | bc -l)
f_rsi=$(echo "100-(100/(1+${f_rs}))" | bc -l | xargs printf "%.0f")
echo -n ",${f_rsi}" >>"${f_hist_file}"
#g_echo_note "RSI-Indicator RSI: ${f_rsi}%"
}

View File

@ -0,0 +1,47 @@
function get_vars_from_csv {
local f_ASSET_HIST_FILE="$1"
if ! [ -s "${f_ASSET_HIST_FILE}" ]
then
g_echo_warn "${f_ASSET_HIST_FILE} does not exist or is empty"
return 1
fi
f_last_line="$(tail -n1 "${f_ASSET_HIST_FILE}")"
readarray -d "," -t f_last_line_array < <(echo "0,${f_last_line}")
get_var_from_line date 1
get_var_from_line price 2
get_var_from_line price_change 3
get_var_from_line macd_histogram 8
get_var_from_line macd_signal_relation 9
f_macd_histogram_relation=$(echo "${f_macd_signal_relation}" | cut -d\| -f1)
f_macd_histogram_signal=$(echo "${f_macd_signal_relation}" | cut -d\| -f2)
get_var_from_line rsi5 10
get_var_from_line rsi14 11
get_var_from_line rsi21 12
get_var_from_line rsi720 13
get_var_from_line rsi60 14
get_var_from_line rsi120 15
get_var_from_line rsi240 16
get_var_from_line rsi420 17
get_var_from_line price_change_1_day 18
get_var_from_line price_change_7_day 19
get_var_from_line price_change_14_day 20
get_var_from_line price_change_30_day 21
}
function get_var_from_line {
if [ -z "${f_last_line_array[$2]}" ]
then
g_echo_note "Didn't get $1 in position $2"
return 1
fi
declare -g f_$1="$(echo ${f_last_line_array[$2]})"
}

View File

@ -0,0 +1,92 @@
function market_performance {
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
## function for scoring limits set in config up or down by specific (market) facts
# generates variable f_market_performance
# forecast bitcoin (is quartered because uncertain)
f_url="https://30rates.com/btc-to-usd-forecast-today-dollar-to-bitcoin"
[ -e btc-forecast ] && find btc-forecast -mmin +60 -delete
if ! [ -s btc-forecast ]
then
g_runcmd g_retrycmd curl -s "$f_url" >btc-forecast || return 1
fi
local f_forecast=$(cat btc-forecast | hxnormalize -x | hxselect 'table' | grep "<strong>" | grep -A1 "Price" -m1 | tail -n1 | cut -d'>' -f3 | cut -d'<' -f1)
if ! echo "$f_forecast" | egrep -q '^[0-9]*\.[0-9]*$|^[0-9]*$'
then
g_echo_warn "Didn't get correct forecast from $f_url"
return 1
fi
local f_today=$(cat btc-forecast | hxnormalize -x | hxselect 'table' | egrep '<strong>' | head -n1 | cut -d'>' -f3 | cut -d'<' -f1)
if ! echo "$f_today" | egrep -q '^[0-9]*\.[0-9]*$|^[0-9]*$'
then
g_echo_warn "Didn't get correct forecast from $f_url"
return 1
fi
local f_btc_forecast=$(g_percentage-diff ${f_today} ${f_forecast})
echo $f_btc_forecast | egrep -q '[0-9]\.[0-9]' || return 1
g_echo_note "BTC forecast: $f_btc_forecast"
f_btc_forecast=$(echo "scale=2; ${f_btc_forecast}/3" | bc -l | sed -r 's/^(-?)\./\10./')
# forecast ethereum (is quartered because uncertain)
local f_url="https://30rates.com/ethereum-price-prediction-tomorrow-week-month-eth-forecast"
[ -e eth-forecast ] && find eth-forecast -mmin +60 -delete
if ! [ -s eth-forecast ]
then
g_runcmd g_retrycmd curl -s "$f_url" >eth-forecast || return 1
fi
f_forecast=$(cat eth-forecast | hxnormalize -x | hxselect 'table' | grep "<strong>" | grep -A1 "Price" -m1 | tail -n1 | cut -d'>' -f3 | cut -d'<' -f1)
if ! echo "$f_forecast" | egrep -q '^[0-9]*\.[0-9]*$|^[0-9]*$'
then
g_echo_warn "Didn't get correct forecast $f_forecast from $f_url"
return 1
fi
f_today=$(cat eth-forecast | hxnormalize -x | hxselect 'table' | egrep '<strong>' | head -n1 | cut -d'>' -f3 | cut -d'<' -f1)
if ! echo "$f_today" | egrep -q '^[0-9]*\.[0-9]*$|^[0-9]*$'
then
g_echo_warn "Didn't get correct forecast from $f_url"
return 1
fi
local f_eth_forecast=$(g_percentage-diff ${f_today} ${f_forecast})
echo $f_eth_forecast | egrep -q '[0-9]\.[0-9]' || return 1
g_echo_note "ETH forecast: $f_eth_forecast"
f_eth_forecast=$(echo "scale=2; ${f_eth_forecast}/3" | bc -l | sed -r 's/^(-?)\./\10./')
# price performance msci world (last week and halved because of the long time)
#local f_back=240
#[[ $(date +%u) -eq 6 ]] && f_back=1500
#[[ $(date +%u) -eq 7 ]] && f_back=2940
local f_from=$(tail -n 10080 asset-histories/MSCI-WORLD-INDEX.history.csv | grep -v ^[A-Z] | head -n1 | cut -d, -f2)
local f_to=$(tail -n 1 asset-histories/MSCI-WORLD-INDEX.history.csv | cut -d, -f2)
local f_exchange_rate_diff_percentage=$(g_percentage-diff ${f_from} ${f_to})
#local f_back=10080
#get_rate_percentage_min_before_and_now MSCI-WORLD- INDEX $f_back || return 1
local f_msci_world_performance=$(echo "scale=2; ${f_exchange_rate_diff_percentage}/2" | bc -l | sed -r 's/^(-?)\./\10./')
# price performance bitcoin (last 30 minutes)
local f_from=$(tail -n 30 asset-histories/BTC${CURRENCY}.history.csv | grep -v ^[A-Z] | head -n1 | cut -d, -f2)
local f_to=$(tail -n 1 asset-histories/BTC${CURRENCY}.history.csv | cut -d, -f2)
local f_exchange_rate_diff_percentage=$(g_percentage-diff ${f_from} ${f_to})
#get_rate_percentage_min_before_and_now BTC ${CURRENCY} 360 || return 1
local f_btc_performance=${f_exchange_rate_diff_percentage}
# price performance ethereum (last 30 minutes)
#get_rate_percentage_min_before_and_now ETH ${CURRENCY} 360 || return 1
local f_from=$(tail -n 30 asset-histories/ETH${CURRENCY}.history.csv | grep -v ^[A-Z] | head -n1 | cut -d, -f2)
local f_to=$(tail -n 1 asset-histories/ETH${CURRENCY}.history.csv | cut -d, -f2)
local f_exchange_rate_diff_percentage=$(g_percentage-diff ${f_from} ${f_to})
local f_eth_performance=${f_exchange_rate_diff_percentage}
# hourly price performance over TOP 250 marketcap by coingecko
local f_top250_marketcap_performance=$(jq -r ".[].price_change_percentage_1h_in_currency" COINGECKO_GET_ASSETS_CMD_OUT | awk '{ SUM += $1} END { printf("%.2f", SUM/250) }')
## calculate market performance
f_market_performance=$(echo "scale=2; (${f_btc_forecast} + ${f_eth_forecast} + ${f_msci_world_performance} + ${f_btc_performance} + ${f_eth_performance} + ${f_top250_marketcap_performance})/6" | bc -l | sed -r 's/^(-?)\./\10./')
local f_date=$(g_date_print)
echo "${f_date} Market Performance: ${f_market_performance}%; BTC forecast: ${f_btc_forecast}%; ETH forecast: ${f_eth_forecast}%; MSCI WORLD: ${f_msci_world_performance}%; BTC: ${f_btc_performance}%; ETH: ${f_eth_performance}%; TOP250 Marketcap: ${f_top250_marketcap_performance}%" >>MARKET_PERFORMANCE
echo -n "${f_market_performance}" >MARKET_PERFORMANCE_LATEST
}

232
functions/webpage.sh Normal file
View File

@ -0,0 +1,232 @@
function webpage {
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
# create status webpage
echo '<html><head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="60" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="/browser.css">
<title>Statuspage Crypto Bot</title>
</head><body>' >../index.html.tmp
echo "<h1>Statuspage Crypto Bot (ReadOnly)</h1>
<h1>Last update $(date "+%F %T")</h1>" >>../index.html.tmp
local f_SPOT_BALANCE=$(tail -n1 "asset-histories/BALANCESPOT${CURRENCY}.history.csv" | cut -d, -f2)
local f_COMPLETE_BALANCE=$(tail -n1 "asset-histories/BALANCECOMPLETE${CURRENCY}.history.csv" | cut -d, -f2)
echo '<h2>Overview</h2>' >>../index.html.tmp
echo "<table>
<tr>
<td><b>Overall Balance:</b></td>
<td><font color=green><b>${CURRENCY} ${f_COMPLETE_BALANCE}</b></font></td>
</td>
<tr>
<td>SPOT Balance (invested):</td>
<td><font color=blue>${CURRENCY} $f_SPOT_BALANCE</font></td>
</tr>
<tr>
<td>Free Balance (not invested):</td>
<td><font color=yellow>${CURRENCY} ${CURRENCY_BALANCE}</font></td>
</tr>
</table>" >>../index.html.tmp
echo "<h2>Trade Performance (overall closed trades)</h2>" >>../index.html.tmp
echo "<table>
<tr>
<td>Performance day (last 24 hours):</td>
<td> $(find trade-histories -name "*-closed.history.csv.result" -mtime -1 -exec cat {} \; | awk '{ SUM += $1} END { printf("%.2f", SUM) }')%</td>
</td>
<tr>
<td>Performance week (last 7 days):</td>
<td> $(find trade-histories -name "*-closed.history.csv.result" -mtime -7 -exec cat {} \; | awk '{ SUM += $1} END { printf("%.2f", SUM) }')%</td>
</tr>
<tr>
<td>Performance month (last 30 days):</td>
<td> $(find trade-histories -name "*-closed.history.csv.result" -mtime -31 -exec cat {} \; | awk '{ SUM += $1} END { printf("%.2f", SUM) }')%</td>
</tr>
<tr>
<td>Performance complete):</td>
<td> $(find trade-histories -name "*-closed.history.csv.result" -exec cat {} \; | awk '{ SUM += $1} END { printf("%.2f", SUM) }')%</td>
</tr>
</table>" >>../index.html.tmp
echo '<h2>Open Trades (Invested Assets)</h2>' >>../index.html.tmp
echo "<table>" >>../index.html.tmp
local line
cat EXCHANGE_GET_BALANCES_CMD_OUT | grep -v ${CURRENCY} | sort | while read line
do
local spot_balances=($(echo $line | sed 's/,/ /g'))
echo "<tr>
<td><a href=\"botdata/asset-histories/${spot_balances[0]}${CURRENCY}.history.csv\">${spot_balances[0]}</a> <a href=\"https://www.coingecko.com/de/munze/$(egrep -i ^$(echo ${spot_balances[0]} | sed "s/${CURRENCY}$//"), COINGECKO_IDS | cut -d, -f2 )\">🔗</a></td>
<td>${spot_balances[1]}</td>
<td>${CURRENCY} ${spot_balances[2]} ( $(cat DIFF_BUY_PRICE_${spot_balances[0]}${CURRENCY})%)</td>
</tr>" >>../index.html.tmp
done
echo "</table>" >>../index.html.tmp
echo "<h2>Market Performance ( $(cat MARKET_PERFORMANCE_LATEST)%)</h2>" >>../index.html.tmp
echo -e "<pre>$(egrep ":00:" MARKET_PERFORMANCE | tail -n10)\n$(tail -n1 MARKET_PERFORMANCE)</pre>" >>../index.html.tmp
echo "<a href=\"botdata/MARKET_PERFORMANCE\">Complete list</a>" >>../index.html.tmp
echo '<h2>Latest trades</h2>' >>../index.html.tmp
echo '<h3>Open</h3>' >>../index.html.tmp
echo "<table><tr>" >>../index.html.tmp
echo "<td>Date</td>
<td>Asset</td>
<td>Action</td>
<td>${CURRENCY} Quantity</td>
<td>${CURRENCY} Price</td>
<td>Commission</td>
<td>Comment</td></tr>" >>../index.html.tmp
local f_trade_file
for f_trade_file in $(ls -t trade-histories/trade-*-open.history.csv 2>/dev/null)
do
local tradeline=$(tail -n1 ${f_trade_file})
local asset=$(echo ${f_trade_file} | cut -d. -f3 | cut -d- -f1)
echo "<td>$(echo ${tradeline} | cut -d, -f1)</td>
<td><a href=\"botdata/asset-histories/${asset}.history.csv\">${asset}</a> <a href=\"https://www.coingecko.com/de/munze/$(egrep -i ^$(echo ${asset} | sed "s/${CURRENCY}$//"), COINGECKO_IDS | cut -d, -f2 )\">🔗</a></td>
<td>$(echo ${tradeline} | cut -d, -f2)</td>
<td>$(echo ${tradeline} | cut -d, -f4)</td>
<td>$(echo ${tradeline} | cut -d, -f5)</td>
<td>$(echo ${tradeline} | cut -d, -f6)</td>
<td>$(echo ${tradeline} | cut -d, -f7,8,9,10,11,12,13,14,15)</td>
</tr>" >>../index.html.tmp
done
echo "</table>" >>../index.html.tmp
echo '<h3>Closed</h3>' >>../index.html.tmp
echo "<table><tr>" >>../index.html.tmp
echo "<td>Date</td>
<td>Asset</td>
<td>Action</td>
<td>${CURRENCY} Quantity</td>
<td>${CURRENCY} Price (result)</td>
<td>Commission</td>
<td>Comment</td></tr>" >>../index.html.tmp
for f_trade_file in $(ls -t trade-histories/trade-*-closed.history.csv 2>/dev/null | head -n 50)
do
local tradeline
cat ${f_trade_file} | while read tradeline
do
local f_action=$(echo ${tradeline} | cut -d, -f2)
local f_price=$(echo ${tradeline} | cut -d, -f5)
if echo ${f_action} | grep -q buy
then
echo ${f_price} >${g_tmp}/buyprice
fi
if echo ${f_action} | grep -q sell
then
if [ -s "${f_trade_file}.result" ]
then
local f_profit=$(cat "${f_trade_file}.result")
f_price="${f_price} ( ${f_profit}%)"
else
local f_profit=$(g_percentage-diff $(cat ${g_tmp}/buyprice) ${f_price})
f_price="${f_price} ( ${f_profit}%)"
echo "${f_profit}" >"${f_trade_file}.result"
fi
fi
local asset=$(echo ${f_trade_file} | cut -d. -f3 | cut -d- -f1)
echo "<td>$(echo ${tradeline} | cut -d, -f1)</td>
<td><a href=\"botdata/asset-histories/${asset}.history.csv\">${asset}</a> <a href=\"https://www.coingecko.com/de/munze/$(egrep -i ^$(echo ${asset} | sed "s/${CURRENCY}$//"), COINGECKO_IDS | cut -d, -f2 )\">🔗</a></td>
<td>${f_action}</td>
<td>$(echo ${tradeline} | cut -d, -f4)</td>
<td>${f_price}</td>
<td>$(echo ${tradeline} | cut -d, -f6)</td>
<td>$(echo ${tradeline} | cut -d, -f7,8,9,10,11,12,13,14,15)</td>
</tr>" >>../index.html.tmp
done
done
echo "</table>" >>../index.html.tmp
# echo "<table><tr>" >>../index.html.tmp
# echo "<td>Date</td>
# <td>Asset</td>
# <td>Action</td>
# <td>${CURRENCY} Quantity</td>
# <td>${CURRENCY} Price (profit/loss)</td>
# <td>Commission</td>
# <td>Comment</td></tr>" >>../index.html.tmp
# grep ^20 trade-histories/*history.csv | sed 's/\// /; s/\./ /; s/:/ /; s/,/ /g' | sort -r -k3 >${g_tmp}/trade-hist-complete
# local tradeline
# cat ${g_tmp}/trade-hist-complete | while read tradeline
# do
# # use array trade
# local trade=($tradeline)
# local f_trace_price=${trade[8]}
# if [ ${trade[4]} = "sell" ]
# then
# local f_trade_date=${trade[3]}
# local f_trade_currency=${trade[1]}
# local f_trade_sell_for=${trade[6]}
# local f_trade_buy_for=$(grep -B1 "^${f_trade_date},sell," "trade-histories/${f_trade_currency}.history.csv" | grep ",buy," | cut -d, -f4 | cut -d" " -f1)
# local f_result=$(echo "scale=2; ${f_trade_sell_for}-$f_trade_buy_for" | bc -l | sed 's/^\./0./; s/^-\./-0./' | xargs printf "%.2f")
# local f_result_percentage=$(g_percentage-diff $f_trade_buy_for ${f_trade_sell_for})
# f_trace_price="$f_trace_price ($f_result( ${f_result_percentage}%))"
# #echo "${trade[1]} $f_trade_buy_for -- ${f_trade_sell_for} == $f_result(${f_result_percentage}%)"
# fi
# echo "<td>${trade[3]}</td>
# <td><a href=\"botdata/asset-histories/${trade[1]}.history.csv\">${trade[1]}</a> <a href=\"https://www.coingecko.com/de/munze/$(egrep -i ^$(echo ${trade[1]} | sed "s/${CURRENCY}$//"), COINGECKO_IDS | cut -d, -f2 )\">🔗</a></td>
# <td>${trade[4]}</td>
# <td>${trade[6]}</td>
# <td>${f_trace_price}</td>
# <td>${trade[9]} ${trade[10]}</td>
# <td>${trade[@]:11:30}</td>
# </tr>" >>../index.html.tmp
#
# done
# echo "</table>" >>../index.html.tmp
echo "<h2>Current config</h2>" >>../index.html.tmp
echo "<pre>$(cat ../../bot.conf | perl -pe 's/\</&#60;/g; s/\>/&#62;/g;')</pre>" >>../index.html.tmp
echo '<h2>Available Assets and histories</h2>' >>../index.html.tmp
echo "<table><tr>" >>../index.html.tmp
echo "<tr><td>Asset</td><td>Date</td><td>Price ${CURRENCY}</td><td>24h change (USD)</td></tr>" >>../index.html.tmp
local asset
cat ASSETS | egrep -v "${BLACKLIST}" | sort | while read asset
do
[ -s asset-histories/${asset}.history.csv ] || continue
echo "<td><a href=\"botdata/asset-histories/${asset}.history.csv\">${asset}</a> <a href=\"https://www.coingecko.com/de/munze/$(egrep -i ^$(echo ${asset} | sed "s/${CURRENCY}$//"), COINGECKO_IDS | cut -d, -f2 )\">🔗</a></td>" >>../index.html.tmp
kcurrency=$(echo ${asset} | sed "s/${CURRENCY}//")
#get_rate_percentage_min_before_and_now ${kcurrency} ${CURRENCY} 1440
local asset=($(cat asset-histories/${asset}.history.csv | egrep -v "0.00000000$" | tail -n2 | head -n1 | sed 's/,/ /g'))
echo "
<td>${asset[0]} ${asset[1]}</td>
<td>${CURRENCY} ${asset[2]}</td>
<td> $(grep "^$kcurrency," ASSET_PRICE_CHANGE_PERCENTAGE_24H | cut -d, -f2)%</td>
</tr>" >>../index.html.tmp
done
echo "</table>" >>../index.html.tmp
echo '<h2>Complete trading histories</h2>' >>../index.html.tmp
echo "<table>" >>../index.html.tmp
find trade-histories -type f -name *.history.csv | cut -d/ -f2 | cut -d. -f1 | sort | while read asset
do
[ -s trade-histories/${asset}.history.csv ] || continue
echo "<tr><td><a href=\"botdata/trade-histories/${asset}.history.csv\">${asset}</a> <a href=\"https://www.coingecko.com/de/munze/$(egrep -i ^$(echo ${asset} | sed "s/${CURRENCY}$//"), COINGECKO_IDS | cut -d, -f2 )\">🔗</a></td></tr>" >>../index.html.tmp
done
echo "</table>" >>../index.html.tmp
# color magic
cat ../index.html.tmp | perl -pe 's/ (\-[0-9]+\.[0-9]+\%)/<font color=red>$1<\/font>/g; s/ ([0-9]+\.[0-9]+\%)/<font color=green>$1<\/font>/g;' >../index.html
#mv ../index.html.tmp ../index.html
}

217
htdocs/browser.css Normal file
View File

@ -0,0 +1,217 @@
.container { position:relative; margin:0 auto; width:959px; }
.column { width:100%; }
/* Mobile (Portrait)
================================================== */
@media only screen and (max-width: 767px) {
.container { width:100%; }
}
/* CSS Reset
================================================== */
html,body,div,span,h1,h6,p,a,ul,li,audio {
border:0;
font:inherit;
font-size:25px;
margin:0;
padding:0;
vertical-align:baseline;
}
body { line-height:1; }
/* ul { list-style:none; }
/* Basic Styles
================================================== */
html,body {
background-color:#000000;
color:#808080;
font:24px Helvetica, Arial, sans-serif;
font-weight:300;
padding:5px 0;
}
/* Typography
================================================== */
h1 { font-size:42px; line-height:44px; margin:20px 0 0; text-align: center; font-weight: bold; text-decoration:underline; }
h2 { font-size:32px; line-height:44px; margin:20px 0 0; text-align: left; font-weight: bold; }
/* Links
================================================== */
a,a:visited { color:#808080; outline:0; text-decoration:none; }
a:hover,a:focus,li:hover,li:focus,label:hover { color:#bbb; }
p a,p a:visited { line-height:inherit; }
/* Misc.
================================================== */
.add-bottom { margin-bottom:20px !important; }
.left { float:left; }
.right { float:right; }
.center { text-align:center; }
/* Audio Player Styles
================================================== */
/* Default / Desktop / Firefox */
audio { margin:0 15px 0 14px; width:670px; }
#mainwrap { box-shadow:0 0 6px 1px rgba(0,0,0,.25); }
#audiowrap { background-color:#111111; margin:0 auto; }
#plwrap { margin:0 auto; }
#tracks { position:relative; text-align:center; }
#nowPlay { display:inline; }
#npTitle { margin:0; padding:21px; text-align:right; }
#npAction { padding:21px; position:absolute; }
#plList { margin:0; }
#plList li { background-color:#111111; cursor:pointer; display:block; margin:0; padding:10px 0; }
.plItem { position:relative; }
.plTitle { left:38px; overflow:hidden; position:absolute; right:1px; text-overflow:ellipsis; top:0; white-space:nowrap; }
.plNum { padding-left:2px; width:25px; }
.plLength { padding-left:21px; position:absolute; right:21px; top:0; }
.plSel,.plSel:hover { background-color:#222222!important; cursor:default!important; }
a[id^="btn"] { background-color:#111111; cursor:pointer; display:inline-block; font-size:50px; margin:0; padding:21px 27px; text-decoration:none; }
a[id^="btn"]:last-child { margin-left:-4px; }
a[id^="btn"]::-moz-focus-inner { border:0; padding:0; }
/* Chrome / Android / Tablet
html[data-useragent*="Chrome"][data-useragent*="Android"] body { color:#373837; }
html[data-useragent*="Chrome"][data-useragent*="Android"] audio { margin-left:4px; width:689px; }
html[data-useragent*="Chrome"][data-useragent*="Android"] #audiowrap { background-color:#fafafa; }
html[data-useragent*="Chrome"][data-useragent*="Android"] a[id^="btn"] { background-color:#fafafa; color:#373837; }
html[data-useragent*="Chrome"][data-useragent*="Android"] a[id^="btn"]:hover { background-color:#eee; }
html[data-useragent*="Chrome"][data-useragent*="Android"] #plList li { background-color:#fafafa; }
html[data-useragent*="Chrome"][data-useragent*="Android"] #plList li:hover { background-color:#eee; }
html[data-useragent*="Chrome"][data-useragent*="Android"] .plSel,
html[data-useragent*="Chrome"][data-useragent*="Android"] .plSel:hover { background-color:#eee!important; }
*/
/* Audio Player Media Queries
================================================== */
/* Tablet Portrait
@media only screen and (min-width: 768px) and (max-width: 959px) {
audio { width:526px; }
html[data-useragent*="MSIE 9.0"] audio { width:536px; }
html[data-useragent*="MSIE 10.0"] audio { width:543px; }
html[data-useragent*="rv:11.0"] audio { width:551px; }
html[data-useragent*="OS 7"] audio { width:546px; }
html[data-useragent*="OS 8"] audio { width:550px; }
html[data-useragent*="OS 9"] audio { width:550px; }
html[data-useragent*="Chrome"] audio { width:533px; }
html[data-useragent*="Chrome"][data-useragent*="Android"] audio { margin-left:4px; width:545px; }
}
/* Mobile Landscape
@media only screen and (min-width: 480px) and (max-width: 767px) {
audio { width:390px; }
html[data-useragent*="MSIE 9.0"] audio { width:400px; }
html[data-useragent*="MSIE 10.0"] audio { width:407px; }
html[data-useragent*="rv:11.0"] audio { width:415px; }
html[data-useragent*="OS 7"] audio { width:410px; }
html[data-useragent*="OS 8"] audio { width:414px; }
html[data-useragent*="OS 9"] audio { width:414px; }
html[data-useragent*="Chrome"] audio { width:397px; }
html[data-useragent*="Chrome"][data-useragent*="Mobile"] audio { margin-left:4px; width:410px; }
#npTitle { width:245px; }
}
/* Mobile Portrait
@media only screen and (max-width: 479px) {
audio { width:270px; }
html[data-useragent*="MSIE 9.0"] audio { width:280px; }
html[data-useragent*="MSIE 10.0"] audio { width:287px; }
html[data-useragent*="rv:11.0"] audio { width:295px; }
html[data-useragent*="OS 7"] audio { width:290px; }
html[data-useragent*="OS 8"] audio { width:294px; }
html[data-useragent*="OS 9"] audio { width:294px; }
html[data-useragent*="Chrome"] audio { width:277px; }
html[data-useragent*="Chrome"][data-useragent*="Mobile"] audio { margin-left:4px; width:290px; }
#npTitle { width:167px; }
}
*/
audio { width:92%; }
/* z.B. für VPN Login */
input {
width: 100%;
font-size:25px;
padding: 12px 20px;
margin: 8px 0;
box-sizing: border-box;
border: 4px solid #808080;
background-color: #222222;
color: #808080;
}
textarea {
width: 100%;
height: 500px;
font-size:12px;
padding: 12px 20px;
margin: 8px 0;
box-sizing: border-box;
border: 4px solid #808080;
background-color: #222222;
color: #808080;
}
pre,#footer {
font:16px sans-serif;
}
.statusok {
font:18px sans-serif;
background-color: #00BF40;
color: black;
}
.statusnok {
font:18px sans-serif;
background-color: #E10020;
color: black;
}
/*Ausblenden des input-Feldes */
.toggleBox input[type="checkbox"] {
position: absolute;
left: -99999px;
}
/* Der Aufklappmechanismus */
.toggleBox input:checked ~ div {
opacity: 0;
height: 0;
display: none;
}
.toggleBox input:not(:checked) ~ div {
opacity: 1;
}
/* Steuerung der Sichtbarkeit der labels */
.toggleBox input:not(:checked) ~ .open,
.toggleBox input:checked ~ .close {
display: none;
}
tr:hover {background-color: coral;}
table, th, td {
border: 1px solid;
border-collapse: collapse;
padding: 5px;
}