Advertisement
Al3XS0n

task_3_v2

May 10th, 2024
686
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.82 KB | None | 0 0
  1. import pandas as pd
  2. import numpy as np
  3. import cvxpy as cvx
  4.  
  5.  
  6. RISK_FREE_RATE = 0.035 # безрисковая процентная ставка
  7. RISK_FREE_RATE_MONTH = 0.035 / 12. # безрисковая процентная ставка(в месяц)
  8. MAXIMAL_VOLATILITY = .02
  9.  
  10. def filter_days(df: pd.DataFrame, timegate: str = '2023-01-01') -> tuple[pd.DataFrame, pd.DataFrame]:
  11.     """ Удаляем выходные дни
  12.  
  13.    :param df: Датафрейм со столбцом Date
  14.    
  15.    :returns: Отфильтрованный DataFrame
  16.    """
  17.     mask = np.is_busday(df['Date'].to_numpy().tolist(), weekmask='1111100')
  18.     df = df[mask]
  19.     return df[df['Date'] < timegate], df[df['Date'] >= timegate]
  20.  
  21.  
  22. def prepare_data(df: pd.DataFrame) -> np.ndarray:
  23.     """ Получаем все необходимые данные из DataFram'а
  24.  
  25.    :param df: DataFrame c данными
  26.    """
  27.     returns = []
  28.  
  29.     cur_month = ''
  30.     begin_pr = -1
  31.     prev = None
  32.     # YYYY-MM-DD
  33.     # 0123456789
  34.     for row in df.iterrows():
  35.         data = row[1]
  36.         if data['Date'][5:7] != cur_month or cur_month == '':
  37.             if cur_month != '':
  38.                 returns.append((prev['Close'] - begin_pr) / begin_pr)
  39.             cur_month = data['Date'][5:7]
  40.             begin_pr = data['Close']
  41.         prev = data
  42.  
  43.     returns.append((df.iloc[-1]['Close'] - begin_pr) / begin_pr)
  44.  
  45.     return np.array(returns)
  46.  
  47.  
  48. def sample_var(data: np.array, percentile: float) -> np.float64:
  49.     """ Получение VaR по выборке по формуле Var(X) = -X_(percentile * n).
  50.    Где n длинна выборки
  51.  
  52.    :param data: выборка
  53.    :param percentile: персентиль VaR'а
  54.  
  55.    :returns: VaR соответсвтующего персентиля
  56.    """
  57.     return -np.sort(data)[int(percentile * len(data))]
  58.  
  59.  
  60. def gaussian_var(data: np.array, percentile: float) -> np.float64:
  61.     """ Получение VaR в предположении гаусовости.
  62.    Формула VaR = -(a + s * q). Где
  63.    - a - оцененное среднее
  64.    - s - оцененная дисперсия
  65.    - q - минус квантиль нужного персентиля Гаусовского распределения
  66.  
  67.    :param data: выборка
  68.    :param percentile: персентиль VaR'а
  69.  
  70.    :returns: VaR соответсвтующего персентиля
  71.    """
  72.  
  73.     mean = np.mean(data)
  74.     std_dev = np.std(data)
  75.     return -mean + 1.65 * std_dev  # 1.65 - квантиль нормального распределения для 5%
  76.  
  77. def rf_weight(weights: np.ndarray | cvx.Variable) -> float:
  78.     return 1 - np.sum(weights) if isinstance(weights, np.ndarray) else cvx.sum(weights)
  79.  
  80. def calc_portfolio(weights: np.ndarray, expectaion: float) -> float:
  81.     return weights.T @ expectaion + rf_weight(weights) * RISK_FREE_RATE_MONTH
  82.  
  83. def backtest(var: float, test_sample: np.ndarray, step: int=5) -> None:
  84.     data = prepare_data(test_sample, step)
  85.     exception_count = np.sum(data < -var)
  86.     exception_freq = exception_count / len(data)
  87.     print(f"Количество исключений {exception_count} из {len(data)}")
  88.     print(f"Исключения в процентах {exception_freq * 100}%")
  89.  
  90.  
  91.  
  92. print(f"{'Читаем данные и объединяем':-^40}")
  93. df_1 = pd.read_csv('AAPL.csv')
  94. df_1['Close_AAPL'] = df_1.Close
  95. df_2 = pd.read_csv('AMZN.csv')
  96. df_2['Close_AMZN'] = df_2.Close
  97. df_3 = pd.read_csv('IBM.csv')
  98. df_3['Close_IBM'] = df_2.Close
  99. df = df_1.merge(df_2.merge(df_3, on='Date', how='inner'), on='Date', how='inner')[['Date', 'Close_AAPL', 'Close_AMZN', 'Close_IBM']]
  100. print(df_1.head(5))
  101. print(df_2.head(5))
  102. print(df_3.head(5))
  103. print(f"{'Итоговый':-^40}")
  104. print(df.head(5))
  105. print(f"{'Done':-^40}")
  106.  
  107. # Удаляем выходные дни
  108. print(f"{'Удаляем выходные дни':-^40}")
  109. train_df, test_df = filter_days(df)
  110. print(train_df.head(5))
  111. print(test_df.head(5))
  112. print(f"{'Done':-^40}")
  113.  
  114.  
  115. # Подготавливаем данные
  116. print(f"{'Считаем месячные доходности акций':-^40}")
  117. tmp1, tmp2, tmp3 = \
  118.     train_df[['Date', 'Close_AAPL', 'Close_AMZN', 'Close_IBM']], \
  119.     train_df[['Date', 'Close_AAPL', 'Close_AMZN', 'Close_IBM']], \
  120.     train_df[['Date', 'Close_AAPL', 'Close_AMZN', 'Close_IBM']]
  121.  
  122. tmp1['Close'] = tmp1['Close_AAPL']
  123. tmp1 = tmp1[['Date', 'Close']]
  124.  
  125. tmp2['Close'] = tmp2['Close_AMZN']
  126. tmp2 = tmp2[['Date', 'Close']]
  127.  
  128. tmp3['Close'] = tmp3['Close_IBM']
  129. tmp3 = tmp3[['Date', 'Close']]
  130.  
  131.  
  132. data_1 = prepare_data(tmp1)
  133. data_2 = prepare_data(tmp2)
  134. data_3 = prepare_data(tmp3)
  135.  
  136. print(data_1[:5])
  137. print(data_2[:5])
  138. print(data_3[:5])
  139. print(f"{'Done':-^40}")
  140.  
  141.  
  142. # CAPM
  143. print(f"{'CAPM':-^40}")
  144. train_data = np.array([data_1, data_2, data_3])
  145.  
  146. expected_returns = train_data.mean(axis=1)
  147. covariance_returns = np.cov(train_data)
  148. print(f"Среднее : {expected_returns}")
  149. print(f"Матрица ковариаций : {covariance_returns}")
  150.  
  151.  
  152. optimal_weights = cvx.Variable(3)
  153. portfolio_return = calc_portfolio(optimal_weights, expected_returns)
  154. portfolio_variance = optimal_weights.T @ covariance_returns @ optimal_weights
  155. optim_task = cvx.Maximize(portfolio_return)
  156. constraints = [
  157.     portfolio_variance <= MAXIMAL_VOLATILITY ** 2,
  158. ]
  159.  
  160. problem = cvx.Problem(optim_task, constraints)
  161. problem.solve()
  162. print(f"Оптимальные веса(Выпуклая оптимизация): {optimal_weights.value}")
  163. print(f"{'Done':-^40}")
  164.  
  165.  
  166. print(f"{'Результат':-^40}")
  167. print(f"Норма доходности: { portfolio_return.value * 100 }%")
  168. print(f"Веса вкладов")
  169. print(f"\tAAPL: {optimal_weights.value[0]}")
  170. print(f"\tAMZN: {optimal_weights.value[1]}")
  171. print(f"\tIBM: {optimal_weights.value[2]}")
  172. print(f"\tБезрисковый: {rf_weight(optimal_weights.value)}")
  173. print(f"{'Done':-^40}")
  174.  
  175.  
  176. print(f"{'Бектестинг':-^40}")
  177. tmp1, tmp2, tmp3 = \
  178.     test_df[['Date', 'Close_AAPL', 'Close_AMZN', 'Close_IBM']], \
  179.     test_df[['Date', 'Close_AAPL', 'Close_AMZN', 'Close_IBM']], \
  180.     test_df[['Date', 'Close_AAPL', 'Close_AMZN', 'Close_IBM']]
  181.  
  182. tmp1['Close'] = tmp1['Close_AAPL']
  183. tmp1 = tmp1[['Date', 'Close']]
  184.  
  185. tmp2['Close'] = tmp2['Close_AMZN']
  186. tmp2 = tmp2[['Date', 'Close']]
  187.  
  188. tmp3['Close'] = tmp3['Close_IBM']
  189. tmp3 = tmp3[['Date', 'Close']]
  190. test_data = np.array([data_1, data_2, data_3])
  191.  
  192. test_return_ratio = calc_portfolio(optimal_weights.value, test_data.mean(axis=1))
  193. std = optimal_weights.value.T @ np.cov(test_data) @ optimal_weights.value
  194. sharp_ratio = (test_return_ratio -  RISK_FREE_RATE_MONTH) / np.sqrt(std)
  195. print(f"Ожидаемая норма доходности: { test_return_ratio * 100 }%")
  196. print(f"Sharpratio: {sharp_ratio}")
  197.  
  198. print(f"{'Done':-^40}")
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement