- Fix SPX auto trading by differntiation of SPX and SPWX

- Prevent destruciton of the refresh token when things go wrong
- add auto trading wip code for order getting, and long trading
- add recording of 90 days out expiration tracking
- Add TSLA
This commit is contained in:
2024-07-17 14:08:55 -05:00
parent d242be4d5e
commit e9a651f92e
9 changed files with 255 additions and 5 deletions

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@ appCredentials.dat
refresh_token.dat
appKey.dat
cert.pem
*.log

View File

@@ -95,6 +95,9 @@
{
"Symbol": "TLT"
},
{
"Symbol": "TSLA"
},
{
"Symbol": "$VIX"
},

92
autoTradeQQQLongCall.sh Executable file
View File

@@ -0,0 +1,92 @@
#!/bin/bash
set -x
IFS=$'\0'
daysOutMin=90
daysOutMax=91
deltaMin=0.35
deltaMax=0.40
inputFile="$1"
if [[ "" == "$inputFile" ]]; then
latestFile="$(ls data/`date +%Y-%m-%d`/*QQQ* | sort | tail -n 1)"
systemd-cat -t "`basename $0` $1" -p debug <<< "Latest File: _${latestFile}_"
inputFile=temp/orderInputFile.json
bzip2 -dc < "${latestFile}" > "${inputFile}"
fi
if [[ ! -f "${inputFile}" ]]; then
errMsg="ERROR: Input file _${inputFile}_ does not exist."
systemd-cat -t "`basename $0` $1" -p err <<< ${errMsg}
>&2 echo "${errMsg}"
exit 1
fi
dateKey=$(jq -r '.callExpDateMap | keys | .[]' temp/orderInputFile.json | sort -r -t ":" +2 | awk -F ":" -e '{theDay=$2; if (theDay < '${daysOutMin}') { print lastDay; exit; } else { lastDay=$0; } }')
systemd-cat -t "`basename $0` $1" -p debug <<< "Date-Key: _${dateKey}_"
daysOut=$(cut -d : -f 2 <<< ${dateKey})
if [[ ${daysOut} -gt ${daysOutMax} ]]; then
systemd-cat -t "`basename $0` $1" -p info <<< "This option is too far in the future. _${daysOut}_ is bigger than the max days in the future is _${daysOutMax}_. Exiting."
exit
fi
#Looking for leg, between the specified deltas
# JTR - the "floor" is to only find the prices at the integer strikes, but I changed my mind about that...
#jq '.callExpDateMap."'${dateKey}'"[]|map({symbol, delta, strikePrice,bid,ask}) | .[] | select(.delta >= '${deltaMin}' and .delta <= '${deltaMax}') | select( (.strikePrice | floor) == .strikePrice)' "${inputFile}" | tail -n 7 > temp/longLeg.json
jq '.callExpDateMap."'${dateKey}'"[]|map({symbol, delta, strikePrice,bid,ask}) | .[] | select(.delta >= '${deltaMin}' and .delta <= '${deltaMax}')' "${inputFile}" | tail -n 7 > temp/longLeg.json
numLinesInLeg=$(wc -l temp/longLeg.json | cut -c1)
if [[ 7 -ne ${numLinesInLeg} ]]; then
errMsg="No suitable long leg found - exiting."
systemd-cat -t "`basename $0` $1" -p warning <<< ${errMsg}
>&2 echo "${errMsg}"
exit 1
fi
longStrike=$(jq -r '.strikePrice' < temp/longLeg.json)
longBid=$(jq -r '.bid' < temp/longLeg.json)
longAsk=$(jq -r '.ask' < temp/longLeg.json)
longSymbol=$(jq -r '.symbol' < temp/longLeg.json)
msg="Long Symbol: _${longSymbol}_ Strike: _${longStrike}_ Bid: _${longBid}_ Ask: _${longAsk}_"
systemd-cat -t "`basename $0` $1" -p info <<< ${msg}
echo "${msg}"
priceOffset=0.0
# Get the Middle price...
price=$(echo "scale=2; ((${longBid}+${longAsk})/2) + ${priceOffset}" | bc)
orderJson=$(jq -c <<-EOM
{
"orderType": "LIMIT",
"session": "NORMAL",
"price": ${price},
"duration": "DAY",
"orderStrategyType": "SINGLE",
"quantity": 1,
"orderLegCollection": [
{
"instruction": "BUY_TO_OPEN",
"quantity": 1,
"instrument": {
"symbol": "${longSymbol}",
"assetType": "OPTION"
}
}
]
}
EOM
)
systemd-cat -t "`basename $0` $1" -p debug <<< "Order: _${orderJson}_"
echo Enter to continue, Ctrl+C to cancel
read
./getNewAccessToken.sh
curl -s -X POST \
'https://api.schwabapi.com/trader/v1/accounts/CEF970366D4CC9553B5E8846E35FD92A1867F3E73C1082A52647256F42E4746B/orders' \
-H "Authorization: Bearer $(<access_token.dat)" \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d "${orderJson}"

