I'm trying to capture profits and set a stop loss in my trading strategy. I want the stop loss to be set daily based on the past data and if the current price, i.e., price for the date falls below the stop_loss levels, sell the stock.

Below is the implementation for the same:

def logging_stop_loss(dict_dfs, result_df, stop_loss_levels):
    trades = []
    positions = {}

    for date_idx, date in enumerate(result_df.index):
        for stock in result_df.columns[result_df.iloc[date_idx]]:
            if (stock, date) not in positions:
                entry_price = dict_dfs['close'].at[date, stock]
                stop_loss_level = stop_loss_levels.at[date, stock]
                positions[(stock, date)] = {
                    'entry_date': date,
                    'entry_price': entry_price,
                    'stop_loss': entry_price * (1 - stop_loss_level),
                    'count': 0  # Initialize count to track days since entry

        closed_positions = []
        for (stock, entry_date), pos in list(positions.items()):
            pos['count'] += 1
            future_date = result_df.index[min(date_idx + pos['count'], len(result_df) - 1)]
            current_price = dict_dfs['close'].at[future_date, stock]
            stop_loss_level = stop_loss_levels.at[future_date, stock]
            pos['stop_loss'] = current_price * (1 - stop_loss_level)

            if current_price < pos['stop_loss']:
                    'stock': stock,
                    'entry_date': pos['entry_date'],
                    'entry_price': pos['entry_price'],
                    'exit_date': future_date,
                    'exit_price': current_price,
                    'return': (current_price - pos['entry_price']) / pos['entry_price']
                closed_positions.append((stock, entry_date))

        for stock_entry in closed_positions:
            del positions[stock_entry]

    return pd.DataFrame(trades)

I have included my code which takes in stop loss calculated using certain logic for all the days. Another dataframe tells me about the trading dates, with TRUE value indicating I enter the trade, and FALSE value indicating I exit the trade. With this logic, I enter the trade and see if stop loss is met. If not, get going to the next date, if it is met, then sell else continue the loop till the end of the closing price dataframe is met. I will then log the entry and exit prices in a dataframe and save it.

This code returns empty logging_stop_loss dataframe, and it has no entry in the dataframe. This being the case, I want to understand what is causing the issue and rectify it. Can someone lead me to the direction which is causing this error and I can modify my logic accordingly.


1 Answer 1


wrong parameter name

def logging_stop_loss( ... , result_df, ... ):
    trades = []
    return pd.DataFrame(trades)

It's pretty clear we use trades to compose a result df.

Now, there may be some other function which carefully composed a result_df of whatever it was tasked with computing. But by the time it arrives here, it is definitely a gazinta, and not a gozouta; it's not like caller expects it to be mutated.

Please choose a more appropriate name, perhaps portfolio.

It wouldn't hurt to type annotate the signature. For example if I see portfolio: pd.DataFrame then there's no need for a three-character portfolio_df suffix.

.iloc[ ]

You're processing several fields of a row. Using .iloc on an index is less convenient than simply asking for a whole row at a time:

    for _, row in result_df.iterrows():

Then you can refer to row.date and so on.

scanning, merging

Your current approach works well enough. It makes a linear scan over the result_df portfolio, crossing that against positions, taking advantage of a bunch \$O(1)\$ constant time probe operations.

Now imagine you were going to solve this problem using SQL. You'd need at least one JOIN, right? Consider applying such a .merge() approach in the context of this pandas problem. By processing similarly sorted tables we can bring matching records together automatically, without need of a nested loop that goes looking for matches.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.