Overall Statistics
Total Trades
1330
Average Win
0.76%
Average Loss
-0.54%
Compounding Annual Return
11.806%
Drawdown
12.100%
Expectancy
0.443
Net Profit
376.303%
Sharpe Ratio
1.023
Probabilistic Sharpe Ratio
46.982%
Loss Rate
40%
Win Rate
60%
Profit-Loss Ratio
1.41
Alpha
0.069
Beta
0.171
Annual Standard Deviation
0.082
Annual Variance
0.007
Information Ratio
-0.033
Tracking Error
0.159
Treynor Ratio
0.49
Total Fees
$0.00
Estimated Strategy Capacity
$670000.00
Lowest Capacity Asset
VNQ T2FCD04TATET
import numpy as np
import pandas as pd
import random
import math

class CasualRedOrangeJackal(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2008, 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.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