Skip to content

Recipes

The following code snippets demonstrate certain common tasks. There is often more than one way to accomplish the same thing, so several variants will be shown. Many blog posts on this site include the code used to generate the charts and studies. Watch this page for more ‘recipes’ to be added in the future.

BarSeries series;
BarSeriesCollection data;
var server = new CsiBarServer(@"c:\data\csi\current");
series = server.LoadSymbol("ES");
series = server.LoadSymbol("GC", new DateTime(2020, 1, 1));
series = server.LoadSymbol("US", new DateTime(1984, 1, 1), new DateTime(1987, 12, 31));
data = server.LoadSymbols("ES", "GC", "US");
data = server.LoadSymbols(new DateTime(2020, 1, 1), "ES", "GC", "US");
data = server.LoadAll();
var svr = new AsciiBarServer(@"c:\data\mktdata", AsciiBarServer.DC);
var bulls = svr.LoadSymbol("AAIIBull").Close; //return just the TimeSeries of closing prices
var alternative = TimeSeries.Load(@"c:\data\mkt\data\AAIIBull.csv");
var server = new CsiBarServer(@"c:\data\csi\current");
var data = server.LoadAll();
var strat = new Balsam.Benchmarks.SmaCrossover();
strat.RunSimulation(data);
strat = new Balsam.Benchmarks.SmaCrossover() { ShortLength = 20, LongLength = 120 };
strat.PrimarySeries = data[0];
strat.RunSimulation();
VariableDictionary vd = new VariableDictionary();
vd["ShortLength"] = 20;
vd["LongLength"] = 120;
strat = new Balsam.Benchmarks.SmaCrossover();
strat.SetProperties(vd);
strat.RunSimulation();
strat = new Balsam.Benchmarks.SmaCrossover();
strat.SetProperties(vd);
strat.MoneyManager = new FixedFractional() { PercentToRisk = 0.0020 };
strat.RunSimulation();
//mulit-threaded simulation
var moneyManager = new FixedFractional();
moneyManager.PercentToRisk = 0.002;
moneyManager.DataStore = Strategy.Run(typeof(SmaCrossover), vd, data);
moneyManager.RunSimulation();
class TestStrat : Strategy
{
public int Threshold { get; set; } = 5;
public double EntryCoefficient { get; set; } = double.NaN;
public double StopCoefficient { get; set; } = 2;
public double TargetCoefficient { get; set; } = double.NaN;
public int Horizon { get; set; } = 5;
protected override void OnStrategyStart()
{
Col1 = Sma(Close, 200);
Col2 = Rsi(Close, 2);
Col3 = Atr(10);
}
protected override void OnBarClose()
{
if (Close.Last > Col1.Last && CrossBelow(Col2, Threshold).Last)
{
if (double.IsNaN(EntryCoefficient))
{
BuyClose(); //enter MOC
//Buy(); //enter on the next bar's opening price
}
else
{
//attempt to enter on a limit at a slightly better price
BuyLimit(Close.Last - Col3.Last * EntryCoefficient);
}
}
ExitOnStop();
ExitAtTarget("Atr target"); //override the default signal name 'Target'
if (MarketPosition == PositionSide.Long && CurrentPosition.BarsSinceEntry >= Horizon)
{
ExitOnClose("Horizon");
}
//ExitOnHorizon(Horizon); //equivalent to the above
}
protected override void OnPositionOpening(Position position)
{
position.Stop = position.Entries.AvgGrossPrice - Col3.Last * StopCoefficient;
SetStop(position, Col3.Last * StopCoefficient); //equivalent to above
SetTarget(position, Col3.Last * TargetCoefficient);
}
}

Below we run a multi-threaded optimization across a portfolio of three equity indices, optimizing the exit parameters from TestStrat above. Note the [Optimize] attributes placed above the property names. Stopcoefficient is tested from 0.5 to 2.5 ATR’s in 0.5 ATR increments. TargetCoefficient is tested from 0.5 to 2 ATR’s in 0.25 ATR increments and also includes a NaN value which disables the target, causing the system to exit on either the stop or horizon. Finally Horizon, or the number of bars a trade is held, is tested with values of 1, 2, 3, 5 and 10. This results in 200 possible parameter combinations. Transaction costs of $2/contract and a half tick of slippage are passed in to the optimization via a VariableDictionary.

class TestStrat : Strategy
{
public static void Run()
{
var server = new CsiBarServer(@"c:\data\csi\current");
var data = server.LoadSymbols("ES", "NQ", "ER");
VariableDictionary vd = new VariableDictionary();
vd["TransactionCosts"] = new TickTransactionCosts { Commission = 2, Ticks = 0.5 };
var opt = new Optimizer();
opt.Optimize(typeof(TestStrat), vd, typeof(FixedFractional), null, data);
}
public int Threshold { get; set; } = 5;
public double EntryCoefficient { get; set; } = double.NaN;
[Optimize(0.5, 2.5, 0.5)]
public double StopCoefficient { get; set; } = 2;
[Optimize(0.5, 2, 0.25, includeNaN: true)]
public double TargetCoefficient { get; set; } = double.NaN;
[Optimize(1, 2, 3, 5, 10)]
public int Horizon { get; set; } = 5;
protected override void OnStrategyStart()
{
Col1 = Sma(Close, 200);
Col2 = Rsi(Close, 2);
Col3 = Atr(10);
}
protected override void OnBarClose()
{
if (Close.Last > Col1.Last && CrossBelow(Col2, Threshold).Last)
{
if (double.IsNaN(EntryCoefficient))
{
Buy();
}
else
{
BuyLimit(Close.Last - Col3.Last * EntryCoefficient);
}
}
ExitOnStop();
ExitAtTarget();
ExitOnHorizon(Horizon); //equivalent to the above
}
protected override void OnPositionOpening(Position position)
{
SetStop(position, Col3.Last * StopCoefficient);
SetTarget(position, Col3.Last * TargetCoefficient);
}
}

When you call Run() above, the optimization will start:

Optimization run 67 of 200 (33.5%)
Elapsed Runtime: 0:00:12 Estimated Completion Time: 10:30:23 AM Estimated Time Remaining: 0:00:25
________________________________________________________________________________________________________________________
Best: Sharpe Ratio: 0.50 Trades: 392 {"StopCoefficient":1,"TargetCoefficient":1,"Horizon":2}
Last: Sharpe Ratio: 0.47 Trades: 392 {"StopCoefficient":1,"TargetCoefficient":1.75,"Horizon":2}
________________________________________________________________________________________________________________________
10:29:44 Property to optimize: StopCoefficient: (0.5 to 2.5 by 0.5)
10:29:44 Property to optimize: TargetCoefficient: (0.5 to 2 by 0.25) + NaN
10:29:44 Property to optimize: Horizon: (1, 2, 3, 5, 10)
10:29:44 Total iterations 200. 0 skipped due to binding constraints.
10:29:44 Monitoring keyboard: <Esc> Cancel <E> Export to Excel <S> Save to file <P> Print compute pool status

When complete, the optimization report will be automatically exported to Excel. The image below shows the top ten parameter combinations sorted by Sharpe Ratio. Optimization Report