public static void ChangePosition(this TradingPosition tradingPosition, UpdateClosePositionInfo marketInfo) { var now = DateTime.UtcNow; tradingPosition.ClosePositionOrder.Price = marketInfo.ClosePrice; if (tradingPosition.ClosePositionOrder.OrderStateType == OrderStateType.Pending || tradingPosition.ClosePositionOrder.OrderStateType == OrderStateType.Suspended) { tradingPosition.ClosePositionOrder.OrderStateType = OrderStateType.Suspended; tradingPosition.ClosePositionOrder.StopPrice = marketInfo.CloseStopPrice; tradingPosition.ClosePositionOrder.OrderType = OrderType.StopLimit; } else { tradingPosition.ClosePositionOrder.OrderStateType = OrderStateType.New; tradingPosition.ClosePositionOrder.StopPrice = null; tradingPosition.ClosePositionOrder.OrderType = OrderType.Limit; } tradingPosition.ClosePositionOrder.Updated = now; tradingPosition.StopLossOrder.Price = 0; tradingPosition.StopLossOrder.StopPrice = marketInfo.StopLossPrice; tradingPosition.StopLossOrder.Updated = now; }
public OpenPositionInfo ProcessMarketPosition(TradingPosition activeTradingPosition) { var settings = _configurationService.GetTradingSettings(); var moment = settings.Moment ?? DateTime.UtcNow; var initialPositionInfo = new UpdateClosePositionInfo { ClosePrice = activeTradingPosition.ClosePositionOrder.Price, CloseStopPrice = activeTradingPosition.ClosePositionOrder.StopPrice ?? 0, StopLossPrice = activeTradingPosition.StopLossOrder.StopPrice ?? 0 }; OpenPositionInfo newPositionInfo = null; var rsiSettings = new CommonIndicatorSettings { Period = 10 }; var higherPeriodMACDSettings = new MACDSettings { EMAPeriod1 = 12, EMAPeriod2 = 26, SignalPeriod = 9 }; var candleRangeSize = new[] { rsiSettings.Period + 2, 2 }.Max(); var targetPeriodLastCandles = _candleLoadingService.LoadCandles( activeTradingPosition.OpenPositionOrder.CurrencyPair.Id, settings.Period, candleRangeSize, moment) .ToList(); if (!targetPeriodLastCandles.Any()) { throw new NoNullAllowedException("No candles loaded"); } var currentTargetPeriodCandle = targetPeriodLastCandles.Last(); var higherPeriodLastCandles = _candleLoadingService.LoadCandles( activeTradingPosition.OpenPositionOrder.CurrencyPair.Id, settings.Period.GetHigherFramePeriod(), rsiSettings.Period, moment) .ToList(); if (!higherPeriodLastCandles.Any()) { throw new NoNullAllowedException("No candles loaded"); } var lowerPeriodCandles = _candleLoadingService.LoadCandles( activeTradingPosition.OpenPositionOrder.CurrencyPair.Id, settings.Period.GetLowerFramePeriod(), rsiSettings.Period + 1, moment) .ToList(); if (!lowerPeriodCandles.Any()) { throw new NoNullAllowedException("No candles loaded"); } var currentLowPeriodCandle = lowerPeriodCandles.Last(); if (currentTargetPeriodCandle.Moment < currentLowPeriodCandle.Moment) { var lastLowPeriodCandles = lowerPeriodCandles .Where(item => item.Moment > currentTargetPeriodCandle.Moment) .OrderBy(item => item.Moment) .ToList(); if (lastLowPeriodCandles.Any()) { targetPeriodLastCandles.Add(new Candle { Moment = lastLowPeriodCandles.Last().Moment, MaxPrice = lastLowPeriodCandles.Max(item => item.MaxPrice), MinPrice = lastLowPeriodCandles.Min(item => item.MinPrice), OpenPrice = lastLowPeriodCandles.First().OpenPrice, ClosePrice = lastLowPeriodCandles.Last().ClosePrice, VolumeInBaseCurrency = lastLowPeriodCandles.Sum(item => item.VolumeInBaseCurrency), VolumeInQuoteCurrency = lastLowPeriodCandles.Sum(item => item.VolumeInQuoteCurrency) }); } } var candlesCount = targetPeriodLastCandles.Count; var period = (candlesCount - 2) > rsiSettings.Period ? rsiSettings.Period : candlesCount - 2; var rsiValues = _indicatorComputingService.ComputeRelativeStrengthIndex( targetPeriodLastCandles, period) .OfType <SimpleIndicatorValue>() .ToList(); var currentRSIValue = rsiValues.ElementAtOrDefault(rsiValues.Count - 1); var previousRSIValue = rsiValues.ElementAtOrDefault(rsiValues.Count - 2); var higherPeriodMACDValues = _indicatorComputingService.ComputeMACD( higherPeriodLastCandles, higherPeriodMACDSettings.EMAPeriod1, higherPeriodMACDSettings.EMAPeriod2, higherPeriodMACDSettings.SignalPeriod) .OfType <MACDValue>() .ToList(); var higherPeriodCurrentMACDValue = higherPeriodMACDValues.ElementAtOrDefault(higherPeriodMACDValues.Count - 1); var rsiBottomBorder = 70; if (higherPeriodCurrentMACDValue?.MACD < 0 && higherPeriodCurrentMACDValue.Histogram < 0) { rsiBottomBorder = 50; } if (higherPeriodCurrentMACDValue?.MACD < 0 || higherPeriodCurrentMACDValue?.Histogram < 0) { rsiBottomBorder = 60; } if ((currentRSIValue?.Value >= rsiBottomBorder && currentRSIValue.Value < 80 && currentRSIValue.Value < previousRSIValue?.Value) || (activeTradingPosition.ClosePositionOrder.OrderStateType != OrderStateType.Pending && currentRSIValue?.Value < 40 && currentRSIValue.Value < previousRSIValue?.Value)) { var updatePositionInfo = new UpdateClosePositionInfo { StopLossPrice = initialPositionInfo.StopLossPrice }; if (activeTradingPosition.ClosePositionOrder.OrderStateType == OrderStateType.Pending || activeTradingPosition.ClosePositionOrder.OrderStateType == OrderStateType.Suspended) { var bottomMeaningfulAskPrice = _orderBookLoadingService.GetBottomMeaningfulAskPrice(activeTradingPosition.ClosePositionOrder.CurrencyPair); updatePositionInfo.ClosePrice = bottomMeaningfulAskPrice - activeTradingPosition.ClosePositionOrder.CurrencyPair.TickSize; var topBidPrice = _orderBookLoadingService.GetTopBidPrice(activeTradingPosition.ClosePositionOrder.CurrencyPair, 3); updatePositionInfo.CloseStopPrice = !activeTradingPosition.ClosePositionOrder.StopPrice.HasValue || topBidPrice >= activeTradingPosition.ClosePositionOrder.StopPrice ? topBidPrice : activeTradingPosition.ClosePositionOrder.StopPrice.Value; } else { var bottomAskPrice = _orderBookLoadingService.GetBottomAskPrice(activeTradingPosition.ClosePositionOrder.CurrencyPair, 3); updatePositionInfo.ClosePrice = activeTradingPosition.ClosePositionOrder.Price <= bottomAskPrice ? activeTradingPosition.ClosePositionOrder.Price : bottomAskPrice; updatePositionInfo.CloseStopPrice = 0; } if (updatePositionInfo.ClosePrice != initialPositionInfo.ClosePrice || updatePositionInfo.CloseStopPrice != initialPositionInfo.CloseStopPrice) { newPositionInfo = updatePositionInfo; } } else if (activeTradingPosition.ClosePositionOrder.OrderStateType != OrderStateType.Pending && currentRSIValue?.Value < rsiBottomBorder && currentRSIValue.Value > previousRSIValue?.Value) { newPositionInfo = new SuspendPositionInfo(); } else if (activeTradingPosition.ClosePositionOrder.OrderStateType != OrderStateType.Pending && currentRSIValue?.Value >= 80) { newPositionInfo = new SuspendPositionInfo(); } if (newPositionInfo == null && currentTargetPeriodCandle.Moment >= currentLowPeriodCandle.Moment && currentRSIValue?.Value > previousRSIValue?.Value) { var fixStopLossInfo = new FixStopLossInfo { StopLossPrice = initialPositionInfo.StopLossPrice }; ComputeStopLossUsingParabolicSAR( fixStopLossInfo, activeTradingPosition.StopLossOrder, currentTargetPeriodCandle); if (fixStopLossInfo.StopLossPrice != initialPositionInfo.StopLossPrice) { newPositionInfo = fixStopLossInfo; } } if (newPositionInfo == null) { return(new HoldPositionInfo()); } return(newPositionInfo); }