public override IEnumerable <Bar> Run(DateTime?startTime, DateTime?endTime) { //========== initialization ========== WarmupStartTime = Globals.WARMUP_START_TIME; StartTime = Globals.START_TIME; EndTime = Globals.END_TIME; Deposit(Globals.INITIAL_CAPITAL); CommissionPerShare = Globals.COMMISSION; // our universe consists of risky & safe assets var riskyAssets = AddDataSources(RISKY_ASSETS); var safeAssets = AddDataSources(SAFE_ASSETS); var universe = riskyAssets.Concat(safeAssets); var bench = AddDataSource(BENCHMARK); //========== simulation loop ========== foreach (var simTime in SimTimes) { // calculate indicators on overy bar Dictionary <Instrument, double> momentum = Instruments .ToDictionary( i => i, i => (1.0 * i.Close.Momentum(21)[0] + 3.0 * i.Close.Momentum(63)[0] + 6.0 * i.Close.Momentum(126)[0] + 12.0 * i.Close.Momentum(252)[0]) / 22.0); // skip if there are any instruments missing from our universe if (!HasInstruments(universe) || !HasInstrument(bench)) { continue; } // trigger rebalancing if (SimTime[0].Month != NextSimTime.Month) // monthly { // calculate covariance var covar = new PortfolioSupport.Covariance(Instruments, 12, 21); // 12 monthly bars // calculate efficient frontier for universe // note how momentum and covariance are annualized here var cla = new PortfolioSupport.MarkowitzCLA( universe.Select(ds => ds.Instrument), i => 252.0 * momentum[i], (i, j) => 252.0 / covar.BarSize * covar[i, j], i => 0.0, i => safeAssets.Contains(i.DataSource) ? 1.0 : MAX_RISKY_ALLOC); // find portfolio with specified risk var pf = cla.TargetVolatility(TVOL); Output.WriteLine("{0:MM/dd/yyyy}: {1}", SimTime[0], pf.ToString()); // adjust all positions _alloc.LastUpdate = SimTime[0]; foreach (var i in pf.Weights.Keys) { _alloc.Allocation[i] = pf.Weights[i]; int targetShares = (int)Math.Floor(NetAssetValue[0] * pf.Weights[i] / i.Close[0]); int currentShares = i.Position; var ticket = i.Trade(targetShares - currentShares); if (ticket != null) { if (i.Position == 0) { ticket.Comment = "open"; } else if (targetShares == 0) { ticket.Comment = "close"; } else { ticket.Comment = "rebalance"; } } } } // plotter output if (!IsOptimizing && TradingDays > 0) { _plotter.AddNavAndBenchmark(this, FindInstrument(BENCHMARK)); _plotter.AddStrategyHoldings(this, universe.Select(ds => ds.Instrument)); if (_alloc.LastUpdate == SimTime[0]) { _plotter.AddTargetAllocationRow(_alloc); } if (IsDataSource) { var v = 10.0 * NetAssetValue[0] / Globals.INITIAL_CAPITAL; yield return(Bar.NewOHLC( this.GetType().Name, SimTime[0], v, v, v, v, 0)); } } } //========== post processing ========== if (!IsOptimizing) { _plotter.AddTargetAllocation(_alloc); _plotter.AddOrderLog(this); _plotter.AddPositionLog(this); _plotter.AddPnLHoldTime(this); _plotter.AddMfeMae(this); _plotter.AddParameters(this); } FitnessValue = this.CalcFitness(); }
public override void Run() { //---------- initialization StartTime = DateTime.Parse("01/01/1990"); EndTime = DateTime.Now.Date - TimeSpan.FromDays(5); // our universe consists of risky & safe assets var universe = RISKY_ASSETS .Concat(SAFE_ASSETS).ToList(); // add all data sources AddDataSource(BENCHMARK); foreach (var nick in universe) { AddDataSource(nick); } Deposit(1e6); CommissionPerShare = 0.015; //---------- simulation loop foreach (var simTime in SimTimes) { // calculate indicators on overy bar Dictionary <Instrument, double> momentum = Instruments .ToDictionary( i => i, i => (1.0 * i.Close.Momentum(21)[0] + 3.0 * i.Close.Momentum(63)[0] + 6.0 * i.Close.Momentum(126)[0] + 12.0 * i.Close.Momentum(252)[0]) / 22.0); // skip if there are any instruments missing from our universe if (!HasInstruments(universe)) { continue; } // trigger rebalancing if (SimTime[0].Month != SimTime[1].Month) // monthly { // calculate covariance var covar = new PortfolioSupport.Covariance(Instruments, 12, 21); // 12 monthly bars // calculate efficient frontier for universe // note how momentum and covariance are annualized here var cla = new PortfolioSupport.MarkowitzCLA( Instruments.Where(i => universe.Contains(i.Nickname)), i => 252.0 * momentum[i], (i, j) => 252.0 / covar.BarSize * covar[i, j], // TODO: is sqrt correct? i => 0.0, i => SAFE_ASSETS.Contains(i.Nickname) ? 1.0 : MAX_RISKY_ALLOC); // find portfolio with specified risk var pf = cla.TargetVolatility(TVOL); Output.WriteLine("{0:MM/dd/yyyy}: {1}", SimTime[0], pf.ToString()); // adjust all positions foreach (var i in pf.Weights.Keys) { int targetShares = (int)Math.Floor(NetAssetValue[0] * pf.Weights[i] / i.Close[0]); int currentShares = i.Position; var ticket = i.Trade(targetShares - currentShares); if (ticket != null) { if (i.Position == 0) { ticket.Comment = "open"; } else if (targetShares == 0) { ticket.Comment = "close"; } else { ticket.Comment = "rebalance"; } } } } _benchmark = _benchmark ?? FindInstrument(BENCHMARK); _plotter.SelectChart(Name, "date"); _plotter.SetX(SimTime[0]); _plotter.Plot("NAV", NetAssetValue[0]); _plotter.Plot(_benchmark.Symbol, _benchmark.Close[0]); _plotter.SelectChart(Name + " holdings", "date"); _plotter.SetX(SimTime[0]); foreach (var n in universe) { var i = FindInstrument(n); _plotter.Plot(i.Symbol, i.Position * i.Close[0] / NetAssetValue[0]); } } //---------- post-processing _plotter.SelectChart(Name + " trades", "date"); foreach (LogEntry entry in Log) { _plotter.SetX(entry.BarOfExecution.Time); _plotter.Plot("action", entry.Action); _plotter.Plot("type", entry.InstrumentType); _plotter.Plot("instr", entry.Symbol); _plotter.Plot("qty", entry.OrderTicket.Quantity); _plotter.Plot("fill", entry.FillPrice); _plotter.Plot("gross", -entry.OrderTicket.Quantity * entry.FillPrice); _plotter.Plot("commission", -entry.Commission); _plotter.Plot("net", -entry.OrderTicket.Quantity * entry.FillPrice - entry.Commission); _plotter.Plot("comment", entry.OrderTicket.Comment ?? ""); } }