View File

@@ -1,5 +1,6 @@
#!/bin/bash
#set -x
set -e
IFS=$'\0'
inputFile="$1"
@@ -19,16 +20,18 @@ fi
dateKey=$(jq -r '.putExpDateMap | keys | .[]' "${inputFile}" | head -n 1)
systemd-cat -t "`basename $0` $1" -p debug <<< "Date-Key: _${dateKey}_"
jq '.putExpDateMap."'${dateKey}'"[]|map({symbol, delta, strikePrice,bid,ask}) |.[] | select(.delta >= -0.30 and .delta <= -0.25) ' "${inputFile}" | tail -n 7 > temp/shortLeg.json
jq '.putExpDateMap."'${dateKey}'"[]|map({symbol,delta,strikePrice,bid,ask,optionRoot}) |.[] | select(.delta >= -0.30 and .delta <= -0.25) ' "${inputFile}" | tail -n 8 > temp/shortLeg.json
shortStrike=$(jq -r '.strikePrice' < temp/shortLeg.json)
shortBid=$(jq -r '.bid' < temp/shortLeg.json)
shortAsk=$(jq -r '.ask' < temp/shortLeg.json)
shortSymbol=$(jq -r '.symbol' < temp/shortLeg.json)
shortOptionRoot=$(jq -r '.optionRoot' < temp/shortLeg.json)
msg="Short Symbol: _${shortSymbol}_ Strike: _${shortStrike}_ Bid: _${shortBid}_ Ask: _${shortAsk}_"
systemd-cat -t "`basename $0` $1" -p info <<< ${msg}
echo "${msg}"
jq '.putExpDateMap."'${dateKey}'"[]|map({symbol, delta, strikePrice,bid,ask}) | .[] | select(.strikePrice >= '${shortStrike}'-50 and .strikePrice < '${shortStrike}')' temp/orderInputFile.json | head -n 7 > temp/longLeg.json
#jq '.putExpDateMap."'${dateKey}'"[]|map({symbol, delta, strikePrice,bid,ask}) | .[] | select(.strikePrice >= '${shortStrike}'-50 and .strikePrice < '${shortStrike}')' temp/orderInputFile.json | head -n 7 > temp/longLeg.json
jq '.putExpDateMap."'${dateKey}'"[]|map({symbol,delta,strikePrice,bid,ask,optionRoot}) | .[] | select(.optionRoot == "'${shortOptionRoot}'" and .strikePrice >= '${shortStrike}'-50 and .strikePrice < '${shortStrike}')' temp/orderInputFile.json | head -n 8 > temp/longLeg.json
longStrike=$(jq -r '.strikePrice' < temp/longLeg.json)
longBid=$(jq -r '.bid' < temp/longLeg.json)
longAsk=$(jq -r '.ask' < temp/longLeg.json)

92
autoTradeSPYLongCall.sh Executable file
View File

