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);
        }
Esempio n. 2
0
        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}");
        }