Home > Net >  Best Approach to implement Stop Loss / Take Profit in Python
Best Approach to implement Stop Loss / Take Profit in Python

Time:07-04

Assume I have an very large array of consecutive values representing a stock price over time.

prices = [22,23,25,23,26,25,28,22] # and so on…

When „buying“ the stock at any point in time (at any index in that array), I set a Stop Loss and a Take Profit.

buy_index = 2 # buying at 25
stop_loss = 23 # would sell at 23 or below
take_profit = 28 # would sell at 28 or higher

That just means I set two prices at which I would sell: one above the buy price and one below.

My question is: how can I efficiently figure out which of both prices I hit first?

I tried using numpy with the following steps:

import numpy as np
prices = np.array(prices)
relevant_prices = prices[buy_index:]
stop_loss_index = np.where[relevant_prices < stop_loss][0]
take_profit_index = np.where[relevant_prices < take_profit][0]

…and then comparing the indexes to determine which case came first. This works, but is extremely slow when done millions of times.

I realize that my code is going through the whole dataset every time it determines an index - there has to be a better way to do this.

CodePudding user response:

Use np.argmax

Since for boolean conditions argmax does not loop over the entire array i.e. short circuits when it finds a True.

Code

Using argmax:

relevant_prices = prices[buy_index:]
stop_loss_index = np.argmax(relevant_prices <= stop_loss)
take_profit_index = np.argmax(relevant_prices >= take_profit)

…and then comparing the indexes to determine which case came first

Demonstration of argmax short-circuiting on boolean arrays

import timeit

print('Million Point Array of False')
arr = np.full(1000000, False, dtype=bool)
%timeit arr.argmax()

print('\nTrue at beginning of Array of False')
arr[0] = True
%timeit arr.argmax()

Output

Note 52 X speed up in the 2nd case where True is at the beginning

Million Point Array of False
56.9 µs ± 1.57 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

True at beginning of Array of False
1.08 µs ± 175 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
​

CodePudding user response:

I'm not completely sure of what you want to do, but I think the following should work:

stop_loss_index = -1
take_profit_index = -1
for i, price in enumerate(prices[buy_index:]):
    if price <= stop_loss: stop_loss_index = i
    elif price >= take_profit: take_profit_index = i

This should give the index or -1 if none is found.

CodePudding user response:

If you'd like to quickly precalculate the answers so that running multiple different queries on buy_index would be efficient, traverse from the end to the beginning and keep a tree with the values seen as you traverse back (in time). Store and update a decoration with the lowest index and corresponding value seen in each subtree. (For the right subtree, this will be the closest-in-time higher value; and for the left, the closest-in-time lower value.)

As you traverse, for each buy_index you're precalculating, look up in the tree the index stored for the relevant values (it's unclear from your description if you'd like the exact or just closest value that's also closest in time) and store them.

  • Related