protected override async Task DoWork(PairConfig pair, CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { try { using (BinanceSocketClient client = new BinanceSocketClient()) { CallResult <UpdateSubscription> res = client.SubscribeToBookTickerUpdates(pair.Symbol, async(data) => { Book book = new Book(); book.ExchangeCode = Exchange.Code; book.Symbol = data.Symbol; book.BestAskPrice = data.BestAskPrice; book.BestAskQuantity = data.BestAskQuantity; book.BestBidPrice = data.BestBidPrice; book.BestBidQuantity = data.BestBidQuantity; await _bookProcessor.Create(book); }); res.Data.ConnectionLost += () => { _logger.LogError($"Connection to {Exchange} is lost"); }; res.Data.ConnectionRestored += (data) => { _logger.LogError($"Connection to {Exchange} is Restored"); }; while (!stoppingToken.IsCancellationRequested) { } } } catch (Exception ex) { _logger.LogError($"{Exchange.Description} Trades service failed with message {ex.Message}", ex); } } }
public Task <PairConfig> Update(PairConfig entity) { return(WithConnection((connection, transaction) => { return _pairConfigManager.Update(entity, connection, transaction); })); }
protected override async Task DoWork(PairConfig config, CancellationToken stoppingToken) { _logger.LogTrace($"{Exchange.Description} Candles monitor is started"); while (!stoppingToken.IsCancellationRequested) { try { using (BinanceClient client = new BinanceClient()) { DateTime now = DateTime.UtcNow; IPeriodCode candlePeriod = config.Timeframe.HasValue ? PeriodCode.Create(config.Timeframe.Value) : DefaultCandleInterval; WebCallResult <IEnumerable <BinanceKline> > klines = client.GetKlines(config.Symbol, candlePeriod.ToPeriodCode(), now.AddDays(-30), now, 500); _logger.LogTrace($"Received candles from {Exchange.Description}"); List <Candle> candles = klines.Data.Select(x => x.ToCandle(config.Symbol, candlePeriod)).ToList(); foreach (Candle candle in candles) { await _candleProcessor.Create(candle); } } await Task.Delay(TimeSpan.FromHours(1)); } catch (Exception ex) { _logger.LogError($"{Exchange.Description} Candles service failed with message: {ex.Message}", ex); } } }
public Task <Deal> Sell(TradingForecast forecast, PairConfig config) { return(WithConnection(async(connection, transaction) => { Book book = await _bookManager.GetLast(forecast.ExchangeCode, forecast.Symbol, connection, transaction); Balance balance = await _balanceManager.Get(config.AssetOne, forecast.ExchangeCode, connection, transaction); Order order = new Order(); order.ExchangeCode = forecast.ExchangeCode; order.Symbol = forecast.Symbol; order.TradingModeCode = TradingModeCode.AUTO; order.FillPoliticsCode = FillPoliticsCode.GTC; order.OrderStatusCode = OrderStatusCode.PENDING; order.OrderTypeCode = OrderTypeCode.LMT; order.OrderSideCode = OrderSideCode.SELL; decimal availableQuantity = (balance.Available <= config.MaxOrderAmount.Value / book.BestBidPrice ? balance.Available : balance.Available / book.BestBidPrice); if (availableQuantity < config.MinOrderAmount.Value / book.BestBidPrice) { throw new Exception($"Not enough funds. Exchange code: {forecast.ExchangeCode}, Asset: {config.AssetTwo}"); } decimal quantity = Math.Round(availableQuantity, 3); order.Price = book.BestBidPrice; order.Amount = quantity; Deal deal = await _dealProcessor.CreateForOrder(order); return deal; })); }
public void SetBoolean() { var config = new PairConfig(); object ob = true; config.SetField("is load", ob); Assert.That(config.ShouldLoad, Is.True); }
public async Task <Deal> UpdateForOrder(Order order, PairConfig config) { if (!order.DealId.HasValue) { return(null); } return(await WithConnection(async (connection, transaction) => { Deal deal = await _dealManager.Get(order.DealId.Value, connection, transaction); if (deal == null) { throw new Exception($"Deal {order.DealId} not found"); } Order storedOrder = await _orderManager.Update(order, connection, transaction); if (order.OrderSideCode == OrderSideCode.BUY.Code) { deal.AvgOpenPrice = order.Price; deal.Amount = order.Amount; deal.EstimatedFee = order.Fee *order.Price; deal.TakeProfit = order.Price + order.Price * (decimal)config.DefaultTakeProfitPercent / 100; deal.StopLoss = order.Price - order.Price * (decimal)config.DefaultStopLossPercent / 100; if (order.TradingModeCode == TradingModeCode.AUTO.Code) { Order sellOrder = new Order(); sellOrder.ExchangeCode = deal.Exchange; sellOrder.Symbol = deal.Symbol; sellOrder.TradingModeCode = TradingModeCode.AUTO.Code; sellOrder.FillPoliticsCode = FillPoliticsCode.GTC.Code; sellOrder.OrderStatusCode = OrderStatusCode.PENDING.Code; sellOrder.DealId = deal.Id; sellOrder.OrderTypeCode = OrderTypeCode.LMT.Code; sellOrder.OrderSideCode = OrderSideCode.SELL.Code; sellOrder.Amount = deal.Amount; sellOrder.Price = deal.TakeProfit; sellOrder.StopLoss = deal.StopLoss; await _orderManager.Create(order, connection, transaction); } } else { deal.AvgClosePrice = order.Price; deal.EstimatedFee += order.Fee; deal.StatusCode = OrderStatusCode.Create(order.OrderStatusCode).ToDealCode().Code; } deal = await _dealManager.Update(deal, connection, transaction); deal.Orders.Add(storedOrder); return deal; })); }
public async Task StopLoss(Trade trade, PairConfig config) { await WithConnection(async (connection, transaction) => { IExchangeCode exchangeCode = ExchangeCode.Create(trade.ExchangeCode); IEnumerable <Deal> deals = await _dealManager.GetOpenDeals(trade.ExchangeCode, trade.Symbol, connection, transaction); foreach (Deal deal in deals) { deal.Orders = await _orderManager.GetOrdersByDealId(deal.Id, connection, transaction) as List <Order>; if (deal.StopLoss.HasValue && trade.Price < deal.StopLoss.Value) { foreach (Order dealOrder in deal.Orders) { if (dealOrder.OrderStatusCode == OrderStatusCode.PENDING.Code || dealOrder.OrderStatusCode == OrderStatusCode.EXPIRED.Code || dealOrder.OrderStatusCode == OrderStatusCode.HOLD.Code) { await _orderManager.Delete(dealOrder.Id, connection, transaction); } else if (dealOrder.OrderStatusCode == OrderStatusCode.LISTED.Code) { dealOrder.OrderStatusCode = OrderStatusCode.CANCELED.Code; dealOrder.Updated = DateTime.UtcNow; dealOrder.UpdateRequired = true; await _orderManager.Update(dealOrder, connection, transaction); NatsClient client = _connector.Client; await client.PubAsJsonAsync(_settings.Value.OrdersQueueName, new Notification <Order>() { Code = ActionCode.UPDATED.Code, Payload = dealOrder }); } } Order order = new Order(); order.ExchangeCode = trade.ExchangeCode; order.Symbol = trade.Symbol; order.TradingModeCode = TradingModeCode.AUTO; order.FillPoliticsCode = FillPoliticsCode.GTC; order.OrderStatusCode = OrderStatusCode.PENDING; order.DealId = deal.Id; order.OrderTypeCode = OrderTypeCode.MKT; order.OrderSideCode = OrderSideCode.SELL; order.Amount = deal.Amount; order.Id = await _orderManager.Create(order, connection, transaction); } } return(Task.CompletedTask); }); }
protected override async Task DoWork(PairConfig pair, CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { try { using (BinanceSocketClient client = new BinanceSocketClient()) { ConnectionInfo cnInfo = new ConnectionInfo(_settings.Value.BusConnectionString); using (NatsClient natsClient = new NatsClient(cnInfo)) { if (!natsClient.IsConnected) { natsClient.Connect(); } CallResult <UpdateSubscription> successKline = null; successKline = client.SubscribeToTradeUpdates(pair.Symbol, async(data) => { Trade trade = data.ToEntity(); if (!_settings.Value.DisadleDealsSaving) { long id = await _tradesProcessor.Create(trade); } await natsClient.PubAsJsonAsync(_settings.Value.TradesQueueName, new Notification <Trade>() { Code = ActionCode.CREATED.Code, Payload = trade }); }); successKline.Data.ConnectionLost += () => { _logger.LogError($"Connection to {Exchange} is lost"); }; successKline.Data.ConnectionRestored += (data) => { _logger.LogError($"Connection to {Exchange} is Restored"); }; while (!stoppingToken.IsCancellationRequested) { } natsClient.Disconnect(); await client.Unsubscribe(successKline.Data); } } } catch (Exception ex) { _logger.LogError($"{Exchange.Description} Trades service failed with message {ex.Message}", ex); } } }
protected override async Task DoWork(PairConfig pair, CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { try { await _tradesProcessor.ClearData(Exchange.Code, pair.Symbol); await _bookProcessor.ClearData(Exchange.Code, pair.Symbol); await Task.Delay(TimeSpan.FromHours(1)); } catch (Exception ex) { _logger.LogError($"{Exchange.Description} Trades service failed with message {ex.Message}", ex); } } }
private void CreatePair(Config config, string pair, IExchangeConfig client) { if (config.Pairs.ContainsKey(pair)) { return; } var newConfig = new PairConfig { PlatformVariables = new Dictionary <string, object>() }; if (client != null) { foreach (var pairVariable in client.PairVariables) { newConfig.PlatformVariables.Add(pairVariable.Key, pairVariable.Value); } } config.Pairs.Add(pair, newConfig); }
protected override async Task DoWork(PairConfig pair, CancellationToken stoppingToken) { _logger.LogInformation($"{Exchange.Description} Candles worker is started"); IPeriodCode candlePeriod = pair.Timeframe.HasValue ? PeriodCode.Create(pair.Timeframe.Value) : DefaultCandleInterval; while (!stoppingToken.IsCancellationRequested) { try { using (BinanceSocketClient client = new BinanceSocketClient()) { ConnectionInfo cnInfo = new ConnectionInfo(_settings.Value.BusConnectionString); using (NatsClient natsClient = new NatsClient(cnInfo)) { if (!natsClient.IsConnected) { natsClient.Connect(); } CallResult <UpdateSubscription> successKline = client.SubscribeToKlineUpdates(pair.Symbol, candlePeriod.ToPeriodCode(), async(data) => { await SaveCandle(data.Data, natsClient); }); successKline.Data.ConnectionLost += () => { _logger.LogError($"Connection to {Exchange} is lost"); }; successKline.Data.ConnectionRestored += (data) => { _logger.LogError($"Connection to {Exchange} is Restored"); }; while (!stoppingToken.IsCancellationRequested) { } natsClient.Disconnect(); await client.Unsubscribe(successKline.Data); } } } catch (Exception ex) { _logger.LogError($"{Exchange.Description} Candles service failed with message: {ex.Message}", ex); } } }
public async Task <PairConfig> Update(PairConfig entity, IDbConnection connection, IDbTransaction transaction = null) { string query = @"update PairConfigs set updated = @updated, isEnabled = @isEnabled, strategyId = @strategyId, refreshDelaySeconds = @refreshDelaySeconds, defaultStopLossPercent = @defaultStopLossPercent, defaultTakeProfitPercent = @defaultTakeProfitPercent, isTestMode = @isTestMode, exchangeFeeSell = @exchangeFeeSell, exchangeFeeBuy = @exchangeFeeBuy, tradingLockedTill = @tradingLockedTill, isMaxAmountPercent = @isMaxAmountPercent, maxOrderAmount = @maxOrderAmount where id = @id returning *;" ; return(await connection.QuerySingleAsync <PairConfig>(query, new { updated = DateTime.UtcNow, isEnabled = entity.IsEnabled, strategyId = entity.StrategyId, refreshDelaySeconds = entity.RefreshDelaySeconds, defaultStopLossPercent = entity.DefaultStopLossPercent, defaultTakeProfitPercent = entity.DefaultTakeProfitPercent, isTestMode = entity.IsTestMode, exchangeFeeSell = entity.ExchangeFeeSell, exchangeFeeBuy = entity.ExchangeFeeBuy, tradingLockedTill = entity.TradingLockedTill, minOrderAmount = entity.MinOrderAmount, maxOrderAmount = entity.MaxOrderAmount }, transaction)); }
public Task TakeProfit(Trade trade, PairConfig config) { throw new NotImplementedException(); }
protected abstract Task DoWork(PairConfig config, CancellationToken stoppingToken);
protected override async Task DoWork(PairConfig config, CancellationToken stoppingToken) { ExchangeConfig exchangeConfig = await _exchangeConfigProcessor.GetExchangeConfig(Exchange.Code); while (!stoppingToken.IsCancellationRequested) { try { string listenKey = String.Empty; using (BinanceClient client = new BinanceClient()) { listenKey = client.StartUserStream().Data; } using (BinanceSocketClient socketClient = new BinanceSocketClient()) { ConnectionInfo cnInfo = new ConnectionInfo(_settings.Value.BusConnectionString); using (NatsClient natsClient = new NatsClient(cnInfo)) { if (!natsClient.IsConnected) { natsClient.Connect(); } CallResult <UpdateSubscription> successAccount = socketClient.SubscribeToUserDataUpdates(listenKey, accountData => { }, async orderData => { Order order = orderData.ToOrder(); Deal deal = await _dealProcessor.UpdateForOrder(order, config); await natsClient.PubAsJsonAsync(_settings.Value.OrdersQueueName, new Notification <Deal>() { Code = ActionCode.UPDATED.Code, Payload = deal }); }, ocoOrderData => { }, async balancesData => { IEnumerable <Balance> balances = balancesData.Select(x => x.ToBalance()); foreach (Balance balance in balances) { await _balanceProcessor.UpdateOrCreate(balance); } }, onAccountBalanceUpdate => { }); while (!stoppingToken.IsCancellationRequested) { } natsClient.Disconnect(); await socketClient.UnsubscribeAll(); } } } catch (Exception ex) { _logger.LogError(ex.Message); } } }
public async Task <long> Create(PairConfig entity, IDbConnection connection, IDbTransaction transaction = null) { string query = @"insert into PairConfigs ( id, created, updated, isEnabled, isDeleted, exchangeCode, symbol, strategyId, refreshDelaySeconds, defaultStopLossPercent, defaultTakeProfitPercent, isTestMode, exchangeFeeSell, exchangeFeeBuy, tradingLockedTill, minOrderAmount, maxOrderAmount ) values ( default, @created, null, true, false, @exchangeCode, @symbol, @strategyId, @refreshDelaySeconds, @defaultStopLossPercent, @defaultTakeProfitPercent, @isTestMode, @exchangeFeeSell, @exchangeFeeBuy, @tradingLockedTill, @minOrderAmount, @maxOrderAmount ) returning id;" ; return(await connection.QuerySingleAsync <long>(query, new { created = DateTime.UtcNow, exchangeCode = entity.ExchangeCode, symbol = entity.Symbol, strategyId = entity.StrategyId, refreshDelaySeconds = entity.RefreshDelaySeconds, defaultStopLossPercent = entity.DefaultStopLossPercent, defaultTakeProfitPercent = entity.DefaultTakeProfitPercent, isTestMode = entity.IsTestMode, exchangeFeeSell = entity.ExchangeFeeSell, exchangeFeeBuy = entity.ExchangeFeeBuy, tradingLockedTill = entity.TradingLockedTill, maxOrderAmount = entity.MaxOrderAmount, minOrderAmount = entity.MinOrderAmount }, transaction)); }
public async Task <ExchangeOrder> Send(Order order, ExchangeConfig config) { ExchangeOrder exchangeOrder = null; PairConfig pairConfig = config.Pairs.FirstOrDefault(x => x.Symbol.Equals(order.Symbol)); if (order.UpdateRequired) { using (BinanceClient client = new BinanceClient(new BinanceClientOptions() { ApiCredentials = new ApiCredentials(config.ApiKey, config.ApiSecret) })) { if (order.OrderStatusCode == OrderStatusCode.PENDING) { (bool success, string error, BinancePlacedOrder order)result;; if (order.OrderTypeCode == OrderTypeCode.MKT.Code) { if (pairConfig.IsTestMode) { WebCallResult <BinancePlacedOrder> orderResult = await client.PlaceTestOrderAsync(order.Symbol, (OrderSide)order.OrderSideCode, OrderType.Market, order.Amount.Value, null, order.Id.ToString(), null, TimeInForce.GoodTillCancel); result = (orderResult.Success, orderResult.Error.Message, orderResult.Data); } else { WebCallResult <BinancePlacedOrder> orderResult = await client.PlaceOrderAsync(order.Symbol, (OrderSide)order.OrderSideCode, OrderType.Market, order.Amount.Value, null, order.Id.ToString(), null, TimeInForce.GoodTillCancel); result = (orderResult.Success, orderResult.Error.Message, orderResult.Data); } } else if (order.OrderTypeCode == OrderTypeCode.LMT.Code) { if (pairConfig.IsTestMode) { WebCallResult <BinancePlacedOrder> orderResult = await client.PlaceTestOrderAsync(order.Symbol, (OrderSide)order.OrderSideCode, OrderType.Limit, order.Amount.Value, null, order.Id.ToString(), order.Price, TimeInForce.GoodTillCancel); result = (orderResult.Success, orderResult.Error.Message, orderResult.Data); } else { WebCallResult <BinancePlacedOrder> orderResult = await client.PlaceOrderAsync(order.Symbol, (OrderSide)order.OrderSideCode, OrderType.Limit, order.Amount.Value, null, order.Id.ToString(), order.Price, TimeInForce.GoodTillCancel); result = (orderResult.Success, orderResult.Error.Message, orderResult.Data); } } else if (order.OrderTypeCode == OrderTypeCode.LST.Code) { if (pairConfig.IsTestMode) { // OCO Order can't be used in test mode WebCallResult <BinancePlacedOrder> orderResult = await client.PlaceTestOrderAsync(order.Symbol, (OrderSide)order.OrderSideCode, OrderType.Limit, order.Amount.Value, null, order.Id.ToString(), order.Price, TimeInForce.GoodTillCancel); result = (orderResult.Success, orderResult.Error.Message, orderResult.Data); } else { if (order.OrderSideCode == OrderSideCode.BUY.Code) { // For now let's use limit standard order WebCallResult <BinancePlacedOrder> orderResult = await client.PlaceOrderAsync(order.Symbol, OrderSide.Buy, OrderType.Limit, order.Amount.Value, null, order.Id.ToString(), order.Price, TimeInForce.GoodTillCancel); result = (orderResult.Success, orderResult.Error.Message, orderResult.Data); } else { WebCallResult <BinanceOrderList> orderResult = await client.PlaceOCOOrderAsync(order.Symbol, OrderSide.Sell, order.Amount.Value, order.Price.Value, order.StopLoss.Value); result = (orderResult.Success, orderResult.Error.Message, orderResult.Data.OrderReports.First()); } } } else { throw new Exception($"{order.Id} selected order type isn't supported"); } if (!result.success) { throw new Exception(result.error); } exchangeOrder = result.order.ToOrder(); _logger.LogInformation($"{Exchange.Description} - Order {order.Id} has been processed with status: {result.order.Status}"); } else if (order.OrderStatusCode == OrderStatusCode.CANCELED) { WebCallResult <BinanceCanceledOrder> cancelResult = await client.CancelOrderAsync(order.Symbol, order.ExchangeOrderId); if (!cancelResult.Success) { throw new Exception(cancelResult.Error.Message); } exchangeOrder = cancelResult.Data.ToOrder(); _logger.LogInformation($"{Exchange.Description} - Order {order.Id} has been processed with status: {cancelResult.Data.Status}"); } else { throw new Exception($"{Exchange.Description} - Can't update update order {order.Id}: wrong status"); } } } return(exchangeOrder); }