Overall Statistics
Total Trades
4245
Average Win
0.07%
Average Loss
-0.03%
Compounding Annual Return
0.778%
Drawdown
21.800%
Expectancy
0.031
Net Profit
1.456%
Sharpe Ratio
0.113
Probabilistic Sharpe Ratio
9.028%
Loss Rate
68%
Win Rate
32%
Profit-Loss Ratio
2.18
Alpha
0.011
Beta
0.019
Annual Standard Deviation
0.109
Annual Variance
0.012
Information Ratio
-0.436
Tracking Error
0.174
Treynor Ratio
0.629
Total Fees
$26540.19
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Data.Custom.USTreasury import *

import numpy as np
import statsmodels.api as sm
from sklearn.decomposition import PCA
from sklearn.ensemble import RandomForestRegressor
from sklearn.linear_model import Ridge, LinearRegression
from sklearn.model_selection import cross_val_score, GridSearchCV

# Import our custom functions
from RegressionFunction import FitRegressionModel

class VerticalParticleShield(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2018, 1, 1)  # Set Start Date
        self.SetCash(1000000)  # Set Strategy Cash
        
        self.SetBrokerageModel(AlphaStreamsBrokerageModel())
        
        self.SetBenchmark('SPY')
        
        self.SetExecution(ImmediateExecutionModel())

        self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())

        self.UniverseSettings.Resolution = Resolution.Minute
        self.SetUniverseSelection(LiquidETFUniverse())
        
        self.AddEquity('TLT')
        self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday), self.TimeRules.AfterMarketOpen('TLT', 5), self.RunRegression)
        
        self.yieldCurve = self.AddData(USTreasuryYieldCurveRate, "USTYCR", Resolution.Daily).Symbol
    
    def RunRegression(self):
        qb = self
        
        symbols = [x for x in LiquidETFUniverse.Treasuries]
        ids = {str(symbol.ID): symbol for symbol in LiquidETFUniverse.Treasuries}
        
        # Get history
        history = qb.History(self.yieldCurve, 100, Resolution.Daily)
        # Get prices and returns
        bonds = history.loc[self.yieldCurve].pct_change().fillna(method='ffill').fillna(method='bfill').fillna(value = 0)
        
        #### Prepare data set -- feature names, training set, and testing set
        training = bonds.iloc[:len(bonds)-1].copy()
        testing = bonds.iloc[len(bonds)-1:].copy()
        
        
        # Find number of components to explain > 95% of variance of treasury prices
        pca = PCA(n_components=0.95)

        # Fit the PCA model to our training data
        pca.fit(training)

        # Initialize the regression model selected in the research notebook
        model = RandomForestRegressor(random_state=0, n_estimators = 100)

        # Fit the regression model and return predictions
        results = FitRegressionModel(self, pca, model, training, testing)
        
        # Find out if the prediction is up or down relative to current price
        
        # Generate Insights
        insights = []
        if results.mean(axis = 1).values[0] > 0:
            insights += [Insight.Price(symbol, timedelta(days = 7), InsightDirection.Up) for symbol in LiquidETFUniverse.Treasuries.Long]
            insights += [Insight.Price(symbol, timedelta(1), InsightDirection.Flat) for symbol in LiquidETFUniverse.Treasuries.Inverse]
        else:
            insights += [Insight.Price(symbol, timedelta(1), InsightDirection.Flat) for symbol in LiquidETFUniverse.Treasuries.Long]
            insights += [Insight.Price(symbol, timedelta(days = 7), InsightDirection.Up) for symbol in LiquidETFUniverse.Treasuries.Inverse]            

        # Emit Insights
        self.EmitInsights(insights)
import numpy as np
import pandas as pd
import statsmodels.api as sm
from sklearn.decomposition import PCA
from sklearn.ensemble import RandomForestRegressor
from sklearn.linear_model import Ridge, LinearRegression
from sklearn.model_selection import cross_val_score, GridSearchCV

def FitRegressionModel(algorithm, pca, model, training, testing, alpha = False):    
    estimators = []
    y_predicted = []
    y_actual = []
    
    # Project the data onto the components
    x_projected = pca.transform(training)

    # Iterate over all principle components:
    for i in range(pca.n_components_):

        # Here, we lag X compared to Y. X will be one time period behind Y
        X = x_projected[:-1, i]
        Y = x_projected[1:, i]
        
        y_actual.append(Y)
        X = sm.add_constant(X)
        
        # Add necessaary components if using RandomForestRegressor
        if alpha:
            test_range = np.arange(10)
            param_grid = {"alpha": test_range}
            grid_search = GridSearchCV(model,param_grid)
            grid_search.fit(X, Y)
            best_params = grid_search.best_params_
        
        # Fit model and make predictions
        est = model.fit(X, Y)
        estimators.append(est)
        y_predicted.append(model.predict(X))
        algorithm.Log("Estimator {}: R2 = {:.3f}\n".format(i, model.score(X,Y)))
    
    y_predicted = np.array(y_predicted).transpose()
    y_actual = np.array(y_actual).transpose()
    
    # Transform back into original space
    y_actual_original_space = pca.inverse_transform(y_actual)
    y_predicted_original_space = pca.inverse_transform(y_predicted)

    # Compute sum of squared error:
    train_sse = np.sum((y_predicted_original_space - y_actual_original_space)** 2)
    algorithm.Log(f'Sum of squared error: {train_sse}\n')
    
    # Transform testing data
    testing_proj = pca.transform(testing)
    testing_prediction = []
    for i in range(pca.n_components_):
        # Create a data row
        row = [1, testing_proj[:,i]]
        row = np.reshape(row, (1, 2))

        # Predict this row
        p = model.predict(row)
        testing_prediction.append(p[0])
    
    # Project predictions back to original space    
    predictions = pca.inverse_transform(testing_prediction)
    actual_pred = pd.DataFrame({'Predicted':predictions}, index = testing.columns)
    return actual_pred