initial version
This commit is contained in:
parent
74755a16e5
commit
51d959891d
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
docker-compose.override.yml
|
||||||
|
htdocs/botdata
|
||||||
|
htdocs/index.html
|
||||||
|
tests
|
||||||
|
.binance-secrets
|
||||||
|
.bitpanda-secrets
|
12
Dockerfile
Normal file
12
Dockerfile
Normal 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
5
analyze.conf
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
ANALYZE_TIME="^2023-04-17"
|
||||||
|
|
||||||
|
. bot.conf
|
||||||
|
|
129
analyze.sh
Executable file
129
analyze.sh
Executable 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
130
dabo-bot.conf
Normal 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
82
dabo-bot.sh
Executable 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"eOrderQty=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
35
docker-compose.yml
Normal 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
4
docker-entrypoint.sh
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
sleep 999999999
|
||||||
|
binance-cli $@
|
||||||
|
|
14
functions/api-calls.sh
Normal file
14
functions/api-calls.sh
Normal 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
36
functions/binance-api-call.sh
Normal file
36
functions/binance-api-call.sh
Normal 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}×tamp=${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
|
||||||
|
}
|
||||||
|
|
118
functions/binance_convert.sh
Normal file
118
functions/binance_convert.sh
Normal 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 \""eId=\${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
|
||||||
|
}
|
46
functions/binance_convert_dust.sh
Normal file
46
functions/binance_convert_dust.sh
Normal 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 ""eId=${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
|
||||||
|
}
|
38
functions/binance_get_token_info.sh
Normal file
38
functions/binance_get_token_info.sh
Normal 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
|
||||||
|
}
|
||||||
|
|
173
functions/check_buy_conditions.sh
Normal file
173
functions/check_buy_conditions.sh
Normal 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
|
||||||
|
}
|
||||||
|
|
54
functions/check_for_buy.sh
Normal file
54
functions/check_for_buy.sh
Normal 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
230
functions/check_for_sell.sh
Normal 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
143
functions/check_sell_conditions.sh
Normal file
143
functions/check_sell_conditions.sh
Normal 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
134
functions/do_trade.sh
Normal 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
83
functions/get_asset.sh
Normal 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
150
functions/get_assets.sh
Normal 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
126
functions/get_balances.sh
Normal 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
27
functions/get_ema.sh
Normal 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
|
||||||
|
}
|
||||||
|
|
118
functions/get_macd_indicator.sh
Normal file
118
functions/get_macd_indicator.sh
Normal 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}"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
63
functions/get_rate_percentage_min_before_and_now.sh
Normal file
63
functions/get_rate_percentage_min_before_and_now.sh
Normal 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
|
||||||
|
}
|
79
functions/get_rsi_indicator.sh
Normal file
79
functions/get_rsi_indicator.sh
Normal 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}%"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
47
functions/get_vars_from_csv.sh
Normal file
47
functions/get_vars_from_csv.sh
Normal 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]})"
|
||||||
|
}
|
||||||
|
|
92
functions/market_performance.sh
Normal file
92
functions/market_performance.sh
Normal 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
232
functions/webpage.sh
Normal 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/\</</g; s/\>/>/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
217
htdocs/browser.css
Normal 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;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user