Как в Pandas реализовать подсчет методом FIFO?

Есть датафрейм, в котором отображаются покупки и продажи. Как при продаже части позиции, получить разницу между продажей и покупкой по методу FIFO?

         date  quantity  price cum_qty 
0  2020-03-13         1  16.53       1 
1  2020-03-18         1  10.21       2 
2  2020-03-26         1  17.61       3  
3  2020-05-01         1  14.70       4  
4  2020-05-22         1  14.51       5 
5  2020-05-27         1  18.15       6  
6  2020-06-08        -2  26.00       4 
7  2020-06-19        -4  17.94       0 

Т.е. когда в строке 6 произошла продажа 2 элементов, то в строках 0 и 1, например, в колонке "Profit" станет: 26 - 16.53 = 9.47 и 26 - 10.21 = 15.79 и т.д.

Дополнение: После продажи в строке 7, получается следующее: мы находим не проданные позиции, а это получается строки с 2-5, и "price" из строки 7 вычитаем "price" из найденной строки:

  • 2: 17.94 - 17.61 = 0.33
  • 3: 17.94 - 14.70 = 3.24
  • ...
  • 5: 17.94 - 18.15 = -0.21
         date  quantity  price  cum_qty   profit 
0  2020-03-13         1  16.53        1     9.47
1  2020-03-18         1  10.21        2    15.79
2  2020-03-26         1  17.61        3     0.33
3  2020-05-01         1  14.70        4     3.24
4  2020-05-22         1  14.51        5     3.43
5  2020-05-27         1  18.15        6    -0.21
6  2020-06-08        -2  26.00        4     0.00 
7  2020-06-19        -4  17.94        0     0.00

Никак не найду с помощью каких функций и методов могу искать строки вверх от имеющейся и менять в них значений по условию. Либо сопоставлять текущую строку с другими по условию. Буду рад предложенным вариантам.

Дополнение 2: Хотелось бы заменить вот этот цикл или оптимизировать его методами pandas.

df['profit'] = Decimal(0)
df['qnt_available'] = df['quantity']
# ------------------
df_sales = df[df['quantity'] < 0]  # получаем датафрейм с продажами
for i, row_sell in df_sales.iterrows():  # перебираем все продажи
    qnt_sell = abs(row_sell.quantity)  # количество проданных позиций
    price_sell = row_sell.price  # цена продажи

    while qnt_sell != 0:  # Цикл до тех пор пока не будут обработаны все продажи из текущей строки
        # формируем новый датафрейм, где остались покупки
        df_buy = df[df['qnt_available'] > 0]
        for j, row_buy in df_buy.iterrows():  # цикл по покупкам
            qnt_buy = row_buy.qnt_available  # количество оставшихся покупок
            price_buy = row_buy.price  # цена покупки

            if qnt_buy == qnt_sell:  # если количество покупок равно количеству продаж, то обнуляем значения
                new_value = 0
                qnt_sell = 0
                profit = (price_sell - price_buy) * qnt_buy  # сумма дохода
            elif qnt_buy > qnt_sell:  # если сумма покупок больше
                new_value = qnt_buy - qnt_sell
                qnt_sell = 0
                profit = (price_sell - price_buy) * qnt_sell
            elif qnt_buy < qnt_sell:  # если сумма покупки меньше
                new_value = 0
                qnt_sell -= qnt_buy
                profit = (price_sell - price_buy) * qnt_buy

            # Записываем новые данные
            df.at[j, 'qnt_available'] = new_value
            df.at[j, 'profit'] += profit

Начальный датафрейм:

         date  quantity  price profit  qnt_available
0  2020-03-13         1  16.53      0              1
1  2020-03-18         1  10.21      0              1
2  2020-03-26         1  17.61      0              1
3  2020-05-01         1  14.70      0              1
4  2020-05-22         1  14.51      0              1
5  2020-05-27         1  18.15      0              1
6  2020-06-08        -2  26.00      0             -2
7  2020-06-19        -4  17.94      0             -4

После обработки первой продажи:

         date  quantity  price profit  qnt_available
0  2020-03-13         1  16.53   9.47              0
1  2020-03-18         1  10.21  15.79              0
2  2020-03-26         1  17.61      0              1
3  2020-05-01         1  14.70      0              1
4  2020-05-22         1  14.51      0              1
5  2020-05-27         1  18.15      0              1
6  2020-06-08        -2  26.00      0             -2
7  2020-06-19        -4  17.94      0             -4

После второй продажи:

         date  quantity  price profit  qnt_available
0  2020-03-13         1  16.53   9.47              0
1  2020-03-18         1  10.21  15.79              0
2  2020-03-26         1  17.61   0.33              0
3  2020-05-01         1  14.70   3.24              0
4  2020-05-22         1  14.51   3.43              0
5  2020-05-27         1  18.15  -0.21              0
6  2020-06-08        -2  26.00      0             -2
7  2020-06-19        -4  17.94      0             -4

Ответы (0 шт):