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.