diff --git a/.gitignore b/.gitignore index 9f4269e..01c6375 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ docker-compose.override.yml +dabo-bot.conf +analyze.conf data/botdata data/index.html data/index.html.tmp diff --git a/README.md b/README.md index d09b239..5c5b2b5 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,8 @@ I thought this fits quite well to the cryptotrading world and that's why i chose - Recording of available price values incl. RSI and MACD indicators of available cryptocurrencies - Analysis tool for collected historical values to try out buy or sell conditions based on them - ReadOnly web interface for overview -- Runnable in a non-root docker container +- Runnable in a non-root docker containe +- multiple different buy and sell strategies possible at the same time ## Buy conditions - definable RSI Indicator signals min/max (RSI5, 14 and 21) @@ -51,17 +52,18 @@ https://gitea.ds9.dedyn.io/olli/debian.ansible.docker https://gitea.ds9.dedyn.io/olli/debian.ansible.traefik.server -Download: +## Download ``` git clone https://gitea.ds9.dedyn.io/olli/dabo.git cd dabo ``` -Build container: +## Build container ``` docker -l warn compose --ansi never build --progress=plain --pull --no-cache --force-rm ``` +## Configure Edit docker-compose.yml or create docker-compose.override.yml to fit yout needs e.g. domain and network settings or basic auth, e.g. for traefik and letsencrypt: ``` echo ' @@ -126,40 +128,67 @@ local API_KEY="YOUR_LONG_API_KEY_FROM_BINANCE" '>dabo/.binance-secrets chmod 400 dabo/.binance-secrets ``` -Edit your Config -Especially change URL, STOCK_EXCHANGE, FEE, CURRENCY,... to fit your needs. +Create Config +Especially set URL, STOCK_EXCHANGE, FEE, CURRENCY,... to fit your needs. ``` -vim dabo/dabo-bot.conf +vim dabo-bot.conf +``` +Defaults in dabo/dabo-bot.conf + + +## Prepare/Create a stretegy + +IMPORTANT!!! + +THE DEFAULT STRATEGY MAY NOT FIT YOUR NEEDS OR WORK PROPERLY. SO YOU CAN LOOSE ALL YOUR MONEY!!! USE ON YOUR OWN RISK!!! + +TEST YOUR OWN STRATEGY COMPREHENSIVELY AND OVER A LOGNER PERIOD OF TIME WITH analyze.sh!!! USE ON YOUR OWN RISK!!! + +Strategie files can be put in the "strategies"-directory the defaults + +There is an example for a buy and a sell strategy file (deactivated by "return 0" in the forst line): +``` +ls strategies/buy.example.conf +ls strategies/sell.example.conf +``` +Aditional strategies can be created with Name +``` +strategies/buy..conf +strategies/sell..conf +``` +e.g named "mannover-sulu-1" for buy strategy and "command-kirk-3" for sell strategy +``` +strategies/buy.mannover-sulu-1.conf +strategies/sell.command-kirk-3.conf ``` - -Prepare/Create a stretegy - -IMPORTANT!!! THE DEFAULT STRATEGY MAY NOT FIT YOUR NEEDS OR WORK FPR YOU PROPERLY. SO YOU CAN LOOSE ALL YOUR MONEY!!! USE ON YOUR OWN RISK!!! - - +## Set Rights Set Rights (UID 10000 for non-root-User in running container): ``` -chown -R 10000:10000 dabo data home +chown -R 10000:10000 dabo data home strategy ``` - +## Operational commands Run/Restart: ``` -docker-compose down # if an old instance is running -docker-compose up -d +docker compose down # if an old instance is running +docker compose up -d ``` +Check +``` +docker compose ps +``` Logs/Output: ``` -docker-compose logs -f +docker compose logs -f ``` -bot.sh is the bot that trades and collects the quotes and analyze.sh is the tool with which you can try out strategies with the historical data. -The configuration files are called bot.conf and analyze.conf. analyze.sh also uses bot.conf but its variables are overwritten by analyze.conf if duplicated. +dabo-bot.sh is the bot that trades and collects the quotes and analyze.sh is the tool with which you can try out strategies with the historical data. +The configuration files are called dabo-bot.conf and analyze.conf. analyze.sh also uses bot.conf but its variables are overwritten by analyze.conf if duplicated. A Binance or Bitpanda account must exist and the API must be enabled. The access data is stored in the file .binance-secrets in the project directory in the variables API_SECRET and API_KEY. @@ -169,4 +198,6 @@ The access rights to this file should be set to the minimum necessary for securi - Crypto preferences (While/Blacklist for certain currencies) - Overview trades/profits/losses for tax declaration - Support for decentralized exchanges like uniswap to gain more "security" -- mutliple trading strategies +- updatemanagement - immuteable .config +- archive old or large csv files + diff --git a/dabo/analyze.conf b/dabo/analyze.conf index 7d97eb1..d43f583 100755 --- a/dabo/analyze.conf +++ b/dabo/analyze.conf @@ -1,3 +1,4 @@ +# Default Config file for Dabo-Bot. Pleasse don't change! ANALYZE_TIME="^2023-04-17" diff --git a/dabo/analyze.sh b/dabo/analyze.sh index 0a5ba5c..b4ac2a6 100755 --- a/dabo/analyze.sh +++ b/dabo/analyze.sh @@ -19,7 +19,8 @@ function analyze { . functions/check_buy_conditions.sh . functions/check_sell_conditions.sh . functions/get_vars_from_csv.sh - . bot.conf + . dabo-bot.conf + . dabo-bot.override.conf . analyze.conf diff --git a/dabo/dabo-bot.conf b/dabo/dabo-bot.conf index 9fae382..b96a2d2 100755 --- a/dabo/dabo-bot.conf +++ b/dabo/dabo-bot.conf @@ -1,12 +1,13 @@ +# Default Config file for Dabo-Bot. Pleasse don't change! # Webpage URL -URL="dabo-bitpanda.ds9.dedyn.io" +URL="mydabobot.mydomain" # The exchange we use for using the correct API (BINANCE or BITPANDA) STOCK_EXCHANGE="BITPANDA" # fee per trade in percentage on exchange (taker and maker added) -FEE="0.4" +FEE="0.5" # Interval in seconds INTERVAL="150" @@ -28,106 +29,6 @@ SIGNAL_GROUP="Krypto-Bot" # 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="-1" - # Stop all trading and sell everything if the complete balance shrinks under this value in ${CURRENCY} -EMERGENCY_STOP="90" - - - -###### 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="40" -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" +EMERGENCY_STOP="1000" diff --git a/dabo/dabo-bot.override.conf b/dabo/dabo-bot.override.conf new file mode 100644 index 0000000..2fa992c --- /dev/null +++ b/dabo/dabo-bot.override.conf @@ -0,0 +1 @@ +keep diff --git a/dabo/dabo-bot.sh b/dabo/dabo-bot.sh index e62dec2..1f90797 100755 --- a/dabo/dabo-bot.sh +++ b/dabo/dabo-bot.sh @@ -49,6 +49,7 @@ do # reload config . ../../dabo-bot.conf + . ../../dabo-bot.override.conf # stock data if [ ${STOCK_EXCHANGE} = "BINANCE" ] diff --git a/dabo/functions/check_buy_conditions.sh b/dabo/functions/check_buy_conditions.sh index f0bb72c..d6fa18a 100644 --- a/dabo/functions/check_buy_conditions.sh +++ b/dabo/functions/check_buy_conditions.sh @@ -1,6 +1,7 @@ function check_buy_conditions { local f_ASSET_HIST_FILE="$1" + local f_strategy="$2" f_ASSET=$(basename ${f_ASSET_HIST_FILE} | cut -d\. -f1) if [ -n "${BOT}" ] @@ -12,33 +13,48 @@ function check_buy_conditions { return 0 fi fi - + + # get asset vars get_vars_from_csv "${f_ASSET_HIST_FILE}" || return 1 ### from here: check for defined state to buy f_BUY="${f_last_line}" + + # load strategy + local f_echo_prefix="BUY ${f_ASSET}@${CURRENCY}:${f_price}:${f_strategy} - " + if [ -s "${f_strategy}" ] + then + . "${f_strategy}" || return 0 + else + g_echo_note "${f_echo_prefix}Strategy file not found" + return 1 + fi + g_echo_note "${f_echo_prefix}Running BUY checks" + # Check market-performance + if [ $(echo "${f_market_performance} > ${GOOD_MARKET_PERFORMANCE_INDEX}" | bc -l) -eq 0 ] + then + g_echo_note "${f_echo_prefix}BUY market performance ${f_market_performance}% looks bad - Dont buy anything" + return 0 + fi + 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" + g_echo_note "${f_echo_prefix}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" + g_echo_note "${f_echo_prefix}MACD conditions NOT met" return 0 fi @@ -62,9 +78,9 @@ function check_buy_conditions { [ ${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 + echo "${f_echo_prefix}RSI conditions met" >/dev/null else - g_echo_note "BUY ${f_ASSET}@${CURRENCY}:${f_price}: RSI conditions NOT met" + g_echo_note "${f_echo_prefix}RSI conditions NOT met" return 0 fi @@ -76,9 +92,9 @@ function check_buy_conditions { [ $(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 + echo "${f_echo_prefix}Price change conditions met" >/dev/null else - g_echo_note "BUY ${f_ASSET}@${CURRENCY}:${f_price}: Price change conditions NOT met" + g_echo_note "${f_echo_prefix}Price change conditions NOT met" return 0 fi @@ -88,7 +104,7 @@ function check_buy_conditions { # 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" + g_echo_note "${f_echo_prefix}MACD Trend not near (3 timeframes) the beginning buy signal" return 0 fi @@ -119,7 +135,7 @@ function check_buy_conditions { then echo "${f_last_line},${f_ASSET}" >>trade.log - f_BUY="BUY ${f_ASSET}@${CURRENCY}:${f_price}: All BUY conditions met!!! + f_BUY="${f_echo_prefix}All BUY conditions met!!! ${f_BUY}" g_echo_note "${f_BUY}" diff --git a/dabo/functions/check_for_buy.sh b/dabo/functions/check_for_buy.sh index e4f52a4..16bf5f9 100644 --- a/dabo/functions/check_for_buy.sh +++ b/dabo/functions/check_for_buy.sh @@ -21,17 +21,6 @@ function check_for_buy { 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}") @@ -41,7 +30,11 @@ function check_for_buy { if [ $(tail -n 6 "$f_ASSET_HIST_FILE" | egrep -v ",,|,$" | wc -l) -ge 5 ] then - check_buy_conditions "$f_ASSET_HIST_FILE" + local f_strategy + for f_strategy in $(find ../../strategies -name "buy.*.conf" -type f) + do + check_buy_conditions "${f_ASSET_HIST_FILE}" "${f_strategy}" + done else g_echo_note "BUY $f_ASSET_HIST_FILE not enough data - waiting for complete values" fi diff --git a/dabo/functions/check_for_sell.sh b/dabo/functions/check_for_sell.sh index 7a1299b..9497129 100644 --- a/dabo/functions/check_for_sell.sh +++ b/dabo/functions/check_for_sell.sh @@ -1,18 +1,6 @@ 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 @@ -34,197 +22,12 @@ function check_for_sell { 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 + local f_strategy + for f_stragegy in $(find ../../strategies -name "sell.*.conf" -type f) + do + check_sell_conditions "${f_ASSET_HIST_FILE}" "${f_strategy}" + done done - - - } diff --git a/dabo/functions/check_sell_conditions.sh b/dabo/functions/check_sell_conditions.sh index c77012e..88aeef6 100644 --- a/dabo/functions/check_sell_conditions.sh +++ b/dabo/functions/check_sell_conditions.sh @@ -1,6 +1,7 @@ function check_sell_conditions { local f_ASSET_HIST_FILE="$1" + local f_strategy="$2" f_ASSET=$(basename ${f_ASSET_HIST_FILE} | cut -d\. -f1) ### from here: check for defined state to sell @@ -8,6 +9,18 @@ function check_sell_conditions { # get data get_vars_from_csv ${f_ASSET_HIST_FILE} || return 1 + + # load strategy + local f_echo_prefix="SELL ${f_ASSET}@${CURRENCY}:${f_price}:${f_strategy} - " + if [ -s "${f_strategy}" ] + then + . "${f_strategy}" || return 0 + else + g_echo_note "${f_echo_prefix}Strategy file not found" + return 1 + fi + g_echo_note "${f_echo_prefix}Running BUY checks" + ### check current result if [ -n "${BOT}" ] diff --git a/dabo/functions/webpage.sh b/dabo/functions/webpage.sh index 9710349..42618d3 100644 --- a/dabo/functions/webpage.sh +++ b/dabo/functions/webpage.sh @@ -7,10 +7,10 @@ function webpage { - -Statuspage Crypto Bot -' >../index.html.tmp - echo "

Statuspage Crypto Bot (ReadOnly)

+' >../index.html.tmp + echo "Dabo! on ${STOCK_EXCHANGE} - ${URL} +" >>../index.html.tmp + echo "

State of Dabo-Bot! on ${STOCK_EXCHANGE} - ${URL} (ReadOnly)

Last update $(date "+%F %T")

" >>../index.html.tmp diff --git a/dabo/strategies/.keep b/dabo/strategies/.keep new file mode 100644 index 0000000..eb853fc --- /dev/null +++ b/dabo/strategies/.keep @@ -0,0 +1 @@ +needed-dir diff --git a/docker-compose.yml b/docker-compose.yml index 9143c0a..a262d36 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,6 +9,8 @@ services: user: 10000:10000 volumes: - ./dabo:/dabo:ro + - ./strategies:/dabo/strategies:ro + - ./dabo-bot.conf:/dabo/dabo-bot.override.conf - ./data:/dabo/htdocs:rw - ./home:/dabo/home:rw - /usr/local/bin/notify.sh:/usr/local/bin/notify.sh:ro diff --git a/strategies/buy.example.conf b/strategies/buy.example.conf new file mode 100755 index 0000000..02ebe1a --- /dev/null +++ b/strategies/buy.example.conf @@ -0,0 +1,56 @@ + +# remove this line if you are fine with this settings and want to use them on your own risk!!! +# It is strongly recommended to test this strategy first via analyze.sh!!! +return 1 + + +# 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 +local GOOD_MARKET_PERFORMANCE_INDEX="100" + +###### BUY CONDITIONS ###### + +### RSI Indicator checks +# Don't buy if the RSI-XX value is >= BUY_RSIXX_BUY_SIGNAL_UNTIL +local BUY_RSI5_SIGNAL_UNTIL="0" +local BUY_RSI14_SIGNAL_UNTIL="0" +local BUY_RSI21_SIGNAL_UNTIL="0" +local BUY_RSI60_SIGNAL_UNTIL="0" +local BUY_RSI120_SIGNAL_UNTIL="0" +local BUY_RSI240_SIGNAL_UNTIL="0" +local BUY_RSI420_SIGNAL_UNTIL="0" +local BUY_RSI720_SIGNAL_UNTIL="0" + +# Don't buy if the RSI-XX value is <= BUY_RSIXX_BUY_SIGNAL_FROM +local BUY_RSI5_SIGNAL_FROM="0" +local BUY_RSI14_SIGNAL_FROM="0" +local BUY_RSI21_SIGNAL_FROM="0" +local BUY_RSI60_SIGNAL_FROM="0" +local BUY_RSI120_SIGNAL_FROM="0" +local BUY_RSI240_SIGNAL_FROM="0" +local BUY_RSI420_SIGNAL_FROM="0" +local 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. +local BUY_MACD_RELATION_FROM="0" +local BUY_MACD_RELATION_TO="0" + +# Don't buy if price change is under this percentage values +local BUY_MIN_PRICE_CHANGE_LAST_1_DAY="0.25" +local BUY_MIN_PRICE_CHANGE_LAST_7_DAY="-1" +local BUY_MIN_PRICE_CHANGE_LAST_14_DAY="-2" +local BUY_MIN_PRICE_CHANGE_LAST_30_DAY="-5" + + +# Dont buy if growth in the last defined time period <= BUY_MINGROWTH +local BUY_MINGROWTH_PERIOD="30" +local BUY_MINGROWTH="-10" + diff --git a/strategies/sell.example.conf b/strategies/sell.example.conf new file mode 100755 index 0000000..0099bcd --- /dev/null +++ b/strategies/sell.example.conf @@ -0,0 +1,56 @@ + +# remove this line if you are fine with this settings and want to use them on your own risk!!! +# It is strongly recommended to test this strategy first via analyze.sh!!! +return 1 + + +# 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 +local GOOD_MARKET_PERFORMANCE_INDEX="-1" + +# Force hold if result negative expect SELL_PERCENTAGE_FROM_LAST_PURCHASE_NEGATIVE. Boolean 1 for true 0 for false. +local SELL_HOLD_IF_RESULT_NEGATIVE="1" + +# If the price falls by this percentage value from the purchase price, then sell in any case +local 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 +local SELL_IF_LAST_RATE_LOWER_THEN="-0.25" + +### RSI Indicator checks + +# SELL if the RSI-XX value is <= SELL_RSIXX_SELL_SIGNAL_UNTIL +local SELL_RSI5_SIGNAL_UNTIL="99" +local SELL_RSI14_SIGNAL_UNTIL="99" +local SELL_RSI21_SIGNAL_UNTIL="99" +local SELL_RSI60_SIGNAL_UNTIL="99" +local SELL_RSI120_SIGNAL_UNTIL="99" +local SELL_RSI240_SIGNAL_UNTIL="99" +local SELL_RSI420_SIGNAL_UNTIL="99" +local SELL_RSI720_SIGNAL_UNTIL="99" + +# SELL if the RSI-XX value is >= SELL_RSIXX_SELL_SIGNAL_FROM +local SELL_RSI5_SIGNAL_FROM="90" +local SELL_RSI14_SIGNAL_FROM="90" +local SELL_RSI21_SIGNAL_FROM="90" +local SELL_RSI60_SIGNAL_FROM="70" +local SELL_RSI120_SIGNAL_FROM="50" +local SELL_RSI240_SIGNAL_FROM="50" +local SELL_RSI420_SIGNAL_FROM="50" +local SELL_RSI720_SIGNAL_FROM="50" + +# If the price after this time period is lower the the trading fee, then sell if SELL_HOLD_IF_RESULT_NEGATIVE is fine with it +local SELL_IF_LOWER_THEN_FEE_AFTER_PERIOD="7200" + +### 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. +local SELL_MACD_RELATION_FROM="25" +