Skip to content

Commit

Permalink
feat: Allow user to adjust along with profit take and stop loss
Browse files Browse the repository at this point in the history
  • Loading branch information
namuan committed Dec 19, 2024
1 parent bdb8fcb commit 44e10f2
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 15 deletions.
28 changes: 16 additions & 12 deletions Options_Analysis.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Extract all contents from compressed files into a designated folder.
The following script can read nested folders, allowing them to be accessed without being placed at the root level.

```shell
uvr optionsdx-data-importer.py --input $(pwd)/data/spy_eod --output data/spy_eod.db -v
./optionsdx-data-importer.py --input $(pwd)/data/spy_eod --output data/spy_eod.db -v
```

## Strategies
Expand All @@ -16,70 +16,74 @@ uvr optionsdx-data-importer.py --input $(pwd)/data/spy_eod --output data/spy_eod
```shell
for dte in {7..60}; do
echo "Running for DTE: $dte"
uvr --no-progress options-straddle-low-vol-trades.py --db-path data/spx_eod.db --dte $dte --profit-take 15 --stop-loss 100 --max-open-trades 5 -v
./options-straddle-low-vol-trades.py --db-path data/spx_eod.db --dte $dte --profit-take 15 --stop-loss 100 --max-open-trades 5 -v
done
```

```shell
uvr --no-progress options-straddle-low-vol-trades.py --db-path data/spx_eod.db --dte 60 --profit-take 10 --stop-loss 100 --max-open-trades 5 -v
./options-straddle-low-vol-trades.py --db-path data/spx_eod.db --dte 60 --profit-take 10 --stop-loss 100 --max-open-trades 5 -v
```

```shell
cp data/spx_eod.db data/spx_eod_vol_filter.db
```

```shell
uvr options-straddle-simple-report.py --database data/spx_eod_vol_filter.db --weeks 4 --dte 60
./options-straddle-simple-report.py --database data/spx_eod_vol_filter.db --weeks 4 --dte 60
```

```shell
uvr options-straddle-simple-equity-graph.py --db-path data/spx_eod_vol_filter.db
./options-straddle-simple-equity-graph.py --db-path data/spx_eod_vol_filter.db
```

### What if we keep all trades with given profit take and stop loss

```shell
for dte in {7..60}; do
echo "Running for DTE: $dte"
uvr --no-progress options-straddle-profit-take-stop-loss-adjustment.py --db-path data/spx_eod.db --dte $dte --profit-take 30 --stop-loss 100 --max-open-trades 5 -v
./options-straddle-profit-take-stop-loss-adjustment.py --db-path data/spx_eod.db --dte $dte --profit-take 30 --stop-loss 100 --max-open-trades 5 -v
done
```

```shell
uvr --no-progress options-straddle-profit-take-stop-loss-adjustment.py --db-path data/spx_eod.db --dte 60 --profit-take 10 --stop-loss 75 --max-open-trades 5 -v
./options-straddle-profit-take-stop-loss-adjustment.py --db-path data/spx_eod.db --dte 60 --profit-take 10 --stop-loss 75 --max-open-trades 5 -v
```

```shell
./options-straddle-profit-take-stop-loss-adjustment.py --db-path data/spx_eod.db --dte 60 --profit-take 10 --stop-loss 75 --max-open-trades 5 --trade-delay 5 -v
```

```shell
cp data/spx_eod.db data/spx_eod_profit_loss_adjustment.db
```

```shell
uvr options-straddle-simple-report.py --database data/spx_eod_profit_loss_adjustment.db --weeks 4 --dte 45
./options-straddle-simple-report.py --database data/spx_eod_profit_loss_adjustment.db --weeks 4 --dte 60
```

```shell
uvr options-straddle-simple-equity-graph.py --db-path data/spx_eod_profit_loss_adjustment.db
./options-straddle-simple-equity-graph.py --db-path data/spx_eod_profit_loss_adjustment.db
```

### What if we keep all trades all the time

```shell
for dte in {7..60}; do
echo "Running for DTE: $dte"
uvr --no-progress options-straddle-simple.py --db-path data/spx_eod.db --dte $dte
./options-straddle-simple.py --db-path data/spx_eod.db --dte $dte
done
```

```shell
uvr --no-progress options-straddle-simple.py --db-path data/spx_eod.db --dte 60 --max-open-trades 99 --trade-delay 1 -v
./options-straddle-simple.py --db-path data/spx_eod.db --dte 60 --max-open-trades 99 -v
```

