Hello everyone,
I am still learning to use QuantConnect and I need your help with RollingWindows. Somehow, I cannot access all datapoints in the RollingWindows created in lines 66-73 when I call them at line 106. Do you know why?
Do you know any alternative to the list with RollingWindows? I have been checking universes, but I would like to have something where I can directly enter the assets I would like to have in this case.
// https://numerics.mathdotnet.com/
// https://numerics.mathdotnet.com/DescriptiveStatistics.html
// http://www.bluebit.gr/NET/Library/topic594.html
using MathNet.Numerics;
using MathNet.Numerics.LinearAlgebra;
namespace QuantConnect.Algorithm.CSharp
{
public class BaH_Markowitz : QCAlgorithm
{
// List of assets to construct the portfolio;
public string[] assets = {"URTH","EEM"};
// Number of assets.
public int numAssets;
// Set the look back period
public int LookBackPeriods = 2;
public override void Initialize()
{
//---------------------------
//--- Backtest Paramters ---
//--------------------------
// Set start date for the backtest.
SetStartDate(2012,1,25);
// Set end date for the backtest.
SetEndDate(2012,1,30);
// Set the initial cash for the backtest.
SetCash(100000);
numAssets = assets.Length;
// Add the assets to the portfolio universe.
foreach(string asset in assets){
AddEquity(asset, Resolution.Daily);
}
/*
// Schedule rebalancing for URTH.
Schedule.On(DateRules.MonthStart("URTH"), TimeRules.AfterMarketOpen("URTH"), ()=>
{
if (!new []{5,6,7,8}.Contains(Time.Month))
{
SetHoldings("URTH", 0.7);
}
});
//Schedule rebalancing for EEM.
Schedule.On(DateRules.MonthStart("EEM"), TimeRules.AfterMarketOpen("EEM"), () =>
{
if (!new []{5,6,7,8}.Contains(Time.Month))
{
SetHoldings("EEM", 0.3);
}
});
*/
Settings.StalePriceTimeSpan = TimeSpan.FromMinutes(60);
SetWarmUp(3);
}
public override void OnData(Slice data)
{
Vector<double> weights = Vector<double>.Build.Dense(numAssets);
if(!Portfolio.Invested){
List<RollingWindow<decimal>> windows = new List<RollingWindow<decimal>>();
foreach(string asset in assets){
RollingWindow<decimal> _window = new RollingWindow<decimal>(LookBackPeriods);
Debug(asset+" added to the universe");
_window.Add(data[asset].Close);
windows.Add(_window);
}
weights = OptPFMarkowitz(assets, windows, LookBackPeriods);
Debug(weights.ToString());
for(int i=0;i<numAssets;i++){
SetHoldings(assets[i],weights[i]);
Debug("New position opened for "+assets[i]);
}
}
/*
if (new []{5,6,7,8}.Contains(Time.Month))
{
Liquidate();
return;
}
*/
}
public Vector<double> OptPFMarkowitz(string[] Securities, List<RollingWindow<decimal>> data, int Periods)
{
// Count the number of securities to have in the portfolio.
int numSec = Securities.Length;
// Create a matrix to save the close price data from the securities.
Matrix<double> closeData = Matrix<double>.Build.Dense(numSec,Periods);
// Fill the data matrix with close prices of the last Periods-points.
int k = 0;
foreach (string Security in Securities){
for (int i=0; i<Periods; i++)
{
closeData[k,i] = (double)data[k][i];
}
k++;
}
// Create a vector to save the average returns of the securities in the last Periods periods.
Vector<double> avgReturn = Vector<double>.Build.Dense(numSec);
// Create a matrix to save the covariance matrix of the securities in the last Periods periods.
Matrix<double> covMatrix = Matrix<double>.Build.Dense(numSec,numSec);
// Create a vector to save the weights to be assigned to each security in the portfolio.
Vector<double> weights = Vector<double>.Build.Dense(numSec);
// Calculate the average return of each security.
avgReturn = (1/numSec)*closeData.RowSums();
// Center the data.
for(int i=0; i<numSec;i++){
for(int j=0; j<numSec;j++){
closeData[i,k] -= avgReturn[i];
}
}
// Compute the covariance matrix.
covMatrix = (1/numSec)*(closeData*closeData.Transpose());
weights = (covMatrix.Inverse()*avgReturn).Normalize(2);
return weights;
}
}
}
Thank you very much.
Kind regards,
Francisco
Ps I don't know how to insert the algo here, since there is no backtest I can choose.
Douglas Stridsberg
You're recreating your list of rolling windows every time OnData is run, essentially clearing them every time the function is run. You should only create rolling windows (i.e. calling new RollingWindow<decimal>(LookBackPeriods)) in one place at one time, then just keep .Add()ing things to it.
Gabriel Fenger
That is a good performance improvement. Thank you very much. Nevertheless, this does not solve the runtime error I get.
Douglas Stridsberg
That isn't a "performance improvement" - it's a fix to a fatal problem in your code. If you re-create (and thus clear) your rolling windows every time you have new data, you will never be able to access the data you've .Add()ed to them; you'll only be able to access the one latest item added to them. This is how variables work in C# and most (if not all) other programming languages.
The creation of the rolling windows should be done in Initialize(). Adding entries to your rolling windows should be done in OnData().
You didn't mention a runtime error. Can you please implement the fix I've outlined and - if you're still getting an error - paste the runtime error message you're getting?
Gabriel Fenger
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!