public async Task Sell(IStockModel stock, string reason) { if (!Trades.ContainsKey(stock)) { return; } Trades.TryRemove(stock, out TradeInfo info); try { UpdateBalance(info, OperationType.Sell); _telegram.PostMessage($"Продажа {info.Lots} акций {stock.Ticker} по рыночной цене (примерно {info.CurrentPrice.FormatPrice(stock.Currency)}): {reason}" + $"\r\nЦена покупки: {info.InitialPrice.FormatPrice(stock.Currency)} Цена продажи: {info.CurrentPrice.FormatPrice(stock.Currency)}\r\n" + $"Profit: {info.Profit.FormatPrice(stock.Currency)}", stock.Ticker); //await MakeOrder(stock.Figi, info.Lots, OperationType.Sell); _archivedTrades.Add(info); //await Task.Delay(1000); } catch (Exception ex) { _telegram.PostMessage(ex.Message, null); _failedTrades.Add(info); return; } await ReportBalances(); }
public async Task <bool> CheckMonthStatsAsync(IStockModel stock, CancellationToken token = default(CancellationToken)) { if (stock.MonthStatsExpired) { lock (stock) { if (!_monthStatsQueue.Contains(stock)) { _monthStatsQueue.Enqueue(stock); } } while (stock.MonthStatsExpired && !token.IsCancellationRequested) { await Task.Delay(100, token); } if (token.IsCancellationRequested) { return(false); } } return(true); }
public async Task Check(IStockModel stock) { if (Trades.TryGetValue(stock, out var info)) { info.CurrentPrice = stock.Price; info.MaxPrice = Math.Max(info.MaxPrice, info.CurrentPrice); var changeFromInitial = (info.CurrentPrice - info.InitialPrice) / info.InitialPrice; if (changeFromInitial > 0.1m) { info.TenPercentRaised = true; } decimal sellPrice = Math.Round(info.MaxPrice * 0.97m, 2); if (info.TenPercentRaised && sellPrice > info.CurrentPrice) { await Sell(stock, $"Цена достигла максимума в размере {info.MaxPrice}, после чего снизилась на 3%." + $"\r\nИзменение с момента покупки составило {changeFromInitial:P2}"); } else if (info.CurrentPrice < info.StopLoss) { await Sell(stock, $"Stop Loss triggered at {changeFromInitial:P2} change."); } else if (changeFromInitial > 0.2m) { await Sell(stock, $"Цена выросла на {changeFromInitial:P2} с момента покупки. Фиксация прибыли."); } } }
private void EnqueueStockForMonthStatsIfExpired(IStockModel stock) { if (stock.MonthStatsExpired) { lock (stock) { if (stock.MonthStatsExpired && !_monthStatsQueue.Contains(stock)) { _monthStatsQueue.Enqueue(stock); } } } }
public async Task Buy(IStockModel stock) { if (Trades.ContainsKey(stock)) { return; } //await UpdateCurrenciesAsync(); decimal price = stock.Price; decimal balance = _currencies[stock.Currency.ToUpper()].Balance; int lots = (int)(balance * 0.2m / price); var tradeInfo = new TradeInfo { Stock = stock, InitialPrice = price, MaxPrice = price, StopLoss = price * 0.9m, Lots = lots }; try { _telegram.PostMessage($"Покупка {lots} акций {stock.Ticker} по рыночной цене (примерно {price.FormatPrice(stock.Currency)})", null); //await MakeOrder(stock.Figi, lots, OperationType.Buy); UpdateBalance(tradeInfo, OperationType.Buy); //await Task.Delay(1000); } catch (Exception ex) { _telegram.PostMessage(ex.Message, null); _failedTrades.Add(tradeInfo); return; } Trades[stock] = tradeInfo; await ReportBalances(); }
public StockModelController(IStockModel repository) { _repository = repository; }
public StockController(IStockModel _stockModel) { stockModel = _stockModel; }
public StockController(IStockModel stockModel) { _stockModel = stockModel; }
public async Task <IActionResult> Post(IStockModel stockModel) { await _hubContext.Clients.All.SendAsync("stock", stockModel); return(Ok()); }
public virtual async Task OnStockUpdated(IStockModel stock) { await _eventAggregator.PublishOnCurrentThreadAsync(stock); }
public static string GetDayChangeInfoText(this IStockModel s) { return(@$ " `{s.Ticker}` {s.TodayDate.ToLocalTime():ddd, dd.MM.yy, H:mm:ss} → {s.LastUpdate:H:mm:ss} *{s.Ticker}* *({s.Name})*
private async Task <bool> GetMonthStats(IStockModel stock) { if (!stock.MonthStatsExpired) { return(true); } _apiCount++; //Debug.WriteLine($"API Request {++_apiCount} for {stock.Ticker} {stock.PriceF} {stock.DayChangeF} {DateTime.Now}"); CandleList prices = null; try { prices = await CommonConnection.Context.MarketCandlesAsync(stock.Figi, DateTime.Now.Date.AddMonths(-1), DateTime.Now.Date.AddDays(1), CandleInterval.Day); stock.LastMonthDataUpdate = DateTime.Now; } catch { return(false); } if (prices.Candles.Count == 0) { return(false); } decimal monthVolume = 0, monthHigh = 0, monthLow = 0, monthAvgPrice = 0, avgDayVolumePerMonth = 0, avgDayPricePerMonth = 0, monthOpen = -1, yesterdayVolume = 0, yesterdayMin = 0, yesterdayMax = 0, yesterdayAvgPrice = 0; var todayCandle = prices.Candles[prices.Candles.Count - 1]; foreach (var candle in prices.Candles) { if (monthOpen == -1) { monthOpen = candle.Open; } monthLow = monthLow == 0 ? candle.Low : Math.Min(monthLow, candle.Low); monthHigh = monthHigh == 0 ? candle.High : Math.Min(monthHigh, candle.High); monthVolume += candle.Volume; avgDayPricePerMonth += (candle.High + candle.Low) / 2; yesterdayVolume = candle.Volume; yesterdayMin = candle.Low; yesterdayMax = candle.High; AddCandleToStock(Tuple.Create(stock, candle)); } monthAvgPrice = (monthLow + monthHigh) / 2; yesterdayAvgPrice = (yesterdayMin + yesterdayMax) / 2; avgDayPricePerMonth /= prices.Candles.Count; avgDayVolumePerMonth = monthVolume / prices.Candles.Count; stock.MonthOpen = monthOpen; stock.MonthHigh = monthHigh; stock.MonthLow = monthLow; stock.MonthVolume = monthVolume; stock.MonthVolumeCost = monthVolume * monthAvgPrice * stock.Lot; stock.AvgDayVolumePerMonth = Math.Round(avgDayVolumePerMonth); stock.AvgDayPricePerMonth = avgDayPricePerMonth; stock.AvgDayVolumePerMonthCost = avgDayPricePerMonth * avgDayVolumePerMonth * stock.Lot; stock.DayVolChgOfAvg = stock.DayVolume / stock.AvgDayVolumePerMonth; stock.YesterdayAvgPrice = yesterdayAvgPrice; stock.YesterdayVolume = yesterdayVolume; stock.YesterdayVolumeCost = yesterdayVolume * yesterdayAvgPrice * stock.Lot; return(true); }