Table of Contents

Pass variables to a money manager

Sometimes it's useful to be able to pass variables from a strategy to a money manager for use in position sizing. The backtester uses a VariableDictionary for this purpose. The VariableDictionary class implements IDictionary<string, object> so it acts like a dictionary with a string for the key. Objects can also be accessed by ordinal position in the order in which they were added.

There are two ways to pass variables from a Strategy to a MoneyManager. The first is via StrategyVariables. This property can be accessed from within a strategy to set arbitrary objects at the strategy level for later use in a money manager. The second and more common approach is to attach variables to a position when it is opened in a strategy. Let's once again revisit the SimpleSma example strategy to make these modifications. Notice in OnStrategyStart() we add "some very important info for later" to StrategyVariables. Then in OnPositionOpening(), we call position.Variables.Add() to add the current 21 day ATR reading to a newly opened position. Note how we use .Last to refer to the most recent value.

class SimpleSma : Strategy
{
    [Optimize(20, 80, 10)]
    public int ShortLength { get; set; } = 50;

    [Optimize(120, 240, 20)]
    public int LongLength { get; set; } = 200;

    [Optimize(3, 5, 0.5, includeNaN: true)]
    public double StopCoefficient { get; set; } = 3;

    protected override void OnStrategyStart()
    {
        Col1 = Sma(Close, ShortLength);
        Col2 = Sma(Close, LongLength);
        Col3 = Atr(21);

        StrategyVariables.Add(Name, "Some very important info for later.");

        Plot(Col1, 0, Color.Blue);
        Plot(Col2, 0, Color.Red);
        Plot(PlotInstruction.PlotStops);
        Plot(Stochastic(10), 1, Color.Purple, paneSize: 33f);
    }

    protected override void OnBarClose()
    {
        if (CrossAbove(Col1, Col2).Last)
        {
            Buy();
        }
        else if (Col1.Last < Col2.Last)
        {
            Sell();
        }

        ExitOnStop();
    }

    protected override void OnPositionOpening(Position position)
    {
        base.OnPositionOpening(position);
        position.Stop = position.Entries.AvgGrossPrice - Col3.Last * StopCoefficient;
        position.Variables.Add("Atr", Col3.Last);
    }
}

Within a money manager we can recover strategy level variables by calling GetStrategyVariables and specifying the strategy name. Variables attached to an opening position can be accessed via the Variables property of a Trade object in the OnEntry() method. In this example, we (arbitrarily) reject trade entries with an Atr reading greater than 5.

class CustomMoneyManager : MoneyManager
{
    protected override void OnStrategyStart()
    {
        base.OnStrategyStart();

        var gv = GetStrategyVariables("SimpleSma");
    }

    protected override void OnEntry(Trade trade)
    {
        if (trade.Variables.GetValueAsDouble("Atr") > 5)
        {
            trade.Cancel();
        }
        else
        {
            trade.Quantity = 10;
        }
    }
}

The VariableDictionary is used throughout the backtester when arbitrary data needs to be passed back and forth. For example, in Optimization we used a VariableDictionary in the Optimize() method to override the default properties of a money manager being used.