Overall Statistics
Total Trades
1148
Average Win
0.74%
Average Loss
-0.52%
Compounding Annual Return
11.896%
Drawdown
11.700%
Expectancy
0.476
Net Profit
287.061%
Sharpe Ratio
1.05
Probabilistic Sharpe Ratio
51.371%
Loss Rate
39%
Win Rate
61%
Profit-Loss Ratio
1.42
Alpha
0.052
Beta
0.287
Annual Standard Deviation
0.08
Annual Variance
0.006
Information Ratio
-0.226
Tracking Error
0.122
Treynor Ratio
0.294
Total Fees
$0.00
Estimated Strategy Capacity
$6900000.00
Lowest Capacity Asset
VTI S551B7YE6N39
import numpy as np
import pandas as pd
import random
import math

# hello
class CasualRedOrangeJackal(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2010, 1, 1)  # Set Start Date  
        self.SetCash(100000)  # Set Strategy Cash
        self.InitCash = 100000
        self.AddEquity("SPY", Resolution.Minute)
        self.MKT = self.AddEquity("SPY", Resolution.Daily).Symbol
        self.spy = []
        self.i = 1000
        
        self.basket = ['VTI', 'VXUS', 'VNQ', 'BND', 'GLD', 'EFA', 'TLT', 'IEF', 'QQQ']  
        
        for ticker in self.basket:        
            self.AddEquity(ticker, Resolution.Minute)
            self.Securities[ticker].FeeModel = ConstantFeeModel(0)
        
        self.Schedule.On(self.DateRules.EveryDay('SPY'), self.TimeRules.At(0, 0), Action(self.ScheduleEndOfMonthRebalance))
        self.Schedule.On(self.DateRules.EveryDay('SPY'), self.TimeRules.BeforeMarketClose('SPY', 5), Action(self.Rebalance))
        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.BeforeMarketClose('SPY', 0), self.record_vars)
    
    def record_vars(self):             
        hist = self.History(self.MKT, 2, Resolution.Daily)['close'].unstack(level= 0).dropna() 
        self.spy.append(hist[self.MKT].iloc[-1])
        spy_perf = self.spy[-1] / self.spy[0] * self.InitCash
        self.Plot('Strategy Equity', 'SPY', spy_perf)

    def ScheduleEndOfMonthRebalance(self):
        month_last_day = DateTime(self.Time.year, self.Time.month, DateTime.DaysInMonth(self.Time.year, self.Time.month))
        trading_days = self.TradingCalendar.GetDaysByType(TradingDayType.BusinessDay, self.Time, month_last_day)
        
        #get the last day in trading_days
        for x in trading_days:
            self.month_last_trading_day = x.Date.date()
    
    def Rebalance(self):
        if self.Time.date() == self.month_last_trading_day:
            dataframe = self.History(self.basket, 180, Resolution.Daily)
            df = dataframe['close'].unstack(level=0)
            self.Liquidate()
            self.Debug(self.Portfolio.Cash)
            
            self.adaptive_asset_allocation(df, 4, 20, 180, self.Portfolio.Cash, 1)
            
    def adaptive_asset_allocation(self, df, nlargest, volatility_window, return_window, portfolio_value, leverage): 
        window_returns = np.log(df.iloc[-1]) - np.log(df.iloc[0])
        nlargest = list(window_returns.nlargest(nlargest).index)
        
        returns = df[nlargest].pct_change()
        returns_cov_normalized = returns[-volatility_window:].apply(lambda x: np.log(1+x)).cov()
        returns_corr_normalized = returns[-volatility_window:].apply(lambda x: np.log(1+x)).corr()
        returns_std = returns.apply(lambda x: np.log(1+x)).std()

        port_returns = []
        port_volatility = []
        port_weights = []
    
        num_assets = len(returns.columns)
        num_portfolios = 100
        individual_rets = window_returns[nlargest]
        
        for port in range(num_portfolios): 
            weights = np.random.random(num_assets)
            weights = weights/np.sum(weights)
            port_weights.append(weights)
    
            rets = np.dot(weights, individual_rets)
            port_returns.append(rets)
    
            var = returns_cov_normalized.mul(weights, axis=0).mul(weights, axis=1).sum().sum()
            sd = np.sqrt(var)
            ann_sd = sd * np.sqrt(256)
            port_volatility.append(ann_sd)
            
        data = {'Returns': port_returns, 'Volatility': port_volatility}
        hover_data = []
        for counter, symbol in enumerate(nlargest): 
            data[symbol] = [w[counter] for w in port_weights]
            hover_data.append(symbol)
    
        portfolios_V1 = pd.DataFrame(data)
        
        min_var_portfolio = portfolios_V1.iloc[portfolios_V1['Volatility'].idxmin()]
        max_sharpe_portfolio = portfolios_V1.iloc[(portfolios_V1['Returns'] / portfolios_V1['Volatility']).idxmax()]
        proportions = min_var_portfolio[nlargest] 
        
        index = 0
        for proportion in proportions: 
            self.SetHoldings(nlargest[index], proportion * leverage)
            self.Debug('{}% of portfolio in {}'.format(proportion * leverage, nlargest[index]))
            index += 1