QuantConnect Research

repository·master·Indexed 21 days ago

https://github.com/quantconnect/research

A collection of Jupyter notebooks and tutorials demonstrating quantitative financial analysis and strategy development using the QuantConnect LEAN platform. The repository includes the Research 2 Production series covering Mean Reversion, Random Forest Regression, Kalman Filters, and LSTM, as well as analysis examples for Fundamental Factor Analysis, Mean-Variance Portfolio Optimization, and Pairs Trading. It provides guidance on using QuantBook for data acquisition via GetFundamental() and History(), as well as generating indicators and portfolio statistics.

Tokens
27.1K
Snippets
73
Records
81
Agent score
74%

What's inside quantconnect-research

  1. Explore QuantConnect Research notebooks and tutorials

    master

    This repository contains a collection of Jupyter notebooks and tutorials designed to demonstrate research methodologies using the QuantConnect LEAN platform. It is organized into several categories to help developers transition from theoretical research to production-ready trading strategies:

    • Topical Events: Analysis of specific market movements and historical events.
    • Idea Streams PodCast: Video-based deep dives into specific quantitative topics (e.g., Tail Risk Hedging, Nowcasting).
    • Research 2 Production Notebook Series: A structured series of notebooks designed to guide you through the workflow of developing a research idea and preparing it for production implementation. Topics include Mean Reversion, Random Forest Regression, Kalman Filters, and LSTM.
    • Analysis Examples: Concrete implementations of quantitative techniques such as Fundamental Factor Analysis, Mean-Variance Portfolio Optimization, and Pairs Trading.
  2. Install and use Inter fonts

    master

    To use the Inter font family, follow these steps:

    1. Install the font files: Choose between the single variable font file or the individual static font files depending on your application's support.
    2. Select styles: Use your application's font picker to view the Inter font family and select from the available styles.

    Variable Font Option (Recommended for apps with full variable font support):

    • Use Inter-VariableFont_slnt,wght.ttf. This single file contains all styles by adjusting the slnt (slant) and wght (weight) axes.

    Static Font Option (Use if your app does not support variable fonts):

    • Use the individual files located in the static/ directory, such as Inter-Regular.ttf, Inter-Bold.ttf, etc.
  3. Learn quantitative techniques via Analysis Examples

    master

    The Analysis Examples directory contains notebooks that demonstrate specific quantitative finance concepts and their implementation in Python using LEAN data:

    • Fundamental Factor Analysis: Uses MorningStar fundamental data to demonstrate factor selection for long/short strategies.
    • Kalman Filter Based Pairs Trading: Introduces cointegration and the application of Kalman Filters for pairs trading.
    • Mean-Variance Portfolio Optimization: Demonstrates modern portfolio theory and finding the efficient frontier.
    • EMA Cross Strategy Based on VXX: Shows how to build an Exponential Moving Average (EMA) cross strategy and extract performance statistics.
    • Pairs Trading Strategy Based on Cointegration: A step-by-step guide through the development and backtesting of a cointegration-based pairs trading strategy.
  4. Use the Research 2 Production Notebook Series

    master

    The Research 2 Production series provides a step-by-step workflow for developing quantitative strategies. Use these notebooks to learn how to apply specific mathematical and machine learning models within the LEAN ecosystem.

    Available modules include:

    • 01 Mean Reversion.ipynb
    • 02 Random Forest Regression.ipynb
    • 03 Uncorrelated Assets.ipynb
    • 04 Kalman Filters and Pairs Trading.ipynb
    • 05 Stationary Processes and Z-Scores.ipynb
    • 06 Principal Component Analysis.ipynb
    • 07 Hidden Markov Models.ipynb
    • 08 Long Short-Term Memory.ipynb
  5. What are Hidden Markov Models (HMM) and how are they used in trading?

    master

    A Hidden Markov Model (HMM) is a stochastic process where the system is modeled as a Markov process, but the states are unobserved (hidden). In trading, HMMs are used for regime detection—identifying whether the market is in a specific state (e.g., a 'Bull' or 'Bear' market) based on observable data like price returns.

    Key aspects of HMMs include:

    • Prediction: Forecasting future values of the process.
    • Filtering: Estimating the current state of the model.
    • Smoothing: Estimating past states of the model.

    In the provided research example, a Gaussian, two-state HMM is fitted to historical returns to predict market regimes.

  6. Perform Mean-Variance Portfolio Optimization

    master

    The PortfolioOptimization class implements mean-variance optimization to find efficient asset allocations. It uses log returns to calculate annual returns and volatility, and employs scipy.optimize.minimize to find optimal weights.

    Key Methods:

    • opt_portfolio(): Maximizes the Sharpe ratio to find the optimal weights, return, and volatility.
    • min_var_portfolio(): Finds the portfolio with the minimum possible volatility.
    • efficient_frontier(mc_returns): Calculates the efficient frontier based on a range of target returns.
    • mc_mean_var(): Uses Monte Carlo simulation to generate a feasible region of possible returns and volatilities.
    • plot(): Visualizes the Monte Carlo simulation, the efficient frontier, the optimal portfolio, the minimum volatility portfolio, and the Capital Market Line (CML).
    # Assuming log_return is a pandas DataFrame of log returns
    # and risk_free_rate is a float
    a = PortfolioOptimization(log_return, risk_free_rate=0, num_assets=len(symbols))
    
    # Get optimal weights, return, and volatility
    opt_weights, opt_return, opt_volatility = a.opt_portfolio()
    
    # Visualize results
    a.plot()
  7. Use Principal Component Analysis (PCA) to mitigate multicollinearity

    master

    In regression models, multicollinearity occurs when independent variables are highly correlated, making it difficult for the model to distinguish their individual effects. Principal Component Analysis (PCA) solves this by mapping the dataset into a new space of linearly-independent, orthogonal vectors (principal components).

    Using PCA provides two main benefits:

    1. Eliminates Multicollinearity: The new dimensions are orthogonal.
    2. Dimensionality Reduction: You can identify and keep only the components that contribute most to the variance, reducing the number of input variables.

    To use PCA with a variance threshold, initialize sklearn.decomposition.PCA with a float between 0 and 1 for n_components. This tells PCA to select the number of components required to explain that percentage of the variance.

    from sklearn.decomposition import PCA
    
    # Initialize PCA to explain 95% of the variance
    pca = PCA(n_components=0.95)
    
    # Fit the model to your training data
    pca.fit(training)
    
    print(f'PCA No. Components: {pca.n_components_}')
  8. Prepare financial data for machine learning training

    master

    To train a machine learning model on time-series financial data, you should transform raw OHLCV data into stationary features (like percentage changes) and create sliding window sequences.

    Use a function similar to prep_data to:

    1. Calculate percentage changes (pct_change()) to normalize the data.
    2. Handle infinities and NaNs using pd.option_context('mode.use_inf_as_na', True).
    3. Create a feature set where each sample consists of n_tsteps previous time steps to predict the target value at t + 1.
    def prep_data(data, n_tsteps=5):
        # Normalize data using percentage change
        df = data.pct_change()
    
        # Drop NaNs and infinities
        with pd.option_context('mode.use_inf_as_na', True):
            df = df.dropna()
    
        features = []
        labels = []
    
        for i in range(len(df)-n_tsteps):
            # Flatten the window of n_tsteps into a single feature vector
            input_data = df.iloc[i:i+n_tsteps].values.flatten()
            features.append(input_data)
            # Target is the 'close' price at the next time step
            label = df['close'].iloc[i+n_tsteps]
            labels.append(label)
    
        return np.array(features), np.array(labels)
  9. Gather historical data using QuantBook

    master

    Use QuantBook to retrieve historical price data for a security. The History method allows you to request data for specific securities over a specified number of bars and resolution.

    qb = QuantBook()
    spy = qb.AddEquity('SPY')
    # Request 360 daily bars for the security
    history = qb.History(qb.Securities.Keys, 360, Resolution.Daily)
    spy_hist = history.loc['SPY']
  10. Perform Fundamental Factor Analysis

    master

    This guide outlines a workflow for testing the significance of fundamental factors (like PE Ratio or Book Value Yield) in explaining stock returns:

    1. Universe Selection: Choose a basket of symbols (e.g., top stocks by dollar volume).
    2. Data Acquisition:
      • Fetch fundamental data using GetFundamental.
      • Clean data: Fill NaNs with forward-fill (ffill), drop remaining NaNs, and transpose to have symbols as rows and dates as columns.
      • Filter for the last day of each month to align with monthly return calculations.
    3. Price History: Fetch historical close prices for the selected symbols and a benchmark (e.g., SPY).
    4. Portfolio Construction:
      • At the start of each month, rank stocks by the chosen factor.
      • Divide ranked stocks into $N$ portfolios (e.g., 5 portfolios).
      • Calculate the average monthly return for each portfolio.
    5. Significance Testing: Evaluate the factor using:
      • Correlation: The correlation between portfolio returns and their rank.
      • Win/Loss Probability: The probability that the 'winning' portfolio (top rank) outperforms the benchmark and the 'loss' portfolio (bottom rank) underperforms it.
      • Excess Return: The difference between the portfolio's annual return and the benchmark's annual return.
  11. Identify uncorrelated assets for portfolio diversification

    master

    To build a more resilient portfolio and limit drawdown, you can identify assets that have the lowest average absolute correlation with the rest of a selected group. This is achieved by calculating a correlation matrix from historical returns and ranking assets based on their mean absolute correlation scaled by their standard deviation (row.abs().mean() / row.abs().std()).

    Follow these steps:

    1. Fetch historical data for a list of tickers using QuantBook.
    2. Calculate hourly (or other resolution) returns using .pct_change().
    3. Pass the returns DataFrame to a ranking function to select the top num_assets with the lowest correlation scores.
    # Define the ranking function
    def GetUncorrelatedAssets(returns, num_assets):
        # Get correlation matrix
        correlation = returns.corr()
    
        # Find assets with lowest mean correlation, scaled by STD
        selected = []
        for index, row in correlation.iteritems():
            corr_rank = row.abs().mean()/row.abs().std()
            selected.append((index, corr_rank))
    
        # Sort and take the top num_assets
        selected = sorted(selected, key = lambda x: x[1])[:num_assets]
        return selected
    
    # Setup QuantBook and fetch data
    qb = QuantBook()
    tickers = ["SQQQ", "TQQQ", "TVIX", "VIXY", "SPLV", "SVXY", "UVXY", "EEMV", "EFAV", "USMV"]
    symbols = [qb.AddEquity(x, Resolution.Minute) for x in tickers]
    
    # Fetch history and calculate returns
    history = qb.History(qb.Securities.Keys, 150, Resolution.Hour)
    returns = history.unstack(level = 1).close.transpose().pct_change().dropna()
    
    # Get 5 assets with least overall correlation
    selected = GetUncorrelatedAssets(returns, 5)
    print(selected)