```shell
cp data/spx_eod.db data/spx_eod_simple.db
```

```shell
uvr options-straddle-simple-report.py --database data/spx_eod_simple.db --weeks 4 --dte 60
./options-straddle-simple-report.py --database data/spx_eod_simple.db --weeks 4 --dte 60
```

```shell
Expand Down
77 changes: 74 additions & 3 deletions options-straddle-profit-take-stop-loss-adjustment.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import logging
from argparse import ArgumentParser, RawDescriptionHelpFormatter
from datetime import datetime

import pandas as pd

Expand All @@ -26,7 +27,7 @@
pd.set_option("display.float_format", lambda x: "%.4f" % x)


def can_close_trade(
def can_close_trade_for_profit_take_stop_loss(
open_trade,
current_underlying_price,
current_call_price,
Expand Down Expand Up @@ -54,6 +55,23 @@ def can_close_trade(
return False, ""


def can_close_trade_for_adjustment(call_price, put_price):
# Handle cases where either price is 0 to avoid division by zero
if not call_price or not put_price or call_price == 0 or put_price == 0:
return False, ""

# Calculate ratios both ways
call_to_put_ratio = call_price / put_price
put_to_call_ratio = put_price / call_price

# Check if either ratio exceeds 4
require_adjustment = call_to_put_ratio > 4 or put_to_call_ratio > 4
if require_adjustment:
return True, "REQUIRE_ADJUSTMENT"
else:
return False, ""


def update_open_trades(db, quote_date, profit_take, stop_loss):
"""Update all open trades with current prices"""
open_trades = db.get_open_trades()
Expand All @@ -72,9 +90,22 @@ def update_open_trades(db, quote_date, profit_take, stop_loss):
trade["TradeId"], quote_date, underlying_price, call_price, put_price
)

trade_can_be_closed, closing_reason = can_close_trade(
trade, underlying_price, call_price, put_price, profit_take, stop_loss
trade_can_be_closed, closing_reason = (
can_close_trade_for_profit_take_stop_loss(
trade,
underlying_price,
call_price,
put_price,
profit_take,
stop_loss,
)
)
if not trade_can_be_closed:
trade_can_be_closed, closing_reason = can_close_trade_for_adjustment(
call_price, put_price
)
# pass

if quote_date >= trade["ExpireDate"] or trade_can_be_closed:
db.update_trade_status(
trade["TradeId"],
Expand All @@ -90,6 +121,36 @@ def update_open_trades(db, quote_date, profit_take, stop_loss):
logging.info(f"Closed trade {trade['TradeId']} at expiry")


def can_create_new_trade(db, quote_date, trade_delay_days):
"""Check if enough time has passed since the last trade"""
if trade_delay_days < 0:
return True

last_open_trade = db.get_last_open_trade()

if last_open_trade.empty:
logging.debug("No open trades found. Can create new trade.")
return True

last_trade_date = last_open_trade["Date"].iloc[0]

last_trade_date = datetime.strptime(last_trade_date, "%Y-%m-%d").date()
quote_date = datetime.strptime(quote_date, "%Y-%m-%d").date()

days_since_last_trade = (quote_date - last_trade_date).days

if days_since_last_trade >= trade_delay_days:
logging.info(
f"Days since last trade: {days_since_last_trade}. Can create new trade."
)
return True
else:
logging.debug(
f"Only {days_since_last_trade} days since last trade. Waiting for {trade_delay_days} days."
)
return False


def parse_args():
parser = ArgumentParser(
description=__doc__, formatter_class=RawDescriptionHelpFormatter
Expand Down Expand Up @@ -136,6 +197,12 @@ def parse_args():
default=99,
help="Maximum number of open trades allowed at a given time",
)
parser.add_argument(
"--trade-delay",
type=int,
default=-1,
help="Minimum number of days to wait between new trades",
)
return parser.parse_args()


Expand All @@ -151,6 +218,10 @@ def main(args):
# Update existing open trades
update_open_trades(db, quote_date, args.profit_take, args.stop_loss)

# Check if enough time has passed since last trade
if not can_create_new_trade(db, quote_date, args.trade_delay):
continue

# Look for new trade opportunities
result = db.get_next_expiry_by_dte(quote_date, args.dte)
if result:
Expand Down

0 comments on commit 44e10f2

Please sign in to comment.