public virtual void AddBuyOrder(IOrderDetails order)
        {
            lock (SyncRoot)
            {
                if (order.Side == OrderSide.Buy && (order.Result == OrderResult.Filled || order.Result == OrderResult.FilledPartially))
                {
                    string  feesPair           = order.FeesCurrency + tradingService.Config.Market;
                    decimal feesPairCurrency   = (feesPair == order.Pair) ? order.Fees : 0;
                    decimal feesMarketCurrency = tradingService.CalculateOrderFees(order);
                    decimal balanceOffset      = -feesMarketCurrency;

                    if (!order.IsNormalized || order.Pair.EndsWith(Constants.Markets.USDT))
                    {
                        balanceOffset -= order.Cost;
                        AddBalance(balanceOffset);
                    }
                    else
                    {
                        string normalizedMarket = tradingService.Exchange.GetPairMarket(order.OriginalPair) == Constants.Markets.USDT ?
                                                  tradingService.Config.Market + tradingService.Exchange.GetPairMarket(order.OriginalPair) :
                                                  tradingService.Exchange.GetPairMarket(order.OriginalPair) + tradingService.Config.Market;

                        if (tradingPairs.TryGetValue(normalizedMarket, out TradingPair normalizedMarketPair))
                        {
                            if (normalizedMarketPair.Cost > order.Cost)
                            {
                                decimal amount = order.Cost / tradingService.GetPrice(normalizedMarket, TradePriceType.Bid);
                                normalizedMarketPair.Amount -= amount;
                                if (normalizedMarketPair.Amount <= 0)
                                {
                                    tradingPairs.TryRemove(normalizedMarket, out normalizedMarketPair);
                                    if (normalizedMarketPair.Amount < 0)
                                    {
                                        loggingService.Error($"Normalized pair {normalizedMarket} has negative amount: {normalizedMarketPair.Amount}");
                                    }
                                }
                            }
                            else
                            {
                                tradingPairs.TryRemove(normalizedMarket, out normalizedMarketPair);
                            }
                        }
                        else
                        {
                            loggingService.Error($"Unable to get normalized pair {normalizedMarketPair}");
                        }
                    }

                    AddOrUpdatePair(order, order.Pair, feesMarketCurrency, feesPairCurrency);
                }
            }
        }
        public void InitiateBuy(BuyOptions options)
        {
            IPairConfig pairConfig = tradingService.GetPairConfig(options.Pair);

            if (!options.ManualOrder && pairConfig.BuyTrailing != 0)
            {
                if (!trailingBuys.ContainsKey(options.Pair))
                {
                    StopTrailingSell(options.Pair);
                    decimal currentPrice  = tradingService.GetPrice(options.Pair);
                    decimal currentMargin = 0;

                    var trailingInfo = new BuyTrailingInfo
                    {
                        BuyOptions         = options,
                        Trailing           = pairConfig.BuyTrailing,
                        TrailingStopMargin = pairConfig.BuyTrailingStopMargin,
                        TrailingStopAction = pairConfig.BuyTrailingStopAction,
                        InitialPrice       = currentPrice,
                        LastTrailingMargin = currentMargin,
                        BestTrailingMargin = currentMargin
                    };

                    if (trailingBuys.TryAdd(options.Pair, trailingInfo))
                    {
                        if (LoggingEnabled)
                        {
                            ITradingPair tradingPair = tradingService.Account.GetTradingPair(options.Pair);
                            loggingService.Info($"Start trailing buy {tradingPair?.FormattedName ?? options.Pair}. " +
                                                $"Price: {currentPrice:0.00000000}, Margin: {currentMargin:0.00}");
                        }
                    }
                }
            }
            else
            {
                orderingService.PlaceBuyOrder(options);
            }
        }
