public async Task <IReadOnlyList <YesterdayCandleData> > GetStocks(CancellationToken ct) { Console.WriteLine("START SEARCHING"); var allStocks = await _contextProvider.Do(ctx => ctx.MarketStocksAsync(), ct); ct.ThrowIfCancellationRequested(); var acceptable = new List <YesterdayCandleData>(); var meetAmount = 0; foreach (var stock in allStocks.Instruments) { CandlePayload?candle = await MeetRequirements(stock, ct).ConfigureAwait(false); if (candle != null) { var data = YesterdayCandleData.Create(stock, candle); acceptable.Add(data); Console.WriteLine(data); meetAmount++; } } Console.WriteLine($"Meet: {meetAmount}/{allStocks.Instruments.Count}"); var topVolumes = PossibleVariants(acceptable); LogTopVolumes(topVolumes); return(topVolumes); }
private async Task Loop() { _state = _stateStorage.LastState(); _followers = _state .Stocks .Select(it => new StockFollower(it.CandleData, _contextProvider, _state.Orders.Add, it.Status)) .ToList(); while (true) { Console.WriteLine($"LOOP START {_timeProvider.Now}"); var lastLoopDate = _state.Time.Date; _state.Time = _timeProvider.Now; if (lastLoopDate < _timeProvider.Today) { _state.DayChanges++; var savedFollowers = _followers .Where(it => it.Status is WaitingForSell) .ToList(); var stocks = await _stocksProvider.GetStocks(_cancellationTokenSource.Token); _followers = stocks .Select(it => new StockFollower(it, _contextProvider, _state.Orders.Add)) .ToList(); _followers.AddRange(savedFollowers); _state.Stocks = _followers.Select(it => new FollowingStock(it.Stock, it.Status)).ToList(); } if (_followers.Count == 0 && _state.Time.Date == _timeProvider.Today) { var tomorrow = _timeProvider.Today.Add(TimeSpan.FromDays(1)); var waiting = tomorrow - _timeProvider.Now + TimeSpan.FromMinutes(5); Console.WriteLine($"GO SLEEPING FOR {waiting}"); await Task.Delay(waiting, _cancellationTokenSource.Token); Console.WriteLine("WAKE UP"); } foreach (var follower in _followers) { await follower.Perform(_timeProvider.Now, _cancellationTokenSource.Token); } _state.Stocks = _followers.Select(it => new FollowingStock(it.Stock, it.Status)).ToList(); _stateStorage.AddState(_state); _timeProvider.SaveTime(); await _contextProvider.Do(it => _state.Dump(it, _cancellationTokenSource.Token)); _followers.RemoveAll(it => it.Status is Closed); } }
public async Task Perform(DateTime time, CancellationToken ct) { Console.WriteLine($"PERFORM START {Stock} at {time}"); var candles = await _contextProvider.Do(ctx => ctx.MarketCandlesAsync(Stock.Figi, time.Subtract(TimeSpan.FromMinutes(20)), time, CandleInterval.Minute), ct); ct.ThrowIfCancellationRequested(); CandlePayload?candle = candles.Candles.LastOrDefault(); candle.Dump(); bool IsBuyStop() => candle != null && (Stock.Close - candle.Close >= Stock.Tick * 20); switch (Status) { case Init _: { if (IsBuyStop()) { Status = new BuyStop(); } else if (candle != null) { Status = new WaitingForBuy(); } } break; case WaitingForBuy _: { if (candle == null) { Status = new Closed(); } else if (IsBuyStop()) { Status = new BuyStop(); } } break; case BuyStop _: { if (candle == null) { Status = new Closed(); } else if (candle.Close > Stock.Close) { PlacedMarketOrder order = await _contextProvider.Do(ctx => ctx.PlaceMarketOrderAsync( new MarketOrder(Stock.Figi, 1, OperationType.Buy) ), ct); ct.ThrowIfCancellationRequested(); order.Dump(); _addOrder(new PlacedOrder(order, Stock.Name, time, candle.Close)); if (order.Status == OrderStatus.Rejected) { Console.WriteLine($"Buy order rejected: {order.RejectReason}"); break; } Status = new WaitingForSell { SellPrice = candle.Close - Stock.Half(), TakeProfit = candle.Close + Stock.Part(60M) }; } } break; case WaitingForSell status: { if (candle == null) { break; } var possiblyNewStop = candle.Close - Stock.Half(); if (possiblyNewStop > status.SellPrice) { status.SellPrice = possiblyNewStop; Console.WriteLine("Limit became higher"); } if (candle.Close <= status.SellPrice || candle.Close >= status.TakeProfit && status.TakeProfit != default) { var position = (await _contextProvider.Do(c => c.PortfolioAsync())) .Positions .FirstOrDefault(it => it.Figi == candle.Figi); if (position != null) { var closeOrder = await _contextProvider.Do(ctx => ctx.PlaceMarketOrderAsync( new MarketOrder(Stock.Figi, 1, OperationType.Sell) ), ct); ct.ThrowIfCancellationRequested(); closeOrder.Dump(); _addOrder(new PlacedOrder(closeOrder, Stock.Name, time, candle.Close)); if (closeOrder.Status == OrderStatus.Rejected) { Console.WriteLine($"Sell order rejected: {closeOrder.RejectReason}"); break; } } Status = new Closed(); } } break; } Console.WriteLine($"STATUS: {Status}"); }