2024-08-26 15:18:24 -05:00
|
|
|
#!/bin/bash
|
|
|
|
|
set -x
|
|
|
|
|
set -e
|
|
|
|
|
IFS=$'\0'
|
|
|
|
|
myPID=$$
|
2024-08-27 12:16:01 -05:00
|
|
|
. helpers.sh
|
2024-08-31 15:57:46 -05:00
|
|
|
./getNewAccessToken.sh
|
|
|
|
|
|
2024-08-26 15:18:24 -05:00
|
|
|
|
|
|
|
|
marketOpen=$([[ $(./getMarketHours.sh | jq '.option[].isOpen' | grep true | wc -l) -ne 0 ]] && echo true || echo false)
|
|
|
|
|
if [[ ${marketOpen} == false ]]; then
|
2024-08-27 12:16:01 -05:00
|
|
|
throw "The market is closed, exiting." info 2
|
2024-08-26 15:18:24 -05:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
inputFile="$1"
|
|
|
|
|
if [[ "" == "$inputFile" ]]; then
|
|
|
|
|
inputFile=temp/orderInputFile.$$.json
|
|
|
|
|
./getOptionChain.sh '$SPX' fromDate $(date "+%Y-%m-%d") toDate $(date "+%Y-%m-%d") > "${inputFile}"
|
|
|
|
|
fi
|
|
|
|
|
if [[ ! -f "${inputFile}" ]]; then
|
2024-08-27 12:16:01 -05:00
|
|
|
throw "ERROR: Input file _${inputFile}_ does not exist." err 1
|
2024-08-26 15:18:24 -05:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
dateKey=$(jq -r '.putExpDateMap | keys | .[]' "${inputFile}" | head -n 1)
|
2024-08-27 12:16:01 -05:00
|
|
|
log "Date-Key: _${dateKey}_" debug
|
2024-08-26 15:18:24 -05:00
|
|
|
|
|
|
|
|
underlyingPrice=$(jq ".underlyingPrice" "${inputFile}")
|
|
|
|
|
atmStrike=$(jq -r '.callExpDateMap[]|keys[]' "${inputFile}" | sort -n | awk -e '{lastStrike=$1; if ($1 > '${underlyingPrice}') {print $1; exit } }')
|
|
|
|
|
|
|
|
|
|
jq '.putExpDateMap."'${dateKey}'"[]|map({symbol,delta,strikePrice,bid,ask,optionRoot}) |.[] | select(.strikePrice=='${atmStrike}') ' "${inputFile}" | tail -n 8 > temp/shortLegP.json
|
|
|
|
|
shortStrikeP=$(jq -r '.strikePrice' < temp/shortLegP.json)
|
|
|
|
|
shortBidP=$(jq -r '.bid' < temp/shortLegP.json)
|
|
|
|
|
shortAskP=$(jq -r '.ask' < temp/shortLegP.json)
|
|
|
|
|
shortSymbolP=$(jq -r '.symbol' < temp/shortLegP.json)
|
|
|
|
|
optionRoot=$(jq -r '.optionRoot' < temp/shortLegP.json)
|
2024-08-27 12:16:01 -05:00
|
|
|
log "Short Put Symbol: _${shortSymbolP}_ Strike: _${shortStrikeP}_ Bid: _${shortBidP}_ Ask: _${shortAskP}_" info
|
2024-08-26 15:18:24 -05:00
|
|
|
|
|
|
|
|
jq '.callExpDateMap."'${dateKey}'"[]|map({symbol,delta,strikePrice,bid,ask,optionRoot}) |.[] | select(.strikePrice=='${atmStrike}') ' "${inputFile}" | tail -n 8 > temp/shortLegC.json
|
|
|
|
|
shortStrikeC=$(jq -r '.strikePrice' < temp/shortLegC.json)
|
|
|
|
|
shortBidC=$(jq -r '.bid' < temp/shortLegC.json)
|
|
|
|
|
shortAskC=$(jq -r '.ask' < temp/shortLegC.json)
|
|
|
|
|
shortSymbolC=$(jq -r '.symbol' < temp/shortLegC.json)
|
2024-08-27 12:16:01 -05:00
|
|
|
log "Short Call Symbol: _${shortSymbolC}_ Strike: _${shortStrikeC}_ Bid: _${shortBidC}_ Ask: _${shortAskC}_" info
|
2024-08-26 15:18:24 -05:00
|
|
|
|
|
|
|
|
jq '.putExpDateMap."'${dateKey}'"[]|map({symbol,delta,strikePrice,bid,ask,optionRoot}) | .[] | select(.optionRoot == "'${optionRoot}'" and .strikePrice >= '${shortStrikeP}'-10 and .strikePrice < '${shortStrikeP}')' "${inputFile}" | head -n 8 > temp/longLegP.json
|
|
|
|
|
longStrikeP=$(jq -r '.strikePrice' < temp/longLegP.json)
|
|
|
|
|
longBidP=$(jq -r '.bid' < temp/longLegP.json)
|
|
|
|
|
longAskP=$(jq -r '.ask' < temp/longLegP.json)
|
|
|
|
|
longSymbolP=$(jq -r '.symbol' < temp/longLegP.json)
|
2024-08-27 12:16:01 -05:00
|
|
|
log "Long Symbol: _${longSymbolP}_ Strike: _${longStrikeP}_ Bid: _${longBidP}_ Ask: _${longAskP}_" info
|
2024-08-26 15:18:24 -05:00
|
|
|
|
|
|
|
|
#Check if this order has already been submitted.
|
|
|
|
|
jq '.callExpDateMap."'${dateKey}'"[]|map({symbol,delta,strikePrice,bid,ask,optionRoot}) | .[] | select(.optionRoot == "'${optionRoot}'" and .strikePrice >= '${shortStrikeC}'+10 and .strikePrice > '${shortStrikeP}')' "${inputFile}" | head -n 8 > temp/longLegC.json
|
|
|
|
|
longStrikeC=$(jq -r '.strikePrice' < temp/longLegC.json)
|
|
|
|
|
longBidC=$(jq -r '.bid' < temp/longLegC.json)
|
|
|
|
|
longAskC=$(jq -r '.ask' < temp/longLegC.json)
|
|
|
|
|
longSymbolC=$(jq -r '.symbol' < temp/longLegC.json)
|
2024-08-27 12:16:01 -05:00
|
|
|
log "Long Symbol: _${longSymbolC}_ Strike: _${longStrikeC}_ Bid: _${longBidC}_ Ask: _${longAskC}_" info
|
2024-08-26 15:18:24 -05:00
|
|
|
|
|
|
|
|
#Check if this order has already been submitted.
|
|
|
|
|
./getOrders.sh | (grep '\(WORKING\|FILLED\),'${longSymbolC:0:12} || true) > temp/existingOrders.${myPID}
|
|
|
|
|
|
|
|
|
|
if [[ $(wc -l < temp/existingOrders.${myPID}) -eq 0 ]];then
|
2024-08-27 12:16:01 -05:00
|
|
|
log "Not Yet traded, continuing" info
|
2024-08-26 15:18:24 -05:00
|
|
|
else
|
2024-08-27 12:16:01 -05:00
|
|
|
throw "Already traded, exiting" info
|
2024-08-26 15:18:24 -05:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
priceOffset=1.1 # try to get $10 more in premium...
|
|
|
|
|
profitTargetPct=25 # cash in at 25% gains
|
|
|
|
|
|
|
|
|
|
#For SPX we need to submit orders at the closest 5cent price
|
|
|
|
|
#To find the closest 5cent price the mathematical solution is
|
|
|
|
|
# 1) Multiply by 20
|
|
|
|
|
# 2) Round to the Coloses full number
|
|
|
|
|
# 3) Divide by 20
|
|
|
|
|
priceOpen=$(echo "scale=2; exact=((${shortBidC}+${shortAskC})/2) + ((${shortBidP}+${shortAskP})/2) - ((${longBidC}+${longAskC})/2) - ((${longBidP}+${longAskP})/2) + ${priceOffset}; scale=0; round5=exact*20/1; scale=2; round5/20" | bc)
|
|
|
|
|
priceClose=$(echo "scale=2; exact=${priceOpen} * (100-${profitTargetPct}) /100; scale=0; round5=exact*20/1; scale=2; round5/20" | bc) # Profit target 25%
|
|
|
|
|
|
|
|
|
|
orderJson=$(jq -c <<-EOM
|
|
|
|
|
{
|
|
|
|
|
"orderType": "NET_CREDIT",
|
|
|
|
|
"session": "NORMAL",
|
|
|
|
|
"price": ${priceOpen},
|
|
|
|
|
"duration": "DAY",
|
|
|
|
|
"orderStrategyType": "SINGLE",
|
|
|
|
|
"quantity": 1,
|
|
|
|
|
"orderLegCollection": [
|
|
|
|
|
{
|
|
|
|
|
"instruction": "SELL_TO_OPEN",
|
|
|
|
|
"quantity": 1,
|
|
|
|
|
"instrument": {
|
|
|
|
|
"symbol": "${shortSymbolP}",
|
|
|
|
|
"assetType": "OPTION"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"instruction": "SELL_TO_OPEN",
|
|
|
|
|
"quantity": 1,
|
|
|
|
|
"instrument": {
|
|
|
|
|
"symbol": "${shortSymbolC}",
|
|
|
|
|
"assetType": "OPTION"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"instruction": "BUY_TO_OPEN",
|
|
|
|
|
"quantity": 1,
|
|
|
|
|
"instrument": {
|
|
|
|
|
"symbol": "${longSymbolP}",
|
|
|
|
|
"assetType": "OPTION"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"instruction": "BUY_TO_OPEN",
|
|
|
|
|
"quantity": 1,
|
|
|
|
|
"instrument": {
|
|
|
|
|
"symbol": "${longSymbolC}",
|
|
|
|
|
"assetType": "OPTION"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"orderStrategyType": "TRIGGER",
|
|
|
|
|
"childOrderStrategies": [
|
|
|
|
|
{
|
|
|
|
|
"orderType": "NET_DEBIT",
|
|
|
|
|
"session": "NORMAL",
|
|
|
|
|
"price": ${priceClose},
|
|
|
|
|
"duration": "DAY",
|
|
|
|
|
"orderStrategyType": "SINGLE",
|
|
|
|
|
"quantity": 1,
|
|
|
|
|
"orderLegCollection": [
|
|
|
|
|
{
|
|
|
|
|
"instruction": "BUY_TO_CLOSE",
|
|
|
|
|
"quantity": 1,
|
|
|
|
|
"instrument": {
|
|
|
|
|
"symbol": "${shortSymbolP}",
|
|
|
|
|
"assetType": "OPTION"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"instruction": "BUY_TO_CLOSE",
|
|
|
|
|
"quantity": 1,
|
|
|
|
|
"instrument": {
|
|
|
|
|
"symbol": "${shortSymbolC}",
|
|
|
|
|
"assetType": "OPTION"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"instruction": "SELL_TO_CLOSE",
|
|
|
|
|
"quantity": 1,
|
|
|
|
|
"instrument": {
|
|
|
|
|
"symbol": "${longSymbolP}",
|
|
|
|
|
"assetType": "OPTION"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"instruction": "SELL_TO_CLOSE",
|
|
|
|
|
"quantity": 1,
|
|
|
|
|
"instrument": {
|
|
|
|
|
"symbol": "${longSymbolC}",
|
|
|
|
|
"assetType": "OPTION"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
EOM
|
|
|
|
|
)
|
|
|
|
|
|
2024-08-27 12:16:01 -05:00
|
|
|
log "Order: _${orderJson}_" debug
|
2024-08-26 15:18:24 -05:00
|
|
|
|
|
|
|
|
if [[ "${noconfirm}" != "true" ]]; then
|
|
|
|
|
echo ${orderJSON} | jq
|
|
|
|
|
echo Enter to continue, Ctrl+C to cancel _${noconfirm}_
|
|
|
|
|
read
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
curl -s -X POST \
|
2024-08-26 21:44:43 -05:00
|
|
|
"https://api.schwabapi.com/trader/v1/accounts/$(./getAccountNumbers.sh Regular)/orders" \
|
|
|
|
|
-H "Authorization: Bearer $(<access_token.dat)" \
|
2024-08-26 15:18:24 -05:00
|
|
|
-H 'accept: */*' \
|
|
|
|
|
-H 'Content-Type: application/json' \
|
2024-08-26 21:44:43 -05:00
|
|
|
-d "${orderJson}"
|
2024-08-26 15:18:24 -05:00
|
|
|
|