Example #3
0
        public IOrderDetails PlaceBuyOrder(BuyOptions options)
        {
            OrderDetails orderDetails = new OrderDetails();

            tradingService.StopTrailingBuy(options.Pair);
            tradingService.StopTrailingSell(options.Pair);

            try
            {
                ITradingPair tradingPair = tradingService.Account.GetTradingPair(options.Pair, includeDust: true);
                options.Price  = tradingService.GetPrice(options.Pair, TradePriceType.Ask, normalize: false);
                options.Amount = options.Amount ?? (options.MaxCost.Value / (options.Pair.EndsWith(Constants.Markets.USDT) ? 1 : options.Price));
                options.Price  = tradingService.Exchange.ClampOrderPrice(options.Pair, options.Price.Value);
                options.Amount = tradingService.Exchange.ClampOrderAmount(options.Pair, options.Amount.Value);

                if (tradingService.CanBuy(options, out string message))
                {
                    IPairConfig pairConfig = tradingService.GetPairConfig(options.Pair);
                    BuyOrder    buyOrder   = new BuyOrder
                    {
                        Type   = pairConfig.BuyType,
                        Date   = DateTimeOffset.Now,
                        Pair   = options.Pair,
                        Price  = options.Price.Value,
                        Amount = options.Amount.Value
                    };

                    lock (tradingService.Account.SyncRoot)
                    {
                        loggingService.Info($"Place buy order for {tradingPair?.FormattedName ?? options.Pair}. " +
                                            $"Price: {buyOrder.Price:0.00000000}, Amount: {buyOrder.Amount:0.########}, Signal Rule: " + (options.Metadata.SignalRule ?? "N/A"));

                        if (!tradingService.Config.VirtualTrading)
                        {
                            orderDetails = tradingService.Exchange.PlaceOrder(buyOrder) as OrderDetails;
                        }
                        else
                        {
                            string pairMarket = tradingService.Exchange.GetPairMarket(options.Pair);
                            orderDetails = new OrderDetails
                            {
                                OrderId      = DateTime.Now.ToFileTimeUtc().ToString(),
                                Side         = OrderSide.Buy,
                                Result       = OrderResult.Filled,
                                Date         = buyOrder.Date,
                                Pair         = buyOrder.Pair,
                                Amount       = buyOrder.Amount,
                                AmountFilled = buyOrder.Amount,
                                Price        = buyOrder.Price,
                                AveragePrice = buyOrder.Price,
                                Fees         = buyOrder.Amount * buyOrder.Price * tradingService.Config.VirtualTradingFees,
                                FeesCurrency = pairMarket
                            };
                        }

                        NormalizeOrder(orderDetails, TradePriceType.Ask);
                        options.Metadata.TradingRules  = pairConfig.Rules.ToList();
                        options.Metadata.LastBuyMargin = options.Metadata.LastBuyMargin ?? tradingPair?.CurrentMargin ?? null;
                        orderDetails.Metadata          = options.Metadata;
                        tradingService.Account.AddBuyOrder(orderDetails);
                        tradingService.Account.Save();
                        tradingService.LogOrder(orderDetails);

                        decimal fees = tradingService.CalculateOrderFees(orderDetails);
                        tradingPair = tradingService.Account.GetTradingPair(orderDetails.Pair, includeDust: true);
                        loggingService.Info("{@Trade}", orderDetails);
                        loggingService.Info($"Buy order result for {orderDetails.OriginalPair ?? tradingPair.FormattedName}: {orderDetails.Result} ({orderDetails.Message}). " +
                                            $"Price: {orderDetails.AveragePrice:0.00000000}, Amount: {orderDetails.Amount:0.########}, " +
                                            $"Filled: {orderDetails.AmountFilled:0.########}, Cost: {orderDetails.Cost:0.00000000}, Fees: {fees:0.00000000}");
                        notificationService.Notify($"Bought {tradingPair.FormattedName}. Amount: {orderDetails.AmountFilled:0.########}, " +
                                                   $"Price: {orderDetails.AveragePrice:0.00000000}, Cost: {(orderDetails.Cost + fees):0.00000000}");
                    }

                    tradingService.ReapplyTradingRules();
                }
                else
                {
                    loggingService.Info(message);
                }
            }
            catch (Exception ex)
            {
                loggingService.Error($"Unable to place buy order for {options.Pair}", ex);
                notificationService.Notify($"Unable to buy {options.Pair}: {ex.Message}");
            }
            return(orderDetails);
        }