@@ -0,0 +1,92 @@
#!/bin/bash
set -x
IFS=$'\0'
daysOutMin=90
daysOutMax=91
deltaMin=0.35
deltaMax=0.40
inputFile="$1"
if [[ "" == "$inputFile" ]]; then
latestFile="$(ls data/`date +%Y-%m-%d`/*SPY* | sort | tail -n 1)"
systemd-cat -t "`basename $0` $1" -p debug <<< "Latest File: _${latestFile}_"
inputFile=temp/orderInputFile.json
bzip2 -dc < "${latestFile}" > "${inputFile}"
fi
if [[ ! -f "${inputFile}" ]]; then
errMsg="ERROR: Input file _${inputFile}_ does not exist."
systemd-cat -t "`basename $0` $1" -p err <<< ${errMsg}
>&2 echo "${errMsg}"
exit 1
fi
dateKey=$(jq -r '.callExpDateMap | keys | .[]' temp/orderInputFile.json | sort -r -t ":" +2 | awk -F ":" -e '{theDay=$2; if (theDay < '${daysOutMin}') { print lastDay; exit; } else { lastDay=$0; } }')
systemd-cat -t "`basename $0` $1" -p debug <<< "Date-Key: _${dateKey}_"
daysOut=$(cut -d : -f 2 <<< ${dateKey})
if [[ ${daysOut} -gt ${daysOutMax} ]]; then
systemd-cat -t "`basename $0` $1" -p info <<< "This option is too far in the future. _${daysOut}_ is bigger than the max days in the future is _${daysOutMax}_. Exiting."
exit
fi
#Looking for leg, between the specified deltas
# JTR - the "floor" is to only find the prices at the integer strikes, but I changed my mind about that...
#jq '.callExpDateMap."'${dateKey}'"[]|map({symbol, delta, strikePrice,bid,ask}) | .[] | select(.delta >= '${deltaMin}' and .delta <= '${deltaMax}') | select( (.strikePrice | floor) == .strikePrice)' "${inputFile}" | tail -n 7 > temp/longLeg.json
jq '.callExpDateMap."'${dateKey}'"[]|map({symbol, delta, strikePrice,bid,ask}) | .[] | select(.delta >= '${deltaMin}' and .delta <= '${deltaMax}')' "${inputFile}" | tail -n 7 > temp/longLeg.json
numLinesInLeg=$(wc -l temp/longLeg.json | cut -c1)
if [[ 7 -ne ${numLinesInLeg} ]]; then
errMsg="No suitable long leg found - exiting."
systemd-cat -t "`basename $0` $1" -p warning <<< ${errMsg}
>&2 echo "${errMsg}"
exit 1
fi
longStrike=$(jq -r '.strikePrice' < temp/longLeg.json)
longBid=$(jq -r '.bid' < temp/longLeg.json)
longAsk=$(jq -r '.ask' < temp/longLeg.json)
longSymbol=$(jq -r '.symbol' < temp/longLeg.json)
msg="Long Symbol: _${longSymbol}_ Strike: _${longStrike}_ Bid: _${longBid}_ Ask: _${longAsk}_"
systemd-cat -t "`basename $0` $1" -p info <<< ${msg}
echo "${msg}"
priceOffset=0.0
# Get the Middle price...
price=$(echo "scale=2; ((${longBid}+${longAsk})/2) + ${priceOffset}" | bc)
orderJson=$(jq -c <<-EOM
{
"orderType": "LIMIT",
"session": "NORMAL",
"price": ${price},
"duration": "DAY",
"orderStrategyType": "SINGLE",
"quantity": 1,
"orderLegCollection": [
{
"instruction": "BUY_TO_OPEN",
"quantity": 1,
"instrument": {
"symbol": "${longSymbol}",
"assetType": "OPTION"
}
}
]
}
EOM
)
systemd-cat -t "`basename $0` $1" -p debug <<< "Order: _${orderJson}_"
echo Enter to continue, Ctrl+C to cancel
read
./getNewAccessToken.sh
curl -s -X POST \
'https://api.schwabapi.com/trader/v1/accounts/5A5B921917D97B89FDA53E1E1D13D2EB11E488ADA20A20B3C787477DE59A770E/orders' \
-H "Authorization: Bearer $(<access_token.dat)" \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d "${orderJson}"

View File

@@ -3,8 +3,11 @@
mkdir -p temp
echo Set Dyn-IP
myIP=$(ip a | grep 'inet.*192.168.10' | awk -F "[ /]*" '{print $3}')
curl -s "https://ddns.kawomi.com/?domain=cstradebotcallback&address=${myIP}"
echo Get latest certificate
ssh root@192.168.10.2 'cd /etc/letsencrypt/live/current && cat privkey.pem cert.pem' > cert.pem
echo
echo OPEN URL: "https://api.schwabapi.com/v1/oauth/authorize?client_id=$(<appKey.dat)&redirect_uri=https://cstradebotcallback.ddns.kawomi.com:2222/"
@@ -17,6 +20,17 @@ curl -s -X POST "https://api.schwabapi.com/v1/oauth/token" \
-H "Authorization: Basic $(<appCredentials.dat)" \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d "grant_type=authorization_code&code=${theCode}&redirect_uri=https://cstradebotcallback.ddns.kawomi.com:2222/" > temp/refreshTokenReqResp.$$.json
jq -r .refresh_token temp/refreshTokenReqResp.$$.json > refresh_token.dat
jq -e -r .refresh_token temp/refreshTokenReqResp.$$.json > temp/refresh_token.$$.dat
if [[ $? -eq 0 ]]; then
errMsg="New Refresh Token created."
systemd-cat -t "`basename $0`" -p info <<< ${errMsg}
echo "${errMsg}"
cp temp/refresh_token.$$.dat refresh_token.dat
else
errMsg="Error getting new refresh token _$(<temp/refresh_token.$$.dat)_"
systemd-cat -t "`basename $0`" -p err <<< ${errMsg}
>&2 echo "${errMsg}"
fi
echo Refresh Token: $(<refresh_token.dat)

