private void GenerateInstructions(ITradingObject[] tradingObjects, Bar[] bars) { // check if positions needs to be adjusted if (_positionAdjusting != null) { var instructions = _positionAdjusting.AdjustPositions(); if (instructions != null) { foreach (var instruction in instructions) { if (instruction.Action == TradingAction.OpenLong) { // comment out below code because evaluation result shows it will degrade performance. //if (_globalSettings.AllowEnteringMarketOnlyWhenPriceIncreasing) //{ // var bar = bars[instruction.TradingObject.Index]; // if (bar.ClosePrice <= bar.OpenPrice) // { // continue; // } //} } _instructionsInCurrentPeriod.Add(instruction); } } } for (var i = 0; i < tradingObjects.Length; ++i) { var tradingObject = tradingObjects[i]; var bar = bars[i]; if (bar.Time == Bar.InvalidTime) { continue; } Position[] positions; if (_context.ExistsPosition(tradingObject.Code)) { var temp = _context.GetPositionDetails(tradingObject.Code); positions = temp as Position[] ?? temp.ToArray(); } else { positions = new Position[0]; } // decide if we need to stop loss for some positions. bool isStopLost = false; List <CloseInstruction> stopLossInstructions = new List <CloseInstruction>(); foreach (var position in positions) { var stopLossPrice = double.MaxValue; if (_globalSettings.StopLossByClosePrice) { if (position.StopLossPrice > bar.ClosePrice) { stopLossPrice = Math.Min(bar.ClosePrice, stopLossPrice); } } else { if (position.StopLossPrice > bar.OpenPrice) { stopLossPrice = Math.Min(bar.OpenPrice, stopLossPrice); } else if (position.StopLossPrice > bar.LowestPrice) { stopLossPrice = Math.Min(position.StopLossPrice, stopLossPrice); } } if (stopLossPrice < double.MaxValue) { TradingPrice price = new TradingPrice( TradingPricePeriod.CurrentPeriod, TradingPriceOption.CustomPrice, stopLossPrice); stopLossInstructions.Add(new CloseInstruction(_period, tradingObject, price) { Comments = string.Format("stop loss @{0:0.000}", stopLossPrice), SellingType = SellingType.ByStopLossPrice, StopLossPriceForSelling = stopLossPrice, PositionIdForSell = position.Id, Volume = position.Volume, }); isStopLost = true; } } // decide if we need to exit market for this trading object. bool isExited = false; List <CloseInstruction> exitInstructions = new List <CloseInstruction>(); if (positions.Any()) { foreach (var component in _marketExiting) { var marketExitingResult = component.ShouldExit(tradingObject); if (marketExitingResult.ShouldExit) { exitInstructions.Add(new CloseInstruction(_period, tradingObject, marketExitingResult.Price) { Comments = "Exiting market: " + marketExitingResult.Comments, SellingType = SellingType.ByVolume, Volume = positions.Sum(p => p.Volume), }); isExited = true; } } } if (isStopLost || isExited) { // merge stop loss instructions and exit instructions var instructions = MergeStopLossAndExitInstructions(stopLossInstructions, exitInstructions); if (instructions.Any()) { _instructionsInCurrentPeriod.AddRange(instructions); } // if there is position to stop loss or exit for given trading object, // we will never consider entering market for the object. continue; } // decide if we should enter market if (!positions.Any()) { if (!_globalSettings.AllowEnteringMarketOnlyWhenPriceIncreasing || bar.ClosePrice > bar.OpenPrice) { var allResults = new List <MarketEnteringComponentResult>(); bool canEnter = true; foreach (var component in _marketEntering) { var marketEnteringResult = component.CanEnter(tradingObject); if (!marketEnteringResult.CanEnter) { canEnter = false; break; } allResults.Add(marketEnteringResult); } if (canEnter) { int nonDefaultPriceCount = allResults.Count(r => r.Price != null); if (nonDefaultPriceCount > 1) { throw new InvalidOperationException("there are more than one non-default price for entering market"); } TradingPrice price = nonDefaultPriceCount == 0 ? null : allResults.Where(r => r.Price != null).First().Price; var comments = "Entering market: " + string.Join(";", allResults.Select(r => r.Comments).Where(c => c != null)); var relatedObjects = allResults.Select(r => r.RelatedObject).Where(r => r != null); CreateInstructionForBuying( tradingObject, price, comments, relatedObjects.Count() == 0 ? null : relatedObjects.ToArray()); _context.DumpBarsFromCurrentPeriod(tradingObject); } } } } // update default price for instructions foreach (var instruction in _instructionsInCurrentPeriod) { _context.SetDefaultPriceForInstructionWhenNecessary(instruction); } }
public void Evaluate(ITradingObject tradingObject, Bar bar) { if (bar.Invalid()) { return; } // remember the trading object and bar because the object could be used in AfterEvaulation _barsInPeriod.Add(tradingObject, bar); _codeToTradingObjectMap.Add(tradingObject.Code, tradingObject); // evaluate all components foreach (var component in _components) { component.Evaluate(tradingObject, bar); } string comments = string.Empty; var positions = _context.ExistsPosition(tradingObject.Code) ? _context.GetPositionDetails(tradingObject.Code) : (IEnumerable <Position>) new List <Position>(); // decide if we need to exit market for this trading object. This is the first priorty work if (positions.Count() > 0) { foreach (var component in _marketExiting) { if (component.ShouldExit(tradingObject, out comments)) { _instructionsInCurrentPeriod.Add( new Instruction() { Action = TradingAction.CloseLong, Comments = "market exiting condition triggered. " + comments, SubmissionTime = _period, TradingObject = tradingObject, SellingType = SellingType.ByVolume, Volume = positions.Sum(p => p.Volume), }); return; } } } // decide if we need to stop loss for some positions int totalVolume = 0; foreach (var position in positions) { if (position.StopLossPrice > bar.ClosePrice) { totalVolume += position.Volume; } } if (totalVolume > 0) { _instructionsInCurrentPeriod.Add( new Instruction() { Action = TradingAction.CloseLong, Comments = string.Format("stop loss @{0:0.000}", bar.ClosePrice), SubmissionTime = _period, TradingObject = tradingObject, SellingType = SellingType.ByStopLossPrice, StopLossPriceForSell = bar.ClosePrice, Volume = totalVolume }); return; } // decide if we should enter market if (positions.Count() == 0) { List <string> allComments = new List <string>(_marketEntering.Count + 1); allComments.Add("Entering market. "); bool canEnter = true; foreach (var component in _marketEntering) { string subComments; if (!component.CanEnter(tradingObject, out subComments)) { canEnter = false; break; } allComments.Add(subComments); } if (canEnter) { CreateIntructionForBuying(tradingObject, bar.ClosePrice, string.Join(";", allComments)); } } }