Exemplo n.º 1
0
        public void Evaluate()
        {
            if (!_evaluatable)
            {
                throw new InvalidOperationException("Evaluate() can be called only once");
            }

            // initialize context
            _strategy.Initialize(_context, _strategyParameterValues);

            // Get all trading objects
            _allTradingObjects = _provider.GetAllTradingObjects();

            // Get last warm up data periods
            _firstNonWarmupDataPeriods = _provider.GetFirstNonWarmupDataPeriods();

            // evaluating
            var lastPeriodTime = DateTime.MinValue;

            Bar[] lastPeriodData = null;
            var   periods        = _provider.GetAllPeriodsOrdered();

            bool fullTradingDataReached = false;

            for (var periodIndex = 0; periodIndex < periods.Length; ++periodIndex)
            {
                var thisPeriodTime = periods[periodIndex];
                var thisPeriodData = _provider.GetDataOfPeriod(thisPeriodTime);

                if (thisPeriodData.Length != _allTradingObjects.Length)
                {
                    throw new InvalidOperationException("the number of data returned does not match the number of trading object");
                }

                // process pure warm up data.
                if (_firstNonWarmupDataPeriods.All(t => t > thisPeriodTime))
                {
                    // update metrics that registered by strategy
                    _context.MetricManager.BeginUpdateMetrics();

                    _context.MetricManager.UpdateMetrics(_allTradingObjects, thisPeriodData);

                    _context.MetricManager.EndUpdateMetrics();

                    continue;
                }

                // remove warm up data if necessary
                var originalThisPeriodData = thisPeriodData;
                if (!fullTradingDataReached)
                {
                    if (_firstNonWarmupDataPeriods.All(t => t <= thisPeriodTime))
                    {
                        // from now on, all data are useful trading data
                        fullTradingDataReached = true;
                    }
                    else
                    {
                        thisPeriodData = new Bar[originalThisPeriodData.Length];
                        Array.Copy(originalThisPeriodData, thisPeriodData, thisPeriodData.Length);

                        for (int i = 0; i < thisPeriodData.Length; ++i)
                        {
                            if (thisPeriodData[i].Time < _firstNonWarmupDataPeriods[i])
                            {
                                thisPeriodData[i].Time = Bar.InvalidTime;
                            }
                        }
                    }
                }

                // set current period data in context
                _context.SetCurrentPeriodData(thisPeriodData);

                // start a new period
                _strategy.StartPeriod(thisPeriodTime);

                // assign all instructions in next period to current period because new period starts
                _currentPeriodInstructions.Clear();
                _currentPeriodInstructions.AddRange(_nextPeriodInstructions);
                _nextPeriodInstructions.Clear();

                // run instructions left over from previous period
                RunCurrentPeriodInstructions(lastPeriodData, thisPeriodData, thisPeriodTime);

#if DEBUG
                // check data
                if (thisPeriodData.Any(bar => bar.Time != Bar.InvalidTime && bar.Time != thisPeriodTime))
                {
                    throw new InvalidOperationException("Time in bar data is different with the time returned by data provider");
                }
#endif

                // update metrics that registered by strategy.
                // here we should always use original data to update metrics.
                _context.MetricManager.BeginUpdateMetrics();
                _context.MetricManager.UpdateMetrics(_allTradingObjects, originalThisPeriodData);
                _context.MetricManager.EndUpdateMetrics();

                // update position lasted period count
                foreach (var code in _context.GetAllPositionCodes())
                {
                    int tradingObjectIndex = _provider.GetIndexOfTradingObject(code);

                    if (thisPeriodData[tradingObjectIndex].Time != Bar.InvalidTime)
                    {
                        foreach (var position in _context.GetPositionDetails(code))
                        {
                            if (position.BuyTime < thisPeriodTime)
                            {
                                position.IncreaseLastedPeriodCount();
                            }
                        }
                    }
                }

                // evaluate bar data
                _strategy.Evaluate(_allTradingObjects, thisPeriodData);

                // get instructions and add them to pending instruction list
                var instructions = _strategy.RetrieveInstructions().ToArray();

                if (instructions.Any(i => i.Action == TradingAction.OpenLong))
                {
                    // update active account only if there is open long instruction
                    _activeAccountId++;
                    _activeAccountId %= _numberOfAccounts;

                    // decide if instructions should be excuted in current account
                    if (_activeAccountId != _accountId)
                    {
                        // remove OpenLong instructions
                        instructions = instructions.Where(i => i.Action != TradingAction.OpenLong).ToArray();
                    }
                }

                if (instructions.Any())
                {
                    foreach (var instruction in instructions)
                    {
                        UpdateInstructionWithDefaultPriceWhenNecessary(instruction);

                        if (instruction.Price.Period == TradingPricePeriod.CurrentPeriod)
                        {
                            _currentPeriodInstructions.Add(instruction);
                        }
                        else if (instruction.Price.Period == TradingPricePeriod.NextPeriod)
                        {
                            _nextPeriodInstructions.Add(instruction);
                        }
                        else
                        {
                            throw new InvalidProgramException("unsupported price period");
                        }
                    }

                    // run instructions for current period
                    RunCurrentPeriodInstructions(lastPeriodData, thisPeriodData, thisPeriodTime);
                }

                // end period
                _strategy.EndPeriod();

                // reset current period data in context
                _context.SetCurrentPeriodData(null);

                // update last period time and data
                lastPeriodTime = thisPeriodTime;
                lastPeriodData = thisPeriodData;

                // update progress event
                if (OnEvaluationProgress != null)
                {
                    OnEvaluationProgress(
                        this,
                        new EvaluationProgressEventArgs(
                            thisPeriodTime,
                            (double)(periodIndex + 1) / periods.Length));
                }
            }

            // finish evaluation
            _strategy.Finish();

            // Sell all equities forcibly.
            ClearEquityForcibly(lastPeriodTime);

            // clear all pending instructions.
            _currentPeriodInstructions.Clear();
            _nextPeriodInstructions.Clear();

            // update 'evaluatable' flag to avoid this function be called twice
            _evaluatable = false;
        }
        public void Predicate()
        {
            if (!_predicatable)
            {
                throw new InvalidOperationException("Predicate() can be called only once");
            }

            // initialize context
            _strategy.Initialize(_context, _strategyParameterValues);

            // Get all trading objects
            _allTradingObjects = _provider.GetAllTradingObjects();

            // Get last warm up data periods
            _firstNonWarmupDataPeriods = _provider.GetFirstNonWarmupDataPeriods();

            // evaluating
            var lastPeriodTime = DateTime.MinValue;

            Bar[] lastPeriodData = null;
            var   periods        = _provider.GetAllPeriodsOrdered();

            bool fullTradingDataReached = false;

            for (var periodIndex = 0; periodIndex < periods.Length; ++periodIndex)
            {
                var thisPeriodTime = periods[periodIndex];
                var thisPeriodData = _provider.GetDataOfPeriod(thisPeriodTime);

                if (thisPeriodData.Length != _allTradingObjects.Length)
                {
                    throw new InvalidOperationException("the number of data returned does not match the number of trading object");
                }

                // process pure warm up data.
                if (_firstNonWarmupDataPeriods.All(t => t > thisPeriodTime))
                {
                    // update metrics that registered by strategy
                    _context.MetricManager.BeginUpdateMetrics();

                    _context.MetricManager.UpdateMetrics(_allTradingObjects, thisPeriodData);

                    _context.MetricManager.EndUpdateMetrics();

                    continue;
                }

                // remove warm up data if necessary
                var originalThisPeriodData = thisPeriodData;
                if (!fullTradingDataReached)
                {
                    if (_firstNonWarmupDataPeriods.All(t => t <= thisPeriodTime))
                    {
                        // from now on, all data are useful trading data
                        fullTradingDataReached = true;
                    }
                    else
                    {
                        thisPeriodData = new Bar[originalThisPeriodData.Length];
                        Array.Copy(originalThisPeriodData, thisPeriodData, thisPeriodData.Length);

                        for (int i = 0; i < thisPeriodData.Length; ++i)
                        {
                            if (thisPeriodData[i].Time < _firstNonWarmupDataPeriods[i])
                            {
                                thisPeriodData[i].Time = Bar.InvalidTime;
                            }
                        }
                    }
                }

                // set current period data in context
                _context.SetCurrentPeriodData(thisPeriodData);

                // start a new period
                _strategy.StartPeriod(thisPeriodTime);

                // assign all instructions in next period to current period because new period starts
                _currentPeriodInstructions.Clear();
                _currentPeriodInstructions.AddRange(_nextPeriodInstructions);
                _nextPeriodInstructions.Clear();

                // run instructions left over from previous period
                RunCurrentPeriodInstructions(lastPeriodData, thisPeriodData, thisPeriodTime);

#if DEBUG
                // check data
                if (thisPeriodData.Any(bar => bar.Time != Bar.InvalidTime && bar.Time != thisPeriodTime))
                {
                    throw new InvalidOperationException("Time in bar data is different with the time returned by data provider");
                }
#endif

                // update metrics that registered by strategy.
                // here we should always use original data to update metrics.
                _context.MetricManager.BeginUpdateMetrics();
                _context.MetricManager.UpdateMetrics(_allTradingObjects, originalThisPeriodData);
                _context.MetricManager.EndUpdateMetrics();

                // add active positions
                if (_unprocessedActivePositions.Any())
                {
                    var positions = _unprocessedActivePositions.Where(p => p.BuyTime <= thisPeriodTime);
                    if (positions.Any())
                    {
                        foreach (var position in positions)
                        {
                            _equityManager.ManualAddPosition(position);
                        }

                        _unprocessedActivePositions = _unprocessedActivePositions.Where(p => p.BuyTime > thisPeriodTime).ToList();
                    }
                }

                // evaluate bar data
                _strategy.Evaluate(_allTradingObjects, thisPeriodData);

                // get instructions and add them to pending instruction list
                var instructions = _strategy.RetrieveInstructions().ToArray();

                if (instructions.Any())
                {
                    if (thisPeriodTime == periods[periods.Length - 1])
                    {
                        _predicatedTransactions = instructions
                                                  .Select(ins => BuildTransactionFromInstruction(ins, thisPeriodTime, thisPeriodData[ins.TradingObject.Index]))
                                                  .ToList();
                    }
                    else
                    {
                        foreach (var instruction in instructions)
                        {
                            UpdateInstructionWithDefaultPriceWhenNecessary(instruction);

                            if (instruction.Price.Period == TradingPricePeriod.CurrentPeriod)
                            {
                                _currentPeriodInstructions.Add(instruction);
                            }
                            else if (instruction.Price.Period == TradingPricePeriod.NextPeriod)
                            {
                                _nextPeriodInstructions.Add(instruction);
                            }
                            else
                            {
                                throw new InvalidProgramException("unsupported price period");
                            }
                        }

                        // run instructions for current period
                        RunCurrentPeriodInstructions(lastPeriodData, thisPeriodData, thisPeriodTime);
                    }
                }

                // end period
                _strategy.EndPeriod();

                // reset current period data in context
                _context.SetCurrentPeriodData(null);

                // update last period time and data
                lastPeriodTime = thisPeriodTime;
                lastPeriodData = thisPeriodData;
            }

            // finish evaluation
            _strategy.Finish();

            // clear all pending instructions.
            _currentPeriodInstructions.Clear();
            _nextPeriodInstructions.Clear();

            // update flag to avoid this function be called twice
            _predicatable = false;
        }