13
getOrders.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/bash
set -x
mkdir -p temp
./getNewAccessToken.sh
tempFile=temp/accountOrders.tmp.$$.json
#fromEnteredTime=$(date -u "+%Y-%m-%dT%H:%M:%S.000Z" -d "-5 days")
fromEnteredTime=$(date -u "+%Y-%m-%dT%H:%M:%S.000Z" -d "-1000 minutes")
toEnteredTime=$(date -u "+%Y-%m-%dT%H:%M:%S.000Z" -d "-10 minutes")
curl -s -X GET "https://api.schwabapi.com/trader/v1/orders?fromEnteredTime=${fromEnteredTime}&toEnteredTime=${toEnteredTime}" -H "Authorization: Bearer $(<access_token.dat)" > ${tempFile}
cat ${tempFile} | jq -r 'map(.enteredTime)[]'

32
record90dayOut.sh Executable file
View File

@@ -0,0 +1,32 @@
#!/bin/bash
#set -x
IFS=$'\0'
daysOutMin=90
daysOutMax=91
inputFile="$1"
latestFile="$1"
if [[ "" == "$inputFile" ]]; then
latestFile="$(ls data/`date +%Y-%m-%d`/*SPY* | sort | tail -n 1)"
systemd-cat -t "`basename $0` $1" -p debug <<< "Latest File: _${latestFile}_"
inputFile=temp/orderInputFile.json
bzip2 -dc < "${latestFile}" > "${inputFile}"
fi
if [[ ! -f "${inputFile}" ]]; then
errMsg="ERROR: Input file _${inputFile}_ does not exist."
systemd-cat -t "`basename $0` $1" -p err <<< ${errMsg}
>&2 echo "${errMsg}"
exit 1
fi
dateKey=$(jq -r '.callExpDateMap | keys | .[]' temp/orderInputFile.json | sort -r -t ":" +2 | awk -F ":" -e '{theDay=$2; if (theDay < '${daysOutMin}') { print lastDay; exit; } else { lastDay=$0; } }')
systemd-cat -t "`basename $0` $1" -p debug <<< "Date-Key: _${dateKey}_"
daysOut=$(cut -d : -f 2 <<< ${dateKey})
if [[ ${daysOut} -gt ${daysOutMax} ]]; then
exit
fi
echo "$(date +%Y-%m-%d): ${dateKey} (${latestFile})" >> record90dayOut.log

View File

@@ -20,7 +20,7 @@ jq -r '.[].Symbol' allSymbols.json | sort | while read theSymbol; do
./recordOptionChainSingleSymbolSingleRun.sh ${theSymbol} toDate $(date "+%Y-%m-%d" -d "+200 days")
if [[ $? -ne 0 ]]; then
systemd-cat -t "`basename $0`" -p warning <<< "falling back to stitching for ${theSymbol}"
./recordOptionChainSingleSymbolSpecialRun.sh ${theSymbol}
./recordOptionChainSingleSymbolSpecialRun.sh ${theSymbol} toDate $(date "+%Y-%m-%d" -d "+400 days")
if [[ $? -ne 0 ]]; then
touch temp/hadErrors.$$.tmp
fi
@@ -43,7 +43,7 @@ jq -r '.[].Symbol' allSymbols.json | sort | while read theSymbol; do
fi
if [[ '$SPX' = ${theSymbol} ]]; then
./recordOptionChainSingleSymbolSingleRun.sh ${theSymbol} fromDate $(date "+%Y-%m-%d" -d "+40 days") toDate $(date "+%Y-%m-%d" -d "+45 days")
./recordOptionChainSingleSymbolSingleRun.sh ${theSymbol} fromDate $(date "+%Y-%m-%d" -d "+40 days") toDate $(date "+%Y-%m-%d" -d "+46 days")
if [[ $? -ne 0 ]]; then
touch temp/hadErrors.$$.tmp
fi