Esempio n. 1
0
        public double CalculateLotSize(double price, string currency, string fullquotename, double risk = 0)
        {
            var MySymbolConf      = this.Pairs.Where(y => y.Name == fullquotename).First();
            var MinimalLot        = MySymbolConf.Filters.OfType <BinanceSymbolLotSizeFilter>().FirstOrDefault();
            var minNotionalFilter = MySymbolConf.Filters.OfType <BinanceSymbolMinNotionalFilter>().SingleOrDefault();

            var PriceSize = MySymbolConf.Filters.OfType <BinanceSymbolPriceFilter>().FirstOrDefault();

            var AdjustedPrice   = BinanceHelpers.ClampPrice(PriceSize.MinPrice, PriceSize.MaxPrice, PriceSize.TickSize, price.ChangeType <decimal>());
            var definedsize     = (AvailableForOrder(currency) / price).ChangeType <decimal>();
            var AdjustedLotSize = BinanceHelpers.ClampQuantity(MinimalLot.MinQuantity, MinimalLot.MaxQuantity, MinimalLot.StepSize, (AvailableForOrder(currency) / price).ChangeType <decimal>()).ChangeType <double>();
            var Validate        = AdjustedLotSize * price > minNotionalFilter.MinNotional.ChangeType <double>();

            if (Validate)
            {
                return(AdjustedLotSize);
            }
            else
            {
                return(minNotionalFilter.MinNotional.ChangeType <double>());
            }
        }
        internal override async Task <BinanceTradeRuleResult> CheckTradeRules(string symbol, decimal?quantity, decimal?price, decimal?stopPrice, OrderType type, CancellationToken ct)
        {
            var outputQuantity  = quantity;
            var outputPrice     = price;
            var outputStopPrice = stopPrice;

            if (BaseClient.TradeRulesBehaviour == TradeRulesBehaviour.None)
            {
                return(BinanceTradeRuleResult.CreatePassed(outputQuantity, outputPrice, outputStopPrice));
            }

            if (ExchangeInfo == null || LastExchangeInfoUpdate == null || (DateTime.UtcNow - LastExchangeInfoUpdate.Value).TotalMinutes > BaseClient.TradeRulesUpdateInterval.TotalMinutes)
            {
                await System.GetExchangeInfoAsync(ct).ConfigureAwait(false);
            }

            if (ExchangeInfo == null)
            {
                return(BinanceTradeRuleResult.CreateFailed("Unable to retrieve trading rules, validation failed"));
            }

            var symbolData = ExchangeInfo.Symbols.SingleOrDefault(s => string.Equals(s.Name, symbol, StringComparison.CurrentCultureIgnoreCase));

            if (symbolData == null)
            {
                return(BinanceTradeRuleResult.CreateFailed($"Trade rules check failed: Symbol {symbol} not found"));
            }

            if (!symbolData.OrderTypes.Contains(type))
            {
                return(BinanceTradeRuleResult.CreateFailed($"Trade rules check failed: {type} order type not allowed for {symbol}"));
            }

            if (symbolData.LotSizeFilter != null || (symbolData.MarketLotSizeFilter != null && type == OrderType.Market))
            {
                var minQty   = symbolData.LotSizeFilter?.MinQuantity;
                var maxQty   = symbolData.LotSizeFilter?.MaxQuantity;
                var stepSize = symbolData.LotSizeFilter?.StepSize;
                if (type == OrderType.Market && symbolData.MarketLotSizeFilter != null)
                {
                    minQty = symbolData.MarketLotSizeFilter.MinQuantity;
                    if (symbolData.MarketLotSizeFilter.MaxQuantity != 0)
                    {
                        maxQty = symbolData.MarketLotSizeFilter.MaxQuantity;
                    }

                    if (symbolData.MarketLotSizeFilter.StepSize != 0)
                    {
                        stepSize = symbolData.MarketLotSizeFilter.StepSize;
                    }
                }

                if (minQty.HasValue && quantity.HasValue)
                {
                    outputQuantity = BinanceHelpers.ClampQuantity(minQty.Value, maxQty !.Value, stepSize !.Value, quantity.Value);
                    if (outputQuantity != quantity.Value)
                    {
                        if (BaseClient.TradeRulesBehaviour == TradeRulesBehaviour.ThrowError)
                        {
                            return(BinanceTradeRuleResult.CreateFailed($"Trade rules check failed: LotSize filter failed. Original quantity: {quantity}, Closest allowed: {outputQuantity}"));
                        }

                        _log.Write(LogVerbosity.Info, $"Quantity clamped from {quantity} to {outputQuantity}");
                    }
                }
            }

            if (price == null)
            {
                return(BinanceTradeRuleResult.CreatePassed(outputQuantity, null, outputStopPrice));
            }

            if (symbolData.PriceFilter != null)
            {
                if (symbolData.PriceFilter.MaxPrice != 0 && symbolData.PriceFilter.MinPrice != 0)
                {
                    outputPrice = BinanceHelpers.ClampPrice(symbolData.PriceFilter.MinPrice, symbolData.PriceFilter.MaxPrice, price.Value);
                    if (outputPrice != price)
                    {
                        if (BaseClient.TradeRulesBehaviour == TradeRulesBehaviour.ThrowError)
                        {
                            return(BinanceTradeRuleResult.CreateFailed($"Trade rules check failed: Price filter max/min failed. Original price: {price}, Closest allowed: {outputPrice}"));
                        }

                        _log.Write(LogVerbosity.Info, $"price clamped from {price} to {outputPrice}");
                    }

                    if (stopPrice != null)
                    {
                        outputStopPrice = BinanceHelpers.ClampPrice(symbolData.PriceFilter.MinPrice,
                                                                    symbolData.PriceFilter.MaxPrice, stopPrice.Value);
                        if (outputStopPrice != stopPrice)
                        {
                            if (BaseClient.TradeRulesBehaviour == TradeRulesBehaviour.ThrowError)
                            {
                                return(BinanceTradeRuleResult.CreateFailed(
                                           $"Trade rules check failed: Stop price filter max/min failed. Original stop price: {stopPrice}, Closest allowed: {outputStopPrice}"));
                            }

                            _log.Write(LogVerbosity.Info,
                                       $"Stop price clamped from {stopPrice} to {outputStopPrice} based on price filter");
                        }
                    }
                }

                if (symbolData.PriceFilter.TickSize != 0)
                {
                    var beforePrice = outputPrice;
                    outputPrice = BinanceHelpers.FloorPrice(symbolData.PriceFilter.TickSize, price.Value);
                    if (outputPrice != beforePrice)
                    {
                        if (BaseClient.TradeRulesBehaviour == TradeRulesBehaviour.ThrowError)
                        {
                            return(BinanceTradeRuleResult.CreateFailed($"Trade rules check failed: Price filter tick failed. Original price: {price}, Closest allowed: {outputPrice}"));
                        }

                        _log.Write(LogVerbosity.Info, $"price rounded from {beforePrice} to {outputPrice}");
                    }

                    if (stopPrice != null)
                    {
                        var beforeStopPrice = outputStopPrice;
                        outputStopPrice = BinanceHelpers.FloorPrice(symbolData.PriceFilter.TickSize, stopPrice.Value);
                        if (outputStopPrice != beforeStopPrice)
                        {
                            if (BaseClient.TradeRulesBehaviour == TradeRulesBehaviour.ThrowError)
                            {
                                return(BinanceTradeRuleResult.CreateFailed(
                                           $"Trade rules check failed: Stop price filter tick failed. Original stop price: {stopPrice}, Closest allowed: {outputStopPrice}"));
                            }

                            _log.Write(LogVerbosity.Info,
                                       $"Stop price floored from {beforeStopPrice} to {outputStopPrice} based on price filter");
                        }
                    }
                }
            }

            return(BinanceTradeRuleResult.CreatePassed(outputQuantity, outputPrice, outputStopPrice));
        }
        public IRuleResult RuleExecuted(Solbot solbot)
        {
            var result  = false;
            var message = string.Empty;

            if (solbot.Communication.StopLoss.IsReady)
            {
                WebCallResult <BinancePlacedOrder> stopLossOrderResult = null;

                var quantity = BinanceHelpers.ClampQuantity(solbot.Communication.Symbol.MinQuantity, solbot.Communication.Symbol.MaxQuantity, solbot.Communication.Symbol.StepSize, solbot.Communication.AvailableAsset.Base);

                var minNotional = quantity * solbot.Communication.Price.Current;

                if (minNotional > solbot.Communication.Symbol.MinNotional)
                {
                    stopLossOrderResult = _binanceClient.Spot.Order.PlaceOrder(
                        solbot.Strategy.AvailableStrategy.Symbol,
                        OrderSide.Sell,
                        OrderType.Market,
                        quantity: quantity);
                }
                else
                {
                    message = "not enough";
                }

                if (!(stopLossOrderResult is null))
                {
                    result = stopLossOrderResult.Success;

                    if (stopLossOrderResult.Success)
                    {
                        solbot.Actions.BoughtPrice     = 0;
                        solbot.Actions.StopLossReached = true;

                        Logger.Info(LogGenerator.TradeResultStart($"{stopLossOrderResult.Data.OrderId}"));

                        var prices      = new List <decimal>();
                        var quantityAll = new List <decimal>();
                        var commission  = new List <decimal>();

                        if (stopLossOrderResult.Data.Fills.AnyAndNotNull())
                        {
                            foreach (var item in stopLossOrderResult.Data.Fills)
                            {
                                Logger.Info(LogGenerator.TradeResult(MarketOrder, item));
                                prices.Add(item.Price);
                                quantityAll.Add(item.Quantity);
                                commission.Add(item.Commission);
                            }
                        }

                        Logger.Info(LogGenerator.TradeResultEnd($"{stopLossOrderResult.Data.OrderId}", prices.Average(), quantityAll.Sum(), commission.Sum()));

                        _pushOverNotificationService.Send(
                            LogGenerator.NotificationTitle(EnvironmentType.PRODUCTION, MarketOrder, solbot.Strategy.AvailableStrategy.Symbol),
                            LogGenerator.NotificationMessage(
                                solbot.Communication.Average.Current,
                                solbot.Communication.Price.Current,
                                solbot.Communication.StopLoss.Change));
                    }
                    else
                    {
                        Logger.Warn(stopLossOrderResult.Error.Message);
                    }
                }
            }

            return(new MarketRuleResult()
            {
                Success = result,
                Message = result
                    ? LogGenerator.OrderMarketSuccess(MarketOrder)
                    : LogGenerator.OrderMarketError(MarketOrder, message)
            });
        }
