private async void OnCandlesUpdated(object sender, CandlesUpdatedEventArgs e) { await _positionUpdatingSemaphore.WaitAsync(); try { if (e.Period != _workingCandlePeriod || Position.CurrencyPairId != e.CurrencyPairId) { return; } if (Position.IsAwaitingOrderUpdating) { return; } if (Position.IsCompletedPosition) { return; } var nextPosition = Position.Clone(); if (Position.IsOpenPosition) { var marketInfo = _marketOpenPositionAnalysisService.ProcessMarketPosition(Position); if (marketInfo.PositionType == OpenMarketPositionType.UpdateOrder) { nextPosition.ChangePosition((UpdateClosePositionInfo)marketInfo); } else if (marketInfo.PositionType == OpenMarketPositionType.FixStopLoss) { nextPosition.ChangePosition((FixStopLossInfo)marketInfo); } else if (marketInfo.PositionType == OpenMarketPositionType.Suspend) { nextPosition.ChangePosition((SuspendPositionInfo)marketInfo); } if (marketInfo.PositionType != OpenMarketPositionType.Hold) { var updatedPosition = await _tradingPositionService.UpdatePosition(Position, nextPosition, true, OnPositionChanged); if (updatedPosition != null) { Position.SyncWithAnotherPosition(updatedPosition, true); } } } else if (Position.IsPendingPosition) { var marketInfo = _marketPendingPositionAnalysisService.ProcessMarketPosition(Position); if (marketInfo.PositionType == PendingMarketPositionType.UpdateOrder) { nextPosition.ChangePosition((UpdateOrderInfo)marketInfo); } else if (marketInfo.PositionType == PendingMarketPositionType.CancelOrder) { nextPosition.ChangePosition((CancelOrderInfo)marketInfo); } if (marketInfo.PositionType != PendingMarketPositionType.Hold) { var updatedPosition = await _tradingPositionService.UpdatePosition(Position, nextPosition, true, OnPositionChanged); if (updatedPosition != null) { Position.SyncWithAnotherPosition(updatedPosition, true); } } } else { throw new BusinessException("Unexpected position state") { Details = $"Order pair: {JsonConvert.SerializeObject(Position)}" } }; } finally { _positionUpdatingSemaphore.Release(); } }
private async Task RunTradingIteration() { try { var onPositionChangedCallback = new Action <PositionChangedEventArgs>(positionChangedEventArgs => _tradingEventsObserver.RaisePositionChanged(positionChangedEventArgs)); await _tradingPositionService.SyncExistingPositionsWithStock(onPositionChangedCallback); var tradingPositions = await _tradingPositionService.GetOpenPositions(); if (tradingPositions.Any()) { foreach (var tradingPosition in tradingPositions) { var nextPosition = tradingPosition.Clone(); if (tradingPosition.IsOpenPosition) { var marketInfo = _marketOpenPositionAnalysisService.ProcessMarketPosition(tradingPosition); if (marketInfo.PositionType == OpenMarketPositionType.UpdateOrder) { nextPosition.ChangePosition((UpdateClosePositionInfo)marketInfo); } else if (marketInfo.PositionType == OpenMarketPositionType.FixStopLoss) { nextPosition.ChangePosition((FixStopLossInfo)marketInfo); } else if (marketInfo.PositionType == OpenMarketPositionType.Suspend) { nextPosition.ChangePosition((SuspendPositionInfo)marketInfo); } if (marketInfo.PositionType != OpenMarketPositionType.Hold) { var updatedPosition = await _tradingPositionService.UpdatePosition(tradingPosition, nextPosition, true, onPositionChangedCallback); if (updatedPosition != null) { tradingPosition.SyncWithAnotherPosition(updatedPosition, true); } } } else if (tradingPosition.IsPendingPosition) { var marketInfo = _marketPendingPositionAnalysisService.ProcessMarketPosition(tradingPosition); if (marketInfo.PositionType == PendingMarketPositionType.UpdateOrder) { nextPosition.ChangePosition((UpdateOrderInfo)marketInfo); } else if (marketInfo.PositionType == PendingMarketPositionType.CancelOrder) { nextPosition.ChangePosition((CancelOrderInfo)marketInfo); } if (marketInfo.PositionType != PendingMarketPositionType.Hold) { var updatedPosition = await _tradingPositionService.UpdatePosition(tradingPosition, nextPosition, true, onPositionChangedCallback); if (updatedPosition != null) { tradingPosition.SyncWithAnotherPosition(updatedPosition, true); } } } else { throw new BusinessException("Unexpected position state") { Details = $"Order pair: {JsonConvert.SerializeObject(tradingPosition)}" } }; } } { var tradingSettings = _configurationService.GetTradingSettings(); var allCurrencyPairs = await _stockRestConnector.GetCurrencyPairs(); var baseCurrencyPairs = allCurrencyPairs .Where(item => tradingSettings.QuoteCurrencies.Any(currencyId => String.Equals(item.QuoteCurrencyId, currencyId, StringComparison.OrdinalIgnoreCase)) && !tradingPositions.Any(orderPair => String.Equals(orderPair.OpenPositionOrder.CurrencyPair.BaseCurrencyId, item.BaseCurrencyId)) ); var allTickers = await _stockRestConnector.GetTickers(); var tradingTickers = allTickers .Where(tickerItem => baseCurrencyPairs.Any(currencyPairItem => String.Equals(tickerItem.CurrencyPairId, currencyPairItem.Id))) .Where(tickerItem => { var tickerCurrencyPair = baseCurrencyPairs.First(currencyPairItem => String.Equals(tickerItem.CurrencyPairId, currencyPairItem.Id)); decimal volumeToCompare; if (String.Equals(tickerCurrencyPair.QuoteCurrencyId, Constants.BTC, StringComparison.OrdinalIgnoreCase)) { volumeToCompare = tickerItem.VolumeInQuoteCurrency; } else { var btcConvertFactor = 0m; var requestCurrencyPair = allCurrencyPairs.FirstOrDefault(item => String.Equals(tickerCurrencyPair.QuoteCurrencyId, item.QuoteCurrencyId, StringComparison.OrdinalIgnoreCase) && String.Equals(item.BaseCurrencyId, Constants.BTC, StringComparison.OrdinalIgnoreCase)); if (requestCurrencyPair != null) { btcConvertFactor = allTickers.First(item => String.Equals(item.CurrencyPairId, requestCurrencyPair.Id, StringComparison.OrdinalIgnoreCase)).LastPrice; } else { requestCurrencyPair = allCurrencyPairs.FirstOrDefault(item => String.Equals(tickerCurrencyPair.QuoteCurrencyId, item.BaseCurrencyId, StringComparison.OrdinalIgnoreCase) && String.Equals(item.QuoteCurrencyId, Constants.BTC, StringComparison.OrdinalIgnoreCase)); if (requestCurrencyPair != null) { btcConvertFactor = 1 / allTickers.First(item => String.Equals(item.CurrencyPairId, requestCurrencyPair.Id, StringComparison.OrdinalIgnoreCase)).LastPrice; } } volumeToCompare = btcConvertFactor > 0 ? tickerItem.VolumeInQuoteCurrency / btcConvertFactor : 0; } return(volumeToCompare > tradingSettings.MinCurrencyPairTradingVolumeInBTC); }) .ToList(); foreach (var currencyPair in baseCurrencyPairs.Where(currencyPairItem => tradingTickers.Any(tickerItem => String.Equals(tickerItem.CurrencyPairId, currencyPairItem.Id, StringComparison.OrdinalIgnoreCase))).ToList()) { var tradingBalance = await _stockRestConnector.GetTradingBalance(currencyPair.QuoteCurrencyId); if (tradingBalance?.Available <= 0) { continue; } var marketInfo = _marketNewPositionAnalysisService.ProcessMarketPosition(currencyPair); if (marketInfo.PositionType != NewMarketPositionType.Wait) { var newPosition = await _tradingPositionService.OpenPosition((NewOrderPositionInfo)marketInfo); newPosition = await _tradingPositionService.UpdatePosition(null, newPosition, true, onPositionChangedCallback); _tradingEventsObserver.RaisePositionChanged(TradingEventType.NewPosition, newPosition); break; } } } } catch (BusinessWarning e) { _loggingService.LogAction(new ErrorAction { ExceptionType = e.GetType().ToString(), Message = e.Message, Details = e.Details, StackTrace = e.StackTrace }); } catch (BusinessException e) { _loggingService.LogAction(new ErrorAction { ExceptionType = e.GetType().ToString(), Message = e.Message, Details = e.Details, StackTrace = e.StackTrace }); OnException(new UnhandledExceptionEventArgs(e, false)); } catch (ParseResponseException e) { _loggingService.LogAction(new ErrorAction { ExceptionType = e.GetType().ToString(), Message = e.Message, Details = e.SourceData, StackTrace = e.StackTrace }); OnException(new UnhandledExceptionEventArgs(e, false)); } catch (Exception e) { _loggingService.LogAction(new ErrorAction { ExceptionType = e.GetType().ToString(), Message = e.Message, StackTrace = e.StackTrace }); OnException(new UnhandledExceptionEventArgs(e, false)); } }