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);
                }
            }
        }
예제 #2
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);
        }