Back

Best Practice: writing a helper class (asking for library changes or sticking to a work-around)

I’d like to write a helper class where I can stash routine operations that I want to do on every backtest.

E.g., I'm always going to want to stash the stock symbol, the test start-end dates, the account cash, etc. I want to do them early in my program, make it easy to go back and change them when re-running the test, and I need storage for them. So helper class that stores them off would be a win.

My original thought was to derive from QCAlgorithm, create a Helper class with properties/methods there, and then derive from the Helper and call Initialize in the Helper-derivative. The compiler is fine with this.

But: the backtest engine says,

"Backtest Error: Could not create instance of QCAlgorithm class. Ensure there is one class inheriting from QCAlgorithm and it overrides Initialize()”

It's worth asking: is there a security reason why we can't derive from QCAlgorithm, or was (understandable) a simple way to implement Lean?

And if the designers let us do so: how would the engine know which QCAlgorithm-derivative to instantiate? Technically there are 2: my helper class, and the class derived from it.

1. the engine could look for the QCAlgorithm-derivative that calls Initialize (but what if the Helper needs to do same?)

2. The engine could look for the QCAlgorithm-derivative that has a specific attribute on it (a common means of adding to the metadata in .NET classes). It'd be easy for the engine to scan the assembly, find all the classes with a custom attribute (e.g., [BackTest]) on it, generate an error if other than one, and continue if just one.

But both of these imply changes to the BackTest engine.

In the meantime: I could sidestep the issue, instead re-design my helper to be instantiated internally by the QCAlgorithm-derivative. It lacks elegance but it would let me solve the problem. Advantage: I can do this myself, without requesting a change to the engine.

Backtest team: any thoughts on the suggestion above, to let us create multiple QCAlgorithm-derivatives in a single backtest program?

 

Update Backtest








A couple of ways that I've solved this (and I would appreciate feedback from the community on this)

1) Make 2 files with a partial class like:

public partial class CoveredCallStrategy : QCAlgorithm

2) Make a new class that is not derived form QCAlgorithm then pass the instance of QCAlgorithm to it:
 


public class MyStrategy : QCAlgorithm
{
private MyClass myClass;
public override void Initialize()
{
myClass = new MyClass(this);
}
}



public class MyClass{
private QCAlgorithm _algorithm;
public MyClass(QCAlgorithm algorithm)
{
_algorithm = algorithm;
}

public void ReferenceTheAlgorithm()
{
Debug("ALGORITHM STATUS "+ _algorithm.Status);
}
}

 

0

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.


Ray, agree. That's my temporary solution: inelegant, but it works. 

- Always put partial on your own classes, gives you the flexibiity of spreading the class definition across .CS files.

- create an instance of the helper in the QCAlgorithm-derivative and initialize the former in the latter's call to Initialize

- create a QCAlgorithm-derived reference field in the helper and initialize it in the helper's constructor.

And it just occurred to me, part of this can be even better solved using Generics. I'll work that up and re-post. And there might be an opportunity to "add" to QCAlgorithm using extension methods.

0

Another option (my favorite) could be to create a QCAlgorithm-derived class, with your custom fields, methods and properties, then derive your algorithm class from it.

 

public class MyBaseAlgorithm : QCAlgorithm
{
// my custom properties and methods...
}

public class MyRealAlgorithm : MyBaseAlgorithm
{
}

 

0

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.


Stefano, that was my original plan and intent - but as I found (and you should try this yourself), deriving from QCAlgrorithm will compile, but LEAN will get confused as to which QCAlgorithm to instantiate. (Strictly speaking, both MyBaseAlgorithm and MyRealAlgorithm are QCAlgorithm-derivatives). 

Run it and you'll get:

"Backtest Error: Could not create instance of QCAlgorithm class. Ensure there is one class inheriting from QCAlgorithm and it overrides Initialize()”

My recommendation to the team is to let us create multiple derivatives of QCAlgorithm, but have a means of designating which one is the one LEAN should instantiate. E.g., using a .NET attribute, e.g.:

[LEAN]

public class MyRealAlgorithm...{...}

And then have the build engine barf if it can't find one or it finds more than one.

(It's the singleton design pattern, which I call the "Highlander Rule": there can be only one.)

 

0

Richard, sorry I forgot to mark the class abstract, so LEAN will not try have two concrete classes to choose from:
 

public abstract class MyBaseAlgorithm : QCAlgorithm
{
}

 

3

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.


Perfect. I didn't think to use abstract, but that's true: ya' can't instantiate an abstract class. 

0

// declaration
public abstract partial class QcHelper : QCAlgorithm
{
public DateTime TestStart { get; protected set;}
public DateTime TestEnd { get; protected set;}
public decimal Cash { get; protected set; }
public string Symbol { get; protected set; }
public Slice LastSlice { get; set; }
public bool DebugLogging { get; set;}
}

// usage:
public partial class MyAlgorithm : QcHelper
{
public override void Initialize()
{
this.TestStart = new DateTime(2009,3,6);
this.TestEnd = DateTime.Today;
this.Cash = 100000;
this.Symbol = "SPY";
...
}
}

This is an example of what I came up with. Cleans up Initialize, makes it more table-driven and easier to update from test-to-test. And all new algorithms derive from QcHelper so I don't have to add those items to the derived class.

Many thanks to Stefano re "abstract".

2

Update Backtest





0

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.


Loading...

This discussion is closed