private async void OnOrderBookUpdated(object sender, OrderBookUpdatedEventArgs e) { if (Position.CurrencyPairId != e.CurrencyPairId) { return; } if (Position.IsAwaitingOrderUpdating) { return; } if (Interlocked.Read(ref _positionUpdatingTasksCount) > 0) { return; } Interlocked.Increment(ref _positionUpdatingTasksCount); await _positionUpdatingSemaphore.WaitAsync(); try { if (!Position.IsCompletedPosition) { if (Position.OpenPositionOrder.OrderStateType == OrderStateType.New) { var newPrice = _orderBookLoadingService.GetTopBidPrice(Position.OpenPositionOrder.CurrencyPair, 3); if (newPrice > Position.OpenPositionOrder.Price) { var nextPosition = Position.Clone(); nextPosition.OpenPositionOrder.Price = newPrice; nextPosition = await _tradingPositionService.UpdatePosition(Position, nextPosition, true, OnPositionChanged); if (nextPosition != null) { Position.SyncWithAnotherPosition(nextPosition, true); } } } else if (Position.ClosePositionOrder.OrderStateType == OrderStateType.New) { var newPrice = _orderBookLoadingService.GetBottomAskPrice(Position.OpenPositionOrder.CurrencyPair, 3); if (newPrice > 0 && newPrice < Position.ClosePositionOrder.Price) { var nextPosition = Position.Clone(); nextPosition.ClosePositionOrder.Price = newPrice; nextPosition = await _tradingPositionService.UpdatePosition(Position, nextPosition, true, OnPositionChanged); if (nextPosition != null) { Position.SyncWithAnotherPosition(nextPosition, true); } } } } } finally { _positionUpdatingSemaphore.Release(); } Interlocked.Decrement(ref _positionUpdatingTasksCount); }
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); }
public PendingPositionInfo ProcessMarketPosition(TradingPosition activeTradingPosition) { var settings = _configurationService.GetTradingSettings(); var moment = settings.Moment ?? DateTime.UtcNow; var rsiSettings = new CommonIndicatorSettings { Period = 14 }; var targetPeriodLastCandles = _candleLoadingService.LoadCandles( activeTradingPosition.OpenPositionOrder.CurrencyPair.Id, settings.Period, rsiSettings.Period * 2, 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, 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) }); currentTargetPeriodCandle = targetPeriodLastCandles.Last(); } } 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 minWilliamsRValue = rsiValues.Where(item => item.Value.HasValue).Select(item => item.Value.Value).Min(); if (currentRSIValue?.Value == null) { throw new NoNullAllowedException("No WilliamR values calculated"); } //var higherPeriodMACDSettings = new MACDSettings //{ // EMAPeriod1 = 12, // EMAPeriod2 = 26, // SignalPeriod = 9 //}; //var higherPeriodMACDValues = _indicatorComputingService.ComputeMACD( // higherPeriodLastCandles, // higherPeriodMACDSettings.EMAPeriod1, // higherPeriodMACDSettings.EMAPeriod2, // higherPeriodMACDSettings.SignalPeriod) // .OfType<MACDValue>() // .ToList(); //var higherPeriodCurrentMACDValue = higherPeriodMACDValues.ElementAtOrDefault(higherPeriodMACDValues.Count - 1); var rsiTopBorder = 45; //if (higherPeriodCurrentMACDValue?.MACD > 0 && higherPeriodCurrentMACDValue.Histogram >= 0) // rsiTopBorder = 65; //if (higherPeriodCurrentMACDValue?.MACD > 0 || higherPeriodCurrentMACDValue?.Histogram >= 0) // rsiTopBorder = 60; if (currentRSIValue.Value <= rsiTopBorder && currentRSIValue.Value > 25 && ((activeTradingPosition.OpenPositionOrder.OrderStateType == OrderStateType.Suspended && currentRSIValue.Value > previousRSIValue?.Value) || (activeTradingPosition.OpenPositionOrder.OrderStateType != OrderStateType.Suspended)) && Math.Abs(minWilliamsRValue - currentRSIValue.Value ?? 0) < 20) { var topBidPrice = _orderBookLoadingService.GetTopBidPrice(activeTradingPosition.OpenPositionOrder.CurrencyPair, 3); var openPrice = activeTradingPosition.OpenPositionOrder.Price >= topBidPrice ? activeTradingPosition.OpenPositionOrder.Price : topBidPrice; if (activeTradingPosition.OpenPositionOrder.OrderStateType == OrderStateType.New && activeTradingPosition.OpenPositionOrder.Price != openPrice) { return new UpdateOrderInfo { OpenPrice = openPrice, ClosePrice = new[] { currentTargetPeriodCandle.MaxPrice, activeTradingPosition.ClosePositionOrder.Price }.Max(), CloseStopPrice = new[] { currentTargetPeriodCandle.MinPrice, activeTradingPosition.ClosePositionOrder.StopPrice ?? 0 }.Min(), StopLossPrice = new[] { currentTargetPeriodCandle.MinPrice - targetPeriodLastCandles.Select(candle => (candle.MaxPrice - candle.MinPrice) * 5).Average(), activeTradingPosition.StopLossOrder.StopPrice ?? 0 }.Min() } } ; return(new PendingOrderInfo()); } return(new CancelOrderInfo()); } }