Compare commits

...

15 Commits

Author SHA1 Message Date
0094d806e8 ccxt switch 2024-06-14 22:45:01 +02:00
f6c358d807 close positions of symbol 2024-06-14 22:44:13 +02:00
f93d33a6a1 ccxt switch 2024-06-14 19:59:33 +02:00
5c32cd3dd1 separate container 2024-06-14 19:57:04 +02:00
c2ee85d7b6 fixes and switch to ccxt 2024-06-14 19:56:43 +02:00
73081d1309 ccxt switch 2024-06-14 19:51:41 +02:00
9a49a05f73 new vars 2024-06-14 19:51:12 +02:00
6665091700 rename 2024-06-14 19:50:39 +02:00
ee0af1a21d ccxt switch 2024-06-14 19:50:27 +02:00
c53b968b21 separate containers 2024-06-14 19:49:51 +02:00
ec7b7a9d8f place orders 2024-06-14 19:49:27 +02:00
c7c8ea9b7f fetch orders 2024-06-14 19:49:10 +02:00
7ade733c8d separate container 2024-06-14 19:48:50 +02:00
fd18f33ed5 separate container 2024-06-14 19:48:42 +02:00
ce5c91fa44 separate container 2024-06-14 19:48:36 +02:00
29 changed files with 351 additions and 615 deletions

View File

@ -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
View 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

View File

@ -35,3 +35,6 @@ EMERGENCY_STOP="1000"
# Leverage
LEVERAGE=""
# margin mode (isolated or cross)
MARGIN_MODE="isolated"

View File

@ -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
View 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
View 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

View File

@ -2,6 +2,7 @@
. /dabo/dabo-prep.sh
sleep 1800
while true
do
transactions_overview

View File

@ -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}&timestamp=${timestamp}"
local signature=$(echo -n "${params}" | openssl dgst -sha256 -hmac "${API_SECRET}" | cut -d" " -f2)
params="?${params}&signature=$signature"
fi
echo "curl -s -H \"X-MBX-APIKEY: $API_KEY\" -X \"$method\" \"https://api.binance.com/${call}${params}\"" >${g_tmp}/API_CMD
echo "curl -s -H \"X-MBX-APIKEY: API_KEY\" -X \"$method\" \"https://api.binance.com/${call}${params}\"" >${g_tmp}/API_CMD_WO_KEY
g_runcmd g_retrycmd sh ${g_tmp}/API_CMD >${g_tmp}/API_CMD_OUT 2>&1
if egrep -q -i '^{"code":|error' ${g_tmp}/API_CMD_OUT
then
g_echo_error "$(cat ${g_tmp}/API_CMD_WO_KEY): $(cat ${g_tmp}/API_CMD_OUT)"
return 1
fi
}

View File

@ -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 \"&quoteId=\${f_quoteid}\"
cat ${g_tmp}/API_CMD_OUT >${f_CMDFILE}_OUT
" >${f_CMDFILE}
# convert/trade
g_echo_note "Command: $(cat ${f_CMDFILE})"
. ${f_CMDFILE}
cat ${g_tmp}/API_CMD_OUT >${f_CMDFILE}_OUT
g_echo_note "Command Output: $(cat ${f_CMDFILE}_OUT)"
# Check return and log trade
f_STATUS=$(cat ${f_CMDFILE}_OUT | grep '^{' | jq -r .orderStatus)
local f_trade_info_msg="CONVERT/TRADE - ${f_ACTION} ${f_ASSET}${f_CURRENCY}
${f_link}
Complete Overview: https://${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
}

View File

@ -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 "&quoteId=${f_quoteid}"
fi
# Only run every 6 houres - binance doesn't allow to do it more often
[ -s BINANCE_LAST_DUST_RUN ] || date >BINANCE_LAST_DUST_RUN
find BINANCE_LAST_DUST_RUN -mmin +362 -delete
[ -s BINANCE_LAST_DUST_RUN ] && return 0
date >BINANCE_LAST_DUST_RUN
g_echo_note "RUNNING FUNCTION ${FUNCNAME} $@"
# find dust
local f_dust_assets=""
local f_dust
binance-api-call POST /sapi/v1/asset/dust-btc
# ignore $CURRENCY and assets in open trades
for f_dust in $(cat ${g_tmp}/API_CMD_OUT | jq -r '.details[].asset' | egrep -v "${CURRENCY}")
do
ls trade-histories/trade-*.${f_dust}${CURRENCY}-open.history.csv >/dev/null 2>&1 && continue
f_dust_assets="${f_dust_assets},$f_dust"
done
f_dust_assets=$(echo ${f_dust_assets} | sed 's/^,//')
# convert dust to BNB
if [ -n "${f_dust_assets}" ]
then
g_signal-notify "Converting dust from ${f_dust_assets} to BNB"
binance-api-call POST /sapi/v1/asset/dust "&asset=${f_dust_assets}"
fi
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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}"

View 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
}

View File

@ -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
}

View 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
}

View File

@ -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

View File

@ -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
View 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
}

View File

@ -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
}

View 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
}

View File

@ -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