public void SetDefaultPriceForInstructionWhenNecessary(Instruction instruction) { if (_settings == null) { return; } if (instruction.Price == null) { TradingPrice price; if (instruction.Action == TradingAction.OpenLong) { price = new TradingPrice(_settings.OpenLongPricePeriod, _settings.OpenLongPriceOption, 0.0); } else if (instruction.Action == TradingAction.CloseLong) { price = new TradingPrice(_settings.CloseLongPricePeriod, _settings.CloseLongPriceOption, 0.0); } else { throw new InvalidOperationException( string.Format("unsupported action {0}", instruction.Action)); } instruction.Price = price; } }
private void CreateInstructionForBuying(ITradingObject tradingObject, TradingPrice price, string comments, object[] relatedObjects) { _instructionsInCurrentPeriod.Add( new OpenInstruction(_period, tradingObject, price) { Comments = comments, Volume = 0, // will be filled in EstimateStoplossAndSizeOfNewPosition() StopLossGapForBuying = 0.0, // will be filled in EstimateStoplossAndSizeOfNewPosition() StopLossPriceForBuying = 0.0, // will be filled in EstimateStoplossAndSizeOfNewPosition() RelatedObjects = relatedObjects }); }
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 TradingStrategyComponentResult() { Comments = string.Empty; Price = null; }