public bool CanBuy(BuyOptions options, out string message) { IPairConfig pairConfig = GetPairConfig(options.Pair); if (!options.ManualOrder && !options.Swap && IsTradingSuspended) { message = $"Cancel buy request for {options.Pair}. Reason: trading suspended"; return(false); } else if (!options.ManualOrder && !options.Swap && !pairConfig.BuyEnabled) { message = $"Cancel buy request for {options.Pair}. Reason: buying not enabled"; return(false); } else if (!options.ManualOrder && Config.ExcludedPairs.Contains(options.Pair)) { message = $"Cancel buy request for {options.Pair}. Reason: exluded pair"; return(false); } else if (!options.ManualOrder && !options.IgnoreExisting && Account.HasTradingPair(options.Pair)) { message = $"Cancel buy request for {options.Pair}. Reason: pair already exists"; return(false); } else if (!options.ManualOrder && !options.Swap && Config.MaxPairs != 0 && Account.GetTradingPairs().Count() >= Config.MaxPairs && !Account.HasTradingPair(options.Pair)) { message = $"Cancel buy request for {options.Pair}. Reason: maximum pairs reached"; return(false); } else if (!options.ManualOrder && !options.Swap && pairConfig.BuyMinBalance != 0 && (Account.GetBalance() - options.MaxCost) < pairConfig.BuyMinBalance) { message = $"Cancel buy request for {options.Pair}. Reason: minimum balance reached"; return(false); } else if (GetCurrentPrice(options.Pair) <= 0) { message = $"Cancel buy request for {options.Pair}. Reason: invalid price"; return(false); } else if (Account.GetBalance() < options.MaxCost) { message = $"Cancel buy request for {options.Pair}. Reason: not enough balance"; return(false); } else if (options.Amount == null && options.MaxCost == null || options.Amount != null && options.MaxCost != null) { message = $"Cancel buy request for {options.Pair}. Reason: either max cost or amount needs to be specified (not both)"; } else if (!options.ManualOrder && !options.Swap && pairConfig.BuySamePairTimeout > 0 && OrderHistory.Any(h => h.Side == OrderSide.Buy && h.Pair == options.Pair) && (DateTimeOffset.Now - OrderHistory.Where(h => h.Pair == options.Pair).Max(h => h.Date)).TotalSeconds < pairConfig.BuySamePairTimeout) { var elapsedSeconds = (DateTimeOffset.Now - OrderHistory.Where(h => h.Pair == options.Pair).Max(h => h.Date)).TotalSeconds; message = $"Cancel buy request for {options.Pair}. Reason: buy same pair timeout (elapsed: {elapsedSeconds:0.#}, timeout: {pairConfig.BuySamePairTimeout:0.#})"; return(false); } message = null; return(true); }