Feature: Child Algorithms

This post is irrelevant to the v2 engine. See our post regarding TuringTrader 16 to learn more about what changed and why.



One of TuringTrader's main goals is to simplify the development of quant strategies. Unfortunately, our subclassable algorithms weren't as usable as we hoped they would be. We therefore further refined the concept, and released a new feature: child algorithms. With these child algorithms it is simpler than ever to develop meta-strategies with TuringTrader.

Why do we need child algorithms?

In many cases, quant strategies form a hierarchy. The most natural way to implement such a hierarchy is to launch one or more child algorithms from a parent algorithm. If you feel that this is too abstract, here are some tangible use cases:

  • implement portfolios of portfolios: in addition to diversification across asset classes, we might want to add diversification across strategies. For example, we could combine a momentum strategy with a mean-reversion strategy. The two strategies are probably only loosely correlated, leading to improved risk-adjusted returns.
  • implement complex data sources: for complex data sources, it is often most useful to implement these as an algorithm. For example, we could create a data source to provide the total return of a bond, based on the daily yield.

Coding with child algorithms

Until now, the entry point to TuringTrader's algorithms always had the following simple signature:

public class MyAlgorithm : Algorithm
{
    public override void Run() 
    {
        // your code here
    }
    ...
}

Most algorithms will still use this signature. However, instead of the convoluted SubclassableAlgorithm, we implemented a more natural way of letting an algorithm create bars for a parent algorithm:

public class MyChildAlgorithm : Algorithm
{
    public override IEnumerable<Bar> Run(DateTime? startTime, DateTime? endTime)
    {
        StartTime = startTime ?? ...
        EndTime = endTime ?? ...
        ...
        var bar = new Bar(); 
        ...
        yield return bar;
        ...
    }

}

A parent algorithm can use these childs in the same way as any other data source:

public class MyParentAlgorithm : Algorithm
{
    public override void Run() 
    {
        ...
        var ds = AddDataSource("algorithm:MyChildAlgorithm");
        ...
    }
    ...
}

This works very well, when the child algorithm is publicly available. If it is not, we can instantiate a data source for the child as follows:

public class MyParentAlgorithm : Algorithm
{
    private class MyChildAlgorithm : Algorithm
    {
        ...
    }
    public override void Run() 
    {
        ...
        var child = new MyChildAlgorithm();
        var ds = DataSource.New(child);
        AddDataSource(ds);
        ...
    }
    ...
}

TuringTrader typically evaluates data sources before running the algorithm that uses them. While this works very well for historical quotes, it might not be what we want when dealing with child algorithms.

If we want to run the child algorithms in sync with the parent algorithm, we can do so as well:

public class MyParentAlgorithm : Algorithm
{
    private class MyChildAlgorithm : Algorithm
    {
        ...
    }
    public override void Run() 
    {
        ...
        var child = new MyChildAlgorithm();
        var ds = AddChildAlgorithm(child);
        ...
    }
    ...
}

If we instantiate our child algorithm like this, the child's NetAssetValue is included in the parent's calculation of NetAssetValue. To allocate some or all of the parent's capital to a child algorithm, we can use SetAllocation. This method basically performs matching [Deposit]s and [Withdrawal]s to transfer cash between the parent and its childs.

To illustrate this further, we added a new demo code here.

Happy coding!