Advertisement
coloriot

for_fedor

Apr 23rd, 2025
25
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.11 KB | None | 0 0
  1. def analyze_portfolio_mamba_backtest(df, window_years=5, test_years=1, n_portfolios=10):
  2.     """
  3.    Perform a MAMBA backtest to generate multiple portfolios.
  4.    This function creates N equally spaced rolling windows for training/testing,
  5.    fits MAMBA models, and computes portfolio returns.
  6.    """
  7.     import pandas as pd
  8.     import numpy as np
  9.     import torch
  10.     from torch import nn, optim
  11.     from sklearn.preprocessing import StandardScaler
  12.  
  13.     independent_vars = ["MARKET_RETURN_ADJ", "SMB", "HML", "MOM",
  14.                         'MARKET_RETURN_ADJ_lag1', 'SMB_lag1', 'HML_lag1', 'MOM_lag1',
  15.                         'MARKET_RETURN_ADJ_lag2', 'SMB_lag2', 'HML_lag2', 'MOM_lag2',
  16.                         'MARKET_RETURN_ADJ_rollmean_3', 'MARKET_RETURN_ADJ_rollstd_3',
  17.                         'SMB_rollmean_3', 'SMB_rollstd_3', 'HML_rollmean_3', 'HML_rollstd_3',
  18.                         'MOM_rollmean_3', 'MOM_rollstd_3', 'MARKET_RETURN_ADJ_rollmean_6',
  19.                         'MARKET_RETURN_ADJ_rollstd_6', 'SMB_rollmean_6', 'SMB_rollstd_6',
  20.                         'HML_rollmean_6', 'HML_rollstd_6', 'MOM_rollmean_6', 'MOM_rollstd_6',
  21.                         'MARKET_RETURN_ADJ_x_SMB', 'MARKET_RETURN_ADJ_x_HML',
  22.                         'MARKET_RETURN_ADJ_x_MOM', 'SMB_x_HML', 'SMB_x_MOM', 'HML_x_MOM',
  23.                         'MARKET_RETURN_ADJ_squared', 'MARKET_RETURN_ADJ_cubed',
  24.                         'SMB_squared', 'SMB_cubed', 'HML_squared', 'HML_cubed',
  25.                         'MOM_squared', 'MOM_cubed', 'Month_sin', 'Month_cos', 'Quarter_sin', 'Quarter_cos']
  26.  
  27.     exclude = set(independent_vars + ["TRADEDATE", 'Year', 'Month', 'Quarter'])
  28.  
  29.     df = df.copy()
  30.     df['TRADEDATE'] = pd.to_datetime(df['TRADEDATE'])
  31.     df = df.sort_values('TRADEDATE')
  32.  
  33.     tradedates = df['TRADEDATE'].drop_duplicates().sort_values().tolist()
  34.     window_months = window_years * 12
  35.     test_months = test_years * 12
  36.     total_months = window_months + test_months
  37.  
  38.     max_possible_starts = len(tradedates) - total_months + 1
  39.     step = max_possible_starts // n_portfolios
  40.  
  41.     results = []
  42.  
  43.     for i in range(0, max_possible_starts, step):
  44.         if len(results) >= n_portfolios:
  45.             break
  46.  
  47.         train_start = tradedates[i]
  48.         train_end = tradedates[i + window_months - 1]
  49.         test_start = tradedates[i + window_months]
  50.         test_end = tradedates[i + window_months + test_months - 1]
  51.  
  52.         train_df = df[(df['TRADEDATE'] >= train_start) & (df['TRADEDATE'] <= train_end)]
  53.         test_df = df[(df['TRADEDATE'] >= test_start) & (df['TRADEDATE'] <= test_end)]
  54.  
  55.         target_cols = [col for col in df.columns if col not in exclude]
  56.         expected_returns = {}
  57.         trained_models = {}
  58.  
  59.         for target in target_cols:
  60.             df_temp = pd.concat([train_df[independent_vars], train_df[target]], axis=1).dropna()
  61.             if df_temp.empty:
  62.                 continue
  63.  
  64.             X = df_temp[independent_vars]
  65.             y = df_temp[target]
  66.  
  67.             scaler = StandardScaler()
  68.             X_scaled = scaler.fit_transform(X)
  69.             X_tensor = torch.tensor(X_scaled, dtype=torch.float32, device=device).unsqueeze(1)
  70.             y_tensor = torch.tensor(y.values.reshape(-1, 1), dtype=torch.float32, device=device)
  71.  
  72.             model = MambaTabularModel(input_dim=X_tensor.shape[-1]).to(device)
  73.             if hasattr(torch, "compile") and device.type != "mps":
  74.                 model = torch.compile(model)
  75.  
  76.             optimizer = optim.Adam(model.parameters(), lr=0.05)
  77.             loss_fn = nn.MSELoss()
  78.  
  79.             for _ in range(50):
  80.                 model.train()
  81.                 optimizer.zero_grad()
  82.                 output = model(X_tensor).mean(dim=1)
  83.                 loss = loss_fn(output, y_tensor)
  84.                 loss.backward()
  85.                 optimizer.step()
  86.  
  87.             model.eval()
  88.             with torch.no_grad():
  89.                 predictions = model(X_tensor).cpu().numpy()
  90.             expected_returns[target] = predictions.mean()
  91.             trained_models[target] = model
  92.  
  93.         if not expected_returns:
  94.             continue
  95.  
  96.         all_stocks = list(expected_returns.keys())
  97.         mu = np.array([expected_returns[s] for s in all_stocks])
  98.         train_returns_df = train_df[all_stocks].dropna()
  99.         cov_matrix = train_returns_df.cov().values
  100.  
  101.         optimal_weights = optimize_portfolio(mu, cov_matrix)
  102.  
  103.         test_returns_df = test_df[all_stocks].dropna()
  104.         if test_returns_df.empty:
  105.             continue
  106.  
  107.         portfolio_returns = backtest_portfolio(test_returns_df, optimal_weights, all_stocks)
  108.         portfolio_beta = 1.0
  109.         risk_metrics = compute_risk_metrics(portfolio_returns, portfolio_beta)
  110.  
  111.         result_row = {
  112.             'Train Start': train_start,
  113.             'Train End': train_end,
  114.             'Test Start': test_start,
  115.             'Test End': test_end,
  116.         }
  117.         result_row.update(risk_metrics)
  118.  
  119.         for stock, weight in zip(all_stocks, optimal_weights):
  120.             result_row[f'Weight_{stock}'] = weight
  121.  
  122.         results.append(result_row)
  123.  
  124.     return pd.DataFrame(results)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement