Как вычислять значения столбцов строка за строкой в ​​мультииндексном панде? - PullRequest
0 голосов
/ 10 октября 2018

У меня есть два кадра данных: the_strongest_stock и data.Они имеют одинаковый мультииндекс: Date и Symbol.the_strongest_stock имеет один соответствующий столбец: Entry_signal.data имеет столбцы Open, High, Low, Close, ATR, No_of_data.Я присоединяю the_strongest_stock к data и регистрирую позиции.

# Entry signal---------------------------------------------------------------

data = data.join(the_strongest_stock[['Entry_signal']], on=['Date','Symbol'])
data.loc[data['No_of_data'] < 250,'Entry_signal'] = False
data['Entry_signal'] = data['Entry_signal'].fillna(False)

# Position log---------------------------------------------------------------

data['Initial_stop'] = (data['Close'] - 10 * data['ATR']).round(2)
data['Stop_level'] = data.groupby(['Symbol',data.groupby('Symbol')['Entry_signal'].cumsum()])['Initial_stop'].cummax()
data['Exit_signal'] = np.where(data['Low'] < data.groupby('Symbol')['Stop_level'].shift(1),True,False)
data['Position'] = np.where(data['Exit_signal'] == True,False,np.where(data['Entry_signal'] == True,True,np.nan))
data['Position'] = data.groupby('Symbol')['Position'].ffill()
data.loc[data['Position'] == False,'Stop_level'] = False

Теперь, когда у меня есть агрегированный фрейм данных data с зарегистрированными Position с, я создаю столбцы для расчета плавающей прибыли и закрытияприбыль, которую сгенерировали сделки.

 # Shares---------------------------------------------------------------

starting_capital = 30000

risk_base = starting_capital
trade_base = starting_capital

close_stop_diff = np.maximum(data.groupby('Symbol')['Close'].shift(1) - data.groupby('Symbol')['Stop_level'].shift(1),0.000001) # to avoid division by zero in share_number
share_number = (risk_base * risk_per_position) / close_stop_diff

data['Shares'] = np.where(
   data['Position'] == False,
   0,
   np.where(
      np.logical_and(
         data.groupby('Symbol')['Position'].shift(1) == False,
         data['Position'] == True),
      np.where(
         share_number * data.groupby('Symbol')['Close'].shift(1) > trade_base + 0.05 * risk_base,
         0,
         share_number),
      np.nan))
data = data.sort_values(by=['Date', 'Symbol'])
data['Shares'] = data.groupby('Symbol')['Shares'].ffill()
data['Shares'] = data['Shares'].astype(float).round(0)

# Open price---------------------------------------------------------------

data.loc[data['Position'] == False, 'Open_price'] = False
data['Open_price'] = np.where(
   data['Exit_signal'] == True,
   False,
   np.where(
      np.logical_and(
         data.groupby('Symbol')['Position'].shift(1) == False,
         data['Position'] == True),
      data['Open'] + skid * (data['High'] - data['Open']),
      np.nan))
data = data.sort_values(by=['Date', 'Symbol'])
data['Open_price'] = data.groupby('Symbol')['Open_price'].ffill()
data['Open_price'] = data['Open_price'].round(2)

# Open value---------------------------------------------------------------

data['Open_value'] = np.where(
   data['Position'] == True,
   data['Shares'] * data['Open_price'],
   0)

# Floating profit---------------------------------------------------------------

data['Floating_P/L'] = np.where(
   data['Position'] == True,
   data['Shares'] * (data['Close'] - data['Open_price']),
   0)
data['Floating_P/L'] = data['Floating_P/L'].fillna(0)
data['Floating_P/L'] = data['Floating_P/L'].round(2)

# Close price---------------------------------------------------------------

data['Close_price'] = np.where(
   np.logical_and(
      data.groupby('Symbol')['Position'].shift(1) == True,
      data['Position'] == False),
   data.groupby('Symbol')['Stop_level'].shift(1) - skid * (data.groupby('Symbol')['Stop_level'].shift(1) - data['Low']),
   False)
data['Close_price'] = data['Close_price'].astype(float).round(2)

# Closed profit---------------------------------------------------------------

data['Closed_P/L'] = np.where(
   np.logical_and(
      data.groupby('Symbol')['Position'].shift(1) == True,
      data['Position'] == False),
   data.groupby('Symbol')['Shares'].shift(1) * (data['Close_price'] - data.groupby('Symbol')['Open_price'].shift(1)),
   0)
data['Closed_P/L'] = data['Closed_P/L'].fillna(0)
data['Closed_P/L'] = data['Closed_P/L'].round(2)

Наконец, я создаю столбцы, чтобы суммировать прибыль и убыток для каждого Date, генерируемого Symbol s

# Totals---------------------------------------------------------------

data['Total_Open_Value'] = data.groupby(by=['Date','Symbol'])['Open_value'].sum().groupby(level=[0]).cumsum().groupby('Date').tail(1)
data['Total_Open_Value'] = data.groupby('Date')['Total_Open_Value'].bfill()

data['Floating_Total'] = data.groupby(by=['Date','Symbol'])['Floating_P/L'].sum().groupby(level=[0]).cumsum().groupby('Date').tail(1)
data['Floating_Total'] = data.groupby('Date')['Floating_Total'].bfill()

data['Closed_Total'] = data.groupby(by=['Date','Symbol'])['Closed_P/L'].sum().groupby(level=[0]).cumsum().groupby('Date').tail(1).cumsum()
data['Closed_Total'] = data.groupby('Date')['Closed_Total'].bfill()

data['Closed_Balance'] = starting_capital + data['Closed_Total'] - data['Total_Open_Value']

data['Equity'] = data['Closed_Balance'] + data['Floating_Total'] + data['Total_Open_Value']

Моя проблемачто таким образом starting_capital является постоянным числом (средняя секция кода, первая строка кода), и я хочу вычислить значение столбца Share для данного Date на основе предыдущего Date * Equityи Closed_Balance.Я попытался переназначить новое содержимое для соответствующих переменных, которые используются для вычисления Shares, в конце кода следующим образом:

risk_base = data.groupby('Date')['Equity'].tail(1).shift(1)
trade_base = data.groupby('Date')['Closed_Balance'].tail(1).shift(1)

, но это не приводит к динамическому изменению столбца Sharesценности.Мне бы хотелось, чтобы столбец Shares знал, что из второго индекса Date он должен рассчитываться с предыдущими значениями Date Equity и Closed_Balance.По первому индексу Date он должен вычисляться с переменной starting_capital, которая является начальным значением для Equity и Closed_Balance.Как я могу сделать эту работу?Я знаю, что Equity / Closed_Balance рассчитывается на основе Shares, а Shares рассчитывается на основе Equity / Closed_Balance, но последний должен сдвинуть на один Date индекс «вверх» в Equity / Closed_Balance, и они также имеют начальные значения.Так что логика должна быть в порядке, не так ли?Я застрял в этом вопросе на несколько дней, было бы здорово, если бы кто-то мог помочь.Спасибо!

...