Example #4
0
        public bool CheckConditions(IEnumerable <IRuleCondition> conditions, Dictionary <string, ISignal> signals, double?globalRating, string pair, ITradingPair tradingPair)
        {
            if (conditions != null)
            {
                foreach (var condition in conditions)
                {
                    ISignal signal = null;
                    if (condition.Signal != null && signals.TryGetValue(condition.Signal, out ISignal s))
                    {
                        signal = s;
                    }

                    if (condition.MinPrice != null && (tradingService.GetPrice(pair) < condition.MinPrice) ||
                        condition.MaxPrice != null && (tradingService.GetPrice(pair) > condition.MaxPrice) ||
                        condition.MinSpread != null && (tradingService.Exchange.GetPriceSpread(pair) < condition.MinSpread) ||
                        condition.MaxSpread != null && (tradingService.Exchange.GetPriceSpread(pair) > condition.MaxSpread) ||
                        condition.MinArbitrage != null && tradingService.Exchange.GetArbitrage(pair, tradingService.Config.Market,
                                                                                               condition.ArbitrageMarket != null ? new List <ArbitrageMarket> {
                        condition.ArbitrageMarket.Value
                    } : null, condition.ArbitrageType).Percentage < condition.MinArbitrage ||
                        condition.MaxArbitrage != null && tradingService.Exchange.GetArbitrage(pair, tradingService.Config.Market,
                                                                                               condition.ArbitrageMarket != null ? new List <ArbitrageMarket> {
                        condition.ArbitrageMarket.Value
                    } : null, condition.ArbitrageType).Percentage > condition.MaxArbitrage ||

                        condition.MinVolume != null && (signal == null || signal.Volume == null || signal.Volume < condition.MinVolume) ||
                        condition.MaxVolume != null && (signal == null || signal.Volume == null || signal.Volume > condition.MaxVolume) ||
                        condition.MinVolumeChange != null && (signal == null || signal.VolumeChange == null || signal.VolumeChange < condition.MinVolumeChange) ||
                        condition.MaxVolumeChange != null && (signal == null || signal.VolumeChange == null || signal.VolumeChange > condition.MaxVolumeChange) ||
                        condition.MinPriceChange != null && (signal == null || signal.PriceChange == null || signal.PriceChange < condition.MinPriceChange) ||
                        condition.MaxPriceChange != null && (signal == null || signal.PriceChange == null || signal.PriceChange > condition.MaxPriceChange) ||
                        condition.MinRating != null && (signal == null || signal.Rating == null || signal.Rating < condition.MinRating) ||
                        condition.MaxRating != null && (signal == null || signal.Rating == null || signal.Rating > condition.MaxRating) ||
                        condition.MinRatingChange != null && (signal == null || signal.RatingChange == null || signal.RatingChange < condition.MinRatingChange) ||
                        condition.MaxRatingChange != null && (signal == null || signal.RatingChange == null || signal.RatingChange > condition.MaxRatingChange) ||
                        condition.MinVolatility != null && (signal == null || signal.Volatility == null || signal.Volatility < condition.MinVolatility) ||
                        condition.MaxVolatility != null && (signal == null || signal.Volatility == null || signal.Volatility > condition.MaxVolatility) ||
                        condition.MinGlobalRating != null && (globalRating == null || globalRating < condition.MinGlobalRating) ||
                        condition.MaxGlobalRating != null && (globalRating == null || globalRating > condition.MaxGlobalRating) ||
                        condition.Pairs != null && (pair == null || !condition.Pairs.Contains(pair)) ||
                        condition.NotPairs != null && (pair == null || condition.NotPairs.Contains(pair)) ||

                        condition.MinAge != null && (tradingPair == null || tradingPair.CurrentAge < condition.MinAge / Application.Speed) ||
                        condition.MaxAge != null && (tradingPair == null || tradingPair.CurrentAge > condition.MaxAge / Application.Speed) ||
                        condition.MinLastBuyAge != null && (tradingPair == null || tradingPair.LastBuyAge < condition.MinLastBuyAge / Application.Speed) ||
                        condition.MaxLastBuyAge != null && (tradingPair == null || tradingPair.LastBuyAge > condition.MaxLastBuyAge / Application.Speed) ||
                        condition.MinMargin != null && (tradingPair == null || tradingPair.CurrentMargin < condition.MinMargin) ||
                        condition.MaxMargin != null && (tradingPair == null || tradingPair.CurrentMargin > condition.MaxMargin) ||
                        condition.MinMarginChange != null && (tradingPair == null || tradingPair.Metadata.LastBuyMargin == null || (tradingPair.CurrentMargin - tradingPair.Metadata.LastBuyMargin) < condition.MinMarginChange) ||
                        condition.MaxMarginChange != null && (tradingPair == null || tradingPair.Metadata.LastBuyMargin == null || (tradingPair.CurrentMargin - tradingPair.Metadata.LastBuyMargin) > condition.MaxMarginChange) ||
                        condition.MinAmount != null && (tradingPair == null || tradingPair.Amount < condition.MinAmount) ||
                        condition.MaxAmount != null && (tradingPair == null || tradingPair.Amount > condition.MaxAmount) ||
                        condition.MinCost != null && (tradingPair == null || tradingPair.CurrentCost < condition.MinCost) ||
                        condition.MaxCost != null && (tradingPair == null || tradingPair.CurrentCost > condition.MaxCost) ||
                        condition.MinDCALevel != null && (tradingPair == null || tradingPair.DCALevel < condition.MinDCALevel) ||
                        condition.MaxDCALevel != null && (tradingPair == null || tradingPair.DCALevel > condition.MaxDCALevel) ||
                        condition.SignalRules != null && (tradingPair == null || tradingPair.Metadata.SignalRule == null || !condition.SignalRules.Contains(tradingPair.Metadata.SignalRule)) ||
                        condition.NotSignalRules != null && (tradingPair == null || tradingPair.Metadata.SignalRule == null || condition.NotSignalRules.Contains(tradingPair.Metadata.SignalRule)))
                    {
                        return(false);
                    }
                }
            }
            return(true);
        }
        public MarketPairsResponse MarketPairs(MarketPairsRequest request)
        {
            if (request?.SignalsFilter == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            ICoreService    coreService    = Application.Resolve <ICoreService>();
            ITradingService tradingService = Application.Resolve <ITradingService>();
            ISignalsService signalsService = Application.Resolve <ISignalsService>();

            IEnumerable <ISignal> allSignals = signalsService.GetAllSignals();

            if (allSignals != null)
            {
                if (request.SignalsFilter.Count > 0)
                {
                    allSignals = allSignals.Where(s => request.SignalsFilter.Contains(s.Name));
                }

                var groupedSignals = allSignals.GroupBy(s => s.Pair).ToDictionary(g => g.Key, g => g.AsEnumerable());

                IEnumerable <MarketPairApiModel> marketPairs = from signalGroup in groupedSignals
                                                               let pair = signalGroup.Key
                                                                          let pairConfig = tradingService.GetPairConfig(pair)
                                                                                           select new MarketPairApiModel
                {
                    Name             = pair,
                    TradingViewName  = $"{tradingService.Config.Exchange.ToUpperInvariant()}:{pair}",
                    VolumeList       = signalGroup.Value.Select(s => new NameValue <long?>(s.Name, s.Volume)),
                    VolumeChangeList = signalGroup.Value.Select(s => new NameValue <double?>(s.Name, s.VolumeChange)),
                    Price            = tradingService.GetPrice(pair).ToString("0.00000000"),
                    PriceChangeList  = signalGroup.Value.Select(s => new NameValue <decimal?>(s.Name, s.PriceChange)),
                    RatingList       = signalGroup.Value.Select(s => new NameValue <double?>(s.Name, s.Rating)),
                    RatingChangeList = signalGroup.Value.Select(s => new NameValue <double?>(s.Name, s.RatingChange)),
                    VolatilityList   = signalGroup.Value.Select(s => new NameValue <double?>(s.Name, s.Volatility)),
                    Spread           = tradingService.Exchange.GetPriceSpread(pair).ToString("0.00"),
                    ArbitrageList    = from market in Enum.GetNames(typeof(ArbitrageMarket)).Where(m => m != tradingService.Config.Market)
                                       let arbitrage = tradingService.Exchange.GetArbitrage(pair, tradingService.Config.Market, new List <ArbitrageMarket> {
                        Enum.Parse <ArbitrageMarket>(market)
                    })
                                                       select new ArbitrageInfo
                    {
                        Name      = $"{arbitrage.Market}-{arbitrage.Type.ToString()[0]}",
                        Arbitrage = arbitrage.IsAssigned ? arbitrage.Percentage.ToString("0.00") : "N/A"
                    },
                    SignalRules    = signalsService.GetTrailingInfo(pair)?.Select(ti => ti.Rule.Name) ?? Array.Empty <string>(),
                    HasTradingPair = tradingService.Account.HasTradingPair(pair),
                    Config         = pairConfig
                };

                return(new MarketPairsResponse
                {
                    MarketPairs = marketPairs.ToList()
                });
            }
            else
            {
                return(null);
            }
        }