コード例 #1
0
        public override void Run()
        {
            //========== initialization ==========

            WarmupStartTime = Globals.WARMUP_START_TIME;
            StartTime       = Globals.START_TIME;
            EndTime         = Globals.END_TIME;

            Deposit(Globals.INITIAL_CAPITAL);
            CommissionPerShare = Globals.COMMISSION;

            var risky = RISKY_PORTFOLIO
                        .Select(a => Tuple.Create(AddDataSource(a.Item1), a.Item2))
                        .ToList();
            var cash = CASH_PORTFOLIO
                       .Select(a => Tuple.Create(AddDataSource(a.Item1), a.Item2))
                       .ToList();
            var universe = risky
                           .Select(a => a.Item1)
                           .Concat(cash
                                   .Select(a => a.Item1))
                           .Distinct()
                           .ToList();

            var economy   = AddDataSource(ECONOMY);
            var market    = AddDataSource(MARKET);
            var benchmark = AddDataSource(BENCHMARK);

            //========== simulation loop ==========

            foreach (var simTime in SimTimes)
            {
                // skip if there are any instruments missing from our universe
                if (!HasInstruments(universe) || !HasInstrument(benchmark) || !HasInstrument(economy))
                {
                    continue;
                }

                // calculate indicators
                var economyLagged  = economy.Instrument.Close.Delay(25); // 1 month publication lag: March observation published April 03
                var economySMA     = economyLagged.SMA(252);
                var economyGrowing = economyLagged[0] < economySMA[0];
                var marketSMA      = market.Instrument.Close.SMA(200); // 10-months moving average
                var marketRising   = market.Instrument.Close[0] > marketSMA[0];

                // trigger monthly rebalancing
                if (SimTime[0].Month != NextSimTime.Month)
                {
                    // determine target allocation: cash, if economy shrinking _and_ markets declining
                    var allocation = economyGrowing || marketRising
                        ? risky
                        : cash;

                    // determine weights
                    var weights = universe
                                  .Select(ds => ds.Instrument)
                                  .ToDictionary(
                        i => i,
                        i => allocation
                        .Where(a => a.Item1 == i.DataSource)
                        .Sum(a => a.Item2));

                    // submit orders
                    _alloc.LastUpdate = SimTime[0];
                    foreach (var i in weights.Keys)
                    {
                        _alloc.Allocation[i] = weights[i];
                        var shares = (int)Math.Floor(weights[i] * NetAssetValue[0] / i.Close[0]);
                        i.Trade(shares - i.Position);
                    }
                }

                // 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 true
                    // additional plotter output
                    _plotter.SelectChart("Unemployment Trend", "Date");
                    _plotter.SetX(SimTime[0]);
                    _plotter.Plot(economy.Instrument.Name, economyLagged[0]);
                    _plotter.Plot(economy.Instrument.Name + "-SMA", economySMA[0]);

                    _plotter.SelectChart("Market Trend", "Date");
                    _plotter.SetX(SimTime[0]);
                    _plotter.Plot(market.Instrument.Name, market.Instrument.Close[0]);
                    _plotter.Plot(market.Instrument.Name + "-SMA", marketSMA[0]);
#endif
                }
            }

            //========== 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();
        }