Esempio n. 4
0
        public void Sell(IPair SourceCandle, string TargetPair, OrderType TypeOforder, Guid Operation, decimal _quantity = 0)
        {
            Console.WriteLine("Order SVC starting for sell : {0}", TargetPair);
            try
            {
                var pivotalbuy        = SourceCandle.Candle.Close.ChangeType <decimal>();
                var MySymbolConf      = this.Pairs.Where(y => y.Name == TargetPair).First();
                var MinimalLot        = MySymbolConf.Filters.OfType <BinanceSymbolLotSizeFilter>().FirstOrDefault();
                var minNotionalFilter = MySymbolConf.Filters.OfType <BinanceSymbolMinNotionalFilter>().SingleOrDefault();

                var PriceSize = MySymbolConf.Filters.OfType <BinanceSymbolPriceFilter>().FirstOrDefault();

                var AdjustedPrice   = BinanceHelpers.ClampPrice(PriceSize.MinPrice, PriceSize.MaxPrice, PriceSize.TickSize, pivotalbuy);
                var AdjustedLotSize = (MinimalLot.MinQuantity / BinanceHelpers.ClampQuantity(MinimalLot.MinQuantity, MinimalLot.MaxQuantity, MinimalLot.StepSize, _quantity));

                while ((_quantity - MinimalLot.MinQuantity) % MinimalLot.StepSize != 0)
                {
                    _quantity += MinimalLot.StepSize;
                }
                var test = (_quantity - MinimalLot.MinQuantity) % MinimalLot.StepSize == 0;

                while ((_quantity * AdjustedPrice) < minNotionalFilter.MinNotional)
                {
                    _quantity += MinimalLot.StepSize;
                }

                var cost = AdjustedLotSize * AdjustedPrice;
                if (TypeOforder == OrderType.Limit)
                {
                    var result = this.Service.Client.PlaceOrder(TargetPair, OrderSide.Sell, OrderType.Limit, timeInForce: TimeInForce.GoodTillCancel, quantity: _quantity
                                                                , price: AdjustedPrice);
                    if (!result.Success)
                    {
                    }
                    else
                    {
                        bool checker = false;
                        int  pass    = 0;
                        while (!checker)
                        {
                            Console.WriteLine("Checking if order filled for pair - {0}", Pairs);
                            pass++;
                            if (pass > 60)
                            {
                                this.Service.Client.CancelOrder(TargetPair, result.Data.OrderId);
                                //this.Service.Client.PlaceOrder(TargetPair, OrderSide.Sell, OrderType.Market, timeInForce: TimeInForce.GoodTillCancel, quantity: _quantity);
                                checker = true;
                            }
                            var orderrslt = this.Service.Client.QueryOrder(TargetPair, result.Data.OrderId);
                            if (orderrslt.Data.Status == OrderStatus.Filled)
                            {
                                Console.WriteLine("Pair {0} - Sell Order passed test api : {1} at quantity {2} price {3} ", TargetPair, result.Success, _quantity, AdjustedPrice);
                                var SourceOrder  = this.ExecutedOrders.Find(y => y.OperationID == Operation);
                                var IndexOfOrder = this.ExecutedOrders.IndexOf(SourceOrder);
                                SourceOrder.Soldprice             = AdjustedPrice;
                                SourceOrder.State                 = OrderExecutionStatus.Submited;
                                SourceOrder.SellLinkedOrder       = result.Data;
                                this.ExecutedOrders[IndexOfOrder] = SourceOrder;

                                Console.WriteLine("Order filled");
                                checker = true;
                            }
                            System.Threading.Thread.Sleep(5000);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
            }
        }
Esempio n. 5
0
        public void Buy(IPair SourceCandle, string TargetPair, OrderType TypeOforder, Guid Operation, decimal _quantity = 0)
        {
            Console.WriteLine("Order Management starting for : {0}", TargetPair);
            try
            {
                var pivotalbuy        = SourceCandle.Candle.Close.ChangeType <decimal>();
                var MySymbolConf      = this.Pairs.Where(y => y.Name == TargetPair).First();
                var MinimalLot        = MySymbolConf.Filters.OfType <BinanceSymbolLotSizeFilter>().FirstOrDefault();
                var minNotionalFilter = MySymbolConf.Filters.OfType <BinanceSymbolMinNotionalFilter>().SingleOrDefault();

                var PriceSize = MySymbolConf.Filters.OfType <BinanceSymbolPriceFilter>().FirstOrDefault();

                var AdjustedPrice   = BinanceHelpers.ClampPrice(PriceSize.MinPrice, PriceSize.MaxPrice, PriceSize.TickSize, pivotalbuy);
                var AdjustedLotSize = (MinimalLot.MinQuantity / BinanceHelpers.ClampQuantity(MinimalLot.MinQuantity, MinimalLot.MaxQuantity, MinimalLot.StepSize, _quantity));

                while ((_quantity - MinimalLot.MinQuantity) % MinimalLot.StepSize != 0)
                {
                    _quantity += MinimalLot.StepSize;
                }
                var test = (_quantity - MinimalLot.MinQuantity) % MinimalLot.StepSize == 0;

                while ((_quantity * AdjustedPrice) < minNotionalFilter.MinNotional)
                {
                    _quantity += MinimalLot.StepSize;
                }

                var Trade = new TradeItem
                {
                    BoughtPrice = AdjustedPrice,
                    Soldprice   = 0m,
                    Symbol      = TargetPair,
                    OperationID = Operation,
                    State       = OrderExecutionStatus.Ready,
                };
                var DenyOperation = ExecutedOrders.Count() > 1 && ExecutedOrders.Where(y => y.OperationID == Operation).ToList().Count() > 1;
                if (TypeOforder == OrderType.Limit && !DenyOperation)
                {
                    var result = this.Service.Client.PlaceOrder(TargetPair, OrderSide.Buy, OrderType.Limit, timeInForce: TimeInForce.GoodTillCancel, quantity: _quantity
                                                                , price: AdjustedPrice);
                    ExecutedOrders.Add(Trade);
                    if (!result.Success)
                    {
                        Console.WriteLine("Order not filled due to : {0}", result.Error.Message);
                        ExecutedOrders.Where(y => y.OperationID == Operation).First().State = OrderExecutionStatus.Error;
                    }
                    else
                    {
                        bool checker = false;
                        int  pass    = 0;
                        //Update order price
                        ExecutedOrders.Where(y => y.OperationID == Operation).First().BuyLinkedOrder = result.Data;
                        ExecutedOrders.Where(y => y.OperationID == Operation).First().BoughtPrice    = AdjustedPrice;
                        ExecutedOrders.Where(y => y.OperationID == Operation).First().OrderID        = result.Data.OrderId;
                        ExecutedOrders.Where(y => y.OperationID == Operation).First().State          = OrderExecutionStatus.Submited;
                        while (!checker)
                        {
                            ExecutedOrders.Where(y => y.OperationID == Operation).First().State = OrderExecutionStatus.Waiting;
                            pass++;
                            if (pass > 60)
                            {
                                this.Service.Client.CancelOrder(TargetPair, result.Data.OrderId);
                                ExecutedOrders.Where(y => y.OperationID == Operation).First().State = OrderExecutionStatus.Error;
                                checker = true;
                            }
                            Console.WriteLine("Checking if order filled for pair - {0}", Pairs);
                            var orderrslt = this.Service.Client.QueryOrder(TargetPair, result.Data.OrderId);
                            if (orderrslt.Data.Status == OrderStatus.Filled)
                            {
                                ExecutedOrders.Where(y => y.OperationID == Operation).First().State = OrderExecutionStatus.Filled;
                                Console.WriteLine("Pair {0} - Buy Order passed : {1} at quantity {2} price {3} ", TargetPair, result.Success, _quantity, AdjustedPrice);
                                Console.WriteLine("Order filled");
                                checker = true;
                            }
                            System.Threading.Thread.Sleep(5000);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
            }
        }
Esempio n. 6
0
        public IRuleResult RuleExecuted(Solbot solbot)
        {
            var result  = false;
            var message = string.Empty;

            if (solbot.Communication.Sell.IsReady)
            {
                var quantity = BinanceHelpers.ClampQuantity(solbot.Communication.Symbol.MinQuantity, solbot.Communication.Symbol.MaxQuantity, solbot.Communication.Symbol.BasePrecision, solbot.Communication.AvailableAsset.Base);

                var sellOrderResult = _kucoinClient.PlaceOrder(
                    solbot.Strategy.AvailableStrategy.Symbol,
                    Kucoin.Net.Objects.KucoinOrderSide.Sell,
                    Kucoin.Net.Objects.KucoinNewOrderType.Market,
                    quantity: quantity);

                if (!(sellOrderResult is null))
                {
                    result = sellOrderResult.Success;

                    if (sellOrderResult.Success)
                    {
                        Logger.Info(LogGenerator.TradeResultStart(sellOrderResult.Data.OrderId));

                        var order = _kucoinClient.GetOrder(sellOrderResult.Data.OrderId);

                        if (!(order is null))
                        {
                            if (order.Success)
                            {
                                Logger.Info(LogGenerator.TradeResultStart(order.Data.ClientOrderId));

                                if (order.Data.DealQuantity != 0)
                                {
                                    var price = (order.Data.Funds / order.Data.DealQuantity).ToKucoinRound();
                                    Logger.Info(LogGenerator.TradeResultKucoin(MarketOrder, order.Data, price));

                                    solbot.Actions.BoughtPrice = price;
                                }

                                Logger.Info(LogGenerator.TradeResultEndKucoin(order.Data.ClientOrderId));
                            }
                            else
                            {
                                Logger.Warn(order.Error.Message);
                            }
                        }

                        solbot.Actions.BoughtPrice = 0;

                        Logger.Info(LogGenerator.TradeResultEndKucoin(sellOrderResult.Data.OrderId));

                        _pushOverNotificationService.Send(
                            LogGenerator.NotificationTitle(EnvironmentType.PRODUCTION, MarketOrder, solbot.Strategy.AvailableStrategy.Symbol),
                            LogGenerator.NotificationMessage(
                                solbot.Communication.Average.Current,
                                solbot.Communication.Price.Current,
                                solbot.Communication.Sell.Change));
                    }
                    else
                    {
                        Logger.Warn(sellOrderResult.Error.Message);
                    }
                }
                else
                {
                    Logger.Warn(sellOrderResult.Error.Message);
                }
            }