Compare commits
15 Commits
214939f3f1
...
0094d806e8
Author | SHA1 | Date | |
---|---|---|---|
0094d806e8 | |||
f6c358d807 | |||
f93d33a6a1 | |||
5c32cd3dd1 | |||
c2ee85d7b6 | |||
73081d1309 | |||
9a49a05f73 | |||
6665091700 | |||
ee0af1a21d | |||
c53b968b21 | |||
ec7b7a9d8f | |||
c7c8ea9b7f | |||
7ade733c8d | |||
fd18f33ed5 | |||
ce5c91fa44 |
@ -30,6 +30,8 @@ I thought this fits quite well to the cryptotrading world and that's why I chose
|
||||
- Runnable in a non-root docker containe
|
||||
- multiple different buy and sell strategies possible at the same time
|
||||
|
||||
- Hedge mode (long and short positions the same time) not supported
|
||||
|
||||
## Buy conditions
|
||||
- definable RSI Indicator signals min/max (RSI5, 14 and 21)
|
||||
- definable MACD signals min/max
|
||||
|
14
dabo/create_webpage.sh
Executable file
14
dabo/create_webpage.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
. /dabo/dabo-prep.sh
|
||||
|
||||
while true
|
||||
do
|
||||
# Reload Config
|
||||
. ../../dabo-bot.conf
|
||||
. ../../dabo-bot.override.conf
|
||||
# get orders
|
||||
webpage
|
||||
sleep 120
|
||||
done
|
||||
|
@ -35,3 +35,6 @@ EMERGENCY_STOP="1000"
|
||||
# Leverage
|
||||
LEVERAGE=""
|
||||
|
||||
# margin mode (isolated or cross)
|
||||
MARGIN_MODE="isolated"
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
. /dabo/dabo-prep.sh
|
||||
|
||||
### MAIN ###
|
||||
g_echo_warn "STARTING DABO BOT $0"
|
||||
g_echo_note "STARTING DABO BOT $0"
|
||||
|
||||
touch firstloop
|
||||
export FULL_LOOP=1
|
||||
@ -51,9 +51,6 @@ do
|
||||
. ../../dabo-bot.conf
|
||||
. ../../dabo-bot.override.conf
|
||||
|
||||
# Headline
|
||||
export csv_headline="Date and Time,Price,Change,EMA12,EMA26,MACD,EMA9 (Sig.),Histogram,MACD Sig.,RSI5,RSI14,RSI21,RSI720,RSI60,RSI120,RSI240,RSI420,Coingecko Change 24h,Coingecko Change 7d,Coingecko Change 14d,Coingecko Change 30d,Coingecko Change 1y,Coingecko MarketCap Change 24h,RANGE DATE,LOWEST IN RANGE,HIGHEST IN RANGE,PIVOT POINT,SUPPORT1,RESIST1,GOLDEN POCKET SUPPORT,GOLDEN POCKET RESIST,GOLDEN POCKET 65 SUPPORT,GOLDEN POCKET 65 RESIST,SUPPORT3,RESIST3,EMA50,EMA100,EMA200,EMA800,Coingecko Price"
|
||||
|
||||
# Timestamp
|
||||
export f_timestamp=$(g_date_print)
|
||||
|
||||
@ -101,8 +98,8 @@ do
|
||||
# Get current symbols
|
||||
[ ${FULL_LOOP} = 1 ] && get_symbols
|
||||
|
||||
# Get current assets
|
||||
get_assets || continue
|
||||
## Get current assets
|
||||
#get_assets || continue
|
||||
|
||||
# Sell something?
|
||||
#check_for_sell
|
||||
@ -117,12 +114,12 @@ do
|
||||
[ ${FULL_LOOP} = 1 ] && check_for_buy
|
||||
|
||||
# Update webpage
|
||||
if jobs | egrep -q "Running.+webpage" && [ ${FULL_LOOP} = 1 ]
|
||||
then
|
||||
g_echo_note "webpage already running"
|
||||
else
|
||||
webpage &
|
||||
fi
|
||||
#if jobs | egrep -q "Running.+webpage" && [ ${FULL_LOOP} = 1 ]
|
||||
#then
|
||||
# g_echo_note "webpage already running"
|
||||
#else
|
||||
# webpage &
|
||||
#fi
|
||||
|
||||
done
|
||||
|
||||
|
19
dabo/fetch-assets.sh
Executable file
19
dabo/fetch-assets.sh
Executable file
@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
. /dabo/dabo-prep.sh
|
||||
|
||||
# Headline
|
||||
export csv_headline="Date and Time,Price,Change,EMA12,EMA26,MACD,EMA9 (Sig.),Histogram,MACD Sig.,RSI5,RSI14,RSI21,RSI720,RSI60,RSI120,RSI240,RSI420,Coingecko Change 24h,Coingecko Change 7d,Coingecko Change 14d,Coingecko Change 30d,Coingecko Change 1y,Coingecko MarketCap Change 24h,RANGE DATE,LOWEST IN RANGE,HIGHEST IN RANGE,PIVOT POINT,SUPPORT1,RESIST1,GOLDEN POCKET SUPPORT,GOLDEN POCKET RESIST,GOLDEN POCKET 65 SUPPORT,GOLDEN POCKET 65 RESIST,SUPPORT3,RESIST3,EMA50,EMA100,EMA200,EMA800,Coingecko Price"
|
||||
|
||||
while true
|
||||
do
|
||||
# Reload Config
|
||||
. ../../dabo-bot.conf
|
||||
. ../../dabo-bot.override.conf
|
||||
# Timestamp
|
||||
export f_timestamp=$(g_date_print)
|
||||
# get assets
|
||||
get_assets
|
||||
sleep 30
|
||||
done
|
||||
|
17
dabo/fetch-orders.sh
Executable file
17
dabo/fetch-orders.sh
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
. /dabo/dabo-prep.sh
|
||||
|
||||
while true
|
||||
do
|
||||
# Reload Config
|
||||
. ../../dabo-bot.conf
|
||||
. ../../dabo-bot.override.conf
|
||||
# Timestamp
|
||||
export f_timestamp=$(g_date_print)
|
||||
# get orders
|
||||
get_symbols
|
||||
get_orders
|
||||
sleep 3600
|
||||
done
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
. /dabo/dabo-prep.sh
|
||||
|
||||
sleep 1800
|
||||
while true
|
||||
do
|
||||
transactions_overview
|
@ -1,36 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
function binance-api-call {
|
||||
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
|
||||
local method=$1
|
||||
local call=$2
|
||||
local params=$3
|
||||
|
||||
if [ -s /dabo/.binance-secrets ]
|
||||
then
|
||||
. /dabo/.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
|
||||
}
|
||||
|
@ -1,142 +0,0 @@
|
||||
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_market_price=$(tail -n1 ${f_ASSET_HIST_FILE} | cut -d, -f2)
|
||||
|
||||
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}-${f_ACTION}-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
|
||||
|
||||
# get trade commission for comparison with convert
|
||||
binance-api-call GET /sapi/v1/asset/tradeFee "&symbol=${f_ASSET}${f_CURRENCY}"
|
||||
local FEE=$(echo "$(cat $g_tmp/API_CMD_OUT | jq -r .[].takerCommission)*100" | bc -l | sed 's/^\./0./; s/^-\./-0./')
|
||||
|
||||
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
|
||||
binance-api-call POST /sapi/v1/convert/getQuote "&fromAsset=${f_CURRENCY}&toAsset=${f_ASSET}&fromAmount=${f_QUANTITY}&walletType=SPOT&validTime=10s" || return 1
|
||||
cat ${g_tmp}/API_CMD_OUT >${f_CMDFILE}_QUOTE_OUT
|
||||
# get convert price
|
||||
local f_convert_price=$(cat ${f_CMDFILE}_QUOTE_OUT | grep '^{' | jq -r .inverseRatio | head -n1)
|
||||
g_percentage-diff ${f_market_price} ${f_convert_price}
|
||||
local f_price_diff=${g_percentage_diff_result}
|
||||
fi
|
||||
|
||||
if [ "${f_ACTION}" = "sell" ]
|
||||
then
|
||||
# get quote on sell
|
||||
binance-api-call POST /sapi/v1/convert/getQuote "&fromAsset=${f_ASSET}&toAsset=${f_CURRENCY}&fromAmount=${f_QUANTITY}&walletType=SPOT&validTime=10s" || return 1
|
||||
cat ${g_tmp}/API_CMD_OUT >${f_CMDFILE}_QUOTE_OUT
|
||||
# get convert price
|
||||
local f_convert_price=$(cat ${f_CMDFILE}_QUOTE_OUT | grep '^{' | jq -r .ratio | head -n1)
|
||||
g_percentage-diff ${f_convert_price} ${f_market_price}
|
||||
local f_price_diff=${g_percentage_diff_result}
|
||||
fi
|
||||
|
||||
if [ $(echo "${f_price_diff} > ${FEE}" | bc -l) -eq 1 ]
|
||||
then
|
||||
local f_note="Price difference between Market Price (${f_market_price} ${f_CURRENCY}) and Binance Convert Price (${f_convert_price} ${f_CURRENCY}) is higher then Trading Fee (${f_price_diff}% > ${FEE}%), so I will better use trade then convert"
|
||||
g_echo_note "$f_note"
|
||||
g_signal-notify "$f_note"
|
||||
return 1
|
||||
fi
|
||||
g_echo_note "Price difference between Market Price (${f_market_price}) and Binance Convert Price (${f_convert_price}) is lower then Trading Fee (${f_price_diff} > ${FEE}), so I will use convert"
|
||||
|
||||
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://${URL}/
|
||||
|
||||
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_convert_price=$(cat ${f_CMDFILE}_QUOTE_OUT | grep '^{' | jq -r .inverseRatio | head -n1)
|
||||
[ "${f_ACTION}" = "sell" ] && local f_convert_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_convert_price},${f_COMMISSION} ${f_COMMISSIONASSET},CONVERT ${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_convert_price},${f_COMMISSION} ${f_COMMISSIONASSET},CONVERT ${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_convert_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
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
#!/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
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
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
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
function onetrading-api-call {
|
||||
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
|
||||
local method=$1
|
||||
local call=$2
|
||||
local params=$3
|
||||
|
||||
if [ -s /dabo/.onetrading-secrets ]
|
||||
then
|
||||
. /dabo/.onetrading-secrets
|
||||
else
|
||||
g_echo_error "No secrets file found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "${call}" | egrep -q "/account/" && local f_token="-H 'Authorization: Bearer ${API_TOKEN}'"
|
||||
echo "curl -s -X ${method} --url https://api.onetrading.com/${call} $f_token -H 'Accept: application/json' ${params}" >${g_tmp}/API_CMD
|
||||
echo "curl -s -X ${method} --url https://api.onetrading.com/${call} -H 'Accept: application/json'" >${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
|
||||
}
|
||||
|
@ -1,32 +0,0 @@
|
||||
function onetrading_get_token_info {
|
||||
|
||||
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
|
||||
|
||||
local f_ASSET=$1
|
||||
local f_CURRENCY=$2
|
||||
f_QUANTITY=$3
|
||||
|
||||
# cleanup cache
|
||||
[ -s ONETRADING_TOKEN_INFO_CMD_OUT ] && find ONETRADING_TOKEN_INFO_CMD_OUT -mmin +60 -or -empty -delete
|
||||
if ! [ -s ONETRADING_TOKEN_INFO_CMD_OUT ]
|
||||
then
|
||||
onetrading-api-call GET public/v1/instruments >ONETRADING_TOKEN_INFO_CMD_OUT
|
||||
cat ${g_tmp}/API_CMD_OUT >ONETRADING_TOKEN_INFO_CMD_OUT
|
||||
fi
|
||||
|
||||
local f_ASSET_PRECISION=$(cat ONETRADING_TOKEN_INFO_CMD_OUT | jq -r ".[] | select(.state==\"ACTIVE\") | select(.quote.code==\"${f_CURRENCY}\") | select(.base.code==\"${f_ASSET}\") | .amount_precision")
|
||||
local f_CURRENCY_PRECISION=$(cat ONETRADING_TOKEN_INFO_CMD_OUT | jq -r ".[] | select(.state==\"ACTIVE\") | select(.quote.code==\"${f_CURRENCY}\") | select(.base.code==\"${f_ASSET}\") | .quote.precision")
|
||||
local f_ASSET_MINSIZE=$(cat ONETRADING_TOKEN_INFO_CMD_OUT | jq -r ".[] | select(.state==\"ACTIVE\") | select(.quote.code==\"${f_CURRENCY}\") | select(.base.code==\"${f_ASSET}\") | .min_size")
|
||||
local f_ASSET_PRICE=$(tail -n1 "asset-histories/${f_ASSET}${f_CURRENCY}.history.csv" | cut -d"," -f2)
|
||||
|
||||
if [ -n "$f_QUANTITY" ] && [ -n "$f_ASSET_PRICE" ]
|
||||
then
|
||||
if [ $(echo "${f_ASSET_MINSIZE} < ${f_QUANTITY}" | bc -l) -eq 0 ]
|
||||
then
|
||||
f_QUANTITY=$(echo "scale=${f_CURRENCY_PRECISION}; ${f_ASSET_MINSIZE}+1" | bc -l)
|
||||
fi
|
||||
f_ASSET_QUANTITY=$(echo "scale=${f_ASSET_PRECISION}; ${f_QUANTITY}/${f_ASSET_PRICE}" | bc -l | sed 's/^\./0./;')
|
||||
fi
|
||||
|
||||
}
|
||||
|
@ -14,10 +14,8 @@ function f_ccxt {
|
||||
return 1
|
||||
fi
|
||||
|
||||
#unset g_ccxt_jobs
|
||||
#local g_ccxt_jobs
|
||||
mapfile -t g_ccxt_jobs < <(jobs -r)
|
||||
# Initialize ccxt in python if not initialized
|
||||
mapfile -t g_ccxt_jobs < <(jobs -r)
|
||||
[[ ${g_ccxt_jobs[*]} =~ *python-pipeexec.py* ]] || unset f_ccxt_initialized
|
||||
if [ -z "$f_ccxt_initialized" ]
|
||||
then
|
||||
@ -44,14 +42,18 @@ function f_ccxt {
|
||||
# reference result to python-result
|
||||
declare -ng f_ccxt_result=g_python_result
|
||||
|
||||
# Check for json output
|
||||
# Check for json output or empty json output
|
||||
f_ccxt_json_out=""
|
||||
[[ $f_ccxt_result =~ ^\[ ]] && [[ $f_ccxt_result =~ \]$ ]] && f_ccxt_json_out=1
|
||||
[[ $f_ccxt_result =~ ^\{ ]] && [[ $f_ccxt_result =~ \}$ ]] && f_ccxt_json_out=1
|
||||
if ! [ "$f_ccxt_result" = '[]' ]
|
||||
then
|
||||
[[ $f_ccxt_result =~ ^\[ ]] && [[ $f_ccxt_result =~ \]$ ]] && f_ccxt_json_out=1
|
||||
[[ $f_ccxt_result =~ ^\{ ]] && [[ $f_ccxt_result =~ \}$ ]] && f_ccxt_json_out=1
|
||||
fi
|
||||
|
||||
# make the output jq-conform if json poutput
|
||||
# avoids errors like: "parse error: Invalid numeric literal at"
|
||||
if [ -n "$f_ccxt_json_out" ]
|
||||
then
|
||||
# make the output jq-conform
|
||||
# avoids errors like: "parse error: Invalid numeric literal at"
|
||||
f_ccxt_result=${f_ccxt_result//\'/\"}
|
||||
f_ccxt_result=${f_ccxt_result// None/ null}
|
||||
f_ccxt_result=${f_ccxt_result// True/ true}
|
||||
@ -62,6 +64,3 @@ function f_ccxt {
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -66,42 +66,7 @@ function check_buy_conditions {
|
||||
# remove CURRENCY from asset
|
||||
f_ASSET=$(echo ${f_ASSET} | sed "s/${CURRENCY}//")
|
||||
|
||||
if [ ${STOCK_EXCHANGE} = "BINANCE" ]
|
||||
then
|
||||
# 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
|
||||
#[ $(g_calc "${f_INVEST_QUANTITY} < ${f_MIN_NOTIONAL}") -eq 0 ] || f_INVEST_QUANTITY=$(g_calc "scale=2; $f_MIN_NOTIONAL/100*105")
|
||||
if ! g_num_is_lower.sh ${f_INVEST_QUANTITY} ${f_MIN_NOTIONAL}
|
||||
then
|
||||
g_calc "scale=2; ${f_MIN_NOTIONAL}/100*105"
|
||||
f_INVEST_QUANTITY=${g_calc_result}
|
||||
fi
|
||||
|
||||
|
||||
# if there is not enough balance for buying because ${f_MIN_NOTIONAL} needed for buying to sell (workaround)
|
||||
g_calc "${CURRENCY_BALANCE} < ${f_MIN_NOTIONAL}*2"
|
||||
if [ ${g_calc_result} -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)
|
||||
g_calc "${CURRENCY_BALANCE} > ${f_INVEST_QUANTITY}"
|
||||
if [ ${g_calc_result} -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
|
||||
|
||||
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
|
||||
order ${f_ASSET}/${CURRENCY} ${f_INVEST_QUANTITY} buy
|
||||
f_BUY=""
|
||||
fi
|
||||
|
||||
|
@ -19,7 +19,7 @@ function check_for_sell {
|
||||
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}"
|
||||
position_close ${f_ASSET}/${CURRENCY}
|
||||
continue
|
||||
fi
|
||||
if tail -n1 $f_ASSET_HIST_FILE | egrep -q "^$(date +%Y-%m-%d)|$(date +%Y-%m-%d -d yesterday)"
|
||||
@ -28,7 +28,7 @@ function check_for_sell {
|
||||
else
|
||||
local f_msg="SELL $f_ASSET_HIST_FILE no current data of invested asset"
|
||||
g_echo_warn "${f_msg}"
|
||||
do_trade ${f_ASSET} ${CURRENCY} ${f_QUANTITY_CURRENCY} sell "${f_msg}"
|
||||
position_close ${f_ASSET}/${CURRENCY}
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
@ -89,14 +89,7 @@ function check_sell_conditions {
|
||||
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
|
||||
position_close ${f_ASSET}/${CURRENCY}
|
||||
fi
|
||||
|
||||
# # ANALYZE
|
||||
|
@ -87,6 +87,9 @@ function currency_converter {
|
||||
if [ -n "$f_rate" ]
|
||||
then
|
||||
[[ $f_histfile =~ ${f_currency}${f_currency_target} ]] && f_reverse=true
|
||||
[ $f_currency_target = "USD" ] && f_reverse=true
|
||||
[ $f_currency = "USD" ] && f_reverse=false
|
||||
[ $f_currency_target = "EUR" ] && [ $f_currency = "USD" ] && f_reverse=true
|
||||
[[ $f_line =~ ^$f_currency_date_hour ]] && break
|
||||
fi
|
||||
fi
|
||||
|
@ -1,159 +0,0 @@
|
||||
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, precision and minsize)
|
||||
${TOKEN_INFO_CMD} ${f_ASSET} ${f_CURRENCY} ${f_QUANTITY}
|
||||
|
||||
if [ ${STOCK_EXCHANGE} = "BINANCE" ]
|
||||
then
|
||||
# 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
|
||||
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}-TRADE_CMD"
|
||||
[ ${STOCK_EXCHANGE} = "BINANCE" ] && echo "${TRADE_CMD}" | perl -pe "s/ACTION/${f_ACTION}/; s/TOKEN/${f_ASSET}${f_CURRENCY}/; s/QUANTITY/${f_QUANTITY}/" >${f_CMDFILE}
|
||||
[ ${STOCK_EXCHANGE} = "ONETRADING" ] && echo "${TRADE_CMD}" | perl -pe "s/ACTION/${f_ACTION}/; s/TOKEN/${f_ASSET}_${f_CURRENCY}/; s/QUANTITY/${f_ASSET_QUANTITY}/" >${f_CMDFILE}
|
||||
# trade
|
||||
g_echo_note "Command: $(cat ${f_CMDFILE})"
|
||||
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 [ ${STOCK_EXCHANGE} = "BINANCE" ]
|
||||
then
|
||||
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
|
||||
fi
|
||||
|
||||
|
||||
# Check return and log trade
|
||||
[ ${STOCK_EXCHANGE} = "BINANCE" ] && f_STATUS=$(cat ${f_CMDFILE}_OUT | grep '^{' | jq -r .status)
|
||||
[ ${STOCK_EXCHANGE} = "ONETRADING" ] && f_STATUS=$(cat ${f_CMDFILE}_OUT | grep '^{' | jq -r .order_id)
|
||||
|
||||
local f_trade_info_msg="TRADE - ${f_ACTION} ${f_ASSET}${f_CURRENCY}
|
||||
${f_link}
|
||||
|
||||
Complete Overview: https://${URL}/
|
||||
|
||||
Comment: ${f_COMMENT}"
|
||||
|
||||
if [ "${f_STATUS}" = "FILLED" ] || echo ${f_STATUS} | egrep -q '.+-.+-.+-.+'
|
||||
then
|
||||
g_echo_note "TRADE SUCCESSFUL!"
|
||||
[ ${STOCK_EXCHANGE} = "BINANCE" ] && local f_PRICE=$(cat ${f_CMDFILE}_OUT | grep '^{' | jq -r .fills[].price | head -n1)
|
||||
[ ${STOCK_EXCHANGE} = "BINANCE" ] && local f_COMMISSION=$(cat ${f_CMDFILE}_OUT | grep '^{' | jq -r .fills[].commission) | head -n1
|
||||
[ ${STOCK_EXCHANGE} = "BINANCE" ] && local f_COMMISSIONASSET=$(cat ${f_CMDFILE}_OUT | grep '^{' | jq -r .fills[].commissionAsset | head -n1)
|
||||
|
||||
if [ ${STOCK_EXCHANGE} = "ONETRADING" ]
|
||||
then
|
||||
sleep 10
|
||||
onetrading-api-call GET public/v1/account/trades
|
||||
cat ${g_tmp}/API_CMD_OUT >${f_CMDFILE}_OUT_ONETRADING_TRADE
|
||||
local f_PRICE=$(cat ${f_CMDFILE}_OUT_ONETRADING_TRADE | jq -r ".trade_history | .[] | select(.trade.order_id==\"${f_STATUS}\") | .trade.price")
|
||||
local f_COMMISSION=$(cat ${f_CMDFILE}_OUT_ONETRADING_TRADE | jq -r ".trade_history | .[] | select(.trade.order_id==\"${f_STATUS}\") | .fee.fee_amount")
|
||||
local f_COMMISSIONASSET=$(cat ${f_CMDFILE}_OUT_ONETRADING_TRADE | jq -r ".trade_history | .[] | select(.trade.order_id==\"${f_STATUS}\") | .fee.fee_currency")
|
||||
fi
|
||||
|
||||
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
|
||||
}
|
@ -8,7 +8,11 @@ function get_asset {
|
||||
|
||||
[ -f "${f_ASSET_HIST_FILE}" ] || echo "Date and Time,Price" >"${f_ASSET_HIST_FILE}"
|
||||
|
||||
local f_line="${f_timestamp},$(grep "^${f_ASSET}," CCXT_TICKERS | cut -d, -f2)"
|
||||
#local f_line="${f_timestamp},$(grep "^${f_ASSET}," CCXT_TICKERS | cut -d, -f2)"
|
||||
local f_price=$(grep "^${f_ASSET}," CCXT_TICKERS | cut -d, -f2)
|
||||
# exponential number (9.881e-05) to normal
|
||||
[[ $f_price =~ ^(-)?(\.)?[0-9]+(\.)?([0-9]+)?(e-[0-9]+)?$ ]] && printf -v f_price -- "%.10f" "$f_price"
|
||||
local f_line="$f_timestamp,$f_price"
|
||||
echo "${f_line}" >>${f_ASSET_HIST_FILE}
|
||||
|
||||
local f_linecount=0
|
||||
@ -31,7 +35,7 @@ function get_asset {
|
||||
return 0
|
||||
fi
|
||||
|
||||
[ ${FULL_LOOP} == 0 ] && return 0
|
||||
#[ ${FULL_LOOP} == 0 ] && return 0
|
||||
grep -q "^$(echo "${f_timestamp}" | cut -d: -f1,2)" "${f_ASSET_HIST_FILE}" || return 0
|
||||
f_ASSET_HIST_FILE="asset-histories/${f_ASSET}.history.csv"
|
||||
#if find "${f_ASSET_HIST_FILE}" -mmin -${INTERVAL_MIN} | grep -q "${f_ASSET_HIST_FILE}"
|
||||
@ -41,7 +45,7 @@ function get_asset {
|
||||
#fi
|
||||
|
||||
# headline
|
||||
#[ -s "${f_ASSET_HIST_FILE}" ] || echo "${csv_headline}" >"${f_ASSET_HIST_FILE}"
|
||||
[ -s "${f_ASSET_HIST_FILE}" ] || echo "${csv_headline}" >"${f_ASSET_HIST_FILE}"
|
||||
if [ -s "${f_ASSET_HIST_FILE}" ]
|
||||
then
|
||||
sed -i -e 1c"$csv_headline" "${f_ASSET_HIST_FILE}"
|
||||
|
@ -27,17 +27,23 @@ function get_assets {
|
||||
mv ASSETS.tmp ASSETS
|
||||
|
||||
## write histfiles parallel
|
||||
local f_ASSET
|
||||
local f_parallel_arg
|
||||
echo -n "parallel -j3 bash -c --" >/tmp/parallel
|
||||
#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_timestamp
|
||||
#export csv_headline
|
||||
#. /tmp/parallel
|
||||
|
||||
## alternatively single jobs (for debugging!?)
|
||||
for f_ASSET in $(cat ASSETS | egrep -v "${BLACKLIST}")
|
||||
do
|
||||
#get_asset "${f_ASSET}"
|
||||
echo -n " \"get_asset ${f_ASSET}\"" >>/tmp/parallel
|
||||
get_asset "${f_ASSET}"
|
||||
done
|
||||
export f_timestamp
|
||||
export csv_headline
|
||||
. /tmp/parallel
|
||||
|
||||
}
|
||||
|
||||
|
@ -19,12 +19,13 @@ function get_marketdata_yahoo_historic {
|
||||
[[ $f_item = "BLAZE-USD" ]] && f_item="BLAZE30179-USD"
|
||||
[[ $f_item = "BEER-USD" ]] && f_item="BEER31337-USD"
|
||||
[[ $f_item = "TAI-USD" ]] && f_item="TAI20605-USD"
|
||||
[[ $f_item = "DEFI-USD" ]] && f_item="DEFI29200-USD"
|
||||
|
||||
# end if already failed the last hour
|
||||
if [ -f FAILED_YAHOO_${f_name}_HISTORIC_DOWNLOAD ]
|
||||
if [ -f FAILED_YAHOO/${f_name}_HISTORIC_DOWNLOAD ]
|
||||
then
|
||||
find "FAILED_YAHOO_${f_name}_HISTORIC_DOWNLOAD" -mmin +60 -delete
|
||||
if [ -f FAILED_YAHOO_${f_name}_HISTORIC_DOWNLOAD ]
|
||||
find "FAILED_YAHOO/${f_name}_HISTORIC_DOWNLOAD" -mmin +60 -delete
|
||||
if [ -f FAILED_YAHOO/${f_name}_HISTORIC_DOWNLOAD ]
|
||||
then
|
||||
#g_echo_note "${f_targetcsv} already failed to downloaded within last hour"
|
||||
return 1
|
||||
@ -65,7 +66,8 @@ function get_marketdata_yahoo_historic {
|
||||
#ERR:
|
||||
#$(cat "${f_targetcsvtmp}".err)
|
||||
#"
|
||||
mv ${f_targetcsvtmp}.err FAILED_YAHOO_${f_name}_HISTORIC_DOWNLOAD
|
||||
mkdir -p FAILED_YAHOO
|
||||
mv ${f_targetcsvtmp}.err FAILED_YAHOO/${f_name}_HISTORIC_DOWNLOAD
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
47
dabo/functions/get_orders.sh
Normal file
47
dabo/functions/get_orders.sh
Normal file
@ -0,0 +1,47 @@
|
||||
function get_orders {
|
||||
|
||||
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
|
||||
|
||||
local f_symbol=$1
|
||||
local f_symbol_file
|
||||
|
||||
# get orders of all symbols available if symbol argument is not given
|
||||
local f_symbols=()
|
||||
if [ -z "$f_symbol" ]
|
||||
then
|
||||
for f_symbol in "${f_symbols_array[@]}"
|
||||
do
|
||||
if [ -z "$LEVERAGE" ]
|
||||
then
|
||||
[[ $f_symbol =~ /${CURRENCY}$ ]] && f_symbols+=("$f_symbol")
|
||||
else
|
||||
[[ $f_symbol =~ /${CURRENCY}:${CURRENCY}$ ]] && f_symbols+=("$f_symbol")
|
||||
fi
|
||||
done
|
||||
else
|
||||
f_symbols+=("$f_symbol")
|
||||
fi
|
||||
[ -z "$f_symbols" ] && return 1
|
||||
|
||||
for f_symbol in "${f_symbols[@]}"
|
||||
do
|
||||
f_symbol_file=${f_symbol//:*}
|
||||
f_symbol_file=${f_symbol_file///}
|
||||
g_echo_note "Getting orders from $f_symbol to \"CCXT_OPEN_ORDERS_$f_symbol_file\""
|
||||
if f_ccxt "print($STOCK_EXCHANGE.fetchOpenOrders(symbol='${f_symbol}'))"
|
||||
then
|
||||
if [ -z "$f_ccxt_json_out" ]
|
||||
then
|
||||
rm -f "CCXT_OPEN_ORDERS_${f_symbol_file}_RAW" "CCXT_OPEN_ORDERS_${f_symbol_file}"
|
||||
continue
|
||||
fi
|
||||
echo $f_ccxt_result | tee "CCXT_OPEN_ORDERS_${f_symbol_file}_RAW" | jq -r "
|
||||
.[] |
|
||||
select(.status==\"open\") |
|
||||
.symbol + \",\" + .type + \",\" + .side + \",\" + (.price|tostring) + \",\" + (.stopPrice|tostring) + \",\" + (.amount
|
||||
|tostring)
|
||||
" >"CCXT_OPEN_ORDERS_${f_symbol_file}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
@ -21,13 +21,13 @@ function get_positions {
|
||||
jq -r "
|
||||
.[] |
|
||||
select(.entryPrice != 0) |
|
||||
.symbol + \",\" + (.notional|tostring) + \",\" + (.entryPrice|tostring) + \",\" + (.markPrice|tostring) + \",\" + .side + \",\" + (.leverage|tostring)
|
||||
" CCXT_POSITIONS_RAW >POSITIONS
|
||||
get_position_array
|
||||
.symbol + \",\" + (.notional|tostring) + \",\" + (.entryPrice|tostring) + \",\" + (.markPrice|tostring) + \",\" + .side + \",\" + (.leverage|tostring) + \",\" + (.contracts|tostring) + \",\" + (.contractSize|tostring) + \",\" + (.liquidationPrice|tostring) + \",\" + (.unrealizedPnl|tostring)
|
||||
" CCXT_POSITIONS_RAW >CCXT_POSITIONS
|
||||
|
||||
}
|
||||
|
||||
function get_position_array {
|
||||
g_array POSITIONS f_get_positions_array
|
||||
g_array CCXT_POSITIONS f_get_positions_array
|
||||
}
|
||||
|
||||
function get_position_line_vars {
|
||||
@ -42,6 +42,11 @@ function get_position_line_vars {
|
||||
[ -z "$f_position_side" ] && f_position_side="long"
|
||||
f_position_leverage=${f_position_array[5]}
|
||||
[ -z "$f_position_leverage" ] && f_position_leverage="1"
|
||||
f_position_contracts=${f_position_array[6]}
|
||||
f_position_contract_size=${f_position_array[7]}
|
||||
f_position_liquidation_price=${f_position_array[8]}
|
||||
f_position_unrealized_pnl=${f_position_array[9]}
|
||||
|
||||
g_percentage-diff $f_position_entry_price $f_position_current_price
|
||||
[ "$f_position_side" = short ] && g_percentage-diff $f_position_current_price $f_position_entry_price
|
||||
f_position_pnl_percentage=$g_percentage_diff_result
|
||||
|
@ -2,27 +2,18 @@ function get_symbols {
|
||||
|
||||
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
|
||||
|
||||
f_ccxt "print($STOCK_EXCHANGE.symbols)"
|
||||
if [ -z "$f_ccxt_json_out" ]
|
||||
then
|
||||
g_echo_warn "Could not get symbols list - no json output"
|
||||
return 1
|
||||
fi
|
||||
local f_symbols=${f_ccxt_result}
|
||||
f_symbols=${f_symbols//\"}
|
||||
f_symbols=${f_symbols//, /+}
|
||||
f_symbols=${f_symbols//\[}
|
||||
f_symbols=${f_symbols//\]}
|
||||
|
||||
local f_symbols=""
|
||||
[ -s CCXT_TICKERS_RAW ] && f_symbols=$(jq -r '.[] | .symbol' CCXT_TICKERS_RAW)
|
||||
f_symbols=${f_symbols//$'\n'/'+'}
|
||||
|
||||
if [ -z "$f_symbols" ]
|
||||
then
|
||||
g_echo_warn "Could not get symbols list - empty"
|
||||
return 1
|
||||
fi
|
||||
|
||||
g_array "$f_symbols" f_symbols_array +
|
||||
g_array "$f_symbols" f_symbols_array_ref +
|
||||
f_symbols_array=("${g_array[@]}")
|
||||
printf '%s\n' "${f_symbols_array[@]}" >SYMBOLS-$STOCK_EXCHANGE
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
73
dabo/functions/order.sh
Normal file
73
dabo/functions/order.sh
Normal file
@ -0,0 +1,73 @@
|
||||
function order {
|
||||
# Info for log
|
||||
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
|
||||
|
||||
# needed vars
|
||||
local f_symbol=$1
|
||||
local f_amount=$2 # amount in $CURRENCY / if crypto_amount:XXX then amount in crypto
|
||||
local f_side=$3 # buy/sell long/short
|
||||
local f_price=$4 # price for limit order - if not given do market order
|
||||
local f_params f_type
|
||||
|
||||
|
||||
### validity checks ###
|
||||
|
||||
# check symbol XXX/$CURRENCY[:$CURRENCY]
|
||||
[[ $f_symbol =~ /$CURRENCY ]] || return 1
|
||||
|
||||
# check side
|
||||
[ "$f_side" = "long" ] && f_side="buy"
|
||||
[ "$f_side" = "short" ] && f_side="sell"
|
||||
[[ $f_side =~ ^buy$|^sell$ ]] || return 1
|
||||
|
||||
# check order type limit/market
|
||||
if [ -z "$f_price" ]
|
||||
then
|
||||
f_type="market"
|
||||
f_price=0
|
||||
else
|
||||
f_type="limit"
|
||||
fi
|
||||
|
||||
### validity checks end###
|
||||
|
||||
# get amount in crypto asset
|
||||
if [[ $f_amount =~ ^crypto_amount: ]]
|
||||
then
|
||||
# if given in crypto
|
||||
f_amount=${f_amount//crypto_amount:}
|
||||
else
|
||||
# if given in $CURRENCY
|
||||
local f_asset=${f_symbol///*}
|
||||
currency_converter $f_amount $CURRENCY $f_asset || return 1
|
||||
local f_amount=$f_currency_converter_result
|
||||
fi
|
||||
|
||||
# check for swap/margin trades
|
||||
if [ -n "$LEVERAGE" ]
|
||||
then
|
||||
# do some margin things
|
||||
|
||||
# check for CCXT swap symbol :$CURRENCY
|
||||
[[ $f_symbol =~ : ]] || f_symbol="$f_symbol:$CURRENCY"
|
||||
|
||||
# set position mode
|
||||
f_ccxt "$STOCK_EXCHANGE.setPositionMode(hedged=False, symbol='$f_symbol')" || return 1
|
||||
|
||||
# set leverage
|
||||
f_ccxt "$STOCK_EXCHANGE.setLeverage($LEVERAGE, '$f_symbol')" || return 1
|
||||
|
||||
# define margibn mode isolated/cross
|
||||
f_params="params={'marginMode': '$MARGIN_MODE'}"
|
||||
else
|
||||
# short/sell not possible in spot market
|
||||
[[ $f_side =~ ^sell$ ]] || return 1
|
||||
fi
|
||||
|
||||
# do the order
|
||||
f_ccxt "print($STOCK_EXCHANGE.createOrder(symbol='${f_symbol}', type='$f_type', price=$f_price, amount='${f_amount}', side='${f_side}', ${f_params}))" || return 1
|
||||
|
||||
# refresh positions
|
||||
get_positions
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md
|
||||
|
||||
function phemex-api-call {
|
||||
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
|
||||
local method=$1
|
||||
local call=$2
|
||||
local params=$3
|
||||
|
||||
if [ -s /dabo/.phemex-secrets ]
|
||||
then
|
||||
. /dabo/.phemex-secrets
|
||||
else
|
||||
g_echo_error "No secrets file found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "${call}" | egrep -q "/account/" && local f_token="-H 'Authorization: Bearer ${API_TOKEN}'"
|
||||
echo "curl -s -X ${method} --url https://api.phemex.com/${call} $f_token -H 'Accept: application/json' ${params}" >${g_tmp}/API_CMD
|
||||
echo "curl -s -X ${method} --url https://api.phemex.com/${call} -H 'Accept: application/json'" >${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
|
||||
}
|
||||
|
22
dabo/functions/position_close.sh
Normal file
22
dabo/functions/position_close.sh
Normal file
@ -0,0 +1,22 @@
|
||||
function position_close {
|
||||
# Info for log
|
||||
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
|
||||
|
||||
local f_symbol=$1
|
||||
local f_position
|
||||
|
||||
get_symbols
|
||||
get_positions
|
||||
get_position_array
|
||||
|
||||
for f_position in "${f_get_positions_array[@]}"
|
||||
do
|
||||
get_position_line_vars "$f_position"
|
||||
if [ "$f_symbol" = "$f_position_symbol" ]
|
||||
then
|
||||
f_side="sell"
|
||||
[ "$f_position_side" = "short" ] && f_side="buy"
|
||||
order $f_symbol crypto_amount:$f_position_contracts $f_side
|
||||
fi
|
||||
done
|
||||
}
|
@ -16,6 +16,57 @@ services:
|
||||
- /usr/local/bin/notify.sh:/usr/local/bin/notify.sh:ro
|
||||
- /usr/local/etc/notify.conf:/usr/local/etc/notify.conf:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '2'
|
||||
memory: 1024M
|
||||
|
||||
dabo-assets:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
restart: unless-stopped
|
||||
user: 10000:10000
|
||||
volumes:
|
||||
- ./dabo:/dabo:ro
|
||||
- ./strategies:/dabo/strategies:ro
|
||||
- ./dabo-bot.conf:/dabo/dabo-bot.override.conf
|
||||
- ./watch-assets.csv:/dabo/watch-assets.csv
|
||||
- ./data:/dabo/htdocs:rw
|
||||
- ./home:/dabo/home:rw
|
||||
- /usr/local/bin/notify.sh:/usr/local/bin/notify.sh:ro
|
||||
- /usr/local/etc/notify.conf:/usr/local/etc/notify.conf:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
entrypoint: /dabo/fetch-assets.sh
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1'
|
||||
memory: 512M
|
||||
|
||||
dabo-orders:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
restart: unless-stopped
|
||||
user: 10000:10000
|
||||
volumes:
|
||||
- ./dabo:/dabo:ro
|
||||
- ./strategies:/dabo/strategies:ro
|
||||
- ./dabo-bot.conf:/dabo/dabo-bot.override.conf
|
||||
- ./watch-assets.csv:/dabo/watch-assets.csv
|
||||
- ./data:/dabo/htdocs:rw
|
||||
- ./home:/dabo/home:rw
|
||||
- /usr/local/bin/notify.sh:/usr/local/bin/notify.sh:ro
|
||||
- /usr/local/etc/notify.conf:/usr/local/etc/notify.conf:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
entrypoint: /dabo/fetch-orders.sh
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.5'
|
||||
memory: 128M
|
||||
|
||||
dabo-transaction-history:
|
||||
build:
|
||||
@ -33,7 +84,35 @@ services:
|
||||
- /usr/local/bin/notify.sh:/usr/local/bin/notify.sh:ro
|
||||
- /usr/local/etc/notify.conf:/usr/local/etc/notify.conf:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
entrypoint: /dabo/transaction-history.sh
|
||||
entrypoint: /dabo/fetch-transaction-history.sh
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1'
|
||||
memory: 128M
|
||||
|
||||
dabo-webpage:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
restart: unless-stopped
|
||||
user: 10000:10000
|
||||
volumes:
|
||||
- ./dabo:/dabo:ro
|
||||
- ./strategies:/dabo/strategies:ro
|
||||
- ./dabo-bot.conf:/dabo/dabo-bot.override.conf
|
||||
- ./watch-assets.csv:/dabo/watch-assets.csv
|
||||
- ./data:/dabo/htdocs:rw
|
||||
- ./home:/dabo/home:rw
|
||||
- /usr/local/bin/notify.sh:/usr/local/bin/notify.sh:ro
|
||||
- /usr/local/etc/notify.conf:/usr/local/etc/notify.conf:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
entrypoint: /dabo/create_webpage.sh
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1'
|
||||
memory: 128M
|
||||
|
||||
dabo-web:
|
||||
image: nginx:latest
|
||||
@ -41,4 +120,9 @@ services:
|
||||
volumes:
|
||||
- ./data:/usr/share/nginx/html:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1'
|
||||
memory: 128M
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user