コード例 #2
0
        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; // the book does not deduct commissions

            var menu  = AddDataSources(ETF_MENU).ToList();
            var bench = AddDataSource(BENCHMARK);

            //========== simulation loop ==========

            foreach (DateTime simTime in SimTimes)
            {
                // calculate momentum w/ algorithm-specific helper function
                var evaluation = Instruments
                                 .ToDictionary(
                    i => i,
                    i => MOMENTUM(i));

                // skip, if there are any missing instruments
                if (!HasInstruments(menu) || !HasInstrument(bench))
                {
                    continue;
                }

                // rank, and select top-3 instruments
                var top3 = menu
                           .Select(ds => ds.Instrument)
                           .OrderByDescending(i => evaluation[i])
                           .Take(NUM_PICKS);

                // calculate target percentage and how far we are off
                double targetPercentage = 1.0 / NUM_PICKS;
                double maxOff           = menu
                                          .Select(ds => ds.Instrument)
                                          .Max(i => (top3.Count() > 0 && top3.Contains(i) ? 1.0 : 0.0)
                                               * Math.Abs(i.Position * i.Close[0] / NetAssetValue[0] - targetPercentage) / targetPercentage);

                // rebalance once per month, and only if we need adjustments exceeding 20%
                if (REBAL_TODAY(maxOff))
                {
                    _alloc.LastUpdate = SimTime[0];

                    foreach (var i in menu.Select(ds => ds.Instrument))
                    {
                        _alloc.Allocation[i] = top3.Contains(i) ? targetPercentage : 0.0;

                        // determine current and target shares per instrument...
                        double targetEquity  = (top3.Contains(i) ? targetPercentage : 0.0) * NetAssetValue[0];
                        int    targetShares  = (int)Math.Floor(targetEquity / i.Close[0]);
                        int    currentShares = i.Position;

                        // ... and trade the delta
                        Order newOrder = i.Trade(targetShares - currentShares, ORDER_TYPE);

                        // add a comment, to make the trading log easier to read
                        if (newOrder != null)
                        {
                            if (currentShares == 0)
                            {
                                newOrder.Comment = "Open";
                            }
                            else if (targetShares == 0)
                            {
                                newOrder.Comment = "Close";
                            }
                            else
                            {
                                newOrder.Comment = "Rebalance";
                            }
                        }
                    }
                }

                // plotter output
                if (!IsOptimizing && TradingDays > 0)
                {
                    _plotter.AddNavAndBenchmark(this, FindInstrument(BENCHMARK));
                    _plotter.AddStrategyHoldings(this, ETF_MENU.Select(nick => FindInstrument(nick)));
                    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();
        }
コード例 #3
0
        public override IEnumerable <Bar> Run(DateTime?startTime, DateTime?endTime)
        {
            //========== initialization ==========

#if USE_BENSDORPS_RANGE
            // matching range in the book
            StartTime       = SubclassedStartTime ?? DateTime.Parse("01/02/1995", CultureInfo.InvariantCulture);
            EndTime         = SubclassedEndTime ?? DateTime.Parse("11/23/2016", CultureInfo.InvariantCulture);
            WarmupStartTime = StartTime - TimeSpan.FromDays(365);
#else
            StartTime       = startTime ?? Globals.START_TIME;
            EndTime         = endTime ?? Globals.END_TIME;
            WarmupStartTime = Globals.WARMUP_START_TIME;
#endif

            Deposit(Globals.INITIAL_CAPITAL);
            CommissionPerShare = Globals.COMMISSION;

            AddDataSources(UNIVERSE.Constituents);
            var spx       = AddDataSource(SPX);
            var benchmark = AddDataSource(BENCHMARK);

            //========== simulation loop ==========

            double nn = 0.0;
            foreach (var s in SimTimes)
            {
                var universe = Instruments
                               .Where(i => i.IsConstituent(UNIVERSE))
                               .ToList();

                //----- calculate indicators

                // calculate indicators for all known instruments,
                // as they might enter the universe any time
                var indicators = Instruments
                                 .ToDictionary(
                    i => i,
                    i => new
                {
                    rsi = i.Close.RSI(3),
                    roc = i.Close.Momentum(200),
                });

                if (!HasInstrument(benchmark))
                {
                    continue;
                }

                var smaBand = spx.Instrument.Close.SMA(200).Multiply(0.98); // 2% below 200-day SMA

                // open positions on Monday
                if (NextSimTime.DayOfWeek < SimTime[0].DayOfWeek) // open positions on Monday
                {
                    // we are not entirely sure how Bensdorp wants this strategy to work.
                    // we see three alternatives
#if false
                    // solution A
                    // create one list of 10 stocks, none of which are overbought,
                    // ranked by momentum
                    // good: new entries are guaranteed to be on keep-list on day 1
                    //       also, we always hold 10 stocks
                    // bad: we might exit stocks with top momentum, as soon as they become overbought
                    // => this strategy seems to never hold stocks longer than 60 days,
                    //    conflicting with the statements made in the book
                    var nextHoldings = universe
                                       .Where(i => spx.Instrument.Close[0] > smaBand[0])
                                       .Where(i => indicators[i].rsi[0] < MAX_RSI)
                                       .OrderByDescending(i => indicators[i].roc[0])
                                       .Take(MAX_ENTRIES)
                                       .ToList();
#endif
#if false
                    // solution B
                    // create separate list for new entries and for keepers
                    // good: this makes sure that we almost always hold 10 stocks
                    // bad: a new stock entered might not meet the hold requirements,
                    //    as it might not have top-10 momentum. this adds somewhat of
                    //    a mean-reversion component to the strategy
                    // => this strategy seems to work very well over the book's backtesting period.
                    //    overall, higher return and higher drawdown than C, worse Sharpe ratio
                    var keep = universe
                               .Where(i => spx.Instrument.Close[0] > smaBand[0])
                               .OrderByDescending(i => indicators[i].roc[0])
                               .Take(MAX_ENTRIES)
                               .Where(i => i.Position != 0)
                               .ToList();
                    var enter = universe
                                .Where(i => spx.Instrument.Close[0] > smaBand[0])
                                .Where(i => i.Position == 0 && indicators[i].rsi[0] < MAX_RSI)
                                .OrderByDescending(i => indicators[i].roc[0])
                                .Take(MAX_ENTRIES - keep.Count)
                                .ToList();
                    var nextHoldings = keep
                                       .Concat(enter)
                                       .ToList();
#endif
#if true
                    // solution C
                    // draw new entries and keeps both from top-10 ranked stocks
                    // good: new entries are guaranteed to be on the keep list on day 1
                    // bad: the enter list might be empty, if all top-10 stocks are overbought
                    //   driving down our exposure and therewith return
                    var top10 = universe
                                .Where(i => spx.Instrument.Close[0] > smaBand[0])
                                .OrderByDescending(i => indicators[i].roc[0])
                                .Take(MAX_ENTRIES)
                                .ToList();
                    var keep = top10
                               .Where(i => i.Position != 0)
                               .ToList();
                    var enter = top10
                                .Where(i => i.Position == 0 && indicators[i].rsi[0] < MAX_RSI)
                                .ToList();
                    var nextHoldings = keep
                                       .Concat(enter)
                                       .ToList();
#endif

                    _alloc.LastUpdate = SimTime[0];
                    _alloc.Allocation.Clear();
                    foreach (var i in Instruments)
                    {
                        double targetPercentage = nextHoldings.Contains(i)
                            ? 1.0 / MAX_ENTRIES
                            : 0.0;
                        int targetShares = (int)Math.Floor(NetAssetValue[0] * targetPercentage / i.Close[0]);

                        if (targetPercentage != 0.0)
                        {
                            _alloc.Allocation[i] = targetPercentage;
                        }

                        i.Trade(targetShares - i.Position);
                    }

                    nn = nextHoldings.Count / 10.0;
                }

                //----- output

                if (!IsOptimizing && TradingDays > 0)
                {
                    _plotter.AddNavAndBenchmark(this, FindInstrument(BENCHMARK));
                    //_plotter.AddStrategyHoldings(this, universe);

                    // plot strategy exposure
                    _plotter.SelectChart("Exposure Chart", "Date");
                    _plotter.SetX(SimTime[0]);
                    _plotter.Plot("Exposure", Instruments.Sum(i => i.Position * i.Close[0]) / NetAssetValue[0]);
                    //_plotter.Plot("Choices", nn);
                    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();
        }
コード例 #4
0
        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();
        }
コード例 #5
0
        public override void Run()
        {
            //========== initialization ==========

            WarmupStartTime = Globals.WARMUP_START_TIME;
            StartTime       = Globals.START_TIME;
            EndTime         = Globals.END_TIME;

            Deposit(Globals.INITIAL_CAPITAL);
            CommissionPerShare = Globals.COMMISSION;

            var market = AddDataSource(MARKET);

            //========== simulation loop ==========

            var entryPrices = new Dictionary <Instrument, double>();

            foreach (var s in SimTimes)
            {
                if (!_alloc.Allocation.ContainsKey(market.Instrument))
                {
                    _alloc.Allocation[market.Instrument] = 0.0;
                }

                double percentToBuySell = Rules(market.Instrument);

                _alloc.LastUpdate = SimTime[0];

                //----- entries

                if (market.Instrument.Position >= 0 && percentToBuySell > 0 ||
                    market.Instrument.Position <= 0 && percentToBuySell < 0)
                {
                    int sharesToBuySell = (int)(Math.Sign(percentToBuySell) * Math.Floor(
                                                    Math.Abs(percentToBuySell) * NetAssetValue[0] / market.Instrument.Close[0]));

                    _alloc.Allocation[market.Instrument] += percentToBuySell;
                    market.Instrument.Trade(sharesToBuySell, ORDER_TYPE);
                }

                //----- exits

                if (market.Instrument.Position > 0 && percentToBuySell < 0 ||
                    market.Instrument.Position < 0 && percentToBuySell > 0)
                {
                    // none of the algorithms attempt to gradually
                    // exit positions, so this is good enough
                    _alloc.Allocation[market.Instrument] = 0.0;
                    market.Instrument.Trade(-market.Instrument.Position, OrderType.closeThisBar);
                }

                //----- output

                if (!IsOptimizing && TradingDays > 0)
                {
                    _plotter.AddNavAndBenchmark(this, market.Instrument);
                    _plotter.AddStrategyHoldings(this, market.Instrument);
                    if (_alloc.LastUpdate == SimTime[0])
                    {
                        _plotter.AddTargetAllocationRow(_alloc);
                    }
                }
            }

            //========== 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();
        }
コード例 #6
0
        public override IEnumerable <Bar> Run(DateTime?startTime, DateTime?endTime)
        {
            //========== initialization ==========

            StartTime       = START_TIME;
            EndTime         = END_TIME;
            WarmupStartTime = StartTime - TimeSpan.FromDays(365);

            Deposit(Globals.INITIAL_CAPITAL);
            CommissionPerShare = Globals.COMMISSION; // it is unclear, if Antonacci considers commissions

            // assets we can trade
            List <string> ASSETS = ASSET_CLASSES
                                   .SelectMany(c => c.assets)
                                   .Distinct()
                                   .Where(nick => nick != ABS_MOMENTUM)
                                   .ToList();

            ASSETS.Add(SAFE_INSTR);

            var assets    = AddDataSources(ASSETS);
            var safe      = AddDataSource(SAFE_INSTR); // we just need the data source
            var absMom    = AddDataSource(ABS_MOMENTUM);
            var benchmark = AddDataSource(BENCHMARK);

            double totalWeights = ASSET_CLASSES.Sum(a => a.weight);

            //========== simulation loop ==========

            foreach (DateTime simTime in SimTimes)
            {
                // skip if there are any missing instruments
                if (!HasInstruments(assets) || !HasInstrument(benchmark) || !HasInstrument(absMom))
                {
                    continue;
                }

                // evaluate momentum for all known instruments
                Dictionary <Instrument, double> instrumentMomentum = Instruments
                                                                     .ToDictionary(i => i, i => MOMENTUM(i));

                // execute trades once per month
                // CAUTION: do not calculate indicators within this block!
                if (SimTime[0].Month != NextSimTime.Month)
                {
                    // create empty structure for instrument weights
                    Dictionary <Instrument, double> instrumentWeights = Instruments
                                                                        .ToDictionary(i => i, i => 0.0);

                    // loop through all asset classes, and find the top-ranked one
                    Instrument safeInstrument = safe.Instrument;
                    foreach (AssetClass assetClass in ASSET_CLASSES)
                    {
                        // find the instrument with the highest momentum
                        // in each asset class
                        var bestInstrument = assetClass.assets
                                             .Select(nick => FindInstrument(nick))
                                             .OrderByDescending(i => instrumentMomentum[i])
                                             .Take(1)
                                             .First();

                        // sum up the weights (because instrument is duplicated)
                        instrumentWeights[bestInstrument] += assetClass.weight / totalWeights;

                        if (assetClass.setSafeInstrument)
                        {
                            safeInstrument = bestInstrument;
                        }
                    }

                    // if momentum of any instrument drops below that of a T-Bill,
                    // we use the safe instrument instead
                    // therefore, we swap T-Bills for the safe instrument:
                    double pcntTbill = instrumentWeights[absMom.Instrument];
                    instrumentWeights[absMom.Instrument] = 0.0;
                    instrumentWeights[safeInstrument]   += pcntTbill;

                    // submit orders
                    _alloc.LastUpdate = SimTime[0];
                    foreach (var ds in assets)
                    {
                        _alloc.Allocation[ds.Instrument] = instrumentWeights[ds.Instrument];

                        int   targetShares  = (int)Math.Floor(instrumentWeights[ds.Instrument] * NetAssetValue[0] / ds.Instrument.Close[0]);
                        int   currentShares = ds.Instrument.Position;
                        Order newOrder      = ds.Instrument.Trade(targetShares - currentShares);

                        if (newOrder != null)
                        {
                            if (currentShares == 0)
                            {
                                newOrder.Comment = "open";
                            }
                            else if (targetShares == 0)
                            {
                                newOrder.Comment = "close";
                            }
                            else
                            {
                                newOrder.Comment = "rebalance";
                            }
                        }
                    }
                }

                // plotter output
                if (!IsOptimizing && TradingDays > 0)
                {
                    _plotter.AddNavAndBenchmark(this, benchmark.Instrument);
                    _plotter.AddStrategyHoldings(this, assets.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();
        }
コード例 #7
0
        public override void Run()
        {
            //========== initialization ==========

            WarmupStartTime = Globals.WARMUP_START_TIME;
            StartTime       = Globals.START_TIME;
            EndTime         = Globals.END_TIME;

            Deposit(Globals.INITIAL_CAPITAL);
            CommissionPerShare = Globals.COMMISSION;

            var market     = AddDataSource(MARKET);
            var volatility = AddDataSource(VOLATILITY);

#if INCLUDE_TRIN_STRATEGY
            AddDataSource(TRIN);
#endif

            //========== simulation loop ==========

            foreach (var s in SimTimes)
            {
                if (!HasInstrument(market) || !HasInstrument(volatility))
                {
                    continue;
                }

                if (!_alloc.Allocation.ContainsKey(market.Instrument))
                {
                    _alloc.Allocation[market.Instrument] = 0.0;
                }

                int buySell = Rules(market.Instrument);

                _alloc.LastUpdate = SimTime[0];

                //----- enter positions

                if (market.Instrument.Position == 0 && buySell != 0)
                {
                    int numShares = buySell * (int)Math.Floor(NetAssetValue[0] / market.Instrument.Close[0]);
                    _alloc.Allocation[market.Instrument] += buySell;
                    market.Instrument.Trade(numShares, OrderType.closeThisBar);
                }

                //----- exit positions

                else if (market.Instrument.Position != 0 && buySell != 0)
                {
                    _alloc.Allocation[market.Instrument] = 0.0;
                    market.Instrument.Trade(-market.Instrument.Position, ORDER_TYPE);
                }

                //----- output

                if (!IsOptimizing && TradingDays > 0)
                {
                    _plotter.AddNavAndBenchmark(this, market.Instrument);
                    _plotter.AddStrategyHoldings(this, market.Instrument);
                    if (_alloc.LastUpdate == SimTime[0])
                    {
                        _plotter.AddTargetAllocationRow(_alloc);
                    }
                }
            }

            //========== post processing ==========

            if (!IsOptimizing && TradingDays > 0)
            {
                _plotter.AddTargetAllocation(_alloc);
                _plotter.AddOrderLog(this);
                _plotter.AddPositionLog(this);
                _plotter.AddPnLHoldTime(this);
                _plotter.AddMfeMae(this);
                _plotter.AddParameters(this);
            }

            FitnessValue = this.CalcFitness();
        }
コード例 #8
0
ファイル: Keller_DAA.cs プロジェクト: yutiansut/TuringTrader
        public override void Run()
        {
            //----- initialization

            WarmupStartTime = Globals.WARMUP_START_TIME;
            StartTime       = Globals.START_TIME;
            EndTime         = Globals.END_TIME;

            Deposit(Globals.INITIAL_CAPITAL);
            CommissionPerShare = Globals.COMMISSION; // paper does not consider trade commissions

            var riskyUniverse      = AddDataSources(RISKY_UNIVERSE);
            var cashUniverse       = AddDataSources(CASH_UNIVERSE);
            var protectiveUniverse = AddDataSources(PROTECTIVE_UNIVERSE);
            var benchmark          = AddDataSource(BENCHMARK);

            //----- simulation loop

            var monthlyBars = new Dictionary <Instrument, TimeSeries <double> >();

            foreach (DateTime simTime in SimTimes)
            {
                // skip if there are any missing instruments
                // we want to make sure our strategy has all instruments available
                if (!HasInstruments(riskyUniverse) ||
                    !HasInstruments(cashUniverse) ||
                    !HasInstruments(protectiveUniverse) ||
                    !HasInstrument(benchmark) ||
                    ASSET_SUB != null && !HasInstruments(ASSET_SUB.Values))
                {
                    continue;
                }

                // rebalance once per month
                // CAUTION: no indicator calculations within this block!
                if (SimTime[0].Month != NextSimTime.Month)
                {
                    // calculate 13612W momentum for all instruments
                    foreach (var i in Instruments)
                    {
                        if (!monthlyBars.ContainsKey(i))
                        {
                            monthlyBars[i] = new TimeSeries <double>();
                        }
                    }

                    foreach (var i in Instruments)
                    {
                        monthlyBars[i].Value = i.Close[0];
                    }

                    Dictionary <Instrument, double> momentum13612W = Instruments
                                                                     .ToDictionary(
                        i => i,
                        i => 0.25 *
                        (12.0 * (monthlyBars[i][0] / monthlyBars[i][1] - 1.0)
                         + 4.0 * (monthlyBars[i][0] / monthlyBars[i][3] - 1.0)
                         + 2.0 * (monthlyBars[i][0] / monthlyBars[i][6] - 1.0)
                         + 1.0 * (monthlyBars[i][0] / monthlyBars[i][12] - 1.0)));

                    // determine number of bad assets in canary universe
                    double b = protectiveUniverse
                               .Select(ds => ds.Instrument)
                               .Sum(i => momentum13612W[i] < 0.0 ? 1.0 : 0.0);

                    // calculate cash fraction
                    //double CF = Math.Min(1.0, b / B) // standard calculation
                    double CF = Math.Min(1.0, 1.0 / T * Math.Floor(b * T / B)); // Easy Trading

                    // as part of Easy Trading, we scale back the number of
                    // top assets as CF increases
                    int t = (int)Math.Round((1.0 - CF) * T);

                    // find T top risky assets
                    IEnumerable <Instrument> topInstruments = riskyUniverse
                                                              .Select(ds => ds.Instrument)
                                                              .OrderByDescending(i => momentum13612W[i])
                                                              .Take(t);

                    // find single cash/ bond asset
                    Instrument cashInstrument = cashUniverse
                                                .Select(ds => ds.Instrument)
                                                .OrderByDescending(i => momentum13612W[i])
                                                .First();

                    // set instrument weights
                    Dictionary <Instrument, double> weights = Instruments
                                                              .ToDictionary(i => i, i => 0.0);

                    weights[cashInstrument] = CF;

                    foreach (Instrument i in topInstruments)
                    {
                        weights[i] += (1.0 - CF) / t;
                    }

                    _alloc.LastUpdate = SimTime[0];
                    foreach (Instrument i in Instruments)
                    {
                        // skip instruments not in our relevant universes
                        if (!riskyUniverse.Contains(i.DataSource) && !cashUniverse.Contains(i.DataSource))
                        {
                            continue;
                        }

                        // for the 'on steroids' versions, we run the signals
                        // as usual, but substitute some assets with leveraged
                        // counterparts for the actual trading
                        var i2 = AssetSub(i);

                        // calculate target allocations
                        _alloc.Allocation[i2] = weights[i];
                        int targetShares = (int)Math.Floor(weights[i] * NetAssetValue[0] / i2.Close[0]);

                        Order newOrder = i2.Trade(targetShares - i2.Position);

                        if (newOrder != null)
                        {
                            if (i.Position == 0)
                            {
                                newOrder.Comment = "open";
                            }
                            else if (targetShares == 0)
                            {
                                newOrder.Comment = "close";
                            }
                            else
                            {
                                newOrder.Comment = "rebalance";
                            }
                        }
                    }
                }

                // plotter output
                if (!IsOptimizing && TradingDays > 0)
                {
                    _plotter.AddNavAndBenchmark(this, FindInstrument(BENCHMARK));
                    _plotter.AddStrategyHoldings(this, Instruments
                                                 .Where(i => riskyUniverse.Contains(i.DataSource) || cashUniverse.Contains(i.DataSource))
                                                 .Select(i => AssetSub(i)));
                    if (_alloc.LastUpdate == SimTime[0])
                    {
                        _plotter.AddTargetAllocationRow(_alloc);
                    }
                }
            }

            //----- 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();
        }
コード例 #9
0
        public override void Run()
        {
            //========== initialization ==========

            WarmupStartTime = Globals.WARMUP_START_TIME;
            StartTime       = Globals.START_TIME;
            EndTime         = Globals.END_TIME;

            Deposit(Globals.INITIAL_CAPITAL);
            CommissionPerShare = Globals.COMMISSION; // Faber does not consider commissions

            var ASSETS = ASSET_CLASSES
                         .SelectMany(c => c.assets)
                         .Distinct()
                         .ToList();

            var benchmark = AddDataSource(BENCHMARK);
            var assets    = AddDataSources(ASSETS);

            //========== simulation loop ==========

            foreach (DateTime simTime in SimTimes)
            {
                // evaluate instrument momentum for all known instruments,
                // we need to make sure to evaluate every instrument only once!
                Dictionary <Instrument, double> instrumentMomentum = Instruments
                                                                     .ToDictionary(i => i,
                                                                                   i => SCORING_FUNC(i));

                // skip if there are any missing instruments,
                // we want to make sure our strategy has all instruemnts available
                if (!HasInstruments(assets) || !HasInstrument(benchmark))
                {
                    continue;
                }

                // execute trades once per month
                if (SimTime[0].Month != NextSimTime.Month)
                {
                    // create empty structure for instrument weights
                    Dictionary <Instrument, double> instrumentWeights = assets
                                                                        .ToDictionary(ds => ds.Instrument, ds => 0.0);

                    // loop through all asset classes and accumulate asset weights
                    foreach (AssetClass assetClass in ASSET_CLASSES)
                    {
                        List <Instrument> assetClassInstruments = assetClass.assets
                                                                  .Select(n => FindInstrument(n))
                                                                  .ToList();

                        var bestInstruments = assetClassInstruments
                                              .OrderByDescending(i => instrumentMomentum[i])
                                              .Take(assetClass.numpicks);

                        foreach (Instrument bestInstrument in bestInstruments)
                        {
                            instrumentWeights[bestInstrument] += assetClass.weight / assetClass.numpicks;
                        }
                    }

                    double totalWeight = ASSET_CLASSES
                                         .Sum(a => a.weight);
                    double equityUnit = NetAssetValue[0] / totalWeight;

                    // create orders
                    _alloc.LastUpdate = SimTime[0];
                    string message = string.Format("{0:MM/dd/yyyy}: ", SimTime[0]);
                    foreach (var i in instrumentWeights.Keys)
                    {
                        _alloc.Allocation[i] = instrumentWeights[i] / totalWeight;
                        message += string.Format("{0} = {1:P2}, ", i.Symbol, instrumentWeights[i]);

                        int   targetShares  = (int)Math.Floor(instrumentWeights[i] * equityUnit / i.Close[0]);
                        int   currentShares = i.Position;
                        Order newOrder      = i.Trade(targetShares - currentShares);

                        if (newOrder != null)
                        {
                            if (currentShares == 0)
                            {
                                newOrder.Comment = "open";
                            }
                            else if (targetShares == 0)
                            {
                                newOrder.Comment = "close";
                            }
                            else
                            {
                                newOrder.Comment = "rebalance";
                            }
                        }
                    }

                    if (TradingDays > 0 && !IsOptimizing && (EndTime - SimTime[0]).TotalDays < 63)
                    {
                        Output.WriteLine(message);
                    }
                }

                // plotter output
                if (TradingDays > 0)
                {
                    _plotter.AddNavAndBenchmark(this, FindInstrument(BENCHMARK));
                    _plotter.AddStrategyHoldings(this, ASSETS.Select(nick => FindInstrument(nick)));
                    if (_alloc.LastUpdate == SimTime[0])
                    {
                        _plotter.AddTargetAllocationRow(_alloc);
                    }
                }
            }

            //========== 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();
        }