Al3XS0n

task_5

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